#312 rename TypeUtilsJDK8Fix to SpecificCompilerWorkarounds and encapsulate all access to Types#erasure(..) by that class, preventing ClassCastExceptions in Eclipse JDT in case we try to determine the erasure of "void"

This commit is contained in:
Andreas Gudian 2014-10-24 20:00:50 +02:00 committed by Gunnar Morling
parent c590e35548
commit 912ba714c1
4 changed files with 57 additions and 26 deletions

View File

@ -24,6 +24,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
@ -40,7 +41,7 @@ import javax.lang.model.util.Types;
import org.mapstruct.ap.util.Executables;
import org.mapstruct.ap.util.Filters;
import org.mapstruct.ap.util.Nouns;
import org.mapstruct.ap.util.TypeUtilsJDK6Fix;
import org.mapstruct.ap.util.SpecificCompilerWorkarounds;
/**
* Represents (a reference to) the type of a bean property, parameter etc. Types are managed per generated source file.
@ -239,7 +240,7 @@ public class Type extends ModelElement implements Comparable<Type> {
return new Type(
typeUtils,
elementUtils,
typeUtils.erasure( typeMirror ),
SpecificCompilerWorkarounds.erasure( typeUtils, typeMirror ),
typeElement,
typeParameters,
implementationType,
@ -429,8 +430,9 @@ 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 TypeUtilsJDK6Fix.isSubType( typeUtils, candidate, classType );
TypeMirror classType =
SpecificCompilerWorkarounds.erasure( typeUtils, elementUtils.getTypeElement( className ).asType() );
return SpecificCompilerWorkarounds.isSubType( typeUtils, candidate, classType );
}
/**

View File

@ -51,7 +51,9 @@ import javax.lang.model.util.Types;
import org.mapstruct.ap.prism.MappingTargetPrism;
import org.mapstruct.ap.prism.TargetTypePrism;
import org.mapstruct.ap.util.AnnotationProcessingException;
import org.mapstruct.ap.util.TypeUtilsJDK6Fix;
import org.mapstruct.ap.util.SpecificCompilerWorkarounds;
import static org.mapstruct.ap.util.SpecificCompilerWorkarounds.erasure;
/**
* Factory creating {@link Type} instances.
@ -74,12 +76,10 @@ public class TypeFactory {
this.elementUtils = elementUtils;
this.typeUtils = typeUtils;
iterableType = typeUtils.erasure( elementUtils.getTypeElement( Iterable.class.getCanonicalName() ).asType() );
collectionType = typeUtils.erasure(
elementUtils.getTypeElement( Collection.class.getCanonicalName() )
.asType()
);
mapType = typeUtils.erasure( elementUtils.getTypeElement( Map.class.getCanonicalName() ).asType() );
iterableType = erasure( typeUtils, elementUtils.getTypeElement( Iterable.class.getCanonicalName() ).asType() );
collectionType =
erasure( typeUtils, elementUtils.getTypeElement( Collection.class.getCanonicalName() ).asType() );
mapType = erasure( typeUtils, elementUtils.getTypeElement( Map.class.getCanonicalName() ).asType() );
implementationTypes.put( Iterable.class.getName(), getType( ArrayList.class ) );
implementationTypes.put( Collection.class.getName(), getType( ArrayList.class ) );
@ -123,10 +123,9 @@ public class TypeFactory {
Type implementationType = getImplementationType( mirror );
boolean isVoid = mirror.getKind() == TypeKind.VOID;
boolean isIterableType = !isVoid && TypeUtilsJDK6Fix.isSubType( typeUtils, mirror, iterableType );
boolean isCollectionType = !isVoid && TypeUtilsJDK6Fix.isSubType( typeUtils, mirror, collectionType );
boolean isMapType = !isVoid && TypeUtilsJDK6Fix.isSubType( typeUtils, mirror, mapType );
boolean isIterableType = SpecificCompilerWorkarounds.isSubType( typeUtils, mirror, iterableType );
boolean isCollectionType = SpecificCompilerWorkarounds.isSubType( typeUtils, mirror, collectionType );
boolean isMapType = SpecificCompilerWorkarounds.isSubType( typeUtils, mirror, mapType );
boolean isEnumType;
boolean isInterface;

View File

@ -36,7 +36,7 @@ import javax.lang.model.util.SimpleTypeVisitor6;
import javax.lang.model.util.Types;
import org.mapstruct.ap.model.common.Type;
import org.mapstruct.ap.util.TypeUtilsJDK6Fix;
import org.mapstruct.ap.util.SpecificCompilerWorkarounds;
/**
* SourceMethodMatcher $8.4 of the JavaLanguage specification describes a method body as such:
@ -222,8 +222,8 @@ public class MethodMatcher {
}
else {
// check if types are in bound
if ( TypeUtilsJDK6Fix.isSubType( typeUtils, t.getLowerBound(), p ) &&
TypeUtilsJDK6Fix.isSubType( typeUtils, p, t.getUpperBound() ) ) {
if ( SpecificCompilerWorkarounds.isSubType( typeUtils, t.getLowerBound(), p ) &&
SpecificCompilerWorkarounds.isSubType( typeUtils, p, t.getUpperBound() ) ) {
genericTypesMap.put( t, p );
return Boolean.TRUE;
}
@ -243,7 +243,7 @@ public class MethodMatcher {
case DECLARED:
// for example method: String method(? extends String)
// isSubType checks range [subtype, type], e.g. isSubtype [Object, String]==true
return TypeUtilsJDK6Fix.isSubType( typeUtils, p, extendsBound );
return SpecificCompilerWorkarounds.isSubType( typeUtils, p, extendsBound );
case TYPEVAR:
// for example method: <T extends String & Serializable> T method(? extends T)
@ -265,7 +265,7 @@ public class MethodMatcher {
// for example method: String method(? super String)
// to check super type, we can simply reverse the argument, but that would initially yield
// a result: <type, superType] (so type not included) so we need to check sameType also.
return TypeUtilsJDK6Fix.isSubType( typeUtils, superBound, p ) ||
return SpecificCompilerWorkarounds.isSubType( typeUtils, superBound, p ) ||
typeUtils.isSameType( p, superBound );
case TYPEVAR:
@ -284,7 +284,7 @@ public class MethodMatcher {
// to check super type, we can simply reverse 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 ( TypeUtilsJDK6Fix.isSubType( typeUtils, superBoundAsDeclared, p ) ||
return ( SpecificCompilerWorkarounds.isSubType( typeUtils, superBoundAsDeclared, p ) ||
typeUtils.isSameType( p, superBoundAsDeclared ) );
default:
// does this situation occur?
@ -325,7 +325,7 @@ public class MethodMatcher {
if ( t != null && bounds != null ) {
for ( TypeMirror bound : bounds ) {
if ( !( bound.getKind().equals( TypeKind.DECLARED ) &&
TypeUtilsJDK6Fix.isSubType( typeUtils, t, bound ) ) ) {
SpecificCompilerWorkarounds.isSubType( typeUtils, t, bound ) ) ) {
return false;
}
}

View File

@ -19,20 +19,25 @@
package org.mapstruct.ap.util;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Types;
/**
* Work-around for a bug related to sub-typing in the Eclipse JSR 269 implementation.
* Contains workarounds for various quirks in specific compilers.
*
* @author Sjaak Derksen
* @author Andreas Gudian
*/
public class TypeUtilsJDK6Fix {
public class SpecificCompilerWorkarounds {
private TypeUtilsJDK6Fix() { }
private SpecificCompilerWorkarounds() { }
/**
* 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
@ -41,6 +46,31 @@ public class TypeUtilsJDK6Fix {
* @throws IllegalArgumentException if given an executable or package type
*/
public static boolean isSubType(Types types, TypeMirror t1, TypeMirror t2) {
return types.isSubtype( types.erasure( t1 ), types.erasure( 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.
*
* @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
* @jls 4.6 Type Erasure
*/
public static TypeMirror erasure(Types types, TypeMirror t) {
if ( t.getKind() == TypeKind.VOID ) {
return t;
}
else {
return types.erasure( t );
}
}
}