[jOOQ/jOOQ#15499] Upgrade jOOR dependency to 0.9.15
This commit is contained in:
parent
47a71a8254
commit
05973af494
@ -26,11 +26,12 @@ import java.lang.invoke.MethodHandles.Lookup;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Deque;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
@ -53,8 +54,14 @@ import javax.tools.ToolProvider;
|
||||
class Compile {
|
||||
|
||||
static Class<?> compile(String className, String content, CompileOptions compileOptions) {
|
||||
return compile(className, content, compileOptions, true);
|
||||
}
|
||||
|
||||
static Class<?> compile(String className, String content, CompileOptions compileOptions, boolean expectResult) {
|
||||
Lookup lookup = MethodHandles.lookup();
|
||||
ClassLoader cl = lookup.lookupClass().getClassLoader();
|
||||
ClassLoader cl = compileOptions.classLoader != null
|
||||
? compileOptions.classLoader
|
||||
: lookup.lookupClass().getClassLoader();
|
||||
|
||||
try {
|
||||
return cl.loadClass(className);
|
||||
@ -62,6 +69,9 @@ class Compile {
|
||||
catch (ClassNotFoundException ignore) {
|
||||
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
|
||||
|
||||
if (compiler == null)
|
||||
throw new ReflectException("No compiler was provided by ToolProvider.getSystemJavaCompiler(). Make sure the jdk.compiler module is available.");
|
||||
|
||||
try {
|
||||
ClassFileManager fileManager = new ClassFileManager(compiler.getStandardFileManager(null, null, null));
|
||||
|
||||
@ -101,21 +111,22 @@ class Compile {
|
||||
|
||||
task.call();
|
||||
|
||||
if (fileManager.isEmpty())
|
||||
if (fileManager.isEmpty()) {
|
||||
if (!expectResult)
|
||||
return null;
|
||||
|
||||
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) {
|
||||
|
||||
result = fileManager.loadAndReturnMainClass(className,
|
||||
(name, bytes) -> Reflect.on(cl).call("defineClass", name, bytes, 0, bytes.length).get());
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Lookup.defineClass() has only been introduced in Java 9. It is
|
||||
// required to get private-access to interfaces in the class hierarchy
|
||||
else {
|
||||
@ -217,7 +228,7 @@ class Compile {
|
||||
ClassFileManager(StandardJavaFileManager standardManager) {
|
||||
super(standardManager);
|
||||
|
||||
fileObjectMap = new HashMap<>();
|
||||
fileObjectMap = new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -238,7 +249,7 @@ class Compile {
|
||||
|
||||
Map<String, byte[]> classes() {
|
||||
if (classes == null) {
|
||||
classes = new HashMap<>();
|
||||
classes = new LinkedHashMap<>();
|
||||
|
||||
for (Entry<String, JavaFileObject> entry : fileObjectMap.entrySet())
|
||||
classes.put(entry.getKey(), entry.getValue().getBytes());
|
||||
@ -250,10 +261,35 @@ class Compile {
|
||||
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;
|
||||
// [#117] We don't know the subclass hierarchy of the top level
|
||||
// classes in the compilation unit, and we can't find out
|
||||
// without either:
|
||||
//
|
||||
// - class loading them (which fails due to NoClassDefFoundError)
|
||||
// - using a library like ASM (which is a big and painful dependency)
|
||||
//
|
||||
// Simple workaround: try until it works, in O(n^2), where n
|
||||
// can be reasonably expected to be small.
|
||||
Deque<Entry<String, byte[]>> queue = new ArrayDeque<>(classes().entrySet());
|
||||
int n1 = queue.size();
|
||||
|
||||
// Try at most n times
|
||||
for (int i1 = 0; i1 < n1 && !queue.isEmpty(); i1++) {
|
||||
int n2 = queue.size();
|
||||
|
||||
for (int i2 = 0; i2 < n2; i2++) {
|
||||
Entry<String, byte[]> entry = queue.pop();
|
||||
|
||||
try {
|
||||
Class<?> c = definer.apply(entry.getKey(), entry.getValue());
|
||||
|
||||
if (mainClassName.equals(entry.getKey()))
|
||||
result = c;
|
||||
}
|
||||
catch (ReflectException e) {
|
||||
queue.offer(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@ -15,6 +15,16 @@ package org.jooq.tools.reflect;
|
||||
|
||||
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.processing.Processor;
|
||||
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
import java.util.Arrays;
|
||||
|
||||
import java.util.Collections;
|
||||
@ -28,21 +38,25 @@ import javax.annotation.processing.Processor;
|
||||
public final class CompileOptions {
|
||||
|
||||
final List<? extends Processor> processors;
|
||||
final List<String> options;
|
||||
final List<String> options;
|
||||
final ClassLoader classLoader;
|
||||
|
||||
public CompileOptions() {
|
||||
this(
|
||||
Collections.emptyList(),
|
||||
Collections.emptyList()
|
||||
Collections.emptyList(),
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
private CompileOptions(
|
||||
List<? extends Processor> processors,
|
||||
List<String> options
|
||||
List<String> options,
|
||||
ClassLoader classLoader
|
||||
) {
|
||||
this.processors = processors;
|
||||
this.options = options;
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
public final CompileOptions processors(Processor... newProcessors) {
|
||||
@ -50,7 +64,7 @@ public final class CompileOptions {
|
||||
}
|
||||
|
||||
public final CompileOptions processors(List<? extends Processor> newProcessors) {
|
||||
return new CompileOptions(newProcessors, options);
|
||||
return new CompileOptions(newProcessors, options, classLoader);
|
||||
}
|
||||
|
||||
public final CompileOptions options(String... newOptions) {
|
||||
@ -58,7 +72,19 @@ public final class CompileOptions {
|
||||
}
|
||||
|
||||
public final CompileOptions options(List<String> newOptions) {
|
||||
return new CompileOptions(processors, newOptions);
|
||||
return new CompileOptions(processors, newOptions, classLoader);
|
||||
}
|
||||
|
||||
final boolean hasOption(String opt) {
|
||||
for (String option : options)
|
||||
if (option.equalsIgnoreCase(opt))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public final CompileOptions classLoader(ClassLoader newClassLoader) {
|
||||
return new CompileOptions(processors, options, newClassLoader);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -23,8 +23,10 @@ import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
@ -61,14 +63,14 @@ public class Reflect {
|
||||
* <p>
|
||||
* For example:
|
||||
* <pre><code>
|
||||
* Supplier<String> supplier = Reflect.compile(
|
||||
* "org.joor.Test",
|
||||
* "package org.joor;\n" +
|
||||
* "class Test implements java.util.function.Supplier<String> {\n" +
|
||||
* " public String get() {\n" +
|
||||
* " return \"Hello World!\";\n" +
|
||||
* " }\n" +
|
||||
* "}\n").create().get();
|
||||
* Supplier<String> supplier = Reflect.compile("org.joor.Test", """
|
||||
* package org.joor;
|
||||
* class Test implements java.util.function.Supplier<String> {
|
||||
* public String get() {
|
||||
* return "Hello World!";
|
||||
* }
|
||||
* }
|
||||
* """).create().get();
|
||||
* </code></pre>
|
||||
*
|
||||
* @param name The qualified class name
|
||||
@ -85,14 +87,14 @@ public class Reflect {
|
||||
* <p>
|
||||
* For example:
|
||||
* <pre><code>
|
||||
* Supplier<String> supplier = Reflect.compile(
|
||||
* "org.joor.Test",
|
||||
* "package org.joor;\n" +
|
||||
* "class Test implements java.util.function.Supplier<String> {\n" +
|
||||
* " public String get() {\n" +
|
||||
* " return \"Hello World!\";\n" +
|
||||
* " }\n" +
|
||||
* "}\n").create().get();
|
||||
* Supplier<String> supplier = Reflect.compile("org.joor.Test", """
|
||||
* package org.joor;
|
||||
* class Test implements java.util.function.Supplier<String> {
|
||||
* public String get() {
|
||||
* return "Hello World!";
|
||||
* }
|
||||
* }
|
||||
* """).create().get();
|
||||
* </code></pre>
|
||||
*
|
||||
* @param name The qualified class name
|
||||
@ -105,6 +107,70 @@ public class Reflect {
|
||||
return onClass(Compile.compile(name, content, options));
|
||||
}
|
||||
|
||||
/**
|
||||
* Annotation-process a class at runtime.
|
||||
* <p>
|
||||
* This works like {@link #compile(String, String)}, but adds the
|
||||
* <code>-proc:only</code> {@link CompileOptions} and thus does not produce any
|
||||
* compilation output.
|
||||
* <p>
|
||||
* For example:
|
||||
* <pre><code>
|
||||
* Supplier<String> supplier = Reflect.compile("org.joor.Test", """
|
||||
* package org.joor;
|
||||
* @MyAnnotation
|
||||
* class Test implements java.util.function.Supplier<String> {
|
||||
* public String get() {
|
||||
* return "Hello World!";
|
||||
* }
|
||||
* }
|
||||
* """).create().get();
|
||||
* </code></pre>
|
||||
*
|
||||
* @param name The qualified class name
|
||||
* @param content The source code for the class
|
||||
* @throws ReflectException if anything went wrong compiling the class.
|
||||
*/
|
||||
public static void process(String name, String content) throws ReflectException {
|
||||
process(name, content, new CompileOptions());
|
||||
}
|
||||
|
||||
/**
|
||||
* Annotation-process a class at runtime.
|
||||
* <p>
|
||||
* This works like {@link #compile(String, String)}, but adds the
|
||||
* <code>-proc:only</code> {@link CompileOptions} and thus does not produce any
|
||||
* compilation output.
|
||||
* <p>
|
||||
* For example:
|
||||
* <pre><code>
|
||||
* Supplier<String> supplier = Reflect.compile("org.joor.Test", """
|
||||
* package org.joor;
|
||||
* @MyAnnotation
|
||||
* class Test implements java.util.function.Supplier<String> {
|
||||
* public String get() {
|
||||
* return "Hello World!";
|
||||
* }
|
||||
* }
|
||||
* """).create().get();
|
||||
* </code></pre>
|
||||
*
|
||||
* @param name The qualified class name
|
||||
* @param content The source code for the class
|
||||
* @param options compiler options
|
||||
* @return A wrapped {@link Class}
|
||||
* @throws ReflectException if anything went wrong compiling the class.
|
||||
*/
|
||||
public static void process(String name, String content, CompileOptions options) throws ReflectException {
|
||||
if (!options.hasOption("-proc:only")) {
|
||||
List<String> o = new ArrayList<>(options.options);
|
||||
o.add("-proc:only");
|
||||
options = options.options(o);
|
||||
}
|
||||
|
||||
Compile.compile(name, content, options, false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Wrap a class name.
|
||||
@ -1013,3 +1079,4 @@ public class Reflect {
|
||||
|
||||
private static class NULL {}
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user