Issue | Fix Version | Assignee | Priority | Status | Resolution | Resolved In Build |
---|---|---|---|---|---|---|
JDK-8225997 | 14 | Vicente Arturo Romero Zaldivar | P4 | Resolved | Fixed | team |
A DESCRIPTION OF THE PROBLEM :
In the module jdk.compiler the in class com.sun.tools.javac.api.ClientCodeWrapper the following calls are not forwarded and lead to calls to interface default which always throws UnsupportedOperationException
ClientCodeWrapper.WrappedJavaFileManager does not wrap method:
default <S> ServiceLoader<S> getServiceLoader(Location location, Class<S> service) throws IOException
ClientCodeWrapper.WrappedStandardJavaFileManager does not wrap method:
void setLocationForModule(Location location, String moduleName, Collection<? extends Path> paths) throws IOException
This is true for all versions of JDK, past and present.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Use the code below, taken directly from the Gradle sources and reduced to the bare minimum example.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
task.call() should fail because the files don't exist.
ACTUAL -
It never reaches that point, because we get an UnsupportedOperationException on a getServiceLoader call
---------- BEGIN SOURCE ----------
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package testcompile;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.StandardLocation;
import javax.tools.ToolProvider;
public class Testcompile implements InvocationHandler {
private static final String HAS_LOCATION_METHOD = "hasLocation";
private static final String LIST_METHOD = "list";
private final Object proxied;
public Testcompile(Object proxied) {
this.proxied = proxied;
}
public static void main(String[] args) {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager standardFileManager = compiler.getStandardFileManager(null, null, StandardCharsets.UTF_8);
List<String> filenames = Arrays.asList("src/main/java/com/project/entities/CompanyInformation.java");
List<String> options = new ArrayList<>();
options.add("-source");
options.add("11");
options.add("-target");
options.add("11");
options.add("-d");
options.add("build/classes/java/main");
options.add("-encoding");
options.add("UTF-8");
options.add("-g");
options.add("-sourcepath");
options.add("");
options.add("--processor-module-path");
options.add("path/to/hibernate-jpamodelgen-5.2.14.Final.jar");
options.add("-s");
options.add("build/generated/sources/annotationProcessor/java/main");
options.add("-XDuseUnsharedTable=true");
options.add("-classpath");
options.add("path/to/hibernate-core-5.2.14.Final.jar:other/paths.jar");
Iterable<? extends JavaFileObject> compilationUnits = standardFileManager.getJavaFileObjectsFromStrings(filenames);
StandardJavaFileManager fileManager = (StandardJavaFileManager) proxy(standardFileManager, StandardJavaFileManager.class);
JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, null, options, null, compilationUnits);
task.call();
}
public static Object proxy(Object proxied, Class<?> targetInterface) {
return Proxy.newProxyInstance(
Testcompile.class.getClassLoader(),
new Class[] {targetInterface},
new Testcompile(proxied));
}
@Override
@SuppressWarnings("unchecked")
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals(HAS_LOCATION_METHOD)) {
// There is currently a requirement in the JDK9 javac implementation
// that when javac is invoked with an explicitly empty sourcepath
// (i.e. {@code --sourcepath ""}), it won't allow you to compile a java 9
// module. However, we really want to explicitly set an empty sourcepath
// so that we don't implicitly pull in unrequested sourcefiles which
// haven't been snapshotted because we will consider the task up-to-date
// if the implicit files change.
//
// This implementation of hasLocation() pretends that the JavaFileManager
// has no concept of a source path.
if (args[0].equals(StandardLocation.SOURCE_PATH)) {
return false;
}
}
if (method.getName().equals(LIST_METHOD)) {
// If we are pretending that we don't have a sourcepath, the compiler will
// look on the classpath for sources. Since we don't want to bring in any
// sources implicitly from the classpath, we have to ignore source files
// found on the classpath.
if (args[0].equals(StandardLocation.CLASS_PATH)) {
((Set<JavaFileObject.Kind>) args[2]).remove(JavaFileObject.Kind.SOURCE);
}
}
return method.invoke(proxied, args);
}
}
---------- END SOURCE ----------
FREQUENCY : always
In the module jdk.compiler the in class com.sun.tools.javac.api.ClientCodeWrapper the following calls are not forwarded and lead to calls to interface default which always throws UnsupportedOperationException
ClientCodeWrapper.WrappedJavaFileManager does not wrap method:
default <S> ServiceLoader<S> getServiceLoader(Location location, Class<S> service) throws IOException
ClientCodeWrapper.WrappedStandardJavaFileManager does not wrap method:
void setLocationForModule(Location location, String moduleName, Collection<? extends Path> paths) throws IOException
This is true for all versions of JDK, past and present.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Use the code below, taken directly from the Gradle sources and reduced to the bare minimum example.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
task.call() should fail because the files don't exist.
ACTUAL -
It never reaches that point, because we get an UnsupportedOperationException on a getServiceLoader call
---------- BEGIN SOURCE ----------
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package testcompile;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.StandardLocation;
import javax.tools.ToolProvider;
public class Testcompile implements InvocationHandler {
private static final String HAS_LOCATION_METHOD = "hasLocation";
private static final String LIST_METHOD = "list";
private final Object proxied;
public Testcompile(Object proxied) {
this.proxied = proxied;
}
public static void main(String[] args) {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager standardFileManager = compiler.getStandardFileManager(null, null, StandardCharsets.UTF_8);
List<String> filenames = Arrays.asList("src/main/java/com/project/entities/CompanyInformation.java");
List<String> options = new ArrayList<>();
options.add("-source");
options.add("11");
options.add("-target");
options.add("11");
options.add("-d");
options.add("build/classes/java/main");
options.add("-encoding");
options.add("UTF-8");
options.add("-g");
options.add("-sourcepath");
options.add("");
options.add("--processor-module-path");
options.add("path/to/hibernate-jpamodelgen-5.2.14.Final.jar");
options.add("-s");
options.add("build/generated/sources/annotationProcessor/java/main");
options.add("-XDuseUnsharedTable=true");
options.add("-classpath");
options.add("path/to/hibernate-core-5.2.14.Final.jar:other/paths.jar");
Iterable<? extends JavaFileObject> compilationUnits = standardFileManager.getJavaFileObjectsFromStrings(filenames);
StandardJavaFileManager fileManager = (StandardJavaFileManager) proxy(standardFileManager, StandardJavaFileManager.class);
JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, null, options, null, compilationUnits);
task.call();
}
public static Object proxy(Object proxied, Class<?> targetInterface) {
return Proxy.newProxyInstance(
Testcompile.class.getClassLoader(),
new Class[] {targetInterface},
new Testcompile(proxied));
}
@Override
@SuppressWarnings("unchecked")
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals(HAS_LOCATION_METHOD)) {
// There is currently a requirement in the JDK9 javac implementation
// that when javac is invoked with an explicitly empty sourcepath
// (i.e. {@code --sourcepath ""}), it won't allow you to compile a java 9
// module. However, we really want to explicitly set an empty sourcepath
// so that we don't implicitly pull in unrequested sourcefiles which
// haven't been snapshotted because we will consider the task up-to-date
// if the implicit files change.
//
// This implementation of hasLocation() pretends that the JavaFileManager
// has no concept of a source path.
if (args[0].equals(StandardLocation.SOURCE_PATH)) {
return false;
}
}
if (method.getName().equals(LIST_METHOD)) {
// If we are pretending that we don't have a sourcepath, the compiler will
// look on the classpath for sources. Since we don't want to bring in any
// sources implicitly from the classpath, we have to ignore source files
// found on the classpath.
if (args[0].equals(StandardLocation.CLASS_PATH)) {
((Set<JavaFileObject.Kind>) args[2]).remove(JavaFileObject.Kind.SOURCE);
}
}
return method.invoke(proxied, args);
}
}
---------- END SOURCE ----------
FREQUENCY : always
- backported by
-
JDK-8225997 Missing methods in ClientCodeWrapper$WrappedJavaFileManager
- Resolved