gpt4 book ai didi

java - 使用 JBoss 自定义类加载器

转载 作者:行者123 更新时间:2023-12-01 13:40:35 25 4
gpt4 key购买 nike

我正在尝试使用 JavaCompiler API 在运行时动态编译和加载类。我将编译后的字节码存储在内存中。所以我使用自定义类加载器来加载该类。

public class CompilerAPITest {

static String sourceCode = "package in.test;" +
"public class DynamicCompilationHelloWorld implements TestInterface{" +
"public void test (){" +
"System.out.println (\"Hello, dynamic compilation world!\");" +
"new in.test.another.SomeClass().fun();" +
"}" +
"}" ;

public void doCompilation (){
SimpleJavaFileObject fileObject = new DynamicJavaSourceCodeObject ("in.test.DynamicCompilationHelloWorld", sourceCode) ;
JavaFileObject javaFileObjects[] = new JavaFileObject[]{fileObject} ;

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

JavaFileManager stdFileManager = new
CompilerAPITest.ClassFileManager(compiler
.getStandardFileManager(null, null, null));

Iterable<? extends JavaFileObject> compilationUnits = Arrays.asList(javaFileObjects);
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();

List<String> options = Arrays.asList("-cp", System.getProperty("java.class.path")
+ ":" + getPath(CompilerAPITest.class));

CompilationTask compilerTask = compiler.getTask(null, stdFileManager, diagnostics, options, null, compilationUnits) ;
boolean status = compilerTask.call();

if (!status){//If compilation error occurs
/*Iterate through each compilation problem and print it*/
for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()){
System.out.format("Error on line %d in %s", diagnostic.getLineNumber(), diagnostic);
}
}
try {
stdFileManager.close() ;//Close the file manager
} catch (IOException e) {
e.printStackTrace();
}

try {
stdFileManager.getClassLoader(null)
.loadClass("in.test.DynamicCompilationHelloWorld").asSubclass(TestInterface.class).newInstance().test();
} catch (ClassNotFoundException e) {
e.printStackTrace();
//This does nothing.
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

public static void main(String args[]){
new CompilerAPITest ().doCompilation() ;
}

class DynamicJavaSourceCodeObject extends SimpleJavaFileObject{
private String qualifiedName ;
private String sourceCode ;

protected DynamicJavaSourceCodeObject(String name, String code) {
super(URI.create("string:///" +name.replaceAll("\\.", "/") + Kind.SOURCE.extension), Kind.SOURCE);
this.qualifiedName = name ;
this.sourceCode = code ;
}

@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors)
throws IOException {
return sourceCode ;
}

public String getQualifiedName() {
return qualifiedName;
}

public void setQualifiedName(String qualifiedName) {
this.qualifiedName = qualifiedName;
}

public String getSourceCode() {
return sourceCode;
}

public void setSourceCode(String sourceCode) {
this.sourceCode = sourceCode;
}

}

private static class ClassFileManager extends
ForwardingJavaFileManager<JavaFileManager> {
private JavaClassObject jclassObject;
public ClassFileManager(StandardJavaFileManager
standardManager) {
super(standardManager);
}
@Override
public ClassLoader getClassLoader(Location location) {
return new java.security.SecureClassLoader() {
@Override
protected Class<?> findClass(String name)
throws ClassNotFoundException {
byte[] b = jclassObject.getBytes();
return super.defineClass(name, jclassObject
.getBytes(), 0, b.length);
}
};
}

@Override
public JavaFileObject getJavaFileForOutput(Location location,
String className, Kind kind, FileObject sibling)
throws IOException {
jclassObject = new JavaClassObject(className, kind);
return jclassObject;
}
}

private static class JavaClassObject extends SimpleJavaFileObject {
protected final ByteArrayOutputStream bos =
new ByteArrayOutputStream();
public JavaClassObject(String name, Kind kind) {
super(URI.create("string:///" + name.replace('.', '/')
+ kind.extension), kind);
}
public byte[] getBytes() {
return bos.toByteArray();
}
@Override
public OutputStream openOutputStream() throws IOException {
return bos;
}
}
}

在独立设置中运行时效果很好。但是,当我在 JBoss 上运行的生产设置中调用 doCompilation() 时,出现以下异常。

java.lang.NoClassDefFoundError: 
in/test/TestInterface(wrong name:
in/test/DynamicCompilationHelloWorld)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:621)
at java.lang.ClassLoader.defineClass(ClassLoader.java:466)
at in.test.CompilerAPITest$ClassFileManager$1.findClass(CompilerAPITest.java:126)

这可能是什么问题?

最佳答案

经过一番谷歌搜索后发现了这个问题。

需要为所使用的自定义类加载器设置父类加载器。

JBoss 中的类加载层次结构略有不同。这里使用了 UnifiedClassLoader,它用于在抛出 ClassNotFoundException 之前检查父类加载器以及对等类加载器。因此,当使用自定义类加载器时,当它无法加载类时,需要将defineClass调用委托(delegate)给UnifiedClassLoader。

这是自定义类加载器的示例代码片段。

private static class ByteClassLoader extends ClassLoader{
private Map<String, JavaFileObject> store = new HashMap<String, JavaFileObject>();
public ByteClassLoader(Map<String, JavaFileObject> str)
{
super( ByteClassLoader.class.getClassLoader() ); // set parent
store = str;
}

protected Class<?> findClass(String name)
throws ClassNotFoundException{
JavaFileObject jfo = store.get(name);
if (jfo == null){
throw new ClassNotFoundException(name);
}

byte[] bytes = ((JavaClassObject)jfo).getBytes();
Class<?> cl = defineClass(name, bytes, 0, bytes.length);
if (cl == null){
throw new ClassNotFoundException(name);
}
return cl;
}
}

为了加载类,

ByteClassLoader cl = new ByteClassLoader(store);
cl.loadClass(className);

需要使用。

这是关于动态编译和类加载的优秀链接。 http://fivedots.coe.psu.ac.th/~ad/jg/javaArt1/onTheFlyArt1.pdf

关于java - 使用 JBoss 自定义类加载器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20827834/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com