#3036 Fix compile errors when intersection types are used in lifecycle methods

This commit is contained in:
Filip Hrisafov 2022-10-03 21:12:19 +02:00 committed by GitHub
parent 266c5fa41c
commit 3a325ea66b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 151 additions and 2 deletions

View File

@ -32,6 +32,10 @@ public final class FullFeatureCompilationExclusionCliEnhancer implements Process
additionalExcludes.add( "org/mapstruct/ap/test/injectionstrategy/cdi/**/*.java" ); 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/injectionstrategy/jakarta_cdi/**/*.java" );
additionalExcludes.add( "org/mapstruct/ap/test/annotatewith/deprecated/jdk11/*.java" ); additionalExcludes.add( "org/mapstruct/ap/test/annotatewith/deprecated/jdk11/*.java" );
if ( processorType == ProcessorTest.ProcessorType.ECLIPSE_JDT ) {
additionalExcludes.add(
"org/mapstruct/ap/test/selection/methodgenerics/wildcards/LifecycleIntersectionMapper.java" );
}
break; break;
case JAVA_9: case JAVA_9:
// TODO find out why this fails: // TODO find out why this fails:

View File

@ -26,6 +26,7 @@
<additionalExclude3>x</additionalExclude3> <additionalExclude3>x</additionalExclude3>
<additionalExclude4>x</additionalExclude4> <additionalExclude4>x</additionalExclude4>
<additionalExclude5>x</additionalExclude5> <additionalExclude5>x</additionalExclude5>
<additionalExclude6>x</additionalExclude6>
</properties> </properties>
<build> <build>

View File

