diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index a760175c0..166466348 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -12,7 +12,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- java: [17, 21]
+ java: [21]
name: 'Linux JDK ${{ matrix.java }}'
runs-on: ubuntu-latest
steps:
@@ -24,31 +24,31 @@ jobs:
distribution: 'zulu'
java-version: ${{ matrix.java }}
- name: 'Test'
- run: ./mvnw ${MAVEN_ARGS} -Djacoco.skip=${{ matrix.java != 17 }} install -DskipDistribution=${{ matrix.java != 17 }}
+ run: ./mvnw ${MAVEN_ARGS} -Djacoco.skip=${{ matrix.java != 21 }} install -DskipDistribution=${{ matrix.java != 21 }}
- name: 'Generate coverage report'
- if: matrix.java == 17
+ if: matrix.java == 21
run: ./mvnw jacoco:report
- name: 'Upload coverage to Codecov'
- if: matrix.java == 17
+ if: matrix.java == 21
uses: codecov/codecov-action@v2
- name: 'Publish Snapshots'
- if: matrix.java == 17 && github.event_name == 'push' && github.ref == 'refs/heads/main' && github.repository == 'mapstruct/mapstruct'
+ if: matrix.java == 21 && github.event_name == 'push' && github.ref == 'refs/heads/main' && github.repository == 'mapstruct/mapstruct'
run: ./mvnw -s etc/ci-settings.xml -DskipTests=true -DskipDistribution=true deploy
integration_test_jdk:
strategy:
fail-fast: false
matrix:
- java: [ 8, 11 ]
+ java: [ 8, 11, 17 ]
name: 'Linux JDK ${{ matrix.java }}'
runs-on: ubuntu-latest
steps:
- name: 'Checkout'
uses: actions/checkout@v4
- - name: 'Set up JDK 17 for building everything'
+ - name: 'Set up JDK 21 for building everything'
uses: actions/setup-java@v4
with:
distribution: 'zulu'
- java-version: 17
+ java-version: 21
- name: 'Install Processor'
run: ./mvnw ${MAVEN_ARGS} -DskipTests install -pl processor -am
- name: 'Set up JDK ${{ matrix.java }} for running integration tests'
@@ -63,11 +63,11 @@ jobs:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- - name: 'Set up JDK 17'
+ - name: 'Set up JDK 21'
uses: actions/setup-java@v4
with:
distribution: 'zulu'
- java-version: 17
+ java-version: 21
- name: 'Test'
run: ./mvnw %MAVEN_ARGS% install
mac:
@@ -75,10 +75,10 @@ jobs:
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
- - name: 'Set up JDK 17'
+ - name: 'Set up JDK 21'
uses: actions/setup-java@v4
with:
distribution: 'zulu'
- java-version: 17
+ java-version: 21
- name: 'Test'
run: ./mvnw ${MAVEN_ARGS} install
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 682fa3687..61f347af3 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -22,7 +22,7 @@ jobs:
- name: Setup Java
uses: actions/setup-java@v4
with:
- java-version: 17
+ java-version: 21
distribution: 'zulu'
cache: maven
diff --git a/documentation/src/main/asciidoc/chapter-6-mapping-collections.asciidoc b/documentation/src/main/asciidoc/chapter-6-mapping-collections.asciidoc
index 79d4544f9..4510c82cc 100644
--- a/documentation/src/main/asciidoc/chapter-6-mapping-collections.asciidoc
+++ b/documentation/src/main/asciidoc/chapter-6-mapping-collections.asciidoc
@@ -212,12 +212,16 @@ When an iterable or map mapping method declares an interface type as return type
|`Set`|`LinkedHashSet`
+|`SequencedSet`|`LinkedHashSet`
+
|`SortedSet`|`TreeSet`
|`NavigableSet`|`TreeSet`
|`Map`|`LinkedHashMap`
+|`SequencedMap`|`LinkedHashMap`
+
|`SortedMap`|`TreeMap`
|`NavigableMap`|`TreeMap`
diff --git a/integrationtest/src/test/java/org/mapstruct/itest/tests/FullFeatureCompilationExclusionCliEnhancer.java b/integrationtest/src/test/java/org/mapstruct/itest/tests/FullFeatureCompilationExclusionCliEnhancer.java
index 77a5e2af0..0cc1a8781 100644
--- a/integrationtest/src/test/java/org/mapstruct/itest/tests/FullFeatureCompilationExclusionCliEnhancer.java
+++ b/integrationtest/src/test/java/org/mapstruct/itest/tests/FullFeatureCompilationExclusionCliEnhancer.java
@@ -34,6 +34,7 @@ public final class FullFeatureCompilationExclusionCliEnhancer implements Process
additionalExcludes.add( "org/mapstruct/ap/test/injectionstrategy/cdi/**/*.java" );
additionalExcludes.add( "org/mapstruct/ap/test/injectionstrategy/jakarta_cdi/**/*.java" );
additionalExcludes.add( "org/mapstruct/ap/test/annotatewith/deprecated/jdk11/*.java" );
+ additionalExcludes.add( "org/mapstruct/ap/test/**/jdk21/*.java" );
if ( processorType == ProcessorTest.ProcessorType.ECLIPSE_JDT ) {
additionalExcludes.add(
"org/mapstruct/ap/test/selection/methodgenerics/wildcards/LifecycleIntersectionMapper.java" );
@@ -42,9 +43,15 @@ public final class FullFeatureCompilationExclusionCliEnhancer implements Process
case JAVA_9:
// TODO find out why this fails:
additionalExcludes.add( "org/mapstruct/ap/test/collection/wildcard/BeanMapper.java" );
+ additionalExcludes.add( "org/mapstruct/ap/test/**/jdk21/*.java" );
break;
case JAVA_11:
additionalExcludes.add( "org/mapstruct/ap/test/**/spring/**/*.java" );
+ additionalExcludes.add( "org/mapstruct/ap/test/**/jdk21/*.java" );
+ break;
+ case JAVA_17:
+ additionalExcludes.add( "org/mapstruct/ap/test/**/jdk21/*.java" );
+ break;
default:
}
diff --git a/integrationtest/src/test/resources/fullFeatureTest/pom.xml b/integrationtest/src/test/resources/fullFeatureTest/pom.xml
index 849f7150f..b5ddae9a7 100644
--- a/integrationtest/src/test/resources/fullFeatureTest/pom.xml
+++ b/integrationtest/src/test/resources/fullFeatureTest/pom.xml
@@ -59,6 +59,8 @@
${additionalExclude9}
${additionalExclude10}
${additionalExclude11}
+ ${additionalExclude12}
+ ${additionalExclude13}
diff --git a/parent/pom.xml b/parent/pom.xml
index 5735d4760..f6ad60a22 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -47,7 +47,7 @@
jdt_apt
1.8
3.25.5
diff --git a/processor/pom.xml b/processor/pom.xml
index 13deafb41..2341c4ddb 100644
--- a/processor/pom.xml
+++ b/processor/pom.xml
@@ -24,7 +24,7 @@
- 17
+ 21
diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/common/TypeFactory.java b/processor/src/main/java/org/mapstruct/ap/internal/model/common/TypeFactory.java
index ceb190a33..c2646f63d 100644
--- a/processor/src/main/java/org/mapstruct/ap/internal/model/common/TypeFactory.java
+++ b/processor/src/main/java/org/mapstruct/ap/internal/model/common/TypeFactory.java
@@ -45,6 +45,7 @@ import org.mapstruct.ap.internal.util.Collections;
import org.mapstruct.ap.internal.util.ElementUtils;
import org.mapstruct.ap.internal.util.Extractor;
import org.mapstruct.ap.internal.util.FormattingMessager;
+import org.mapstruct.ap.internal.util.JavaCollectionConstants;
import org.mapstruct.ap.internal.util.JavaStreamConstants;
import org.mapstruct.ap.internal.util.Message;
import org.mapstruct.ap.internal.util.NativeTypes;
@@ -149,6 +150,18 @@ public class TypeFactory {
ConcurrentNavigableMap.class.getName(),
withDefaultConstructor( getType( ConcurrentSkipListMap.class ) )
);
+ implementationTypes.put(
+ JavaCollectionConstants.SEQUENCED_SET_FQN,
+ sourceVersionAtLeast19 ?
+ withFactoryMethod( getType( LinkedHashSet.class ), LINKED_HASH_SET_FACTORY_METHOD_NAME ) :
+ withLoadFactorAdjustment( getType( LinkedHashSet.class ) )
+ );
+ implementationTypes.put(
+ JavaCollectionConstants.SEQUENCED_MAP_FQN,
+ sourceVersionAtLeast19 ?
+ withFactoryMethod( getType( LinkedHashMap.class ), LINKED_HASH_MAP_FACTORY_METHOD_NAME ) :
+ withLoadFactorAdjustment( getType( LinkedHashMap.class ) )
+ );
this.loggingVerbose = loggingVerbose;
}
diff --git a/processor/src/main/java/org/mapstruct/ap/internal/util/JavaCollectionConstants.java b/processor/src/main/java/org/mapstruct/ap/internal/util/JavaCollectionConstants.java
new file mode 100644
index 000000000..68d556c54
--- /dev/null
+++ b/processor/src/main/java/org/mapstruct/ap/internal/util/JavaCollectionConstants.java
@@ -0,0 +1,21 @@
+/*
+ * 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;
+
+/**
+ * Helper holding Java collections full qualified class names for conversion registration,
+ * to achieve Java compatibility.
+ *
+ * @author Cause Chung
+ */
+public final class JavaCollectionConstants {
+ public static final String SEQUENCED_MAP_FQN = "java.util.SequencedMap";
+ public static final String SEQUENCED_SET_FQN = "java.util.SequencedSet";
+
+ private JavaCollectionConstants() {
+
+ }
+}
diff --git a/processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/jdk21/SequencedCollectionsDefaultImplementationTest.java b/processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/jdk21/SequencedCollectionsDefaultImplementationTest.java
new file mode 100644
index 000000000..4551d5b0b
--- /dev/null
+++ b/processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/jdk21/SequencedCollectionsDefaultImplementationTest.java
@@ -0,0 +1,74 @@
+/*
+ * 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.test.collection.defaultimplementation.jdk21;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.SequencedMap;
+import java.util.SequencedSet;
+
+import org.mapstruct.ap.test.collection.defaultimplementation.Source;
+import org.mapstruct.ap.test.collection.defaultimplementation.SourceFoo;
+import org.mapstruct.ap.test.collection.defaultimplementation.Target;
+import org.mapstruct.ap.test.collection.defaultimplementation.TargetFoo;
+import org.mapstruct.ap.testutil.IssueKey;
+import org.mapstruct.ap.testutil.ProcessorTest;
+import org.mapstruct.ap.testutil.WithClasses;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.entry;
+
+@WithClasses({
+ Source.class,
+ Target.class,
+ SourceFoo.class,
+ TargetFoo.class,
+ SequencedCollectionsMapper.class
+})
+@IssueKey("3420")
+class SequencedCollectionsDefaultImplementationTest {
+
+ @ProcessorTest
+ public void shouldUseDefaultImplementationForSequencedMap() {
+ SequencedMap target =
+ SequencedCollectionsMapper.INSTANCE.sourceFooMapToTargetFooSequencedMap( createSourceFooMap() );
+
+ assertResultMap( target );
+ }
+
+ @ProcessorTest
+ public void shouldUseDefaultImplementationForSequencedSet() {
+ SequencedSet target =
+ SequencedCollectionsMapper.INSTANCE.sourceFoosToTargetFooSequencedSet( createSourceFooList() );
+
+ assertResultList( target );
+ }
+
+ private void assertResultList(Iterable fooIterable) {
+ assertThat( fooIterable ).isNotNull();
+ assertThat( fooIterable ).containsOnly( new TargetFoo( "Bob" ), new TargetFoo( "Alice" ) );
+ }
+
+ private void assertResultMap(Map result) {
+ assertThat( result ).isNotNull();
+ assertThat( result ).hasSize( 2 );
+ assertThat( result ).contains( entry( "1", new TargetFoo( "Bob" ) ), entry( "2", new TargetFoo( "Alice" ) ) );
+ }
+
+ private Map createSourceFooMap() {
+ Map map = new HashMap<>();
+ map.put( 1L, new SourceFoo( "Bob" ) );
+ map.put( 2L, new SourceFoo( "Alice" ) );
+
+ return map;
+ }
+
+ private List createSourceFooList() {
+ return Arrays.asList( new SourceFoo( "Bob" ), new SourceFoo( "Alice" ) );
+ }
+}
diff --git a/processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/jdk21/SequencedCollectionsMapper.java b/processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/jdk21/SequencedCollectionsMapper.java
new file mode 100644
index 000000000..bbffb56b0
--- /dev/null
+++ b/processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/jdk21/SequencedCollectionsMapper.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.ap.test.collection.defaultimplementation.jdk21;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.SequencedMap;
+import java.util.SequencedSet;
+
+import org.mapstruct.Mapper;
+import org.mapstruct.ap.test.collection.defaultimplementation.SourceFoo;
+import org.mapstruct.ap.test.collection.defaultimplementation.TargetFoo;
+import org.mapstruct.factory.Mappers;
+
+@Mapper
+public interface SequencedCollectionsMapper {
+
+ SequencedCollectionsMapper INSTANCE = Mappers.getMapper( SequencedCollectionsMapper.class );
+
+ SequencedSet sourceFoosToTargetFooSequencedSet(Collection foos);
+
+ SequencedMap sourceFooMapToTargetFooSequencedMap(Map foos);
+}
diff --git a/readme.md b/readme.md
index 907c8411c..16a70f3f0 100644
--- a/readme.md
+++ b/readme.md
@@ -130,7 +130,8 @@ To learn more about MapStruct, refer to the [project homepage](https://mapstruct
## Building from Source
-MapStruct uses Maven for its build. Java 17 is required for building MapStruct from source. To build the complete project, run
+MapStruct uses Maven for its build. Java 21 is required for building MapStruct from source.
+To build the complete project, run
./mvnw clean install