views:

77

answers:

2

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;

 }

}
+3  A: 

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;
Matthew Flaschen
Now, for some reason, it is trying to open bin\java\lang\Object.classjava.io.FileNotFoundException: bin\java\lang\Object.class (The system cannot find the path specified)I don't know why though.
Fellixombc
When I print out className, i get org.fellixombc.mysql.net.Clientjava.lang.ObjectSo I must of messed up some where in findClass()
Fellixombc
Ahh, thank you. I'm getting another error, but I think i can handle this one. Anyways, thank you for your time!
Fellixombc
+1  A: 

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.

Vineet Reynolds
So a simple solution would be to use DataInputStream and use the readFully() method?
Fellixombc
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.
Vineet Reynolds