调用使用JarInputStream读取方法读取的字节的defineClass时的ClassFormatError

时间:2012-03-03 16:20:12

标签: java classloader

我使用以下方法从jar条目中读取字节(仅包含类文件)。 jar里面没有jar文件。

private List<byte[]> readFromJarFile(File cp) 
{
    List<byte[]> cbytes = new ArrayList<byte[]>();
    try 
    {
        java.util.jar.JarInputStream jin = new java.util.jar.JarInputStream(new java.io.FileInputStream(cp));
        java.util.jar.JarEntry je = jin.getNextJarEntry();
        while (je != null)
        {
            if (!je.isDirectory() && je.toString().endsWith(".class")) 
            {
                //assume class file size < Integer.MAX_VALUE
                System.out.printf("readFromJarFile: jar entry name %s ...%n",je.toString());
                byte[] cbyte = new byte[(int) je.getSize()];
                jin.read(cbyte,0,(int) je.getSize());
                cbytes.add(cbyte);
            }
            je = jin.getNextJarEntry();
        }
    }
    catch (java.io.IOException ie)
    {
        ie.printStackTrace();
    }

    return cbytes;
}

现在当我调用defineClass时,抛出异常后,从上面的方法返回一个字节数组。

java.lang.ClassFormatError: Unknown constant tag 0 in class file <Unknown>
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631)
at java.lang.ClassLoader.defineClass(ClassLoader.java:615)
at java.lang.ClassLoader.defineClass(ClassLoader.java:465)
at san.tool.JPAEntityProcessor$JPAClassLoader.loadClass(JPAEntityProcessor.java:34)
at san.tool.JPAEntityProcessor.processJPAEntities(JPAEntityProcessor.java:49)
at san.tool.JPAEntityProcessorTest.testWithJarFile(JPAEntityProcessorTest.java:40)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at 

我搜索了这个网站和互联网上的所有其他论坛,但找不到答案。我期待着会员们的一些见解。

谢谢和问候 Santanu

2 个答案:

答案 0 :(得分:4)

jin.read(cbyte,0,(int) je.getSize());

无法保证read方法会将je.getSize()字节读入缓冲区。相反,它返回实际读取的字节数。您需要将读取尝试包装到循环中并读取,直到缓冲区填满。

这样的事情:

int len = (int) je.getSize();
int offset = 0;
int read;
while ((read = jin.read(cbyte, offset, len - offset)) > 0) {
    offset += read;
}

UPD 经过一年的努力,我意识到,我的原始例子在读完整个流后会卡住。后来“固定”版本实际上不会进入循环。所以,这里是简短,正确和经过测试的版本。

答案 1 :(得分:0)

我遇到了同样的问题,实际上正确的方法是:

int read = 0;
int len = (int) je.getSize();
int offset = 0;
do {
    read = jin.read(cbyte, offset, len - offset);
    offset += read;
} while (read > 0);

这是我测试和工作的。请注意,在上面的答案中,它永远不会进入循环,因为read被初始化为零。