diff --git a/integrationtest/src/test/java/org/mapstruct/itest/tests/MavenIntegrationTest.java b/integrationtest/src/test/java/org/mapstruct/itest/tests/MavenIntegrationTest.java
index 7e9175dd9..0bef2994f 100644
--- a/integrationtest/src/test/java/org/mapstruct/itest/tests/MavenIntegrationTest.java
+++ b/integrationtest/src/test/java/org/mapstruct/itest/tests/MavenIntegrationTest.java
@@ -131,6 +131,13 @@ public class MavenIntegrationTest {
void recordsCrossModuleTest() {
}
+ @ProcessorTest(baseDir = "recordsCrossModuleInterfaceTest", processorTypes = {
+ ProcessorTest.ProcessorType.JAVAC
+ })
+ @EnabledForJreRange(min = JRE.JAVA_17)
+ void recordsCrossModuleInterfaceTest() {
+ }
+
@ProcessorTest(baseDir = "expressionTextBlocksTest", processorTypes = {
ProcessorTest.ProcessorType.JAVAC
})
diff --git a/integrationtest/src/test/resources/recordsCrossModuleInterfaceTest/module-1/pom.xml b/integrationtest/src/test/resources/recordsCrossModuleInterfaceTest/module-1/pom.xml
new file mode 100644
index 000000000..72df10f62
--- /dev/null
+++ b/integrationtest/src/test/resources/recordsCrossModuleInterfaceTest/module-1/pom.xml
@@ -0,0 +1,22 @@
+
+
+
+ 4.0.0
+
+
+ recordsCrossModuleInterfaceTest
+ org.mapstruct
+ 1.0.0
+
+
+ records-cross-module-1
+
+
diff --git a/integrationtest/src/test/resources/recordsCrossModuleInterfaceTest/module-1/src/main/java/org/mapstruct/itest/records/module1/NestedInterface.java b/integrationtest/src/test/resources/recordsCrossModuleInterfaceTest/module-1/src/main/java/org/mapstruct/itest/records/module1/NestedInterface.java
new file mode 100644
index 000000000..ffa53f88b
--- /dev/null
+++ b/integrationtest/src/test/resources/recordsCrossModuleInterfaceTest/module-1/src/main/java/org/mapstruct/itest/records/module1/NestedInterface.java
@@ -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();
+}
diff --git a/integrationtest/src/test/resources/recordsCrossModuleInterfaceTest/module-1/src/main/java/org/mapstruct/itest/records/module1/RootInterface.java b/integrationtest/src/test/resources/recordsCrossModuleInterfaceTest/module-1/src/main/java/org/mapstruct/itest/records/module1/RootInterface.java
new file mode 100644
index 000000000..fb23ffe15
--- /dev/null
+++ b/integrationtest/src/test/resources/recordsCrossModuleInterfaceTest/module-1/src/main/java/org/mapstruct/itest/records/module1/RootInterface.java
@@ -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();
+}
diff --git a/integrationtest/src/test/resources/recordsCrossModuleInterfaceTest/module-1/src/main/java/org/mapstruct/itest/records/module1/SourceNestedRecord.java b/integrationtest/src/test/resources/recordsCrossModuleInterfaceTest/module-1/src/main/java/org/mapstruct/itest/records/module1/SourceNestedRecord.java
new file mode 100644
index 000000000..6a0ddb86a
--- /dev/null
+++ b/integrationtest/src/test/resources/recordsCrossModuleInterfaceTest/module-1/src/main/java/org/mapstruct/itest/records/module1/SourceNestedRecord.java
@@ -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 {
+}
diff --git a/integrationtest/src/test/resources/recordsCrossModuleInterfaceTest/module-1/src/main/java/org/mapstruct/itest/records/module1/SourceRootRecord.java b/integrationtest/src/test/resources/recordsCrossModuleInterfaceTest/module-1/src/main/java/org/mapstruct/itest/records/module1/SourceRootRecord.java
new file mode 100644
index 000000000..151ad5208
--- /dev/null
+++ b/integrationtest/src/test/resources/recordsCrossModuleInterfaceTest/module-1/src/main/java/org/mapstruct/itest/records/module1/SourceRootRecord.java
@@ -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 {
+}
diff --git a/integrationtest/src/test/resources/recordsCrossModuleInterfaceTest/module-2/pom.xml b/integrationtest/src/test/resources/recordsCrossModuleInterfaceTest/module-2/pom.xml
new file mode 100644
index 000000000..5f42efd18
--- /dev/null
+++ b/integrationtest/src/test/resources/recordsCrossModuleInterfaceTest/module-2/pom.xml
@@ -0,0 +1,30 @@
+
+
+
+ 4.0.0
+
+
+ recordsCrossModuleInterfaceTest
+ org.mapstruct
+ 1.0.0
+
+
+ records-cross-module-2
+
+
+
+
+ org.mapstruct
+ records-cross-module-1
+ 1.0.0
+
+
+
diff --git a/integrationtest/src/test/resources/recordsCrossModuleInterfaceTest/module-2/src/main/java/org/mapstruct/itest/records/module2/RecordInterfaceIssueMapper.java b/integrationtest/src/test/resources/recordsCrossModuleInterfaceTest/module-2/src/main/java/org/mapstruct/itest/records/module2/RecordInterfaceIssueMapper.java
new file mode 100644
index 000000000..a763359a9
--- /dev/null
+++ b/integrationtest/src/test/resources/recordsCrossModuleInterfaceTest/module-2/src/main/java/org/mapstruct/itest/records/module2/RecordInterfaceIssueMapper.java
@@ -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);
+}
diff --git a/integrationtest/src/test/resources/recordsCrossModuleInterfaceTest/module-2/src/main/java/org/mapstruct/itest/records/module2/TargetNestedRecord.java b/integrationtest/src/test/resources/recordsCrossModuleInterfaceTest/module-2/src/main/java/org/mapstruct/itest/records/module2/TargetNestedRecord.java
new file mode 100644
index 000000000..d02a4b58e
--- /dev/null
+++ b/integrationtest/src/test/resources/recordsCrossModuleInterfaceTest/module-2/src/main/java/org/mapstruct/itest/records/module2/TargetNestedRecord.java
@@ -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
+) {
+}
diff --git a/integrationtest/src/test/resources/recordsCrossModuleInterfaceTest/module-2/src/main/java/org/mapstruct/itest/records/module2/TargetRootRecord.java b/integrationtest/src/test/resources/recordsCrossModuleInterfaceTest/module-2/src/main/java/org/mapstruct/itest/records/module2/TargetRootRecord.java
new file mode 100644
index 000000000..09a69f1bf
--- /dev/null
+++ b/integrationtest/src/test/resources/recordsCrossModuleInterfaceTest/module-2/src/main/java/org/mapstruct/itest/records/module2/TargetRootRecord.java
@@ -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
+) {
+}
diff --git a/integrationtest/src/test/resources/recordsCrossModuleInterfaceTest/module-2/src/test/java/org/mapstruct/itest/records/module2/RecordsTest.java b/integrationtest/src/test/resources/recordsCrossModuleInterfaceTest/module-2/src/test/java/org/mapstruct/itest/records/module2/RecordsTest.java
new file mode 100644
index 000000000..5f7a99273
--- /dev/null
+++ b/integrationtest/src/test/resources/recordsCrossModuleInterfaceTest/module-2/src/test/java/org/mapstruct/itest/records/module2/RecordsTest.java
@@ -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" );
+ }
+
+}
diff --git a/integrationtest/src/test/resources/recordsCrossModuleInterfaceTest/pom.xml b/integrationtest/src/test/resources/recordsCrossModuleInterfaceTest/pom.xml
new file mode 100644
index 000000000..120c849dc
--- /dev/null
+++ b/integrationtest/src/test/resources/recordsCrossModuleInterfaceTest/pom.xml
@@ -0,0 +1,26 @@
+
+
+
+ 4.0.0
+
+
+ org.mapstruct
+ mapstruct-it-parent
+ 1.0.0
+ ../pom.xml
+
+
+ recordsCrossModuleInterfaceTest
+ pom
+
+
+ module-1
+ module-2
+
+
diff --git a/integrationtest/src/test/resources/recordsCrossModuleTest/mapper/test/java/org/mapstruct/itest/records/mapper/RecordsTest.java b/integrationtest/src/test/resources/recordsCrossModuleTest/mapper/src/test/java/org/mapstruct/itest/records/mapper/RecordsTest.java
similarity index 100%
rename from integrationtest/src/test/resources/recordsCrossModuleTest/mapper/test/java/org/mapstruct/itest/records/mapper/RecordsTest.java
rename to integrationtest/src/test/resources/recordsCrossModuleTest/mapper/src/test/java/org/mapstruct/itest/records/mapper/RecordsTest.java
diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/common/Type.java b/processor/src/main/java/org/mapstruct/ap/internal/model/common/Type.java
index 54305cffc..652083406 100644
--- a/processor/src/main/java/org/mapstruct/ap/internal/model/common/Type.java
+++ b/processor/src/main/java/org/mapstruct/ap/internal/model/common/Type.java
@@ -50,7 +50,7 @@ import org.mapstruct.ap.internal.util.Nouns;
import org.mapstruct.ap.internal.util.TypeUtils;
import org.mapstruct.ap.internal.util.accessor.Accessor;
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.PresenceCheckAccessor;
import org.mapstruct.ap.internal.util.accessor.ReadAccessor;
@@ -1047,7 +1047,7 @@ public class Type extends ModelElement implements Comparable {
List setterMethods = getSetters();
List readAccessors = new ArrayList<>( getPropertyReadAccessors().values() );
// 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.
// an accessor could substitute the setter in that case and act as setter.
diff --git a/processor/src/main/java/org/mapstruct/ap/internal/util/Filters.java b/processor/src/main/java/org/mapstruct/ap/internal/util/Filters.java
index 123f72832..5f7fe74bf 100644
--- a/processor/src/main/java/org/mapstruct/ap/internal/util/Filters.java
+++ b/processor/src/main/java/org/mapstruct/ap/internal/util/Filters.java
@@ -39,22 +39,16 @@ import static org.mapstruct.ap.internal.util.accessor.AccessorType.SETTER;
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 ) {
+ catch ( NoSuchMethodException e ) {
recordComponentsMethod = null;
- recordComponentAccessorMethod = null;
}
RECORD_COMPONENTS_METHOD = recordComponentsMethod;
- RECORD_COMPONENT_ACCESSOR_METHOD = recordComponentAccessorMethod;
}
private final AccessorNamingUtils accessorNaming;
@@ -89,25 +83,18 @@ public class Filters {
}
public Map recordAccessorsIn(Collection recordComponents) {
- if ( RECORD_COMPONENT_ACCESSOR_METHOD == null ) {
+ if ( recordComponents.isEmpty() ) {
return java.util.Collections.emptyMap();
}
- try {
- Map recordAccessors = new LinkedHashMap<>();
- for ( Element recordComponent : recordComponents ) {
- ExecutableElement recordExecutableElement =
- (ExecutableElement) RECORD_COMPONENT_ACCESSOR_METHOD.invoke( recordComponent );
- recordAccessors.put(
- recordComponent.getSimpleName().toString(),
- ReadAccessor.fromGetter( recordExecutableElement, getReturnType( recordExecutableElement ) )
- );
- }
+ Map recordAccessors = new LinkedHashMap<>();
+ for ( Element recordComponent : recordComponents ) {
+ recordAccessors.put(
+ recordComponent.getSimpleName().toString(),
+ ReadAccessor.fromRecordComponent( recordComponent )
+ );
+ }
- return recordAccessors;
- }
- catch ( IllegalAccessException | InvocationTargetException e ) {
- return java.util.Collections.emptyMap();
- }
+ return recordAccessors;
}
private TypeMirror getReturnType(ExecutableElement executableElement) {
diff --git a/processor/src/main/java/org/mapstruct/ap/internal/util/accessor/ElementAccessor.java b/processor/src/main/java/org/mapstruct/ap/internal/util/accessor/ElementAccessor.java
new file mode 100644
index 000000000..24e71cc85
--- /dev/null
+++ b/processor/src/main/java/org/mapstruct/ap/internal/util/accessor/ElementAccessor.java
@@ -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 {
+
+ 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;
+ }
+
+}
diff --git a/processor/src/main/java/org/mapstruct/ap/internal/util/accessor/ReadAccessor.java b/processor/src/main/java/org/mapstruct/ap/internal/util/accessor/ReadAccessor.java
index a790a3361..5177bfc75 100644
--- a/processor/src/main/java/org/mapstruct/ap/internal/util/accessor/ReadAccessor.java
+++ b/processor/src/main/java/org/mapstruct/ap/internal/util/accessor/ReadAccessor.java
@@ -5,6 +5,7 @@
*/
package org.mapstruct.ap.internal.util.accessor;
+import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeMirror;
@@ -17,7 +18,7 @@ public interface ReadAccessor extends Accessor {
String getReadValueSource();
static ReadAccessor fromField(VariableElement variableElement) {
- return new ReadDelegateAccessor( new FieldElementAccessor( variableElement ) ) {
+ return new ReadDelegateAccessor( new ElementAccessor( variableElement ) ) {
@Override
public String getReadValueSource() {
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) {
return new ReadDelegateAccessor( new ExecutableElementAccessor( element, accessedType, AccessorType.GETTER ) ) {
@Override
diff --git a/processor/src/main/java/org/mapstruct/ap/internal/util/accessor/FieldElementAccessor.java b/processor/src/main/java/org/mapstruct/ap/internal/util/accessor/RecordElementAccessor.java
similarity index 77%
rename from processor/src/main/java/org/mapstruct/ap/internal/util/accessor/FieldElementAccessor.java
rename to processor/src/main/java/org/mapstruct/ap/internal/util/accessor/RecordElementAccessor.java
index 517490053..d163f462f 100644
--- a/processor/src/main/java/org/mapstruct/ap/internal/util/accessor/FieldElementAccessor.java
+++ b/processor/src/main/java/org/mapstruct/ap/internal/util/accessor/RecordElementAccessor.java
@@ -5,6 +5,7 @@
*/
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;
@@ -13,9 +14,9 @@ import javax.lang.model.type.TypeMirror;
*
* @author Filip Hrisafov
*/
-public class FieldElementAccessor extends AbstractAccessor {
+public class RecordElementAccessor extends AbstractAccessor {
- public FieldElementAccessor(VariableElement element) {
+ public RecordElementAccessor(Element element) {
super( element );
}
@@ -31,7 +32,7 @@ public class FieldElementAccessor extends AbstractAccessor {
@Override
public AccessorType getAccessorType() {
- return AccessorType.FIELD;
+ return AccessorType.GETTER;
}
}