mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#3661 Use correct type for the Record component read accessors
This commit is contained in:
parent
12c9c6c1f0
commit
2686e852b6
@ -131,6 +131,13 @@ public class MavenIntegrationTest {
|
|||||||
void recordsCrossModuleTest() {
|
void recordsCrossModuleTest() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ProcessorTest(baseDir = "recordsCrossModuleInterfaceTest", processorTypes = {
|
||||||
|
ProcessorTest.ProcessorType.JAVAC
|
||||||
|
})
|
||||||
|
@EnabledForJreRange(min = JRE.JAVA_17)
|
||||||
|
void recordsCrossModuleInterfaceTest() {
|
||||||
|
}
|
||||||
|
|
||||||
@ProcessorTest(baseDir = "expressionTextBlocksTest", processorTypes = {
|
@ProcessorTest(baseDir = "expressionTextBlocksTest", processorTypes = {
|
||||||
ProcessorTest.ProcessorType.JAVAC
|
ProcessorTest.ProcessorType.JAVAC
|
||||||
})
|
})
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
<?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>
|
||||||
|
<artifactId>recordsCrossModuleInterfaceTest</artifactId>
|
||||||
|
<groupId>org.mapstruct</groupId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>records-cross-module-1</artifactId>
|
||||||
|
|
||||||
|
</project>
|
@ -0,0 +1,10 @@
|
|||||||
|
/*
|
||||||
|
* 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.module1;
|
||||||
|
|
||||||
|
public interface NestedInterface {
|
||||||
|
String field();
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
/*
|
||||||
|
* 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.module1;
|
||||||
|
|
||||||
|
public interface RootInterface {
|
||||||
|
NestedInterface nested();
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
/*
|
||||||
|
* 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.module1;
|
||||||
|
|
||||||
|
public record SourceNestedRecord(
|
||||||
|
String field
|
||||||
|
) implements NestedInterface {
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
/*
|
||||||
|
* 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.module1;
|
||||||
|
|
||||||
|
public record SourceRootRecord(
|
||||||
|
SourceNestedRecord nested
|
||||||
|
) implements RootInterface {
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
<?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>
|
||||||
|
<artifactId>recordsCrossModuleInterfaceTest</artifactId>
|
||||||
|
<groupId>org.mapstruct</groupId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>records-cross-module-2</artifactId>
|
||||||
|
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mapstruct</groupId>
|
||||||
|
<artifactId>records-cross-module-1</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
@ -0,0 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* 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.module2;
|
||||||
|
|
||||||
|
import org.mapstruct.itest.records.module1.SourceRootRecord;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface RecordInterfaceIssueMapper {
|
||||||
|
|
||||||
|
RecordInterfaceIssueMapper INSTANCE = Mappers.getMapper(RecordInterfaceIssueMapper.class);
|
||||||
|
|
||||||
|
TargetRootRecord map(SourceRootRecord source);
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
/*
|
||||||
|
* 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.module2;
|
||||||
|
|
||||||
|
public record TargetNestedRecord(
|
||||||
|
String field
|
||||||
|
) {
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
/*
|
||||||
|
* 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.module2;
|
||||||
|
|
||||||
|
public record TargetRootRecord(
|
||||||
|
TargetNestedRecord nested
|
||||||
|
) {
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* 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.module2;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mapstruct.itest.records.module1.SourceRootRecord;
|
||||||
|
import org.mapstruct.itest.records.module1.SourceNestedRecord;
|
||||||
|
|
||||||
|
public class RecordsTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldMap() {
|
||||||
|
SourceRootRecord source = new SourceRootRecord( new SourceNestedRecord( "test" ) );
|
||||||
|
TargetRootRecord target = RecordInterfaceIssueMapper.INSTANCE.map( source );
|
||||||
|
|
||||||
|
assertThat( target ).isNotNull();
|
||||||
|
assertThat( target.nested() ).isNotNull();
|
||||||
|
assertThat( target.nested().field() ).isEqualTo( "test" );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
<?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>recordsCrossModuleInterfaceTest</artifactId>
|
||||||
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
|
<modules>
|
||||||
|
<module>module-1</module>
|
||||||
|
<module>module-2</module>
|
||||||
|
</modules>
|
||||||
|
</project>
|
@ -50,7 +50,7 @@ import org.mapstruct.ap.internal.util.Nouns;
|
|||||||
import org.mapstruct.ap.internal.util.TypeUtils;
|
import org.mapstruct.ap.internal.util.TypeUtils;
|
||||||
import org.mapstruct.ap.internal.util.accessor.Accessor;
|
import org.mapstruct.ap.internal.util.accessor.Accessor;
|
||||||
import org.mapstruct.ap.internal.util.accessor.AccessorType;
|
import org.mapstruct.ap.internal.util.accessor.AccessorType;
|
||||||
import org.mapstruct.ap.internal.util.accessor.FieldElementAccessor;
|
import org.mapstruct.ap.internal.util.accessor.ElementAccessor;
|
||||||
import org.mapstruct.ap.internal.util.accessor.MapValueAccessor;
|
import org.mapstruct.ap.internal.util.accessor.MapValueAccessor;
|
||||||
import org.mapstruct.ap.internal.util.accessor.PresenceCheckAccessor;
|
import org.mapstruct.ap.internal.util.accessor.PresenceCheckAccessor;
|
||||||
import org.mapstruct.ap.internal.util.accessor.ReadAccessor;
|
import org.mapstruct.ap.internal.util.accessor.ReadAccessor;
|
||||||
@ -1047,7 +1047,7 @@ public class Type extends ModelElement implements Comparable<Type> {
|
|||||||
List<Accessor> setterMethods = getSetters();
|
List<Accessor> setterMethods = getSetters();
|
||||||
List<Accessor> readAccessors = new ArrayList<>( getPropertyReadAccessors().values() );
|
List<Accessor> readAccessors = new ArrayList<>( getPropertyReadAccessors().values() );
|
||||||
// All the fields are also alternative accessors
|
// All the fields are also alternative accessors
|
||||||
readAccessors.addAll( filters.fieldsIn( getAllFields(), FieldElementAccessor::new ) );
|
readAccessors.addAll( filters.fieldsIn( getAllFields(), ElementAccessor::new ) );
|
||||||
|
|
||||||
// there could be a read accessor (field or method) for a list/map that is not present as setter.
|
// there could be a read accessor (field or method) for a list/map that is not present as setter.
|
||||||
// an accessor could substitute the setter in that case and act as setter.
|
// an accessor could substitute the setter in that case and act as setter.
|
||||||
|
@ -39,22 +39,16 @@ import static org.mapstruct.ap.internal.util.accessor.AccessorType.SETTER;
|
|||||||
public class Filters {
|
public class Filters {
|
||||||
|
|
||||||
private static final Method RECORD_COMPONENTS_METHOD;
|
private static final Method RECORD_COMPONENTS_METHOD;
|
||||||
private static final Method RECORD_COMPONENT_ACCESSOR_METHOD;
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
Method recordComponentsMethod;
|
Method recordComponentsMethod;
|
||||||
Method recordComponentAccessorMethod;
|
|
||||||
try {
|
try {
|
||||||
recordComponentsMethod = TypeElement.class.getMethod( "getRecordComponents" );
|
recordComponentsMethod = TypeElement.class.getMethod( "getRecordComponents" );
|
||||||
recordComponentAccessorMethod = Class.forName( "javax.lang.model.element.RecordComponentElement" )
|
|
||||||
.getMethod( "getAccessor" );
|
|
||||||
}
|
}
|
||||||
catch ( NoSuchMethodException | ClassNotFoundException e ) {
|
catch ( NoSuchMethodException e ) {
|
||||||
recordComponentsMethod = null;
|
recordComponentsMethod = null;
|
||||||
recordComponentAccessorMethod = null;
|
|
||||||
}
|
}
|
||||||
RECORD_COMPONENTS_METHOD = recordComponentsMethod;
|
RECORD_COMPONENTS_METHOD = recordComponentsMethod;
|
||||||
RECORD_COMPONENT_ACCESSOR_METHOD = recordComponentAccessorMethod;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private final AccessorNamingUtils accessorNaming;
|
private final AccessorNamingUtils accessorNaming;
|
||||||
@ -89,26 +83,19 @@ public class Filters {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, ReadAccessor> recordAccessorsIn(Collection<Element> recordComponents) {
|
public Map<String, ReadAccessor> recordAccessorsIn(Collection<Element> recordComponents) {
|
||||||
if ( RECORD_COMPONENT_ACCESSOR_METHOD == null ) {
|
if ( recordComponents.isEmpty() ) {
|
||||||
return java.util.Collections.emptyMap();
|
return java.util.Collections.emptyMap();
|
||||||
}
|
}
|
||||||
try {
|
|
||||||
Map<String, ReadAccessor> recordAccessors = new LinkedHashMap<>();
|
Map<String, ReadAccessor> recordAccessors = new LinkedHashMap<>();
|
||||||
for ( Element recordComponent : recordComponents ) {
|
for ( Element recordComponent : recordComponents ) {
|
||||||
ExecutableElement recordExecutableElement =
|
|
||||||
(ExecutableElement) RECORD_COMPONENT_ACCESSOR_METHOD.invoke( recordComponent );
|
|
||||||
recordAccessors.put(
|
recordAccessors.put(
|
||||||
recordComponent.getSimpleName().toString(),
|
recordComponent.getSimpleName().toString(),
|
||||||
ReadAccessor.fromGetter( recordExecutableElement, getReturnType( recordExecutableElement ) )
|
ReadAccessor.fromRecordComponent( recordComponent )
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return recordAccessors;
|
return recordAccessors;
|
||||||
}
|
}
|
||||||
catch ( IllegalAccessException | InvocationTargetException e ) {
|
|
||||||
return java.util.Collections.emptyMap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private TypeMirror getReturnType(ExecutableElement executableElement) {
|
private TypeMirror getReturnType(ExecutableElement executableElement) {
|
||||||
return getWithinContext( executableElement ).getReturnType();
|
return getWithinContext( executableElement ).getReturnType();
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright MapStruct Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.internal.util.accessor;
|
||||||
|
|
||||||
|
import javax.lang.model.element.Element;
|
||||||
|
import javax.lang.model.element.VariableElement;
|
||||||
|
import javax.lang.model.type.TypeMirror;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An {@link Accessor} that wraps a {@link VariableElement}.
|
||||||
|
*
|
||||||
|
* @author Filip Hrisafov
|
||||||
|
*/
|
||||||
|
public class ElementAccessor extends AbstractAccessor<Element> {
|
||||||
|
|
||||||
|
private final AccessorType accessorType;
|
||||||
|
|
||||||
|
public ElementAccessor(VariableElement variableElement) {
|
||||||
|
this( variableElement, AccessorType.FIELD );
|
||||||
|
}
|
||||||
|
|
||||||
|
public ElementAccessor(Element element, AccessorType accessorType) {
|
||||||
|
super( element );
|
||||||
|
this.accessorType = accessorType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeMirror getAccessedType() {
|
||||||
|
return element.asType();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return element.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AccessorType getAccessorType() {
|
||||||
|
return accessorType;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.internal.util.accessor;
|
package org.mapstruct.ap.internal.util.accessor;
|
||||||
|
|
||||||
|
import javax.lang.model.element.Element;
|
||||||
import javax.lang.model.element.ExecutableElement;
|
import javax.lang.model.element.ExecutableElement;
|
||||||
import javax.lang.model.element.VariableElement;
|
import javax.lang.model.element.VariableElement;
|
||||||
import javax.lang.model.type.TypeMirror;
|
import javax.lang.model.type.TypeMirror;
|
||||||
@ -17,7 +18,7 @@ public interface ReadAccessor extends Accessor {
|
|||||||
String getReadValueSource();
|
String getReadValueSource();
|
||||||
|
|
||||||
static ReadAccessor fromField(VariableElement variableElement) {
|
static ReadAccessor fromField(VariableElement variableElement) {
|
||||||
return new ReadDelegateAccessor( new FieldElementAccessor( variableElement ) ) {
|
return new ReadDelegateAccessor( new ElementAccessor( variableElement ) ) {
|
||||||
@Override
|
@Override
|
||||||
public String getReadValueSource() {
|
public String getReadValueSource() {
|
||||||
return getSimpleName();
|
return getSimpleName();
|
||||||
@ -25,6 +26,15 @@ public interface ReadAccessor extends Accessor {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ReadAccessor fromRecordComponent(Element element) {
|
||||||
|
return new ReadDelegateAccessor( new ElementAccessor( element, AccessorType.GETTER ) ) {
|
||||||
|
@Override
|
||||||
|
public String getReadValueSource() {
|
||||||
|
return getSimpleName() + "()";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
static ReadAccessor fromGetter(ExecutableElement element, TypeMirror accessedType) {
|
static ReadAccessor fromGetter(ExecutableElement element, TypeMirror accessedType) {
|
||||||
return new ReadDelegateAccessor( new ExecutableElementAccessor( element, accessedType, AccessorType.GETTER ) ) {
|
return new ReadDelegateAccessor( new ExecutableElementAccessor( element, accessedType, AccessorType.GETTER ) ) {
|
||||||
@Override
|
@Override
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.internal.util.accessor;
|
package org.mapstruct.ap.internal.util.accessor;
|
||||||
|
|
||||||
|
import javax.lang.model.element.Element;
|
||||||
import javax.lang.model.element.VariableElement;
|
import javax.lang.model.element.VariableElement;
|
||||||
import javax.lang.model.type.TypeMirror;
|
import javax.lang.model.type.TypeMirror;
|
||||||
|
|
||||||
@ -13,9 +14,9 @@ import javax.lang.model.type.TypeMirror;
|
|||||||
*
|
*
|
||||||
* @author Filip Hrisafov
|
* @author Filip Hrisafov
|
||||||
*/
|
*/
|
||||||
public class FieldElementAccessor extends AbstractAccessor<VariableElement> {
|
public class RecordElementAccessor extends AbstractAccessor<Element> {
|
||||||
|
|
||||||
public FieldElementAccessor(VariableElement element) {
|
public RecordElementAccessor(Element element) {
|
||||||
super( element );
|
super( element );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,7 +32,7 @@ public class FieldElementAccessor extends AbstractAccessor<VariableElement> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AccessorType getAccessorType() {
|
public AccessorType getAccessorType() {
|
||||||
return AccessorType.FIELD;
|
return AccessorType.GETTER;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user