解决方案 »

  1.   

    好吧,貌似找到原因了,是 ClassLoader 的问题:
    http://stackoverflow.com/questions/21960255/accessing-package-private-element-between-parent-child-classloaders如何在子 ClassLoader 加载的类中访问父 ClassLoader 加载的类型的 ‘包可见’ 方法?这里说如果不用反射,是无解的。换个思路,已知目标类型的 ClassLoader 都是 JVM 的 application classloader,有没有办法让动态生成的类也用这个 application classloader 来加载?
      

  2.   


    看了下你提供的例子,你可以直接把class RecordAccessor做为参数给JavaFileManager:
    示例:package lxb.csdn;import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.io.OutputStream;
    import java.lang.reflect.Method;
    import java.net.URI;
    import java.security.SecureClassLoader;
    import java.util.ArrayList;
    import java.util.List;import javax.tools.FileObject;
    import javax.tools.ForwardingJavaFileManager;
    import javax.tools.JavaCompiler;
    import javax.tools.JavaFileManager;
    import javax.tools.JavaFileObject;
    import javax.tools.JavaFileObject.Kind;
    import javax.tools.SimpleJavaFileObject;
    import javax.tools.StandardJavaFileManager;
    import javax.tools.ToolProvider;public class DynaCompTest { public static void main(String[] args) throws Exception {
    //你的实际包名
    String fullName = "lxb.csdn.DynaClass";

    StringBuilder src = new StringBuilder();
    src.append("package lxb.csdn; \n");//你的实际包名
    src.append("public class DynaClass{\n");
    src.append("   String print(){\n");
    src.append("     return \"hello, I am \" + ");
    src.append("this.getClass().getSimpleName();\n");
    src.append("  }\n}\n");

    System.out.println(src);


    JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
    //把DynaCompTest class实例作为为参数给JavaFileManager
    JavaFileManager fileManager = new ClassFileManager(javaCompiler.getStandardFileManager(null, null, null), 
    DynaCompTest.class); List<JavaFileObject> jfiles = new ArrayList<JavaFileObject>();
            jfiles.add(new CharSequenceJavaFileObject(fullName, src));        javaCompiler.getTask(null, fileManager, null, null,null, jfiles).call();
            
            Object instance = fileManager.getClassLoader(null).loadClass(fullName).newInstance();
           
            Method m = instance.getClass().getDeclaredMethod("print", null);
            m.setAccessible(true);
            
            System.out.println(m.invoke(instance, null)); }}@SuppressWarnings("rawtypes")
    class ClassFileManager extends ForwardingJavaFileManager{
     private JavaClassObject jclassObject;
     private Class parent;//增加一个class字段
     
     @SuppressWarnings("unchecked")
    public ClassFileManager(StandardJavaFileManager standardManager, Class parent) {
            super(standardManager);
            this.parent = parent;
     }  public ClassLoader getClassLoader(Location location) {
        //获取目标类型的 ClassLoader 
            return new SecureClassLoader(parent.getClassLoader()) {
                @Override
                protected Class<?> findClass(String name) throws ClassNotFoundException {
                    byte[] b = jclassObject.getBytes();
                    return super.defineClass(name, jclassObject.getBytes(), 0, b.length);
                }
            };
     }
     
     public JavaFileObject getJavaFileForOutput(Location location, String className, 
         Kind kind, FileObject sibling)throws IOException {
                jclassObject = new JavaClassObject(className, kind);
            return jclassObject;
        }
    }class JavaClassObject extends SimpleJavaFileObject{

    protected 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;
    }
    }class CharSequenceJavaFileObject extends SimpleJavaFileObject {
    private CharSequence content; public CharSequenceJavaFileObject(String className, CharSequence content) {
            super(URI.create("string:///" + className.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
            this.content = content;
        }

    @Override
    public CharSequence getCharContent(boolean ignoreEncodingErrors) {
            return content;
        }}
      

  3.   

    楼主想要的效果是什么,是不是下面代码的效果package com.test.dyna;import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.io.OutputStream;
    import java.net.URI;
    import java.security.SecureClassLoader;
    import java.util.ArrayList;
    import java.util.List;import javax.tools.FileObject;
    import javax.tools.ForwardingJavaFileManager;
    import javax.tools.JavaCompiler;
    import javax.tools.JavaFileManager;
    import javax.tools.JavaFileObject;
    import javax.tools.SimpleJavaFileObject;
    import javax.tools.StandardJavaFileManager;
    import javax.tools.ToolProvider;
    import javax.tools.JavaFileObject.Kind;public class DynaCompTest { public static void main(String[] args) throws InstantiationException,
    IllegalAccessException, ClassNotFoundException {
    // TODO Auto-generated method stub // Full name of the class that will be compiled.
    // If class should be in some package,
    // fullName should contain it too
    // (ex. "testpackage.DynaClass")
    String fullName = "com.test.dyna.DynaClass"; // Here we specify the source code of the class to be compiled
    StringBuilder src = new StringBuilder();
    src.append("package com.test.dyna;\n");
    src.append("import com.test.dyna.RecordAccessor;\n");
    src.append("public class DynaClass extends RecordAccessor{\n");
    src.append("    public String toString() {\n");
    src.append("        return \"Hello, I am \" + ");
    src.append("this.getClass().getSimpleName();\n");
    src.append("    }\n");
    src.append("    protected void sayHello() {\n");
    src.append("        System.out.println(\"Hello World!!!!\");\n");
    src.append("    }\n");
    src.append("}\n"); System.out.println(src); // We get an instance of JavaCompiler. Then
    // we create a file manager
    // (our custom implementation of it)
    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
    JavaFileManager fileManager = new ClassFileManager(
    compiler.getStandardFileManager(null, null, null)); // Dynamic compiling requires specifying
    // a list of "files" to compile. In our case
    // this is a list containing one "file" which is in our case
    // our own implementation (see details below)
    List<JavaFileObject> jfiles = new ArrayList<JavaFileObject>();
    jfiles.add(new CharSequenceJavaFileObject(fullName, src)); // We specify a task to the compiler. Compiler should use our file
    // manager and our list of "files".
    // Then we run the compilation with call()
    compiler.getTask(null, fileManager, null, null, null, jfiles).call(); // Creating an instance of our compiled class and
    // running its toString() method
    Object instance = fileManager.getClassLoader(null).loadClass(fullName)
    .newInstance();
    System.out.println(instance); RecordAccessor rd = (RecordAccessor) instance;
    rd.sayHello(); }
    }class ClassFileManager extends ForwardingJavaFileManager {
    /**
     * Instance of JavaClassObject that will store the compiled bytecode of our
     * class
     */
    private JavaClassObject jclassObject; /**
     * Will initialize the manager with the specified standard java file manager
     * 
     * @param standardManger
     */
    public ClassFileManager(StandardJavaFileManager standardManager) {
    super(standardManager);
    } /**
     * Will be used by us to get the class loader for our compiled class. It
     * creates an anonymous class extending the SecureClassLoader which uses the
     * byte code created by the compiler and stored in the JavaClassObject, and
     * returns the Class for it
     */
    @Override
    public ClassLoader getClassLoader(Location location) {
    return new SecureClassLoader() {
    @Override
    protected Class<?> findClass(String name)
    throws ClassNotFoundException {
    byte[] b = jclassObject.getBytes();
    return super.defineClass(name, jclassObject.getBytes(), 0,
    b.length);
    }
    };
    } /**
     * Gives the compiler an instance of the JavaClassObject so that the
     * compiler can write the byte code into it.
     */
    @Override
    public JavaFileObject getJavaFileForOutput(Location location,
    String className, Kind kind, FileObject sibling) throws IOException {
    jclassObject = new JavaClassObject(className, kind);
    return jclassObject;
    }
    }class CharSequenceJavaFileObject extends SimpleJavaFileObject { /**
     * CharSequence representing the source code to be compiled
     */
    private CharSequence content; /**
     * This constructor will store the source code in the internal "content"
     * variable and register it as a source code, using a URI containing the
     * class full name
     * 
     * @param className
     *            name of the public class in the source code
     * @param content
     *            source code to compile
     */
    public CharSequenceJavaFileObject(String className, CharSequence content) {
    super(URI.create("string:///" + className.replace('.', '/')
    + Kind.SOURCE.extension), Kind.SOURCE);
    this.content = content;
    } /**
     * Answers the CharSequence to be compiled. It will give the source code
     * stored in variable "content"
     */
    @Override
    public CharSequence getCharContent(boolean ignoreEncodingErrors) {
    return content;
    }
    }class JavaClassObject extends SimpleJavaFileObject { /**
     * Byte code created by the compiler will be stored in this
     * ByteArrayOutputStream so that we can later get the byte array out of it
     * and put it in the memory as an instance of our class.
     */
    protected final ByteArrayOutputStream bos = new ByteArrayOutputStream(); /**
     * Registers the compiled class object under URI containing the class full
     * name
     * 
     * @param name
     *            Full name of the compiled class
     * @param kind
     *            Kind of the data. It will be CLASS in our case
     */
    public JavaClassObject(String name, Kind kind) {
    super(
    URI.create("string:///" + name.replace('.', '/')
    + kind.extension), kind);
    } /**
     * Will be used by our file manager to get the byte code that can be put
     * into memory to instantiate our class
     * 
     * @return compiled byte code
     */
    public byte[] getBytes() {
    return bos.toByteArray();
    } /**
     * Will provide the compiler with an output stream that leads to our byte
     * array. This way the compiler will write everything into the byte array
     * that we will instantiate later
     */
    @Override
    public OutputStream openOutputStream() throws IOException {
    return bos;
    }
    }输出结果如下:
    package com.test.dyna;
    import com.test.dyna.RecordAccessor;
    public class DynaClass extends RecordAccessor{
        public String toString() {
            return "Hello, I am " + this.getClass().getSimpleName();
        }
        protected void sayHello() {
            System.out.println("Hello World!!!!");
        }
    }Hello, I am DynaClass
    Hello World!!!!