From 233fc6de98aa662172bd1b00401c574e25ae371d Mon Sep 17 00:00:00 2001 From: Filip Hrisafov Date: Sat, 3 Oct 2020 12:46:14 +0200 Subject: [PATCH] #2215: Avoid NPE in IntelliJ EAP 2020.3 Starting from IntelliJ 2020.3 (Build 203.4203.26) the ProcessingEnvironment is wrapped in a Proxy class by IntelliJ. MapStruct should gracefully handle that and not throw an NPE. Additionally, we should do best effort to put the used compiler in the generated annotation info --- .../processor/DefaultVersionInformation.java | 33 +++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/processor/src/main/java/org/mapstruct/ap/internal/processor/DefaultVersionInformation.java b/processor/src/main/java/org/mapstruct/ap/internal/processor/DefaultVersionInformation.java index 60e5f112d..c4baf1bf5 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/processor/DefaultVersionInformation.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/processor/DefaultVersionInformation.java @@ -6,6 +6,8 @@ package org.mapstruct.ap.internal.processor; import java.io.IOException; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Proxy; import java.net.MalformedURLException; import java.net.URL; import java.util.jar.Manifest; @@ -103,7 +105,28 @@ public class DefaultVersionInformation implements VersionInformation { } private static String getCompiler(ProcessingEnvironment processingEnv) { - String className = processingEnv.getClass().getName(); + String className; + if ( Proxy.isProxyClass( processingEnv.getClass() ) ) { + // IntelliJ IDEA wraps the ProcessingEnvironment in a Proxy. + // Therefore we need smarter logic to determine the type of the compiler + String processingEnvToString = processingEnv.toString(); + if ( processingEnvToString.contains( COMPILER_NAME_JAVAC ) ) { + // The toString of the javac ProcessingEnvironment is "javac ProcessingEnvironment" + className = JAVAC_PE_CLASS; + } + else if ( processingEnvToString.startsWith( JDT_BATCH_PE_CLASS ) ) { + // The toString of the JDT Batch is from Object#toString so it contains the class name + className = JDT_BATCH_PE_CLASS; + } + else { + InvocationHandler invocationHandler = Proxy.getInvocationHandler( processingEnv ); + return "Proxy handler " + invocationHandler.getClass() + " from " + + getLibraryName( invocationHandler.getClass(), false ); + } + } + else { + className = processingEnv.getClass().getName(); + } if ( className.equals( JAVAC_PE_CLASS ) ) { return COMPILER_NAME_JAVAC; @@ -135,7 +158,10 @@ public class DefaultVersionInformation implements VersionInformation { } } - if ( "jar".equals( resource.getProtocol() ) ) { + if ( resource == null ) { + return ""; + } + else if ( "jar".equals( resource.getProtocol() ) ) { return extractJarFileName( resource.getFile() ); } else if ( "jrt".equals( resource.getProtocol() ) ) { @@ -149,6 +175,9 @@ public class DefaultVersionInformation implements VersionInformation { } private static Manifest openManifest(String classFileName, URL resource) { + if ( resource == null ) { + return null; + } try { URL manifestUrl = createManifestUrl( classFileName, resource ); return new Manifest( manifestUrl.openStream() );