[jOOQ/jOOQ#9157] [jOOQ/jOOR#57] Try again
When running the Java 8 distribution's code of jOOR on Java 9, CACHED_LOOKUP_CONSTRUCTOR is null because we're not allowed to access that from JDK 9+. This means we can no longer use it in reflection logic, e.g. when implementing in-memory compilation. We have to use the Java 9+ logic via meta-reflection.
This commit is contained in:
parent
d8b63da46c
commit
3bfb0c9756
@ -28,7 +28,10 @@ import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.tools.FileObject;
|
||||
import javax.tools.ForwardingJavaFileManager;
|
||||
@ -60,29 +63,32 @@ class Compile {
|
||||
try {
|
||||
ClassFileManager fileManager = new ClassFileManager(compiler.getStandardFileManager(null, null, null));
|
||||
|
||||
List<CharSequenceJavaFileObject> files = new ArrayList<CharSequenceJavaFileObject>();
|
||||
List<CharSequenceJavaFileObject> files = new ArrayList<>();
|
||||
files.add(new CharSequenceJavaFileObject(className, content));
|
||||
StringWriter out = new StringWriter();
|
||||
|
||||
List<String> options = new ArrayList<String>();
|
||||
StringBuilder classpath = new StringBuilder();
|
||||
String separator = System.getProperty("path.separator");
|
||||
String prop = System.getProperty("java.class.path");
|
||||
List<String> options = new ArrayList<>(compileOptions.options);
|
||||
if (!options.contains("-classpath")) {
|
||||
StringBuilder classpath = new StringBuilder();
|
||||
String separator = System.getProperty("path.separator");
|
||||
String prop = System.getProperty("java.class.path");
|
||||
|
||||
if (prop != null && !"".equals(prop))
|
||||
classpath.append(prop);
|
||||
if (prop != null && !"".equals(prop))
|
||||
classpath.append(prop);
|
||||
|
||||
if (cl instanceof URLClassLoader) {
|
||||
for (URL url : ((URLClassLoader) cl).getURLs()) {
|
||||
if (classpath.length() > 0)
|
||||
classpath.append(separator);
|
||||
if (cl instanceof URLClassLoader) {
|
||||
for (URL url : ((URLClassLoader) cl).getURLs()) {
|
||||
if (classpath.length() > 0)
|
||||
classpath.append(separator);
|
||||
|
||||
if ("file".equals(url.getProtocol()))
|
||||
classpath.append(new File(url.getFile()));
|
||||
if ("file".equals(url.getProtocol()))
|
||||
classpath.append(new File(url.toURI()));
|
||||
}
|
||||
}
|
||||
|
||||
options.addAll(Arrays.asList("-classpath", classpath.toString()));
|
||||
}
|
||||
|
||||
options.addAll(Arrays.asList("-classpath", classpath.toString()));
|
||||
CompilationTask task = compiler.getTask(out, fileManager, null, options, null, files);
|
||||
|
||||
if (!compileOptions.processors.isEmpty())
|
||||
@ -90,16 +96,21 @@ class Compile {
|
||||
|
||||
task.call();
|
||||
|
||||
if (fileManager.o == null)
|
||||
if (fileManager.isEmpty())
|
||||
throw new ReflectException("Compilation error: " + out);
|
||||
|
||||
Class<?> result = null;
|
||||
|
||||
// This works if we have private-access to the interfaces in the class hierarchy
|
||||
if (Reflect.CACHED_LOOKUP_CONSTRUCTOR != null) {
|
||||
byte[] b = fileManager.o.getBytes();
|
||||
result = Reflect.on(cl).call("defineClass", className, b, 0, b.length).get();
|
||||
}
|
||||
|
||||
|
||||
|
||||
result = fileManager.loadAndReturnMainClass(className,
|
||||
(name, bytes) -> Reflect.on(cl).call("defineClass", name, bytes, 0, bytes.length).get());
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -150,6 +161,22 @@ class Compile {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static final class JavaFileObject extends SimpleJavaFileObject {
|
||||
final ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
|
||||
@ -168,10 +195,13 @@ class Compile {
|
||||
}
|
||||
|
||||
static final class ClassFileManager extends ForwardingJavaFileManager<StandardJavaFileManager> {
|
||||
JavaFileObject o;
|
||||
private final Map<String, JavaFileObject> fileObjectMap;
|
||||
private Map<String, byte[]> classes;
|
||||
|
||||
ClassFileManager(StandardJavaFileManager standardManager) {
|
||||
super(standardManager);
|
||||
|
||||
fileObjectMap = new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -181,8 +211,42 @@ class Compile {
|
||||
JavaFileObject.Kind kind,
|
||||
FileObject sibling
|
||||
) {
|
||||
return o = new JavaFileObject(className, kind);
|
||||
JavaFileObject result = new JavaFileObject(className, kind);
|
||||
fileObjectMap.put(className, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
boolean isEmpty() {
|
||||
return fileObjectMap.isEmpty();
|
||||
}
|
||||
|
||||
Map<String, byte[]> classes() {
|
||||
if (classes == null) {
|
||||
classes = new HashMap<>();
|
||||
|
||||
for (Entry<String, JavaFileObject> entry : fileObjectMap.entrySet())
|
||||
classes.put(entry.getKey(), entry.getValue().getBytes());
|
||||
}
|
||||
|
||||
return classes;
|
||||
}
|
||||
|
||||
Class<?> loadAndReturnMainClass(String mainClassName, ThrowingBiFunction<String, byte[], Class<?>> definer) throws Exception {
|
||||
Class<?> result = null;
|
||||
|
||||
for (Entry<String, byte[]> entry : classes().entrySet()) {
|
||||
Class<?> c = definer.apply(entry.getKey(), entry.getValue());
|
||||
if (mainClassName.equals(entry.getKey()))
|
||||
result = c;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
interface ThrowingBiFunction<T, U, R> {
|
||||
R apply(T t, U u) throws Exception;
|
||||
}
|
||||
|
||||
static final class CharSequenceJavaFileObject extends SimpleJavaFileObject {
|
||||
|
||||
@ -13,10 +13,9 @@
|
||||
*/
|
||||
package org.jooq.tools.reflect;
|
||||
|
||||
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@ -28,25 +27,37 @@ import javax.annotation.processing.Processor;
|
||||
public final class CompileOptions {
|
||||
|
||||
final List<? extends Processor> processors;
|
||||
final List<String> options;
|
||||
|
||||
public CompileOptions() {
|
||||
this(
|
||||
Collections.emptyList(),
|
||||
Collections.emptyList()
|
||||
);
|
||||
}
|
||||
|
||||
private CompileOptions(List<? extends Processor> processors) {
|
||||
private CompileOptions(
|
||||
List<? extends Processor> processors,
|
||||
List<String> options
|
||||
) {
|
||||
this.processors = processors;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
@SuppressWarnings("hiding")
|
||||
public CompileOptions processors(Processor... processors) {
|
||||
return processors(Arrays.asList(processors));
|
||||
public final CompileOptions processors(Processor... newProcessors) {
|
||||
return processors(Arrays.asList(newProcessors));
|
||||
}
|
||||
|
||||
@SuppressWarnings("hiding")
|
||||
public CompileOptions processors(List<? extends Processor> processors) {
|
||||
return new CompileOptions(processors);
|
||||
public final CompileOptions processors(List<? extends Processor> newProcessors) {
|
||||
return new CompileOptions(newProcessors, options);
|
||||
}
|
||||
|
||||
public final CompileOptions options(String... newOptions) {
|
||||
return options(Arrays.asList(newOptions));
|
||||
}
|
||||
|
||||
public final CompileOptions options(List<String> newOptions) {
|
||||
return new CompileOptions(processors, newOptions);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user