use of java.lang.StackWalker.Option.RETAIN_CLASS_REFERENCE in project jOOR by jOOQ.
the class Compile method compile.
static Class<?> compile(String className, String content, CompileOptions compileOptions) {
Lookup lookup = MethodHandles.lookup();
ClassLoader cl = lookup.lookupClass().getClassLoader();
try {
return cl.loadClass(className);
} 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));
List<CharSequenceJavaFileObject> files = new ArrayList<>();
files.add(new CharSequenceJavaFileObject(className, content));
StringWriter out = new StringWriter();
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 (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.toURI()));
}
}
options.addAll(Arrays.asList("-classpath", classpath.toString()));
}
CompilationTask task = compiler.getTask(out, fileManager, null, options, null, files);
if (!compileOptions.processors.isEmpty())
task.setProcessors(compileOptions.processors);
task.call();
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) {
result = fileManager.loadAndReturnMainClass(className, (name, bytes) -> Reflect.on(cl).call("defineClass", name, bytes, 0, bytes.length).get());
} else /* [java-9] */
// Lookup.defineClass() has only been introduced in Java 9. It is
// required to get private-access to interfaces in the class hierarchy
{
// This method is called by client code from two levels up the current stack frame
// We need a private-access lookup from the class in that stack frame in order to get
// private-access to any local interfaces at that location.
Class<?> caller = StackWalker.getInstance(RETAIN_CLASS_REFERENCE).walk(s -> s.skip(2).findFirst().get().getDeclaringClass());
// we can use the private-access Lookup of the caller class
if (className.startsWith(caller.getPackageName() + ".") && // A better implementation is difficult at this point.
Character.isUpperCase(className.charAt(caller.getPackageName().length() + 1))) {
Lookup privateLookup = MethodHandles.privateLookupIn(caller, lookup);
result = fileManager.loadAndReturnMainClass(className, (name, bytes) -> privateLookup.defineClass(bytes));
} else // Otherwise, use an arbitrary class loader. This approach doesn't allow for
// loading private-access interfaces in the compiled class's type hierarchy
{
ByteArrayClassLoader c = new ByteArrayClassLoader(fileManager.classes());
result = fileManager.loadAndReturnMainClass(className, (name, bytes) -> c.loadClass(name));
}
}
return result;
} catch (ReflectException e) {
throw e;
} catch (Exception e) {
throw new ReflectException("Error while compiling " + className, e);
}
}
}
use of java.lang.StackWalker.Option.RETAIN_CLASS_REFERENCE in project jOOQ by jOOQ.
the class Compile method compile.
static Class<?> compile(String className, String content, CompileOptions compileOptions) {
Lookup lookup = MethodHandles.lookup();
ClassLoader cl = lookup.lookupClass().getClassLoader();
try {
return cl.loadClass(className);
} catch (ClassNotFoundException ignore) {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
try {
ClassFileManager fileManager = new ClassFileManager(compiler.getStandardFileManager(null, null, null));
List<CharSequenceJavaFileObject> files = new ArrayList<>();
files.add(new CharSequenceJavaFileObject(className, content));
StringWriter out = new StringWriter();
List<String> options = new ArrayList<>(compileOptions.options);
if (!options.contains("-classpath")) {
StringBuilder classpath = new StringBuilder();
String separator = System.getProperty("path.separator");
String cp = System.getProperty("java.class.path");
String mp = System.getProperty("jdk.module.path");
if (cp != null && !"".equals(cp))
classpath.append(cp);
if (mp != null && !"".equals(mp))
classpath.append(mp);
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.toURI()));
}
}
options.addAll(Arrays.asList("-classpath", classpath.toString()));
}
CompilationTask task = compiler.getTask(out, fileManager, null, options, null, files);
if (!compileOptions.processors.isEmpty())
task.setProcessors(compileOptions.processors);
task.call();
if (fileManager.isEmpty())
throw new ReflectException("Compilation error: " + out);
Class<?> result = null;
if (Reflect.CACHED_LOOKUP_CONSTRUCTOR != null) {
result = fileManager.loadAndReturnMainClass(className, (name, bytes) -> Reflect.on(cl).call("defineClass", name, bytes, 0, bytes.length).get());
} else // Lookup.defineClass() has only been introduced in Java 9. It is
// required to get private-access to interfaces in the class hierarchy
{
// This method is called by client code from two levels up the current stack frame
// We need a private-access lookup from the class in that stack frame in order to get
// private-access to any local interfaces at that location.
Class<?> caller = StackWalker.getInstance(RETAIN_CLASS_REFERENCE).walk(s -> s.skip(2).findFirst().get().getDeclaringClass());
// we can use the private-access Lookup of the caller class
if (className.startsWith(caller.getPackageName() + ".") && // A better implementation is difficult at this point.
Character.isUpperCase(className.charAt(caller.getPackageName().length() + 1))) {
Lookup privateLookup = MethodHandles.privateLookupIn(caller, lookup);
result = fileManager.loadAndReturnMainClass(className, (name, bytes) -> privateLookup.defineClass(bytes));
} else // Otherwise, use an arbitrary class loader. This approach doesn't allow for
// loading private-access interfaces in the compiled class's type hierarchy
{
ByteArrayClassLoader c = new ByteArrayClassLoader(fileManager.classes());
result = fileManager.loadAndReturnMainClass(className, (name, bytes) -> c.loadClass(name));
}
}
return result;
} catch (ReflectException e) {
throw e;
} catch (Exception e) {
throw new ReflectException("Error while compiling " + className, e);
}
}
}
Aggregations