861 remove compiler specific workarounds (#2227)

This commit is contained in:
Sjaak Derksen 2020-10-21 20:02:28 +02:00 committed by GitHub
parent 74d06fea5d
commit c2e8034030
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
43 changed files with 611 additions and 771 deletions

View File

@ -12,7 +12,7 @@ import java.util.SortedSet;
import java.util.TreeSet;
import javax.lang.model.type.TypeKind;
import javax.lang.model.util.Elements;
import org.mapstruct.ap.internal.util.ElementUtils;
import org.mapstruct.ap.internal.model.common.Accessibility;
import org.mapstruct.ap.internal.model.common.ModelElement;
@ -35,7 +35,7 @@ public abstract class GeneratedType extends ModelElement {
private T myself;
protected TypeFactory typeFactory;
protected Elements elementUtils;
protected ElementUtils elementUtils;
protected Options options;
protected VersionInformation versionInformation;
protected SortedSet<Type> extraImportedTypes;
@ -46,7 +46,7 @@ public abstract class GeneratedType extends ModelElement {
myself = selfType.cast( this );
}
public T elementUtils(Elements elementUtils) {
public T elementUtils(ElementUtils elementUtils) {
this.elementUtils = elementUtils;
return myself;
}

View File

@ -15,8 +15,8 @@ import java.util.function.Supplier;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import org.mapstruct.ap.internal.util.ElementUtils;
import org.mapstruct.ap.internal.util.TypeUtils;
import org.mapstruct.ap.internal.model.common.Assignment;
import org.mapstruct.ap.internal.model.common.FormattingParameters;
@ -103,8 +103,8 @@ public class MappingBuilderContext {
}
private final TypeFactory typeFactory;
private final Elements elementUtils;
private final Types typeUtils;
private final ElementUtils elementUtils;
private final TypeUtils typeUtils;
private final FormattingMessager messager;
private final AccessorNamingUtils accessorNaming;
private final EnumMappingStrategy enumMappingStrategy;
@ -120,8 +120,8 @@ public class MappingBuilderContext {
//CHECKSTYLE:OFF
public MappingBuilderContext(TypeFactory typeFactory,
Elements elementUtils,
Types typeUtils,
ElementUtils elementUtils,
TypeUtils typeUtils,
FormattingMessager messager,
AccessorNamingUtils accessorNaming,
EnumMappingStrategy enumMappingStrategy,
@ -175,11 +175,11 @@ public class MappingBuilderContext {
return typeFactory;
}
public Elements getElementUtils() {
public ElementUtils getElementUtils() {
return elementUtils;
}
public Types getTypeUtils() {
public TypeUtils getTypeUtils() {
return typeUtils;
}

View File

@ -14,7 +14,7 @@ import java.util.Map;
import java.util.Set;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Types;
import org.mapstruct.ap.internal.util.TypeUtils;
import org.mapstruct.ap.internal.gem.BeanMappingGem;
import org.mapstruct.ap.internal.model.common.Parameter;
@ -295,7 +295,7 @@ public class ValueMappingMethod extends MappingMethod {
return ctx.getEnumMappingStrategy().getEnumConstant( typeElement, enumConstant );
}
private SelectionParameters getSelectionParameters(Method method, Types typeUtils) {
private SelectionParameters getSelectionParameters(Method method, TypeUtils typeUtils) {
BeanMappingGem beanMapping = BeanMappingGem.instanceOn( method.getExecutable() );
if ( beanMapping != null ) {
List<TypeMirror> qualifiers = beanMapping.qualifiedBy().get();

View File

@ -9,7 +9,7 @@ import java.util.Collection;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Types;
import org.mapstruct.ap.internal.util.TypeUtils;
import org.mapstruct.ap.spi.BuilderInfo;
@ -84,7 +84,7 @@ public class BuilderType {
}
public static BuilderType create(BuilderInfo builderInfo, Type typeToBuild, TypeFactory typeFactory,
Types typeUtils) {
TypeUtils typeUtils) {
if ( builderInfo == null ) {
return null;
}

View File

@ -28,22 +28,21 @@ import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVariable;
import javax.lang.model.type.WildcardType;
import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.Elements;
import javax.lang.model.util.SimpleTypeVisitor8;
import javax.lang.model.util.Types;
import org.mapstruct.ap.internal.gem.CollectionMappingStrategyGem;
import org.mapstruct.ap.internal.util.AccessorNamingUtils;
import org.mapstruct.ap.internal.util.ElementUtils;
import org.mapstruct.ap.internal.util.Executables;
import org.mapstruct.ap.internal.util.Fields;
import org.mapstruct.ap.internal.util.Filters;
import org.mapstruct.ap.internal.util.JavaStreamConstants;
import org.mapstruct.ap.internal.util.NativeTypes;
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 static org.mapstruct.ap.internal.util.Collections.first;
import org.mapstruct.ap.internal.util.NativeTypes;
/**
* Represents (a reference to) the type of a bean property, parameter etc. Types are managed per generated source file.
@ -57,8 +56,8 @@ import org.mapstruct.ap.internal.util.NativeTypes;
*/
public class Type extends ModelElement implements Comparable<Type> {
private final Types typeUtils;
private final Elements elementUtils;
private final TypeUtils typeUtils;
private final ElementUtils elementUtils;
private final TypeFactory typeFactory;
private final AccessorNamingUtils accessorNaming;
@ -109,7 +108,7 @@ public class Type extends ModelElement implements Comparable<Type> {
private final Filters filters;
//CHECKSTYLE:OFF
public Type(Types typeUtils, Elements elementUtils, TypeFactory typeFactory,
public Type(TypeUtils typeUtils, ElementUtils elementUtils, TypeFactory typeFactory,
AccessorNamingUtils accessorNaming,
TypeMirror typeMirror, TypeElement typeElement,
List<Type> typeParameters, ImplementationType implementationType, Type componentType,
@ -662,7 +661,7 @@ public class Type extends ModelElement implements Comparable<Type> {
private List<ExecutableElement> getAllMethods() {
if ( allMethods == null ) {
allMethods = Executables.getAllEnclosedExecutableElements( elementUtils, typeElement );
allMethods = elementUtils.getAllEnclosedExecutableElements( typeElement );
}
return allMethods;
@ -670,7 +669,7 @@ public class Type extends ModelElement implements Comparable<Type> {
private List<VariableElement> getAllFields() {
if ( allFields == null ) {
allFields = Fields.getAllEnclosedFields( elementUtils, typeElement );
allFields = elementUtils.getAllEnclosedFields( typeElement );
}
return allFields;
@ -861,7 +860,7 @@ public class Type extends ModelElement implements Comparable<Type> {
private boolean isStream(TypeMirror candidate) {
TypeElement streamTypeElement = elementUtils.getTypeElement( JavaStreamConstants.STREAM_FQN );
TypeMirror streamType = streamTypeElement == null ? null : typeUtils.erasure( streamTypeElement.asType() );
return streamType != null && typeUtils.isSubtype( candidate, streamType );
return streamType != null && typeUtils.isSubtypeErased( candidate, streamType );
}
private boolean isMap(TypeMirror candidate) {
@ -871,7 +870,7 @@ public class Type extends ModelElement implements Comparable<Type> {
private boolean isSubType(TypeMirror candidate, Class<?> clazz) {
String className = clazz.getCanonicalName();
TypeMirror classType = typeUtils.erasure( elementUtils.getTypeElement( className ).asType() );
return typeUtils.isSubtype( candidate, classType );
return typeUtils.isSubtypeErased( candidate, classType );
}
/**
@ -1141,9 +1140,9 @@ public class Type extends ModelElement implements Comparable<Type> {
private static class TypeVarMatcher extends SimpleTypeVisitor8<Type, Type> {
private TypeVariable typeVarToMatch;
private Types types;
private TypeUtils types;
TypeVarMatcher( Types types, Type typeVarToMatch ) {
TypeVarMatcher(TypeUtils types, Type typeVarToMatch ) {
super( null );
this.typeVarToMatch = (TypeVariable) typeVarToMatch.getTypeMirror();
this.types = types;

View File

@ -36,8 +36,8 @@ import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVariable;
import javax.lang.model.type.WildcardType;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import org.mapstruct.ap.internal.util.ElementUtils;
import org.mapstruct.ap.internal.util.TypeUtils;
import org.mapstruct.ap.internal.gem.BuilderGem;
import org.mapstruct.ap.internal.util.AnnotationProcessingException;
@ -81,8 +81,8 @@ public class TypeFactory {
return sb.toString();
};
private final Elements elementUtils;
private final Types typeUtils;
private final ElementUtils elementUtils;
private final TypeUtils typeUtils;
private final FormattingMessager messager;
private final RoundContext roundContext;
@ -97,8 +97,8 @@ public class TypeFactory {
private final boolean loggingVerbose;
public TypeFactory(Elements elementUtils, Types typeUtils, FormattingMessager messager, RoundContext roundContext,
Map<String, String> notToBeImportedTypes, boolean loggingVerbose) {
public TypeFactory(ElementUtils elementUtils, TypeUtils typeUtils, FormattingMessager messager,
RoundContext roundContext, Map<String, String> notToBeImportedTypes, boolean loggingVerbose) {
this.elementUtils = elementUtils;
this.typeUtils = typeUtils;
this.messager = messager;
@ -198,10 +198,10 @@ public class TypeFactory {
ImplementationType implementationType = getImplementationType( mirror );
boolean isIterableType = typeUtils.isSubtype( mirror, iterableType );
boolean isCollectionType = typeUtils.isSubtype( mirror, collectionType );
boolean isMapType = typeUtils.isSubtype( mirror, mapType );
boolean isStreamType = streamType != null && typeUtils.isSubtype( mirror, streamType );
boolean isIterableType = typeUtils.isSubtypeErased( mirror, iterableType );
boolean isCollectionType = typeUtils.isSubtypeErased( mirror, collectionType );
boolean isMapType = typeUtils.isSubtypeErased( mirror, mapType );
boolean isStreamType = streamType != null && typeUtils.isSubtypeErased( mirror, streamType );
boolean isEnumType;
boolean isInterface;

View File

@ -11,8 +11,8 @@ import java.util.Objects;
import java.util.Optional;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import org.mapstruct.ap.internal.util.ElementUtils;
import org.mapstruct.ap.internal.util.TypeUtils;
import org.mapstruct.ap.internal.model.common.TypeFactory;
import org.mapstruct.ap.internal.gem.BeanMappingGem;
@ -50,7 +50,7 @@ public class BeanMappingOptions extends DelegatingOptions {
public static BeanMappingOptions getInstanceOn(BeanMappingGem beanMapping, MapperOptions mapperOptions,
ExecutableElement method, FormattingMessager messager,
Types typeUtils, TypeFactory typeFactory
TypeUtils typeUtils, TypeFactory typeFactory
) {
if ( beanMapping == null || !isConsistent( beanMapping, method, messager ) ) {
BeanMappingOptions options = new BeanMappingOptions( null, null, mapperOptions );
@ -143,7 +143,7 @@ public class BeanMappingOptions extends DelegatingOptions {
}
@Override
public MappingControl getMappingControl(Elements elementUtils) {
public MappingControl getMappingControl(ElementUtils elementUtils) {
return Optional.ofNullable( beanMapping ).map( BeanMappingGem::mappingControl )
.filter( GemValue::hasValue )
.map( GemValue::getValue )

View File

@ -9,7 +9,7 @@ import java.util.Collections;
import java.util.Set;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import org.mapstruct.ap.internal.util.ElementUtils;
import org.mapstruct.ap.internal.option.Options;
import org.mapstruct.ap.internal.gem.BuilderGem;
@ -124,7 +124,7 @@ public class DefaultOptions extends DelegatingOptions {
}
@Override
public MappingControl getMappingControl(Elements elementUtils) {
public MappingControl getMappingControl(ElementUtils elementUtils) {
return MappingControl.fromTypeMirror( mapper.mappingControl().getDefaultValue(), elementUtils );
}

View File

@ -10,7 +10,7 @@ import java.util.List;
import java.util.Set;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import org.mapstruct.ap.internal.util.ElementUtils;
import org.mapstruct.ap.internal.gem.BuilderGem;
import org.mapstruct.ap.internal.gem.CollectionMappingStrategyGem;
@ -101,7 +101,7 @@ public abstract class DelegatingOptions {
return next.getBuilder();
}
public MappingControl getMappingControl(Elements elementUtils) {
public MappingControl getMappingControl(ElementUtils elementUtils) {
return next.getMappingControl( elementUtils );
}

View File

@ -8,8 +8,8 @@ package org.mapstruct.ap.internal.model.source;
import java.util.Optional;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import org.mapstruct.ap.internal.util.ElementUtils;
import org.mapstruct.ap.internal.util.TypeUtils;
import org.mapstruct.ap.internal.model.common.FormattingParameters;
import org.mapstruct.ap.internal.gem.IterableMappingGem;
@ -31,7 +31,7 @@ public class IterableMappingOptions extends DelegatingOptions {
public static IterableMappingOptions fromGem(IterableMappingGem iterableMapping,
MapperOptions mappperOptions, ExecutableElement method,
FormattingMessager messager, Types typeUtils) {
FormattingMessager messager, TypeUtils typeUtils) {
if ( iterableMapping == null || !isConsistent( iterableMapping, method, messager ) ) {
IterableMappingOptions options = new IterableMappingOptions( null, null, null, mappperOptions );
@ -102,7 +102,7 @@ public class IterableMappingOptions extends DelegatingOptions {
.orElse( next().getNullValueMappingStrategy() );
}
public MappingControl getElementMappingControl(Elements elementUtils) {
public MappingControl getElementMappingControl(ElementUtils elementUtils) {
return Optional.ofNullable( iterableMapping ).map( IterableMappingGem::elementMappingControl )
.filter( GemValue::hasValue )
.map( GemValue::getValue )

View File

@ -8,8 +8,8 @@ package org.mapstruct.ap.internal.model.source;
import java.util.Optional;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import org.mapstruct.ap.internal.util.ElementUtils;
import org.mapstruct.ap.internal.util.TypeUtils;
import org.mapstruct.ap.internal.model.common.FormattingParameters;
import org.mapstruct.ap.internal.gem.MapMappingGem;
@ -32,7 +32,8 @@ public class MapMappingOptions extends DelegatingOptions {
private final MapMappingGem mapMapping;
public static MapMappingOptions fromGem(MapMappingGem mapMapping, MapperOptions mapperOptions,
ExecutableElement method, FormattingMessager messager, Types typeUtils) {
ExecutableElement method, FormattingMessager messager,
TypeUtils typeUtils) {
if ( mapMapping == null || !isConsistent( mapMapping, method, messager ) ) {
MapMappingOptions options = new MapMappingOptions(
@ -146,7 +147,7 @@ public class MapMappingOptions extends DelegatingOptions {
.orElse( next().getNullValueMappingStrategy() );
}
public MappingControl getKeyMappingControl(Elements elementUtils) {
public MappingControl getKeyMappingControl(ElementUtils elementUtils) {
return Optional.ofNullable( mapMapping ).map( MapMappingGem::keyMappingControl )
.filter( GemValue::hasValue )
.map( GemValue::getValue )
@ -154,7 +155,7 @@ public class MapMappingOptions extends DelegatingOptions {
.orElse( next().getMappingControl( elementUtils ) );
}
public MappingControl getValueMappingControl(Elements elementUtils) {
public MappingControl getValueMappingControl(ElementUtils elementUtils) {
return Optional.ofNullable( mapMapping ).map( MapMappingGem::valueMappingControl )
.filter( GemValue::hasValue )
.map( GemValue::getValue )

View File

@ -8,7 +8,7 @@ package org.mapstruct.ap.internal.model.source;
import java.util.Set;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import org.mapstruct.ap.internal.util.ElementUtils;
import org.mapstruct.ap.internal.gem.BuilderGem;
import org.mapstruct.ap.internal.gem.CollectionMappingStrategyGem;
@ -132,7 +132,7 @@ public class MapperConfigOptions extends DelegatingOptions {
}
@Override
public MappingControl getMappingControl(Elements elementUtils) {
public MappingControl getMappingControl(ElementUtils elementUtils) {
return mapperConfig.mappingControl().hasValue() ?
MappingControl.fromTypeMirror( mapperConfig.mappingControl().getValue(), elementUtils ) :
next().getMappingControl( elementUtils );

View File

@ -12,7 +12,7 @@ import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import org.mapstruct.ap.internal.util.ElementUtils;
import org.mapstruct.ap.internal.option.Options;
import org.mapstruct.ap.internal.gem.BuilderGem;
@ -162,7 +162,7 @@ public class MapperOptions extends DelegatingOptions {
}
@Override
public MappingControl getMappingControl(Elements elementUtils) {
public MappingControl getMappingControl(ElementUtils elementUtils) {
return mapper.mappingControl().hasValue() ?
MappingControl.fromTypeMirror( mapper.mappingControl().getValue(), elementUtils ) :
next().getMappingControl( elementUtils );

View File

@ -14,7 +14,7 @@ import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import org.mapstruct.ap.internal.util.ElementUtils;
import org.mapstruct.ap.internal.gem.MappingControlGem;
import org.mapstruct.ap.internal.gem.MappingControlUseGem;
@ -32,7 +32,7 @@ public class MappingControl {
private boolean allowMappingMethod = false;
private boolean allow2Steps = false;
public static MappingControl fromTypeMirror(TypeMirror mirror, Elements elementUtils) {
public static MappingControl fromTypeMirror(TypeMirror mirror, ElementUtils elementUtils) {
MappingControl mappingControl = new MappingControl();
if ( TypeKind.DECLARED == mirror.getKind() ) {
resolveControls( mappingControl, ( (DeclaredType) mirror ).asElement(), new HashSet<>(), elementUtils );
@ -60,7 +60,7 @@ public class MappingControl {
}
private static void resolveControls(MappingControl control, Element element, Set<Element> handledElements,
Elements elementUtils) {
ElementUtils elementUtils) {
for ( AnnotationMirror annotationMirror : element.getAnnotationMirrors() ) {
Element lElement = annotationMirror.getAnnotationType().asElement();
if ( isAnnotation( lElement, MAPPING_CONTROL_FQN ) ) {
@ -102,7 +102,7 @@ public class MappingControl {
}
}
private static boolean isAnnotationInPackage(Element element, String packageFQN, Elements elementUtils) {
private static boolean isAnnotationInPackage(Element element, String packageFQN, ElementUtils elementUtils) {
if ( ElementKind.ANNOTATION_TYPE == element.getKind() ) {
return packageFQN.equals( elementUtils.getPackageOf( element ).getQualifiedName().toString() );
}

View File

@ -18,8 +18,8 @@ import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import org.mapstruct.ap.internal.util.ElementUtils;
import org.mapstruct.ap.internal.util.TypeUtils;
import org.mapstruct.ap.internal.gem.MappingGem;
import org.mapstruct.ap.internal.gem.MappingsGem;
@ -93,7 +93,7 @@ public class MappingOptions extends DelegatingOptions {
public static void addInstances(MappingsGem gem, ExecutableElement method,
BeanMappingOptions beanMappingOptions,
FormattingMessager messager, Types typeUtils,
FormattingMessager messager, TypeUtils typeUtils,
Set<MappingOptions> mappings) {
for ( MappingGem mapping : gem.value().getValue() ) {
@ -102,7 +102,8 @@ public class MappingOptions extends DelegatingOptions {
}
public static void addInstance(MappingGem mapping, ExecutableElement method,
BeanMappingOptions beanMappingOptions, FormattingMessager messager, Types typeUtils,
BeanMappingOptions beanMappingOptions, FormattingMessager messager,
TypeUtils typeUtils,
Set<MappingOptions> mappings) {
if ( !isConsistent( mapping, method, messager ) ) {
@ -421,7 +422,7 @@ public class MappingOptions extends DelegatingOptions {
}
@Override
public MappingControl getMappingControl(Elements elementUtils) {
public MappingControl getMappingControl(ElementUtils elementUtils) {
return Optional.ofNullable( mapping ).map( MappingGem::mappingControl )
.filter( GemValue::hasValue )
.map( GemValue::getValue )

View File

@ -19,7 +19,7 @@ import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVariable;
import javax.lang.model.type.WildcardType;
import javax.lang.model.util.SimpleTypeVisitor6;
import javax.lang.model.util.Types;
import org.mapstruct.ap.internal.util.TypeUtils;
import org.mapstruct.ap.internal.model.common.Parameter;
import org.mapstruct.ap.internal.model.common.Type;
@ -53,10 +53,10 @@ import org.mapstruct.ap.internal.model.common.TypeFactory;
public class MethodMatcher {
private final SourceMethod candidateMethod;
private final Types typeUtils;
private final TypeUtils typeUtils;
private final TypeFactory typeFactory;
MethodMatcher(Types typeUtils, TypeFactory typeFactory, SourceMethod candidateMethod) {
MethodMatcher(TypeUtils typeUtils, TypeFactory typeFactory, SourceMethod candidateMethod) {
this.typeUtils = typeUtils;
this.candidateMethod = candidateMethod;
this.typeFactory = typeFactory;
@ -312,8 +312,8 @@ public class MethodMatcher {
// check if types are in bound
TypeMirror lowerBound = t.getLowerBound();
TypeMirror upperBound = t.getUpperBound();
if ( ( isNullType( lowerBound ) || typeUtils.isSubtype( lowerBound, p ) )
&& ( isNullType( upperBound ) || typeUtils.isSubtype( p, upperBound ) ) ) {
if ( ( isNullType( lowerBound ) || typeUtils.isSubtypeErased( lowerBound, p ) )
&& ( isNullType( upperBound ) || typeUtils.isSubtypeErased( p, upperBound ) ) ) {
genericTypesMap.put( t, p );
return Boolean.TRUE;
}
@ -359,7 +359,7 @@ public class MethodMatcher {
// for example method: String method(? super String)
// to check super type, we can simply inverse the argument, but that would initially yield
// a result: <type, superType] (so type not included) so we need to check sameType also.
return typeUtils.isSubtype( superBound, p ) || typeUtils.isSameType( p, superBound );
return typeUtils.isSubtypeErased( superBound, p ) || typeUtils.isSameType( p, superBound );
case TYPEVAR:
@ -377,7 +377,7 @@ public class MethodMatcher {
// to check super type, we can simply inverse the argument, but that would initially yield
// a result: <type, superType] (so type not included) so we need to check sameType also.
TypeMirror superBoundAsDeclared = typeParameter.getBounds().get( 0 );
return ( typeUtils.isSubtype( superBoundAsDeclared, p ) || typeUtils.isSameType(
return ( typeUtils.isSubtypeErased( superBoundAsDeclared, p ) || typeUtils.isSameType(
p,
superBoundAsDeclared ) );
default:
@ -415,7 +415,7 @@ public class MethodMatcher {
List<? extends TypeMirror> bounds = tpe != null ? tpe.getBounds() : null;
if ( t != null && bounds != null ) {
for ( TypeMirror bound : bounds ) {
if ( !( bound.getKind() == TypeKind.DECLARED && typeUtils.isSubtype( t, bound ) ) ) {
if ( !( bound.getKind() == TypeKind.DECLARED && typeUtils.isSubtypeErased( t, bound ) ) ) {
return false;
}
}

View File

@ -9,7 +9,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Objects;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Types;
import org.mapstruct.ap.internal.util.TypeUtils;
import org.mapstruct.ap.internal.model.common.SourceRHS;
@ -24,7 +24,7 @@ public class SelectionParameters {
private final List<TypeMirror> qualifiers;
private final List<String> qualifyingNames;
private final TypeMirror resultType;
private final Types typeUtils;
private final TypeUtils typeUtils;
private final SourceRHS sourceRHS;
/**
@ -45,12 +45,12 @@ public class SelectionParameters {
}
public SelectionParameters(List<TypeMirror> qualifiers, List<String> qualifyingNames, TypeMirror resultType,
Types typeUtils) {
TypeUtils typeUtils) {
this( qualifiers, qualifyingNames, resultType, typeUtils, null );
}
private SelectionParameters(List<TypeMirror> qualifiers, List<String> qualifyingNames, TypeMirror resultType,
Types typeUtils, SourceRHS sourceRHS) {
TypeUtils typeUtils, SourceRHS sourceRHS) {
this.qualifiers = qualifiers;
this.qualifyingNames = qualifyingNames;
this.resultType = resultType;

View File

@ -13,7 +13,7 @@ import java.util.Set;
import java.util.stream.Collectors;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.util.Types;
import org.mapstruct.ap.internal.util.TypeUtils;
import org.mapstruct.ap.internal.model.common.Accessibility;
import org.mapstruct.ap.internal.model.common.Parameter;
@ -37,7 +37,7 @@ import static org.mapstruct.ap.internal.util.Collections.first;
*/
public class SourceMethod implements Method {
private final Types typeUtils;
private final TypeUtils typeUtils;
private final TypeFactory typeFactory;
private final Type declaringMapper;
@ -82,7 +82,7 @@ public class SourceMethod implements Method {
private IterableMappingOptions iterableMapping = null;
private MapMappingOptions mapMapping = null;
private BeanMappingOptions beanMapping = null;
private Types typeUtils;
private TypeUtils typeUtils;
private TypeFactory typeFactory = null;
private MapperOptions mapper = null;
private List<SourceMethod> prototypeMethods = Collections.emptyList();
@ -146,7 +146,7 @@ public class SourceMethod implements Method {
return this;
}
public Builder setTypeUtils(Types typeUtils) {
public Builder setTypeUtils(TypeUtils typeUtils) {
this.typeUtils = typeUtils;
return this;
}

View File

@ -8,8 +8,8 @@ package org.mapstruct.ap.internal.model.source.selector;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import org.mapstruct.ap.internal.util.ElementUtils;
import org.mapstruct.ap.internal.util.TypeUtils;
import org.mapstruct.ap.internal.model.common.Type;
import org.mapstruct.ap.internal.model.common.TypeFactory;
@ -25,7 +25,7 @@ public class MethodSelectors {
private final List<MethodSelector> selectors;
public MethodSelectors(Types typeUtils, Elements elementUtils, TypeFactory typeFactory,
public MethodSelectors(TypeUtils typeUtils, ElementUtils elementUtils, TypeFactory typeFactory,
FormattingMessager messager) {
selectors = Arrays.asList(
new MethodFamilySelector(),

View File

@ -12,8 +12,8 @@ import java.util.Set;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import org.mapstruct.ap.internal.util.ElementUtils;
import org.mapstruct.ap.internal.util.TypeUtils;
import org.mapstruct.ap.internal.model.common.Type;
import org.mapstruct.ap.internal.model.source.Method;
@ -40,10 +40,10 @@ import org.mapstruct.ap.internal.gem.QualifierGem;
*/
public class QualifierSelector implements MethodSelector {
private final Types typeUtils;
private final TypeUtils typeUtils;
private final TypeMirror namedAnnotationTypeMirror;
public QualifierSelector( Types typeUtils, Elements elementUtils ) {
public QualifierSelector(TypeUtils typeUtils, ElementUtils elementUtils ) {
this.typeUtils = typeUtils;
namedAnnotationTypeMirror = elementUtils.getTypeElement( "org.mapstruct.Named" ).asType();
}

View File

@ -9,7 +9,7 @@ import java.util.ArrayList;
import java.util.List;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Types;
import org.mapstruct.ap.internal.util.TypeUtils;
import org.mapstruct.ap.internal.model.common.Type;
import org.mapstruct.ap.internal.model.source.Method;
@ -24,9 +24,9 @@ import org.mapstruct.ap.internal.model.source.Method;
*/
public class TargetTypeSelector implements MethodSelector {
private final Types typeUtils;
private final TypeUtils typeUtils;
public TargetTypeSelector( Types typeUtils ) {
public TargetTypeSelector( TypeUtils typeUtils ) {
this.typeUtils = typeUtils;
}

View File

@ -11,7 +11,7 @@ import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Types;
import org.mapstruct.ap.internal.util.TypeUtils;
import org.mapstruct.ap.internal.gem.XmlElementRefGem;
import org.mapstruct.ap.internal.model.common.Type;
@ -37,9 +37,9 @@ import org.mapstruct.ap.internal.gem.XmlElementDeclGem;
*/
public class XmlElementDeclSelector implements MethodSelector {
private final Types typeUtils;
private final TypeUtils typeUtils;
public XmlElementDeclSelector(Types typeUtils) {
public XmlElementDeclSelector(TypeUtils typeUtils) {
this.typeUtils = typeUtils;
}

View File

@ -13,18 +13,17 @@ import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.Element;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import javax.tools.Diagnostic.Kind;
import org.mapstruct.ap.internal.model.common.TypeFactory;
import org.mapstruct.ap.internal.option.Options;
import org.mapstruct.ap.internal.processor.ModelElementProcessor.ProcessorContext;
import org.mapstruct.ap.internal.util.AccessorNamingUtils;
import org.mapstruct.ap.internal.util.ElementUtils;
import org.mapstruct.ap.internal.util.FormattingMessager;
import org.mapstruct.ap.internal.util.Message;
import org.mapstruct.ap.internal.util.RoundContext;
import org.mapstruct.ap.internal.util.workarounds.TypesDecorator;
import org.mapstruct.ap.internal.util.TypeUtils;
import org.mapstruct.ap.internal.version.VersionInformation;
import org.mapstruct.ap.spi.EnumMappingStrategy;
import org.mapstruct.ap.spi.EnumTransformationStrategy;
@ -41,7 +40,8 @@ public class DefaultModelElementProcessorContext implements ProcessorContext {
private final Options options;
private final TypeFactory typeFactory;
private final VersionInformation versionInformation;
private final Types delegatingTypes;
private final TypeUtils delegatingTypes;
private final ElementUtils delegatingElements;
private final AccessorNamingUtils accessorNaming;
private final RoundContext roundContext;
@ -52,10 +52,11 @@ public class DefaultModelElementProcessorContext implements ProcessorContext {
this.messager = new DelegatingMessager( processingEnvironment.getMessager(), options.isVerbose() );
this.accessorNaming = roundContext.getAnnotationProcessorContext().getAccessorNaming();
this.versionInformation = DefaultVersionInformation.fromProcessingEnvironment( processingEnvironment );
this.delegatingTypes = new TypesDecorator( processingEnvironment, versionInformation );
this.delegatingTypes = TypeUtils.create( processingEnvironment, versionInformation );
this.delegatingElements = ElementUtils.create( processingEnvironment, versionInformation );
this.roundContext = roundContext;
this.typeFactory = new TypeFactory(
processingEnvironment.getElementUtils(),
delegatingElements,
delegatingTypes,
messager,
roundContext,
@ -71,13 +72,13 @@ public class DefaultModelElementProcessorContext implements ProcessorContext {
}
@Override
public Types getTypeUtils() {
public TypeUtils getTypeUtils() {
return delegatingTypes;
}
@Override
public Elements getElementUtils() {
return processingEnvironment.getElementUtils();
public ElementUtils getElementUtils() {
return delegatingElements;
}
@Override

View File

@ -18,8 +18,8 @@ import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import org.mapstruct.ap.internal.util.ElementUtils;
import org.mapstruct.ap.internal.util.TypeUtils;
import org.mapstruct.ap.internal.model.BeanMappingMethod;
import org.mapstruct.ap.internal.model.ContainerMappingMethod;
@ -73,8 +73,8 @@ import static org.mapstruct.ap.internal.util.Collections.join;
*/
public class MapperCreationProcessor implements ModelElementProcessor<List<SourceMethod>, Mapper> {
private Elements elementUtils;
private Types typeUtils;
private ElementUtils elementUtils;
private TypeUtils typeUtils;
private FormattingMessager messager;
private Options options;
private VersionInformation versionInformation;

View File

@ -21,9 +21,15 @@ import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.ExecutableType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import org.mapstruct.ap.internal.gem.BeanMappingGem;
import org.mapstruct.ap.internal.gem.IterableMappingGem;
import org.mapstruct.ap.internal.gem.MapMappingGem;
import org.mapstruct.ap.internal.gem.MappingGem;
import org.mapstruct.ap.internal.gem.MappingsGem;
import org.mapstruct.ap.internal.gem.ObjectFactoryGem;
import org.mapstruct.ap.internal.gem.ValueMappingGem;
import org.mapstruct.ap.internal.gem.ValueMappingsGem;
import org.mapstruct.ap.internal.model.common.Parameter;
import org.mapstruct.ap.internal.model.common.Type;
import org.mapstruct.ap.internal.model.common.TypeFactory;
@ -36,24 +42,16 @@ import org.mapstruct.ap.internal.model.source.MappingOptions;
import org.mapstruct.ap.internal.model.source.ParameterProvidedMethods;
import org.mapstruct.ap.internal.model.source.SourceMethod;
import org.mapstruct.ap.internal.model.source.ValueMappingOptions;
import org.mapstruct.ap.internal.gem.BeanMappingGem;
import org.mapstruct.ap.internal.gem.IterableMappingGem;
import org.mapstruct.ap.internal.gem.MapMappingGem;
import org.mapstruct.ap.internal.gem.MappingGem;
import org.mapstruct.ap.internal.gem.MappingsGem;
import org.mapstruct.ap.internal.gem.ObjectFactoryGem;
import org.mapstruct.ap.internal.gem.ValueMappingGem;
import org.mapstruct.ap.internal.gem.ValueMappingsGem;
import org.mapstruct.ap.internal.option.Options;
import org.mapstruct.ap.internal.util.AccessorNamingUtils;
import org.mapstruct.ap.internal.util.AnnotationProcessingException;
import org.mapstruct.ap.internal.util.ElementUtils;
import org.mapstruct.ap.internal.util.Executables;
import org.mapstruct.ap.internal.util.FormattingMessager;
import org.mapstruct.ap.internal.util.Message;
import org.mapstruct.ap.internal.util.TypeUtils;
import org.mapstruct.ap.spi.EnumTransformationStrategy;
import static org.mapstruct.ap.internal.util.Executables.getAllEnclosedExecutableElements;
/**
* A {@link ModelElementProcessor} which retrieves a list of {@link SourceMethod}s
* representing all the mapping methods of the given bean mapper type as well as
@ -73,8 +71,8 @@ public class MethodRetrievalProcessor implements ModelElementProcessor<Void, Lis
private TypeFactory typeFactory;
private AccessorNamingUtils accessorNaming;
private Map<String, EnumTransformationStrategy> enumTransformationStrategies;
private Types typeUtils;
private Elements elementUtils;
private TypeUtils typeUtils;
private ElementUtils elementUtils;
private Options options;
@Override
@ -119,7 +117,7 @@ public class MethodRetrievalProcessor implements ModelElementProcessor<Void, Lis
TypeElement typeElement = asTypeElement( mapperAnnotation.mapperConfigType() );
List<SourceMethod> methods = new ArrayList<>();
for ( ExecutableElement executable : getAllEnclosedExecutableElements( elementUtils, typeElement ) ) {
for ( ExecutableElement executable : elementUtils.getAllEnclosedExecutableElements( typeElement ) ) {
ExecutableType methodType = typeFactory.getMethodType( mapperAnnotation.mapperConfigType(), executable );
List<Parameter> parameters = typeFactory.getParameters( methodType, executable );
@ -160,7 +158,7 @@ public class MethodRetrievalProcessor implements ModelElementProcessor<Void, Lis
MapperOptions mapperOptions, List<SourceMethod> prototypeMethods) {
List<SourceMethod> methods = new ArrayList<>();
for ( ExecutableElement executable : getAllEnclosedExecutableElements( elementUtils, usedMapper ) ) {
for ( ExecutableElement executable : elementUtils.getAllEnclosedExecutableElements( usedMapper ) ) {
SourceMethod method = getMethod(
usedMapper,
executable,

View File

@ -8,8 +8,8 @@ package org.mapstruct.ap.internal.processor;
import java.util.Map;
import javax.annotation.processing.Filer;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import org.mapstruct.ap.internal.util.ElementUtils;
import org.mapstruct.ap.internal.util.TypeUtils;
import javax.tools.Diagnostic.Kind;
import org.mapstruct.ap.internal.model.common.TypeFactory;
@ -35,7 +35,7 @@ public interface ModelElementProcessor<P, R> {
/**
* Context object passed to
* {@link ModelElementProcessor#process(ProcessorContext, TypeElement, Object)}
* providing access to common infrastructure objects such as {@link Types}
* providing access to common infrastructure objects such as {@link TypeUtils}
* etc.
*
* @author Gunnar Morling
@ -44,9 +44,9 @@ public interface ModelElementProcessor<P, R> {
Filer getFiler();
Types getTypeUtils();
TypeUtils getTypeUtils();
Elements getElementUtils();
ElementUtils getElementUtils();
TypeFactory getTypeFactory();

View File

@ -32,8 +32,8 @@ import javax.lang.model.type.ExecutableType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import org.mapstruct.ap.internal.util.ElementUtils;
import org.mapstruct.ap.internal.util.TypeUtils;
import org.mapstruct.ap.internal.conversion.ConversionProvider;
import org.mapstruct.ap.internal.conversion.Conversions;
@ -78,7 +78,7 @@ public class MappingResolverImpl implements MappingResolver {
private static final int LIMIT_REPORTING_AMBIGUOUS = 5;
private final FormattingMessager messager;
private final Types typeUtils;
private final TypeUtils typeUtils;
private final TypeFactory typeFactory;
private final List<Method> sourceModel;
@ -98,7 +98,7 @@ public class MappingResolverImpl implements MappingResolver {
*/
private final Set<SupportingMappingMethod> usedSupportedMappings = new HashSet<>();
public MappingResolverImpl(FormattingMessager messager, Elements elementUtils, Types typeUtils,
public MappingResolverImpl(FormattingMessager messager, ElementUtils elementUtils, TypeUtils typeUtils,
TypeFactory typeFactory, List<Method> sourceModel,
List<MapperReference> mapperReferences, boolean verboseLogging) {
this.messager = messager;

View File

@ -0,0 +1,286 @@
/*
* 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;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.Name;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import org.mapstruct.ap.spi.TypeHierarchyErroneousException;
import static javax.lang.model.util.ElementFilter.fieldsIn;
import static javax.lang.model.util.ElementFilter.methodsIn;
public abstract class AbstractElementUtilsDecorator implements ElementUtils {
private final Elements delegate;
AbstractElementUtilsDecorator(ProcessingEnvironment processingEnv) {
this.delegate = processingEnv.getElementUtils();
}
@Override
public PackageElement getPackageElement(CharSequence name) {
return delegate.getPackageElement( name );
}
@Override
public TypeElement getTypeElement(CharSequence name) {
return delegate.getTypeElement( name );
}
@Override
public Map<? extends ExecutableElement, ? extends AnnotationValue> getElementValuesWithDefaults(
AnnotationMirror a) {
return delegate.getElementValuesWithDefaults( a );
}
@Override
public String getDocComment(Element e) {
return delegate.getDocComment( e );
}
@Override
public boolean isDeprecated(Element e) {
return delegate.isDeprecated( e );
}
@Override
public Name getBinaryName(TypeElement type) {
return delegate.getBinaryName( type );
}
@Override
public PackageElement getPackageOf(Element type) {
return delegate.getPackageOf( type );
}
@Override
public List<? extends Element> getAllMembers(TypeElement type) {
return delegate.getAllMembers( type );
}
@Override
public List<? extends AnnotationMirror> getAllAnnotationMirrors(Element e) {
return delegate.getAllAnnotationMirrors( e );
}
@Override
public boolean hides(Element hider, Element hidden) {
return delegate.hides( hider, hidden );
}
@Override
public boolean overrides(ExecutableElement overrider, ExecutableElement overridden, TypeElement type) {
return delegate.overrides( overrider, overridden, type );
}
@Override
public String getConstantExpression(Object value) {
return delegate.getConstantExpression( value );
}
@Override
public void printElements(Writer w, Element... elements) {
delegate.printElements( w, elements );
}
@Override
public Name getName(CharSequence cs) {
return delegate.getName( cs );
}
@Override
public boolean isFunctionalInterface(TypeElement type) {
return delegate.isFunctionalInterface( type );
}
@Override
public List<ExecutableElement> getAllEnclosedExecutableElements(TypeElement element) {
List<ExecutableElement> enclosedElements = new ArrayList<>();
element = replaceTypeElementIfNecessary( element );
addEnclosedMethodsInHierarchy( enclosedElements, element, element );
return enclosedElements;
}
@Override
public List<VariableElement> getAllEnclosedFields( TypeElement element) {
List<VariableElement> enclosedElements = new ArrayList<>();
element = replaceTypeElementIfNecessary( element );
addEnclosedFieldsInHierarchy( enclosedElements, element, element );
return enclosedElements;
}
private void addEnclosedMethodsInHierarchy(List<ExecutableElement> alreadyAdded, TypeElement element,
TypeElement parentType) {
if ( element != parentType ) { // otherwise the element was already checked for replacement
element = replaceTypeElementIfNecessary( element );
}
if ( element.asType().getKind() == TypeKind.ERROR ) {
throw new TypeHierarchyErroneousException( element );
}
addMethodNotYetOverridden( alreadyAdded, methodsIn( element.getEnclosedElements() ), parentType );
if ( hasNonObjectSuperclass( element ) ) {
addEnclosedMethodsInHierarchy(
alreadyAdded,
asTypeElement( element.getSuperclass() ),
parentType
);
}
for ( TypeMirror interfaceType : element.getInterfaces() ) {
addEnclosedMethodsInHierarchy(
alreadyAdded,
asTypeElement( interfaceType ),
parentType
);
}
}
/**
* @param alreadyCollected methods that have already been collected and to which the not-yet-overridden methods will
* be added
* @param methodsToAdd methods to add to alreadyAdded, if they are not yet overridden by an element in the list
* @param parentType the type for with elements are collected
*/
private void addMethodNotYetOverridden(List<ExecutableElement> alreadyCollected,
List<ExecutableElement> methodsToAdd,
TypeElement parentType) {
List<ExecutableElement> safeToAdd = new ArrayList<>( methodsToAdd.size() );
for ( ExecutableElement toAdd : methodsToAdd ) {
if ( isNotPrivate( toAdd ) && isNotObjectEquals( toAdd )
&& methodWasNotYetOverridden( alreadyCollected, toAdd, parentType ) ) {
safeToAdd.add( toAdd );
}
}
alreadyCollected.addAll( 0, safeToAdd );
}
/**
* @param executable the executable to check
* @return {@code true}, iff the executable does not represent {@link java.lang.Object#equals(Object)} or an
* overridden version of it
*/
private boolean isNotObjectEquals(ExecutableElement executable) {
if ( executable.getSimpleName().contentEquals( "equals" ) && executable.getParameters().size() == 1
&& asTypeElement( executable.getParameters().get( 0 ).asType() ).getQualifiedName().contentEquals(
"java.lang.Object"
) ) {
return false;
}
return true;
}
/**
* @param alreadyCollected the list of already collected methods of one type hierarchy (order is from sub-types to
* super-types)
* @param executable the method to check
* @param parentType the type for which elements are collected
* @return {@code true}, iff the given executable was not yet overridden by a method in the given list.
*/
private boolean methodWasNotYetOverridden(List<ExecutableElement> alreadyCollected,
ExecutableElement executable, TypeElement parentType) {
for ( ListIterator<ExecutableElement> it = alreadyCollected.listIterator(); it.hasNext(); ) {
ExecutableElement executableInSubtype = it.next();
if ( executableInSubtype == null ) {
continue;
}
if ( delegate.overrides( executableInSubtype, executable, parentType ) ) {
return false;
}
else if ( delegate.overrides( executable, executableInSubtype, parentType ) ) {
// remove the method from another interface hierarchy that is overridden by the executable to add
it.remove();
return true;
}
}
return true;
}
private void addEnclosedFieldsInHierarchy( List<VariableElement> alreadyAdded,
TypeElement element, TypeElement parentType) {
if ( element != parentType ) { // otherwise the element was already checked for replacement
element = replaceTypeElementIfNecessary( element );
}
if ( element.asType().getKind() == TypeKind.ERROR ) {
throw new TypeHierarchyErroneousException( element );
}
addFields( alreadyAdded, fieldsIn( element.getEnclosedElements() ) );
if ( hasNonObjectSuperclass( element ) ) {
addEnclosedFieldsInHierarchy(
alreadyAdded,
asTypeElement( element.getSuperclass() ),
parentType
);
}
}
private static void addFields(List<VariableElement> alreadyCollected, List<VariableElement> variablesToAdd) {
List<VariableElement> safeToAdd = new ArrayList<>( variablesToAdd.size() );
safeToAdd.addAll( variablesToAdd );
alreadyCollected.addAll( 0, safeToAdd );
}
/**
* @param element the type element to check
* @return {@code true}, iff the type has a super-class that is not java.lang.Object
*/
private boolean hasNonObjectSuperclass(TypeElement element) {
if ( element.getSuperclass().getKind() == TypeKind.ERROR ) {
throw new TypeHierarchyErroneousException( element );
}
return element.getSuperclass().getKind() == TypeKind.DECLARED
&& !asTypeElement( element.getSuperclass() ).getQualifiedName().toString().equals( "java.lang.Object" );
}
/**
* @param mirror the type positionHint
* @return the corresponding type element
*/
private TypeElement asTypeElement(TypeMirror mirror) {
return (TypeElement) ( (DeclaredType) mirror ).asElement();
}
/**
* @param executable the executable to check
* @return {@code true}, iff the executable does not have a private modifier
*/
private boolean isNotPrivate(ExecutableElement executable) {
return !executable.getModifiers().contains( Modifier.PRIVATE );
}
protected abstract TypeElement replaceTypeElementIfNecessary(TypeElement element);
}

View File

@ -3,10 +3,9 @@
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.ap.internal.util.workarounds;
package org.mapstruct.ap.internal.util;
import java.util.List;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
@ -21,23 +20,18 @@ import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.WildcardType;
import javax.lang.model.util.Types;
import org.mapstruct.ap.internal.version.VersionInformation;
/**
* Replaces the usage of {@link Types} within MapStruct by delegating to the original implementation or to our specific
* workarounds if necessary.
* Replaces the usage of {@link TypeUtils} within MapStruct by delegating to the original implementation or to our
* specific workarounds if necessary.
*
* @author Andreas Gudian
*/
public class TypesDecorator implements Types {
private final Types delegate;
private final ProcessingEnvironment processingEnv;
private final VersionInformation versionInformation;
public abstract class AbstractTypeUtilsDecorator implements TypeUtils {
public TypesDecorator(ProcessingEnvironment processingEnv, VersionInformation versionInformation) {
private final Types delegate;
AbstractTypeUtilsDecorator(ProcessingEnvironment processingEnv) {
this.delegate = processingEnv.getTypeUtils();
this.processingEnv = processingEnv;
this.versionInformation = versionInformation;
}
@Override
@ -52,12 +46,12 @@ public class TypesDecorator implements Types {
@Override
public boolean isSubtype(TypeMirror t1, TypeMirror t2) {
return SpecificCompilerWorkarounds.isSubtype( delegate, t1, t2 );
return delegate.isSubtype( t1, t2 );
}
@Override
public boolean isAssignable(TypeMirror t1, TypeMirror t2) {
return SpecificCompilerWorkarounds.isAssignable( delegate, t1, t2 );
return delegate.isAssignable( t1, t2 );
}
@Override
@ -77,7 +71,7 @@ public class TypesDecorator implements Types {
@Override
public TypeMirror erasure(TypeMirror t) {
return SpecificCompilerWorkarounds.erasure( delegate, t );
return delegate.erasure( t );
}
@Override
@ -132,11 +126,11 @@ public class TypesDecorator implements Types {
@Override
public TypeMirror asMemberOf(DeclaredType containing, Element element) {
return SpecificCompilerWorkarounds.asMemberOf(
delegate,
processingEnv,
versionInformation,
containing,
element );
return delegate.asMemberOf( containing, element );
}
@Override
public boolean isSubtypeErased(TypeMirror t1, TypeMirror t2) {
return delegate.isSubtype( erasure( t1 ), erasure( t2 ) );
}
}

View File

@ -6,9 +6,9 @@
package org.mapstruct.ap.internal.util;
/**
* Utilities for working with classes. It is mainly needed because using the {@link javax.lang.model.util.Elements}
* Utilities for working with classes. It is mainly needed because using the {@link ElementUtils}
* is not always correct. For example when compiling with JDK 9 and source version 8 classes from different modules
* are available by {@link javax.lang.model.util.Elements#getTypeElement(CharSequence)} but they are actually not
* are available by {@link ElementUtils#getTypeElement(CharSequence)} but they are actually not
* if those modules are not added during compilation.
*
* @author Filip Hrisafov

View File

@ -0,0 +1,40 @@
/*
* 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;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;
public class EclipseElementUtilsDecorator extends AbstractElementUtilsDecorator {
private final Elements delegate;
EclipseElementUtilsDecorator(ProcessingEnvironment processingEnv) {
super( processingEnv );
this.delegate = processingEnv.getElementUtils();
}
/**
* When running during Eclipse Incremental Compilation, we might get a TypeElement that has an UnresolvedTypeBinding
* and which is not automatically resolved. In that case, getEnclosedElements returns an empty list. We take that as
* a hint to check if the TypeElement resolved by FQN might have any enclosed elements and, if so, return the
* resolved element.
*
* @param element the original element
* @return the element freshly resolved using the qualified name, if the original element did not return any
* enclosed elements, whereas the resolved element does return enclosed elements.
*/
protected TypeElement replaceTypeElementIfNecessary(TypeElement element) {
if ( element.getEnclosedElements().isEmpty() ) {
TypeElement resolvedByName = delegate.getTypeElement( element.getQualifiedName() );
if ( resolvedByName != null && !resolvedByName.getEnclosedElements().isEmpty() ) {
return resolvedByName;
}
}
return element;
}
}

View File

@ -0,0 +1,15 @@
/*
* 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;
import javax.annotation.processing.ProcessingEnvironment;
public class EclipseTypeUtilsDecorator extends AbstractTypeUtilsDecorator {
EclipseTypeUtilsDecorator(ProcessingEnvironment processingEnv) {
super( processingEnv );
}
}

View File

@ -0,0 +1,46 @@
/*
* 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;
import java.util.List;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.util.Elements;
import org.mapstruct.ap.internal.version.VersionInformation;
public interface ElementUtils extends Elements {
static ElementUtils create(ProcessingEnvironment processingEnvironment, VersionInformation info ) {
if ( info.isEclipseJDTCompiler() ) {
return new EclipseElementUtilsDecorator( processingEnvironment );
}
else {
return new JavacElementUtilsDecorator( processingEnvironment );
}
}
/**
* Finds all executable elements within the given type element, including executable elements defined in super
* classes and implemented interfaces. Methods defined in {@link java.lang.Object},
* implementations of {@link java.lang.Object#equals(Object)} and private methods are ignored
*
* @param element the element to inspect
* @return the executable elements usable in the type
*/
List<ExecutableElement> getAllEnclosedExecutableElements(TypeElement element);
/**
* Finds all variable elements within the given type element, including variable
* elements defined in super classes and implemented interfaces and including the fields in the .
*
* @param element the element to inspect
* @return the executable elements usable in the type
*/
List<VariableElement> getAllEnclosedFields(TypeElement element);
}

View File

@ -7,24 +7,12 @@ package org.mapstruct.ap.internal.util;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import org.mapstruct.ap.internal.gem.AfterMappingGem;
import org.mapstruct.ap.internal.gem.BeforeMappingGem;
import org.mapstruct.ap.internal.util.accessor.Accessor;
import org.mapstruct.ap.spi.TypeHierarchyErroneousException;
import static javax.lang.model.util.ElementFilter.methodsIn;
import static org.mapstruct.ap.internal.util.workarounds.SpecificCompilerWorkarounds.replaceTypeElementIfNecessary;
/**
* Provides functionality around {@link ExecutableElement}s.
@ -74,151 +62,6 @@ public class Executables {
}
}
/**
* @param mirror the type positionHint
*
* @return the corresponding type element
*/
private static TypeElement asTypeElement(TypeMirror mirror) {
return (TypeElement) ( (DeclaredType) mirror ).asElement();
}
/**
* Finds all executable elements within the given type element, including executable elements defined in super
* classes and implemented interfaces. Methods defined in {@link java.lang.Object},
* implementations of {@link java.lang.Object#equals(Object)} and private methods are ignored
*
* @param elementUtils element helper
* @param element the element to inspect
*
* @return the executable elements usable in the type
*/
public static List<ExecutableElement> getAllEnclosedExecutableElements(Elements elementUtils, TypeElement element) {
List<ExecutableElement> enclosedElements = new ArrayList<>();
element = replaceTypeElementIfNecessary( elementUtils, element );
addEnclosedElementsInHierarchy( elementUtils, enclosedElements, element, element );
return enclosedElements;
}
private static void addEnclosedElementsInHierarchy(Elements elementUtils, List<ExecutableElement> alreadyAdded,
TypeElement element, TypeElement parentType) {
if ( element != parentType ) { // otherwise the element was already checked for replacement
element = replaceTypeElementIfNecessary( elementUtils, element );
}
if ( element.asType().getKind() == TypeKind.ERROR ) {
throw new TypeHierarchyErroneousException( element );
}
addNotYetOverridden( elementUtils, alreadyAdded, methodsIn( element.getEnclosedElements() ), parentType );
if ( hasNonObjectSuperclass( element ) ) {
addEnclosedElementsInHierarchy(
elementUtils,
alreadyAdded,
asTypeElement( element.getSuperclass() ),
parentType
);
}
for ( TypeMirror interfaceType : element.getInterfaces() ) {
addEnclosedElementsInHierarchy(
elementUtils,
alreadyAdded,
asTypeElement( interfaceType ),
parentType
);
}
}
/**
* @param alreadyCollected methods that have already been collected and to which the not-yet-overridden methods will
* be added
* @param methodsToAdd methods to add to alreadyAdded, if they are not yet overridden by an element in the list
* @param parentType the type for with elements are collected
*/
private static void addNotYetOverridden(Elements elementUtils, List<ExecutableElement> alreadyCollected,
List<ExecutableElement> methodsToAdd, TypeElement parentType) {
List<ExecutableElement> safeToAdd = new ArrayList<>( methodsToAdd.size() );
for ( ExecutableElement toAdd : methodsToAdd ) {
if ( isNotPrivate( toAdd ) && isNotObjectEquals( toAdd )
&& wasNotYetOverridden( elementUtils, alreadyCollected, toAdd, parentType ) ) {
safeToAdd.add( toAdd );
}
}
alreadyCollected.addAll( 0, safeToAdd );
}
/**
* @param executable the executable to check
*
* @return {@code true}, iff the executable does not represent {@link java.lang.Object#equals(Object)} or an
* overridden version of it
*/
private static boolean isNotObjectEquals(ExecutableElement executable) {
if ( executable.getSimpleName().contentEquals( "equals" ) && executable.getParameters().size() == 1
&& asTypeElement( executable.getParameters().get( 0 ).asType() ).getQualifiedName().contentEquals(
"java.lang.Object"
) ) {
return false;
}
return true;
}
/**
* @param executable the executable to check
*
* @return {@code true}, iff the executable does not have a private modifier
*/
private static boolean isNotPrivate(ExecutableElement executable) {
return !executable.getModifiers().contains( Modifier.PRIVATE );
}
/**
* @param elementUtils the elementUtils
* @param alreadyCollected the list of already collected methods of one type hierarchy (order is from sub-types to
* super-types)
* @param executable the method to check
* @param parentType the type for which elements are collected
* @return {@code true}, iff the given executable was not yet overridden by a method in the given list.
*/
private static boolean wasNotYetOverridden(Elements elementUtils, List<ExecutableElement> alreadyCollected,
ExecutableElement executable, TypeElement parentType) {
for ( ListIterator<ExecutableElement> it = alreadyCollected.listIterator(); it.hasNext(); ) {
ExecutableElement executableInSubtype = it.next();
if ( executableInSubtype == null ) {
continue;
}
if ( elementUtils.overrides( executableInSubtype, executable, parentType ) ) {
return false;
}
else if ( elementUtils.overrides( executable, executableInSubtype, parentType ) ) {
// remove the method from another interface hierarchy that is overridden by the executable to add
it.remove();
return true;
}
}
return true;
}
/**
* @param element the type element to check
*
* @return {@code true}, iff the type has a super-class that is not java.lang.Object
*/
private static boolean hasNonObjectSuperclass(TypeElement element) {
if ( element.getSuperclass().getKind() == TypeKind.ERROR ) {
throw new TypeHierarchyErroneousException( element );
}
return element.getSuperclass().getKind() == TypeKind.DECLARED
&& !asTypeElement( element.getSuperclass() ).getQualifiedName().toString().equals( "java.lang.Object" );
}
/**
* @param executableElement the element to check
* @return {@code true}, if the executable element is a method annotated with {@code @BeforeMapping} or

View File

@ -5,21 +5,15 @@
*/
package org.mapstruct.ap.internal.util;
import java.util.ArrayList;
import java.util.List;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import org.mapstruct.ap.spi.TypeHierarchyErroneousException;
import static javax.lang.model.util.ElementFilter.fieldsIn;
import static org.mapstruct.ap.internal.util.workarounds.SpecificCompilerWorkarounds.replaceTypeElementIfNecessary;
/**
* Provides functionality around {@link VariableElement}s.
*
@ -42,53 +36,6 @@ public class Fields {
return !method.getModifiers().contains( Modifier.STATIC );
}
/**
* Finds all variable elements within the given type element, including variable
* elements defined in super classes and implemented interfaces and including the fields in the .
*
* @param elementUtils element helper
* @param element the element to inspect
*
* @return the executable elements usable in the type
*/
public static List<VariableElement> getAllEnclosedFields(Elements elementUtils, TypeElement element) {
List<VariableElement> enclosedElements = new ArrayList<>();
element = replaceTypeElementIfNecessary( elementUtils, element );
addEnclosedElementsInHierarchy( elementUtils, enclosedElements, element, element );
return enclosedElements;
}
private static void addEnclosedElementsInHierarchy(Elements elementUtils, List<VariableElement> alreadyAdded,
TypeElement element, TypeElement parentType) {
if ( element != parentType ) { // otherwise the element was already checked for replacement
element = replaceTypeElementIfNecessary( elementUtils, element );
}
if ( element.asType().getKind() == TypeKind.ERROR ) {
throw new TypeHierarchyErroneousException( element );
}
addFields( alreadyAdded, fieldsIn( element.getEnclosedElements() ) );
if ( hasNonObjectSuperclass( element ) ) {
addEnclosedElementsInHierarchy(
elementUtils,
alreadyAdded,
asTypeElement( element.getSuperclass() ),
parentType
);
}
}
private static void addFields(List<VariableElement> alreadyCollected, List<VariableElement> variablesToAdd) {
List<VariableElement> safeToAdd = new ArrayList<>( variablesToAdd.size() );
safeToAdd.addAll( variablesToAdd );
alreadyCollected.addAll( 0, safeToAdd );
}
private static TypeElement asTypeElement(TypeMirror mirror) {
return (TypeElement) ( (DeclaredType) mirror ).asElement();
}

View File

@ -20,7 +20,6 @@ import javax.lang.model.element.VariableElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.ExecutableType;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Types;
import org.mapstruct.ap.internal.util.accessor.Accessor;
import org.mapstruct.ap.internal.util.accessor.ExecutableElementAccessor;
@ -60,10 +59,10 @@ public class Filters {
}
private final AccessorNamingUtils accessorNaming;
private final Types typeUtils;
private final TypeUtils typeUtils;
private final TypeMirror typeMirror;
public Filters(AccessorNamingUtils accessorNaming, Types typeUtils, TypeMirror typeMirror) {
public Filters(AccessorNamingUtils accessorNaming, TypeUtils typeUtils, TypeMirror typeMirror) {
this.accessorNaming = accessorNaming;
this.typeUtils = typeUtils;
this.typeMirror = typeMirror;

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;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.TypeElement;
public class JavacElementUtilsDecorator extends AbstractElementUtilsDecorator {
JavacElementUtilsDecorator(ProcessingEnvironment processingEnv) {
super( processingEnv );
}
@Override
protected TypeElement replaceTypeElementIfNecessary(TypeElement element) {
return element;
}
}

View File

@ -0,0 +1,15 @@
/*
* 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;
import javax.annotation.processing.ProcessingEnvironment;
public class JavacTypeUtilsDecorator extends AbstractTypeUtilsDecorator {
JavacTypeUtilsDecorator(ProcessingEnvironment processingEnv) {
super( processingEnv );
}
}

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.internal.util;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Types;
import org.mapstruct.ap.internal.version.VersionInformation;
public interface TypeUtils extends Types {
static TypeUtils create(ProcessingEnvironment processingEnvironment, VersionInformation info ) {
if ( info.isEclipseJDTCompiler() ) {
return new EclipseTypeUtilsDecorator( processingEnvironment );
}
else {
return new JavacTypeUtilsDecorator( processingEnvironment );
}
}
boolean isSubtypeErased(TypeMirror t1, TypeMirror t2);
}

View File

@ -1,182 +0,0 @@
/*
* 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.workarounds;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Types;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
import org.eclipse.jdt.internal.compiler.apt.model.ElementImpl;
import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
/**
* Contains the workaround for {@link Types#asMemberOf(DeclaredType, Element)} using Eclipse implementation types.
* <p>
* <strong>This class may only be accessed through {@link EclipseClassLoaderBridge} when running within Eclipse</strong>
*
* @author Andreas Gudian
*/
final class EclipseAsMemberOfWorkaround {
private EclipseAsMemberOfWorkaround() {
}
/**
* Eclipse-specific implementation of {@link Types#asMemberOf(DeclaredType, Element)}.
* <p>
* Returns {@code null} if the implementation could not determine the result.
*/
static TypeMirror asMemberOf(ProcessingEnvironment environment, DeclaredType containing,
Element element) {
ElementImpl elementImpl = tryCast( element, ElementImpl.class );
BaseProcessingEnvImpl env = tryCast( environment, BaseProcessingEnvImpl.class );
if ( elementImpl == null || env == null ) {
return null;
}
ReferenceBinding referenceBinding =
(ReferenceBinding) ( (ElementImpl) environment.getTypeUtils().asElement( containing ) )._binding;
MethodBinding methodBinding = (MethodBinding) elementImpl._binding;
// matches in super-classes have priority
MethodBinding inSuperclassHiearchy = findInSuperclassHierarchy( methodBinding, referenceBinding );
if ( inSuperclassHiearchy != null ) {
return env.getFactory().newTypeMirror( inSuperclassHiearchy );
}
// if nothing was found, traverse the interfaces and collect all candidate methods that match
List<MethodBinding> candidatesFromInterfaces = new ArrayList<>();
collectFromInterfaces(
methodBinding,
referenceBinding,
new HashSet<>(),
candidatesFromInterfaces );
// there can be multiple matches for the same method name from adjacent interface hierarchies.
candidatesFromInterfaces.sort( MostSpecificMethodBindingComparator.INSTANCE );
if ( !candidatesFromInterfaces.isEmpty() ) {
// return the most specific match
return env.getFactory().newTypeMirror( candidatesFromInterfaces.get( 0 ) );
}
return null;
}
private static <T> T tryCast(Object instance, Class<T> type) {
if ( type.isInstance( instance ) ) {
return type.cast( instance );
}
return null;
}
private static void collectFromInterfaces(MethodBinding methodBinding, ReferenceBinding typeBinding,
Set<ReferenceBinding> visitedTypes, List<MethodBinding> found) {
if ( typeBinding == null ) {
return;
}
// also check the interfaces of the superclass hierarchy (the superclasses themselves don't contain a match,
// we checked that already)
collectFromInterfaces( methodBinding, typeBinding.superclass(), visitedTypes, found );
for ( ReferenceBinding ifc : typeBinding.superInterfaces() ) {
if ( visitedTypes.contains( ifc ) ) {
continue;
}
visitedTypes.add( ifc );
// finding a match in one interface
MethodBinding f = findMatchingMethodBinding( methodBinding, ifc.methods() );
if ( f == null ) {
collectFromInterfaces( methodBinding, ifc, visitedTypes, found );
}
else {
// no need for recursion if we found a candidate in this type already
found.add( f );
}
}
}
/**
* @param baseMethod binding to compare against
* @param methods the candidate methods
* @return The method from the list of candidates that matches the name and original/erasure of
* {@code methodBinding}, or {@code null} if none was found.
*/
private static MethodBinding findMatchingMethodBinding(MethodBinding baseMethod, MethodBinding[] methods) {
for ( MethodBinding method : methods ) {
if ( CharOperation.equals( method.selector, baseMethod.selector )
&& ( method.original() == baseMethod || method.areParameterErasuresEqual( baseMethod ) ) ) {
return method;
}
}
return null;
}
private static MethodBinding findInSuperclassHierarchy(MethodBinding baseMethod, ReferenceBinding typeBinding) {
while ( typeBinding != null ) {
MethodBinding matching = findMatchingMethodBinding( baseMethod, typeBinding.methods() );
if ( matching != null ) {
return matching;
}
typeBinding = typeBinding.superclass();
}
return null;
}
/**
* Compares MethodBindings by their signature: the more specific method is considered <em>lower</em>.
*
* @author Andreas Gudian
*/
private static final class MostSpecificMethodBindingComparator implements Comparator<MethodBinding> {
private static final MostSpecificMethodBindingComparator INSTANCE = new MostSpecificMethodBindingComparator();
@Override
public int compare(MethodBinding first, MethodBinding second) {
boolean firstParamsAssignableFromSecond =
first.areParametersCompatibleWith( second.parameters );
boolean secondParamsAssignableFromFirst =
second.areParametersCompatibleWith( first.parameters );
if ( firstParamsAssignableFromSecond != secondParamsAssignableFromFirst ) {
return firstParamsAssignableFromSecond ? 1 : -1;
}
if ( TypeBinding.equalsEquals( first.returnType, second.returnType ) ) {
return 0;
}
boolean firstReturnTypeAssignableFromSecond =
second.returnType.isCompatibleWith( first.returnType );
return firstReturnTypeAssignableFromSecond ? 1 : -1;
}
}
}

View File

@ -1,75 +0,0 @@
/*
* 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.workarounds;
import java.lang.reflect.Method;
import java.net.URLClassLoader;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror;
/**
* In Eclipse 4.6, the ClassLoader of the annotation processor does not provide access to the implementation types of
* the APT-API anymore, so we need to create a new ClassLoader containing the processor class path URLs and having the
* ClassLoader of the APT-API implementations as parent. The method invocation then consequently needs to be done via
* reflection.
*
* @author Andreas Gudian
*/
class EclipseClassLoaderBridge {
private static final String ECLIPSE_AS_MEMBER_OF_WORKAROUND =
"org.mapstruct.ap.internal.util.workarounds.EclipseAsMemberOfWorkaround";
private static ClassLoader classLoader;
private static Method asMemberOf;
private EclipseClassLoaderBridge() {
}
/**
* Invokes {@link EclipseAsMemberOfWorkaround#asMemberOf(ProcessingEnvironment, DeclaredType, Element)} via
* reflection using a special ClassLoader.
*/
static TypeMirror invokeAsMemberOfWorkaround(ProcessingEnvironment env, DeclaredType containing, Element element)
throws Exception {
return (TypeMirror) getAsMemberOf( element.getClass().getClassLoader() ).invoke(
null,
env,
containing,
element );
}
private static ClassLoader getOrCreateClassLoader(ClassLoader parent) {
if ( classLoader == null ) {
classLoader = new URLClassLoader(
( (URLClassLoader) EclipseClassLoaderBridge.class.getClassLoader() ).getURLs(),
parent );
}
return classLoader;
}
private static Method getAsMemberOf(ClassLoader platformClassLoader) throws Exception {
if ( asMemberOf == null ) {
Class<?> workaroundClass =
getOrCreateClassLoader( platformClassLoader ).loadClass( ECLIPSE_AS_MEMBER_OF_WORKAROUND );
Method found = workaroundClass.getDeclaredMethod(
"asMemberOf",
ProcessingEnvironment.class,
DeclaredType.class,
Element.class );
found.setAccessible( true );
asMemberOf = found;
}
return asMemberOf;
}
}

View File

@ -1,140 +0,0 @@
/*
* 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.workarounds;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import org.mapstruct.ap.internal.version.VersionInformation;
/**
* Contains workarounds for various quirks in specific compilers.
*
* @author Sjaak Derksen
* @author Andreas Gudian
*/
public class SpecificCompilerWorkarounds {
private SpecificCompilerWorkarounds() {
}
/**
* Tests whether one type is assignable to another, checking for VOID first.
*
* @param types the type utils
* @param t1 the first type
* @param t2 the second type
* @return {@code true} if and only if the first type is assignable to the second
* @throws IllegalArgumentException if given an executable or package type
*/
static boolean isAssignable(Types types, TypeMirror t1, TypeMirror t2) {
if ( t1.getKind() == TypeKind.VOID ) {
return false;
}
return types.isAssignable( t1, t2 );
}
/**
* Tests whether one type is a subtype of another. Any type is considered to be a subtype of itself. Also see <a
* href="http://docs.oracle.com/javase/specs/jls/se8/html/jls-4.html">JLS section 4.10, Subtyping</a>.
* <p>
* Work-around for a bug related to sub-typing in the Eclipse JSR 269 implementation.
*
* @param types the type utils
* @param t1 the first type
* @param t2 the second type
* @return {@code true} if and only if the first type is a subtype of the second
* @throws IllegalArgumentException if given an executable or package type
*/
static boolean isSubtype(Types types, TypeMirror t1, TypeMirror t2) {
if ( t1.getKind() == TypeKind.VOID ) {
return false;
}
return types.isSubtype( erasure( types, t1 ), erasure( types, t2 ) );
}
/**
* Returns the erasure of a type.
* <p>
* Performs an additional test on the given type to check if it is not void. Calling
* {@link Types#erasure(TypeMirror)} with a void kind type will create a ClassCastException in Eclipse JDT. See the
* JLS, section 4.6 Type Erasure, for reference.
*
* @param types the type utils
* @param t the type to be erased
* @return the erasure of the given type
* @throws IllegalArgumentException if given a package type
*/
static TypeMirror erasure(Types types, TypeMirror t) {
if ( t.getKind() == TypeKind.VOID || t.getKind() == TypeKind.NULL ) {
return t;
}
else {
return types.erasure( t );
}
}
/**
* When running during Eclipse Incremental Compilation, we might get a TypeElement that has an UnresolvedTypeBinding
* and which is not automatically resolved. In that case, getEnclosedElements returns an empty list. We take that as
* a hint to check if the TypeElement resolved by FQN might have any enclosed elements and, if so, return the
* resolved element.
*
* @param elementUtils element utils
* @param element the original element
* @return the element freshly resolved using the qualified name, if the original element did not return any
* enclosed elements, whereas the resolved element does return enclosed elements.
*/
public static TypeElement replaceTypeElementIfNecessary(Elements elementUtils, TypeElement element) {
if ( element.getEnclosedElements().isEmpty() ) {
TypeElement resolvedByName = elementUtils.getTypeElement( element.getQualifiedName() );
if ( resolvedByName != null && !resolvedByName.getEnclosedElements().isEmpty() ) {
return resolvedByName;
}
}
return element;
}
/**
* Workaround for Bugs in the Eclipse implementation of {@link Types#asMemberOf(DeclaredType, Element)}.
*
* @see <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=382590">Eclipse Bug 382590 (fixed in Eclipse 4.6)</a>
* @see <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=481555">Eclipse Bug 481555</a>
*/
static TypeMirror asMemberOf(Types typeUtils, ProcessingEnvironment env, VersionInformation versionInformation,
DeclaredType containing, Element element) {
TypeMirror result = null;
Exception lastException = null;
try {
try {
result = typeUtils.asMemberOf( containing, element );
}
catch ( IllegalArgumentException e ) {
lastException = e;
if ( versionInformation.isEclipseJDTCompiler() ) {
result = EclipseClassLoaderBridge.invokeAsMemberOfWorkaround( env, containing, element );
}
}
}
catch ( Exception e ) {
lastException = e;
}
if ( null == result ) {
throw new RuntimeException( "Fallback implementation of asMemberOf didn't work for "
+ element + " in " + containing, lastException );
}
return result;
}
}

View File

@ -23,9 +23,9 @@ import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVisitor;
import javax.lang.model.type.WildcardType;
import javax.lang.model.util.Types;
import org.junit.Test;
import org.mapstruct.ap.internal.util.TypeUtils;
import static org.assertj.core.api.Assertions.assertThat;
@ -73,7 +73,12 @@ public class SelectionParametersTest {
}
}
private final Types typeUtils = new Types() {
private final TypeUtils typeUtils = new TypeUtils() {
@Override
public boolean isSubtypeErased(TypeMirror t1, TypeMirror t2) {
throw new UnsupportedOperationException( "isSubTypeErased is not supported" );
}
@Override
public Element asElement(TypeMirror t) {
throw new UnsupportedOperationException( "asElement is not supported" );