0

Any ideas why I am getting this error? (Yes, I looked up the error, and still haven't found a solution)

My error:

Exception in thread "main" java.lang.ClassFormatError: Truncated class file
 at java.lang.ClassLoader.defineClass1(Native Method)
 at java.lang.ClassLoader.defineClass(Unknown Source)
 at java.lang.ClassLoader.defineClass(Unknown Source)
 at org.fellixombc.mysql.util.MysqlClassLoader.findClass(MysqlClassLoader.java:22)
 at org.fellixombc.mysql.util.MysqlClassLoader.loadClass(MysqlClassLoader.java:14)
 at org.fellixombc.mysql.Main.main(Main.java:9)

Files:

Main.java

package org.fellixombc.mysql;

import org.fellixombc.mysql.util.MysqlClassLoader;

public class Main {
    public static void main(String[] args) {
        MysqlClassLoader mcl = new MysqlClassLoader();
        try {
            mcl.loadClass("org.fellixombc.mysql.net.Client");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

Client.java:

package org.fellixombc.mysql.net;

public class Client {
    public Client() {
        System.out.println("Hello!");
    }
}

MysqlClassLoder.java:

package org.fellixombc.mysql.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class MysqlClassLoader extends ClassLoader {
    public MysqlClassLoader() {
        super(MysqlClassLoader.class.getClassLoader());
    }

    @Override
    public Class<?> loadClass(String className) throws ClassNotFoundException {
        return findClass(className);
    }

    @Override
    public Class<?> findClass(String className) throws ClassNotFoundException {
        byte[] b = null;
        try {
            b = loadClassData(className);
            Class c = defineClass(className, b, 0, b.length);
            if(c != null)
                return c;
            return super.findClass(className);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    private byte[] loadClassData(String className) throws IOException {
        int size = className.length();
        byte buff[] = new byte[size];

        // Open the file
        FileInputStream fis = new FileInputStream("bin/" + className.replace('.', File.separatorChar) + ".class");
        fis.available();
        fis.read(buff);
        fis.close();

        return buff;
    }
}

2 Answers 2

3

Yes, you're reading at most a byte count equal to the number of characters in the filename. Instead, you need to read the whole file. Here's one method, using readFully as you suggested.

File f = new File("bin/" + className.replace('.', File.separatorChar) + ".class");
DataInputStream is = new DataInputStream(new FileInputStream(f));
int len = (int)f.length();
byte[] buff = new byte[len];
is.readFully(buff);
is.close();
return buff;

Since you're not handling built-in classes like Object, I think you need to catch the FileNotFoundException from loadClassData in your findClass, then call super.findClass. E.g.:

try {
  try {
    b = loadClassData(className);
  }
  catch(FileNotFoundException fnf) {
    return super.findClass(className);
  }
  Class c = defineClass(className, b, 0, b.length);
  if(c != null)
    return c;
  return super.findClass(className);
} catch (IOException e) {
  e.printStackTrace();
}
return null;
Sign up to request clarification or add additional context in comments.

3 Comments

Now, for some reason, it is trying to open bin\java\lang\Object.class java.io.FileNotFoundException: bin\java\lang\Object.class (The system cannot find the path specified) I don't know why though.
When I print out className, i get org.fellixombc.mysql.net.Client java.lang.Object So I must of messed up some where in findClass()
Ahh, thank you. I'm getting another error, but I think i can handle this one. Anyways, thank you for your time!
1

You are reading only N bytes (N=length of class name) from the .class file into the buffer (in loadClassData) before returning it.

You need to read the contents of the entire class before you return the buffer for the class to be properly defined.

2 Comments

So a simple solution would be to use DataInputStream and use the readFully() method?
Not really, you can use FileInputStream, but you'll need to read the entire contents of the class. The second line in loadClassData() is the cause of the problem : byte buff[] = new byte[size]; should instead be the size of the actual file.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.