#2014 Add support for mapping from Java 14 records

This commit is contained in:
Filip Hrisafov 2020-02-22 17:51:10 +01:00
parent 273487f152
commit f5771c4177
10 changed files with 264 additions and 1 deletions

View File

@ -14,6 +14,9 @@ matrix:
- jdk: openjdk13
# There is an issue with the documentation so skip it
script: mvn -B -V clean install -DskipDistribution=true
- jdk: openjdk14
# There is an issue with the documentation so skip it
script: mvn -B -V clean install -DskipDistribution=true
# There is an issue with the documentation so skip it
- jdk: openjdk-ea
script: mvn -B -V clean install -DskipDistribution=true

View File

@ -5,6 +5,8 @@
*/
package org.mapstruct.itest.tests;
import org.junit.jupiter.api.condition.EnabledForJreRange;
import org.junit.jupiter.api.condition.JRE;
import org.junit.jupiter.api.parallel.Execution;
import org.junit.jupiter.api.parallel.ExecutionMode;
import org.mapstruct.itest.testutil.extension.ProcessorTest;
@ -99,6 +101,13 @@ public class MavenIntegrationTest {
void protobufBuilderTest() {
}
@ProcessorTest(baseDir = "recordsTest", processorTypes = {
ProcessorTest.ProcessorType.JAVAC
})
@EnabledForJreRange(min = JRE.JAVA_14)
void recordsTest() {
}
@ProcessorTest(baseDir = "simpleTest")
void simpleTest() {
}

View File

@ -0,0 +1,102 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright MapStruct Authors.
Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-it-parent</artifactId>
<version>1.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>recordsTest</artifactId>
<packaging>jar</packaging>
<profiles>
<profile>
<id>generate-via-compiler-plugin</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<compilerArgument
combine.self="override"></compilerArgument>
<compilerId>\${compiler-id}</compilerId>
<compilerArgs>--enable-preview</compilerArgs>
</configuration>
<dependencies>
<dependency>
<groupId>org.eclipse.tycho</groupId>
<artifactId>tycho-compiler-jdt</artifactId>
<version>${org.eclipse.tycho.compiler-jdt.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
</profile>
<profile>
<id>debug-forked-javac</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<executions>
<execution>
<id>default-compile</id>
<configuration>
<fork>true</fork>
<compilerArgs>
<arg>--enable-preview</arg>
<arg>-J-Xdebug</arg>
<arg>-J-Xnoagent</arg>
<arg>-J-Djava.compiler=NONE</arg>
<arg>-J-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000</arg>
</compilerArgs>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<forkCount>1</forkCount>
<argLine>--enable-preview</argLine>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,13 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.itest.records;
/**
* @author Filip Hrisafov
*/
public record CustomerDto(String name, String email) {
}

View File

@ -0,0 +1,31 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.itest.records;
/**
* @author Filip Hrisafov
*/
public class CustomerEntity {
private String name;
private String mail;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getMail() {
return mail;
}
public void setMail(String mail) {
this.mail = mail;
}
}

View File

@ -0,0 +1,23 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.itest.records;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
/**
* @author Filip Hrisafov
*/
@Mapper
public interface CustomerMapper {
CustomerMapper INSTANCE = Mappers.getMapper( CustomerMapper.class );
@Mapping(target = "mail", source = "email")
CustomerEntity fromRecord(CustomerDto record);
}

View File

@ -0,0 +1,25 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.itest.records;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Test;
import org.mapstruct.itest.records.CustomerDto;
import org.mapstruct.itest.records.CustomerEntity;
import org.mapstruct.itest.records.CustomerMapper;
public class RecordsTest {
@Test
public void shouldMapRecord() {
CustomerEntity customer = CustomerMapper.INSTANCE.fromRecord( new CustomerDto( "Kermit", "kermit@test.com" ) );
assertThat( customer ).isNotNull();
assertThat( customer.getName() ).isEqualTo( "Kermit" );
assertThat( customer.getMail() ).isEqualTo( "kermit@test.com" );
}
}

View File

@ -510,7 +510,7 @@
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.3</version>
<version>0.8.5</version>
</plugin>
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>

View File

@ -498,6 +498,11 @@ public class Type extends ModelElement implements Comparable<Type> {
}
}
Map<String, Accessor> recordAccessors = filters.recordsIn( typeElement );
for ( Map.Entry<String, Accessor> recordEntry : recordAccessors.entrySet() ) {
modifiableGetters.putIfAbsent( recordEntry.getKey(), recordEntry.getValue() );
}
List<Accessor> fieldsList = filters.fieldsIn( getAllFields() );
for ( Accessor field : fieldsList ) {
String propertyName = getPropertyName( field );

View File

@ -5,11 +5,16 @@
*/
package org.mapstruct.ap.internal.util;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.ExecutableType;
@ -30,9 +35,29 @@ import static org.mapstruct.ap.internal.util.accessor.AccessorType.SETTER;
* Filter methods for working with {@link Element} collections.
*
* @author Gunnar Morling
* @author Filip Hrisafov
*/
public class Filters {
private static final Method RECORD_COMPONENTS_METHOD;
private static final Method RECORD_COMPONENT_ACCESSOR_METHOD;
static {
Method recordComponentsMethod;
Method recordComponentAccessorMethod;
try {
recordComponentsMethod = TypeElement.class.getMethod( "getRecordComponents" );
recordComponentAccessorMethod = Class.forName( "javax.lang.model.element.RecordComponentElement" )
.getMethod( "getAccessor" );
}
catch ( NoSuchMethodException | ClassNotFoundException e ) {
recordComponentsMethod = null;
recordComponentAccessorMethod = null;
}
RECORD_COMPONENTS_METHOD = recordComponentsMethod;
RECORD_COMPONENT_ACCESSOR_METHOD = recordComponentAccessorMethod;
}
private final AccessorNamingUtils accessorNaming;
private final Types typeUtils;
private final TypeMirror typeMirror;
@ -50,6 +75,33 @@ public class Filters {
.collect( Collectors.toCollection( LinkedList::new ) );
}
public Map<String, Accessor> recordsIn(TypeElement typeElement) {
if ( RECORD_COMPONENTS_METHOD == null || RECORD_COMPONENT_ACCESSOR_METHOD == null ) {
return java.util.Collections.emptyMap();
}
try {
@SuppressWarnings("unchecked")
List<Element> recordComponents = (List<Element>) RECORD_COMPONENTS_METHOD.invoke( typeElement );
Map<String, Accessor> recordAccessors = new LinkedHashMap<>();
for ( Element recordComponent : recordComponents ) {
ExecutableElement recordExecutableElement =
(ExecutableElement) RECORD_COMPONENT_ACCESSOR_METHOD.invoke( recordComponent );
recordAccessors.put(
recordComponent.getSimpleName().toString(),
new ExecutableElementAccessor( recordExecutableElement,
getReturnType( recordExecutableElement ),
GETTER
)
);
}
return recordAccessors;
}
catch ( IllegalAccessException | InvocationTargetException e ) {
return java.util.Collections.emptyMap();
}
}
private TypeMirror getReturnType(ExecutableElement executableElement) {
return getWithinContext( executableElement ).getReturnType();
}