有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java自定义类加载器加载一个jar会在类文件的常量池中给我一个非法的UTF8字符串

我需要使用自定义类加载器来加载第三方驱动程序。我们的计划是,驱动程序只需共享jar档案,但要使用一个。dar后缀(驱动程序存档)。然后,当jvm忽略此文件扩展名并像处理资源一样处理dar文件(这意味着忽略其中的类文件)时,这些归档文件被简单地添加到类路径中

现在我的问题是,我的类加载器在类文件异常的常量池中给了我一个非法的UTF8字符串。我怎样才能避开这个问题呢

public class DriversClassLoader extends ClassLoader {

    public DriversClassLoader() {
        super(ClassLoader.getSystemClassLoader());
    }

    @Override
    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
        if( name.startsWith("java.")) {
            return super.loadClass(name, resolve);
        } else {
            // see if we have already loaded the class.
            Class<?> c = findLoadedClass(name);
            if (c != null) return c;

            try {
                URL driversUrl = super.getResource("drivers.dar").toURI().toURL();
                System.out.println(driversUrl);
                JarInputStream jis = new JarInputStream(driversUrl.openConnection().getInputStream());

                ZipEntry entry;
                while ((entry = jis.getNextEntry()) != null) {
                    if (entry.getName().matches(name)) {
                        System.out.println("loading: " + entry);
                        byte[] cBytes = new byte[(int) entry.getSize()];
                        jis.read(cBytes, 0, cBytes.length);

                        // this is where I get the exception
                        c = defineClass(name, cBytes, 0, cBytes.length);
                        if (resolve) resolveClass(c);
                        return c;
                    }
                }
            } catch (Exception e) {
                throw new ClassNotFoundException("loading of class " + name + " failed", e);
            }

            // else delegate to parent
            return super.loadClass(name, resolve);

            /*
            URL res = getResource(name);
            if (res == null) throw new ClassNotFoundException("Class " + name + "not found in:");

            try {
                byte[] cBytes = IOUtils.toByteArray(new InputStreamReader(res.openStream()));
                c = defineClass(name, cBytes, 0, cBytes.length);
                if (resolve) resolveClass(c);
                return c;
            } catch (Exception e) {
                throw new ClassNotFoundException("loading of class " + name + " failed", e);
            }

            // delegate to parent
            return super.loadClass(name, resolve);*/
        }
    }

    @Override
    public URL getResource(String name) {
        try {
            URL driversUrl = super.getResource("drivers.dar").toURI().toURL();
            System.out.println(driversUrl);
            JarInputStream jis = new JarInputStream(driversUrl.openConnection().getInputStream());

            ZipEntry entry;
            while ((entry = jis.getNextEntry()) != null) {

                if (entry.getName().matches(name)) {
                    System.out.println(entry);
                    return new URL("jar:" + driversUrl + "!/" + entry);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        // delegate to parent
        return super.getResource(name);
    }

    @Override
    public Enumeration<URL> getResources(String name) throws IOException {
        //super.get
        return super.getResources(name);
    }
}

那我就干脆

Class<?> aClass = Class.forName("a.class", false, new DriverClassLoader());
System.out.println("aclass = " + aClass);

编辑1: 但该文件包含有效的类:

java -cp ../rangeCache/src/main/resources/drivers.dar pkg.test.Test

从dar jar输出Hello

但这并不是:

java -cp target/libs/range-cache-302-SNAPSHOT.jar:drivers/ com.data.cache.range.drivers.DriversClassLoader
jar:file:/home/rangeCache/target/libs/range-cache-302-SNAPSHOT.jar!/drivers.dar
loading: com/data/cache/range/drivers/DatastaxCassandraDriver.class
Exception in thread "main" java.lang.ClassFormatError: Illegal UTF8 string in constant pool in class file com/data/cache/range/drivers/DatastaxCassandraDriver/class
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:760)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:642)
    at com.mindbusters.data.cache.range.drivers.DriversClassLoader.loadClass(DriversClassLoader.java:40)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:348)
    at com.data.cache.range.drivers.DriversClassLoader.main(DriversClassLoader.java:105)

共 (1) 个答案

  1. # 1 楼答案

    ZipEntry读取字节的代码已损坏

    您首先不应该依赖ZipEntry.getSize(),因为如果不知道-1可能会返回(请参阅Javadocs)

    然后InputStream.read(byte[], int , int)读取的字节数可能小于请求的字节数。 您应该读取循环中的字节,直到返回-1,或者像以前一样使用IOUtils.toByteArray