@ -28,6 +28,7 @@ import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement; import javax.lang.model.element.VariableElement;
import javax.lang.model.type.ArrayType; import javax.lang.model.type.ArrayType;
import javax.lang.model.type.DeclaredType; import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.IntersectionType;
import javax.lang.model.type.PrimitiveType; import javax.lang.model.type.PrimitiveType;
import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror; import javax.lang.model.type.TypeMirror;
@ -114,6 +115,7 @@ public class Type extends ModelElement implements Comparable<Type> {
private List<Accessor> alternativeTargetAccessors = null; private List<Accessor> alternativeTargetAccessors = null;
private Type boundingBase = null; private Type boundingBase = null;
private List<Type> boundTypes = null;
private Type boxedEquivalent = null; private Type boxedEquivalent = null;
@ -354,6 +356,10 @@ public class Type extends ModelElement implements Comparable<Type> {
return (typeMirror.getKind() == TypeKind.TYPEVAR); return (typeMirror.getKind() == TypeKind.TYPEVAR);
} }
public boolean isIntersection() {
return typeMirror.getKind() == TypeKind.INTERSECTION;
}
public boolean isJavaLangType() { public boolean isJavaLangType() {
return packageName != null && packageName.startsWith( "java." ); return packageName != null && packageName.startsWith( "java." );
} }
@ -1264,6 +1270,29 @@ public class Type extends ModelElement implements Comparable<Type> {
return boundingBase; return boundingBase;
} }
public List<Type> getTypeBounds() {
if ( this.boundTypes != null ) {
return boundTypes;
}
Type bound = getTypeBound();
if ( bound == null ) {
this.boundTypes = Collections.emptyList();
}
else if ( !bound.isIntersection() ) {
this.boundTypes = Collections.singletonList( bound );
}
else {
List<? extends TypeMirror> bounds = ( (IntersectionType) bound.typeMirror ).getBounds();
this.boundTypes = new ArrayList<>( bounds.size() );
for ( TypeMirror mirror : bounds ) {
boundTypes.add( typeFactory.getType( mirror ) );
}
}
return this.boundTypes;
}
public boolean hasAccessibleConstructor() { public boolean hasAccessibleConstructor() {
if ( hasAccessibleConstructor == null ) { if ( hasAccessibleConstructor == null ) {
hasAccessibleConstructor = false; hasAccessibleConstructor = false;

View File

@ -325,8 +325,7 @@ public class MethodMatcher {
*/ */
private boolean candidatesWithinBounds(Map<Type, TypeVarCandidate> methodParCandidates ) { private boolean candidatesWithinBounds(Map<Type, TypeVarCandidate> methodParCandidates ) {
for ( Map.Entry<Type, TypeVarCandidate> entry : methodParCandidates.entrySet() ) { for ( Map.Entry<Type, TypeVarCandidate> entry : methodParCandidates.entrySet() ) {
Type bound = entry.getKey().getTypeBound(); for ( Type bound : entry.getKey().getTypeBounds() ) {
if ( bound != null ) {
for ( Type.ResolvedPair pair : entry.getValue().pairs ) { for ( Type.ResolvedPair pair : entry.getValue().pairs ) {
if ( entry.getKey().hasUpperBound() ) { if ( entry.getKey().hasUpperBound() ) {
if ( !pair.getMatch().asRawType().isAssignableTo( bound.asRawType() ) ) { if ( !pair.getMatch().asRawType().isAssignableTo( bound.asRawType() ) ) {

View File

@ -0,0 +1,96 @@
/*
* 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.selection.methodgenerics.wildcards;
import org.mapstruct.AfterMapping;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.MappingTarget;
import org.mapstruct.factory.Mappers;
/**
* @author Filip Hrisafov
*/
@Mapper
public interface LifecycleIntersectionMapper {
LifecycleIntersectionMapper INSTANCE = Mappers.getMapper( LifecycleIntersectionMapper.class );
@Mapping(target = "realm", ignore = true)
RealmTarget mapRealm(String source);
@Mapping(target = "uniqueRealm", ignore = true)
UniqueRealmTarget mapUniqueRealm(String source);
@Mapping(target = "realm", ignore = true)
@Mapping(target = "uniqueRealm", ignore = true)
BothRealmsTarget mapBothRealms(String source);
@AfterMapping
default <T extends RealmObject & UniqueRealmObject> void afterMapping(String source, @MappingTarget T target) {
target.setRealm( "realm_" + source );
target.setUniqueRealm( "uniqueRealm_" + source );
}
interface RealmObject {
void setRealm(String realm);
}
interface UniqueRealmObject {
void setUniqueRealm(String realm);
}
class RealmTarget implements RealmObject {
protected String realm;
public String getRealm() {
return realm;
}
@Override
public void setRealm(String realm) {
this.realm = realm;
}
}
class UniqueRealmTarget implements UniqueRealmObject {
protected String uniqueRealm;
@Override
public void setUniqueRealm(String uniqueRealm) {
this.uniqueRealm = uniqueRealm;
}
public String getUniqueRealm() {
return uniqueRealm;
}
}
class BothRealmsTarget implements RealmObject, UniqueRealmObject {
protected String realm;
protected String uniqueRealm;
public String getRealm() {
return realm;
}
@Override
public void setRealm(String realm) {
this.realm = realm;
}
public String getUniqueRealm() {
return uniqueRealm;
}
@Override
public void setUniqueRealm(String uniqueRealm) {
this.uniqueRealm = uniqueRealm;
}
}
}

View File

@ -5,6 +5,7 @@
*/ */
package org.mapstruct.ap.test.selection.methodgenerics.wildcards; package org.mapstruct.ap.test.selection.methodgenerics.wildcards;
import org.mapstruct.ap.testutil.IssueKey;
import org.mapstruct.ap.testutil.ProcessorTest; import org.mapstruct.ap.testutil.ProcessorTest;
import org.mapstruct.ap.testutil.WithClasses; import org.mapstruct.ap.testutil.WithClasses;
import org.mapstruct.ap.testutil.runner.Compiler; import org.mapstruct.ap.testutil.runner.Compiler;
@ -54,4 +55,23 @@ public class WildCardTest {
assertThat( target ).isNotNull(); assertThat( target ).isNotNull();
assertThat( target.getProp() ).isEqualTo( typeC ); assertThat( target.getProp() ).isEqualTo( typeC );
} }
// Eclipse does not handle intersection types correctly (TODO: worthwhile to investigate?)
@ProcessorTest(Compiler.JDK)
@WithClasses(LifecycleIntersectionMapper.class)
@IssueKey("3036")
public void testLifecycleIntersection() {
LifecycleIntersectionMapper.RealmTarget realmTarget = LifecycleIntersectionMapper.INSTANCE.mapRealm( "test" );
assertThat( realmTarget.getRealm() ).isNull();
LifecycleIntersectionMapper.UniqueRealmTarget uniqueRealmTarget =
LifecycleIntersectionMapper.INSTANCE.mapUniqueRealm( "test" );
assertThat( uniqueRealmTarget.getUniqueRealm() ).isNull();
LifecycleIntersectionMapper.BothRealmsTarget bothRealmsTarget =
LifecycleIntersectionMapper.INSTANCE.mapBothRealms( "test" );
assertThat( bothRealmsTarget.getRealm() ).isEqualTo( "realm_test" );
assertThat( bothRealmsTarget.getUniqueRealm() ).isEqualTo( "uniqueRealm_test" );
}
} }