views:

159

answers:

4

Is it possible to dig up a classes name from bytecode which is formed from the class' source code?

The situation is this: I get a classes bytecode remotely from somewhere, it doesn't matter where it comes from. To effectively load that class with a classloader i would need to have the class name as well... right?

+1  A: 

You should be able to use javap to disassemble the byte code, if that just happens once in a while.

For doing it at runtime: use a byte-code manipulation library like Apache's BCEL (http://jakarta.apache.org/bcel) to analyse the byte code.

ankon
Is there no built-in functionality for this?
JHollanti
@JHollanti - what you want is backwards from the way things are usually done - you start with a name (often from a descriptor file) and then use path conventions to load the class bytes. There is no standard way to load and run multiple arbitrary classes (which one would be the entry point? etc.)
McDowell
+2  A: 

The easiest way is probably using something like ASM:

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.commons.EmptyVisitor;

public class PrintClassName {
  public static void main(String[] args) throws IOException {
    class ClassNamePrinter extends EmptyVisitor {
      @Override
      public void visit(int version, int access, String name, String signature,
          String superName, String[] interfaces) {
        System.out.println("Class name: " + name);
      }
    }

    InputStream binary = new FileInputStream(args[0]);
    try {
      ClassReader reader = new ClassReader(binary);
      reader.accept(new ClassNamePrinter(), 0);
    } finally {
      binary.close();
    }
  }
}

If you can't use a 3rd party library, you could read the class file format yourself.

McDowell
A: 

I think you can use the ClassLoader.defineClass method, in a subclass of ClassLoader, to get the Class object for a given bytecode. (not tested)

Carlos Heuberger
+2  A: 

If you just need the class name, it's probably easier to parse the beginning of the class file yourself instead of adding a 3rd party library for class code manipulation just for this purpose. You just need the classes and strings from the constant pool, skip the access flags and then replace / with . in the class name. If you have a byte array, you can call this method with new ByteArrayInputStream(byteArray):

public static String getClassName(InputStream is) throws Exception {
    DataInputStream dis = new DataInputStream(is);
    dis.readLong(); // skip header and class version
    int cpcnt = (dis.readShort()&0xffff)-1;
    int[] classes = new int[cpcnt];
    String[] strings = new String[cpcnt];
    for(int i=0; i<cpcnt; i++) {
     int t = dis.read();
     if(t==7) classes[i] = dis.readShort()&0xffff;
     else if(t==1) strings[i] = dis.readUTF();
     else if(t==5 || t==6) dis.readLong();
     else if(t==8) dis.readShort();
     else dis.readInt();
    }
    dis.readShort(); // skip access flags
    return strings[classes[(dis.readShort()&0xffff)-1]-1].replace('/', '.');
}
jarnbjo
Neat. I hadn't looked at the details, but that's more succinct than I had expected.
McDowell
Yes, it's not particulary difficult. I sometimes wonder why people suggest to use 3rd party libraries (like in this case ASM) to solve rather simple problems, when the wrapup required the use the 3rd party library itself is almost more code than what it would require to solve the problem using a little brain and the standard Java API. Can't programmers program anymore and are they just able to copy, paste and glue libraries together to produce an almost-working, bloated result?
jarnbjo
Great, thanks! Sounds like a solid solution. I won't have a chance to try it out immediately, but i trust this works. "Can't programmers program anymore and are they just..."To a large extent, yes ;) Many of todays "coders" are not so much coders as they are integrators of libraries. Plus (especially with this task) to produce an error free solution would require a lot of work and study as i'm not at all familiar with Java bytecode. But thanks!
JHollanti