#3240 Add Support for Java21 SequencedSet and SequencedMap

This commit is contained in:
Cause Chung 2025-05-11 17:33:35 +02:00 committed by Filip Hrisafov
parent 668eeb5de1
commit 2c84d04463
12 changed files with 164 additions and 16 deletions

View File

@ -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

View File

@ -22,7 +22,7 @@ jobs:
- name: Setup Java
uses: actions/setup-java@v4
with:
java-version: 17
java-version: 21
distribution: 'zulu'
cache: maven

View File

@ -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`

View File

@ -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:
}

View File

@ -59,6 +59,8 @@
<exclude>${additionalExclude9}</exclude>
<exclude>${additionalExclude10}</exclude>
<exclude>${additionalExclude11}</exclude>
<exclude>${additionalExclude12}</exclude>
<exclude>${additionalExclude13}</exclude>
</excludes>
</configuration>
</plugin>

View File

@ -47,7 +47,7 @@
<m2e.apt.activation>jdt_apt</m2e.apt.activation>
<!--
The minimum Java Version that is needed to build a module in MapStruct.
The processor module needs at least Java 17.
The processor module needs at least Java 21.
-->
<minimum.java.version>1.8</minimum.java.version>
<protobuf.version>3.25.5</protobuf.version>

View File

@ -24,7 +24,7 @@
<!-- Netbeans has a problem when we use late binding with @ in the surefire arg line.
Therefore we set this empty property here-->
<jacocoArgLine />
<minimum.java.version>17</minimum.java.version>
<minimum.java.version>21</minimum.java.version>
</properties>
<dependencies>

View File

@ -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;
}

View File

@ -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() {
}
}

View File

@ -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<String, TargetFoo> target =
SequencedCollectionsMapper.INSTANCE.sourceFooMapToTargetFooSequencedMap( createSourceFooMap() );
assertResultMap( target );
}
@ProcessorTest
public void shouldUseDefaultImplementationForSequencedSet() {
SequencedSet<TargetFoo> target =
SequencedCollectionsMapper.INSTANCE.sourceFoosToTargetFooSequencedSet( createSourceFooList() );
assertResultList( target );
}
private void assertResultList(Iterable<TargetFoo> fooIterable) {
assertThat( fooIterable ).isNotNull();
assertThat( fooIterable ).containsOnly( new TargetFoo( "Bob" ), new TargetFoo( "Alice" ) );
}
private void assertResultMap(Map<String, TargetFoo> result) {
assertThat( result ).isNotNull();
assertThat( result ).hasSize( 2 );
assertThat( result ).contains( entry( "1", new TargetFoo( "Bob" ) ), entry( "2", new TargetFoo( "Alice" ) ) );
}
private Map<Long, SourceFoo> createSourceFooMap() {
Map<Long, SourceFoo> map = new HashMap<>();
map.put( 1L, new SourceFoo( "Bob" ) );
map.put( 2L, new SourceFoo( "Alice" ) );
return map;
}
private List<SourceFoo> createSourceFooList() {
return Arrays.asList( new SourceFoo( "Bob" ), new SourceFoo( "Alice" ) );
}
}

View File

@ -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<TargetFoo> sourceFoosToTargetFooSequencedSet(Collection<SourceFoo> foos);
SequencedMap<String, TargetFoo> sourceFooMapToTargetFooSequencedMap(Map<Long, SourceFoo> foos);
}

View File

@ -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