From bfaa524cb7f37f35fd00d5f3bf2a05850291e62b Mon Sep 17 00:00:00 2001 From: Andreas Gudian Date: Sat, 21 Feb 2015 20:59:10 +0100 Subject: [PATCH] #460 add workaround for TypeElements that occasionally seem "empty" during incremental compilation in Eclipse JDT --- .../ap/model/common/TypeFactory.java | 4 +++- .../org/mapstruct/ap/util/Executables.java | 6 +++++ .../ap/util/SpecificCompilerWorkarounds.java | 23 +++++++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/processor/src/main/java/org/mapstruct/ap/model/common/TypeFactory.java b/processor/src/main/java/org/mapstruct/ap/model/common/TypeFactory.java index 9b7bb2047..3d64c942c 100644 --- a/processor/src/main/java/org/mapstruct/ap/model/common/TypeFactory.java +++ b/processor/src/main/java/org/mapstruct/ap/model/common/TypeFactory.java @@ -58,6 +58,7 @@ import org.mapstruct.ap.util.AnnotationProcessingException; import org.mapstruct.ap.util.SpecificCompilerWorkarounds; import static org.mapstruct.ap.util.SpecificCompilerWorkarounds.erasure; +import static org.mapstruct.ap.util.SpecificCompilerWorkarounds.replaceTypeElementIfNecessary; /** * Factory creating {@link Type} instances. @@ -258,7 +259,8 @@ public class TypeFactory { * @return the ExecutableType representing the method as part of usedMapper */ public ExecutableType getMethodType(TypeElement usedMapper, ExecutableElement method) { - TypeMirror asMemberOf = typeUtils.asMemberOf( (DeclaredType) usedMapper.asType(), method ); + DeclaredType asType = (DeclaredType) replaceTypeElementIfNecessary( elementUtils, usedMapper ).asType(); + TypeMirror asMemberOf = typeUtils.asMemberOf( asType, method ); ExecutableType methodType = asMemberOf.accept( new ExecutableTypeRetrievalVisitor(), null ); return methodType; } diff --git a/processor/src/main/java/org/mapstruct/ap/util/Executables.java b/processor/src/main/java/org/mapstruct/ap/util/Executables.java index c5af647a3..dc410800f 100644 --- a/processor/src/main/java/org/mapstruct/ap/util/Executables.java +++ b/processor/src/main/java/org/mapstruct/ap/util/Executables.java @@ -35,6 +35,7 @@ import javax.lang.model.util.SimpleElementVisitor6; import javax.lang.model.util.SimpleTypeVisitor6; import static javax.lang.model.util.ElementFilter.methodsIn; +import static org.mapstruct.ap.util.SpecificCompilerWorkarounds.replaceTypeElementIfNecessary; /** * Provides functionality around {@link ExecutableElement}s. @@ -185,6 +186,7 @@ public class Executables { */ public static List getAllEnclosedExecutableElements(Elements elementUtils, TypeElement element) { List enclosedElements = new ArrayList(); + element = replaceTypeElementIfNecessary( elementUtils, element ); addEnclosedElementsInHierarchy( elementUtils, enclosedElements, element, element ); return enclosedElements; @@ -192,6 +194,10 @@ public class Executables { private static void addEnclosedElementsInHierarchy(Elements elementUtils, List alreadyAdded, TypeElement element, TypeElement parentType) { + if ( element != parentType ) { // otherwise the element was already checked for replacement + element = replaceTypeElementIfNecessary( elementUtils, element ); + } + addNotYetOverridden( elementUtils, alreadyAdded, methodsIn( element.getEnclosedElements() ), parentType ); if ( hasNonObjectSuperclass( element ) ) { diff --git a/processor/src/main/java/org/mapstruct/ap/util/SpecificCompilerWorkarounds.java b/processor/src/main/java/org/mapstruct/ap/util/SpecificCompilerWorkarounds.java index ccef2147c..e8095bf91 100644 --- a/processor/src/main/java/org/mapstruct/ap/util/SpecificCompilerWorkarounds.java +++ b/processor/src/main/java/org/mapstruct/ap/util/SpecificCompilerWorkarounds.java @@ -18,8 +18,10 @@ */ package org.mapstruct.ap.util; +import javax.lang.model.element.TypeElement; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.Elements; import javax.lang.model.util.Types; /** @@ -72,4 +74,25 @@ public class SpecificCompilerWorkarounds { 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; + } }