Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/329.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
用不同的包名动态加载java中的类_Java_Class_Dynamic Class Loaders - Fatal编程技术网

用不同的包名动态加载java中的类

用不同的包名动态加载java中的类,java,class,dynamic-class-loaders,Java,Class,Dynamic Class Loaders,是否可以在Java中加载一个类并“伪造”类的包名/规范名?我尝试过这样做,很明显,但是我在ClassDefNotFoundException中得到了一条“类名不匹配”的消息 我这样做的原因是我试图加载一个在默认包中编写的API,这样我就可以直接使用它而不用使用反射。代码将针对表示包和包名导入的文件夹结构中的类进行编译。即: ./com/DefaultPackageClass.class 我目前的代码如下: public Class loadClass(String name) throws Cl

是否可以在Java中加载一个类并“伪造”类的包名/规范名?我尝试过这样做,很明显,但是我在
ClassDefNotFoundException
中得到了一条“类名不匹配”的消息

我这样做的原因是我试图加载一个在默认包中编写的API,这样我就可以直接使用它而不用使用反射。代码将针对表示包和包名导入的文件夹结构中的类进行编译。即:

./com/DefaultPackageClass.class 我目前的代码如下:

public Class loadClass(String name) throws ClassNotFoundException {
    if(!CLASS_NAME.equals(name))
            return super.loadClass(name);

    try {
        URL myUrl = new URL(fileUrl);
        URLConnection connection = myUrl.openConnection();
        InputStream input = connection.getInputStream();
        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
        int data = input.read();

        while(data != -1){
            buffer.write(data);
            data = input.read();
        }

        input.close();

        byte[] classData = buffer.toByteArray();

        return defineClass(CLASS_NAME,
                classData, 0, classData.length);

    } catch (MalformedURLException e) {
        throw new UndeclaredThrowableException(e);
    } catch (IOException e) {
        throw new UndeclaredThrowableException(e); 
    }

}

也许将API从默认包移动到更合理的位置会更容易?听起来你好像没有访问源代码的权限。我不确定包是否被编码到类文件中,因此简单地移动API类可能值得一试。否则,像JAD这样的Java反编译器通常会做得很好,因此您可以在反编译的源代码中更改包名并重新编译它。

您应该能够完成一些工作,尽管在构建时重命名包比在加载时重命名包更容易。

,这可以使用ASM字节码库来完成。事实上,该库实际上附带了一个专门用于处理这些类名重新映射()的类。下面是使用此类的类装入器示例:

public class MagicClassLoader extends ClassLoader {

    private final String defaultPackageName;

    public MagicClassLoader(String defaultPackageName) {
        super();
        this.defaultPackageName = defaultPackageName;
    }

    public MagicClassLoader(String defaultPackageName, ClassLoader parent) {
        super(parent);
        this.defaultPackageName = defaultPackageName;
    }

    @Override
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        byte[] bytecode = ...; // I will leave this part up to you
        byte[] remappedBytecode;

        try {
            remappedBytecode = rewriteDefaultPackageClassNames(bytecode);
        } catch (IOException e) {
            throw new RuntimeException("Could not rewrite class " + name);
        }

        return defineClass(name, remappedBytecode, 0, remappedBytecode.length);
    }

    public byte[] rewriteDefaultPackageClassNames(byte[] bytecode) throws IOException {
        ClassReader classReader = new ClassReader(bytecode);
        ClassWriter classWriter = new ClassWriter(classReader, 0);

        Remapper remapper = new DefaultPackageClassNameRemapper();
        classReader.accept(
                new RemappingClassAdapter(classWriter, remapper),
                0
            );

        return classWriter.toByteArray();
    }

    class DefaultPackageClassNameRemapper extends Remapper {

        @Override
        public String map(String typeName) {
            boolean hasPackageName = typeName.indexOf('.') != -1;
            if (hasPackageName) {
                return typeName;
            } else {
                return defaultPackageName + "." + typeName;
            }
        }

    }

}

这是在任何重新映射之前顺序的列表:

> javap -private -c Order Compiled from "Order.java" public class Order extends java.lang.Object{ private Customer customer; public Order(Customer); Code: 0: aload_0 1: invokespecial #10; //Method java/lang/Object."":()V 4: aload_0 5: aload_1 6: putfield #13; //Field customer:LCustomer; 9: return public Customer getCustomer(); Code: 0: aload_0 1: getfield #13; //Field customer:LCustomer; 4: areturn public void setCustomer(Customer); Code: 0: aload_0 1: aload_1 2: putfield #13; //Field customer:LCustomer; 5: return } 如您所见,重新映射已将所有
Order
引用更改为
com.mycompany.Order
,将所有
Customer
引用更改为
com.mycompany.Customer

此类加载器必须加载以下所有类:

  • 属于默认包,或
  • 使用属于默认包的其他类

不,我没有访问源的权限。将类移动到目录在运行时不起作用,尽管它似乎在编译时起作用。如果可能的话,我不想对类进行黑客攻击。你是说在运行时更改类的包不是黑客攻击吗?对我来说,问题是哪一个更糟糕,然后使用另一个。。。
public class Customer {

}
public class Order {

    private Customer customer;

    public Order(Customer customer) {
        this.customer = customer;
    }

    public Customer getCustomer() {
        return customer;
    }

    public void setCustomer(Customer customer) {
        this.customer = customer;
    }

}
> javap -private -c Order Compiled from "Order.java" public class Order extends java.lang.Object{ private Customer customer; public Order(Customer); Code: 0: aload_0 1: invokespecial #10; //Method java/lang/Object."":()V 4: aload_0 5: aload_1 6: putfield #13; //Field customer:LCustomer; 9: return public Customer getCustomer(); Code: 0: aload_0 1: getfield #13; //Field customer:LCustomer; 4: areturn public void setCustomer(Customer); Code: 0: aload_0 1: aload_1 2: putfield #13; //Field customer:LCustomer; 5: return } > javap -private -c Order Compiled from "Order.java" public class com.mycompany.Order extends com.mycompany.java.lang.Object{ private com.mycompany.Customer customer; public com.mycompany.Order(com.mycompany.Customer); Code: 0: aload_0 1: invokespecial #30; //Method "com.mycompany.java/lang/Object"."":()V 4: aload_0 5: aload_1 6: putfield #32; //Field customer:Lcom.mycompany.Customer; 9: return public com.mycompany.Customer getCustomer(); Code: 0: aload_0 1: getfield #32; //Field customer:Lcom.mycompany.Customer; 4: areturn public void setCustomer(com.mycompany.Customer); Code: 0: aload_0 1: aload_1 2: putfield #32; //Field customer:Lcom.mycompany.Customer; 5: return }