diff --git a/processor/src/main/java/org/mapstruct/ap/internal/util/workarounds/EclipseAsMemberOfWorkaround.java b/processor/src/main/java/org/mapstruct/ap/internal/util/workarounds/EclipseAsMemberOfWorkaround.java index 34e6f97a3..f2fa62171 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/util/workarounds/EclipseAsMemberOfWorkaround.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/util/workarounds/EclipseAsMemberOfWorkaround.java @@ -41,7 +41,7 @@ import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; /** * Contains the workaround for {@link Types#asMemberOf(DeclaredType, Element)} using Eclipse implementation types. *
- * This class may only be loaded when running within Eclipse + * This class may only be accessed through {@link EclipseClassLoaderBridge} when running within Eclipse * * @author Andreas Gudian */ diff --git a/processor/src/main/java/org/mapstruct/ap/internal/util/workarounds/EclipseClassLoaderBridge.java b/processor/src/main/java/org/mapstruct/ap/internal/util/workarounds/EclipseClassLoaderBridge.java new file mode 100644 index 000000000..b24e985d6 --- /dev/null +++ b/processor/src/main/java/org/mapstruct/ap/internal/util/workarounds/EclipseClassLoaderBridge.java @@ -0,0 +1,88 @@ +/** + * Copyright 2012-2016 Gunnar Morling (http://www.gunnarmorling.de/) + * and/or other contributors as indicated by the @authors tag. See the + * copyright.txt file in the distribution for a full listing of all + * contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +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; + } +} diff --git a/processor/src/main/java/org/mapstruct/ap/internal/util/workarounds/SpecificCompilerWorkarounds.java b/processor/src/main/java/org/mapstruct/ap/internal/util/workarounds/SpecificCompilerWorkarounds.java index 5cb78c81c..d91113da6 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/util/workarounds/SpecificCompilerWorkarounds.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/util/workarounds/SpecificCompilerWorkarounds.java @@ -36,7 +36,8 @@ import org.mapstruct.ap.internal.version.VersionInformation; * @author Andreas Gudian */ public class SpecificCompilerWorkarounds { - private SpecificCompilerWorkarounds() { } + private SpecificCompilerWorkarounds() { + } /** * Tests whether one type is assignable to another, checking for VOID first. @@ -120,7 +121,7 @@ public class SpecificCompilerWorkarounds { /** * Workaround for Bugs in the Eclipse implementation of {@link Types#asMemberOf(DeclaredType, Element)}. * - * @see Eclipse Bug 382590 + * @see Eclipse Bug 382590 (fixed in Eclipse 4.6) * @see Eclipse Bug 481555 */ static TypeMirror asMemberOf(Types typeUtils, ProcessingEnvironment env, VersionInformation versionInformation, @@ -134,7 +135,7 @@ public class SpecificCompilerWorkarounds { catch ( IllegalArgumentException e ) { lastException = e; if ( versionInformation.isEclipseJDTCompiler() ) { - result = EclipseAsMemberOfWorkaround.asMemberOf( env, containing, element ); + result = EclipseClassLoaderBridge.invokeAsMemberOfWorkaround( env, containing, element ); } } }