开发者

How to read the fully qualified name of a .class file

Hey, I think the title sums it, but still.

I need to extract the fully qualified name of an object from its compiled .class file, could anyone point me in the right direction?

Thanks,

Ada开发者_如何学JAVAm.


getClass().getName()

Update: You can load the class-file into a byte[] (using standard i/o) and then use getClass().getClassLoader().defineClass(...)


public String getFullClassName(String classFileName) throws IOException {           
        File file = new File(classFileName);

        FileChannel roChannel = new RandomAccessFile(file, "r").getChannel(); 
        ByteBuffer bb = roChannel.map(FileChannel.MapMode.READ_ONLY, 0, (int)roChannel.size());         

        Class<?> clazz = defineClass((String)null, bb, (ProtectionDomain)null);
        return clazz.getName();
    }


Use a library like BCEL to read the classfile into memory and query it for the class name.


You can read this by parsing the binary. The class file format is defined in the VM Spec.

Have a look at the DataInputStream if you're new to parsing binaries.


Depending on what IDE you are using there might be a mechanism for doing this. For example in eclipse you can drill down to the .class file and right click on it and select "copy fully qualified name".

Older versions of eclipse might not have this feature, but I have used this plugin before:

http://www.jave.de/eclipse/copyfully/index.html

It works pretty much the same way. Hope this helps.


You can take a look for example at the AnnotationScanner from the JSF Implementation, they do load the classes manually (to avoid perm-space pollution) to find JSF annotations. In particular look at this:

   /**
     * This class is encapsulating binary .class file information as defined at
     * http://java.sun.com/docs/books/vmspec/2nd-edition/html/ClassFile.doc.html
     * <p/>
     * This is used by the annotation frameworks to quickly scan .class files
     * for the presence of annotations. This avoid the annotation framework
     * having to load each .class file in the class loader.
     * <p/>
     * Taken from the GlassFish V2 source base.
     */
    @SuppressWarnings({"UnusedDeclaration"})
    private static final class ClassFile {

        private static final int magic = 0xCAFEBABE;

        public static final int ACC_PUBLIC = 0x1;
        public static final int ACC_PRIVATE = 0x2;
        public static final int ACC_PROTECTED = 0x4;
        public static final int ACC_STATIC = 0x8;
        public static final int ACC_FINAL = 0x10;
        public static final int ACC_SYNCHRONIZED = 0x20;
        public static final int ACC_THREADSAFE = 0x40;
        public static final int ACC_TRANSIENT = 0x80;
        public static final int ACC_NATIVE = 0x100;
        public static final int ACC_INTERFACE = 0x200;
        public static final int ACC_ABSTRACT = 0x400;

        public short majorVersion;
        public short minorVersion;
        public ConstantPoolInfo constantPool[];
        public short accessFlags;
        public ConstantPoolInfo thisClass;
        public ConstantPoolInfo superClass;
        public ConstantPoolInfo interfaces[];

        /**
         * bunch of stuff I really don't care too much for now.
         * <p/>
         * FieldInfo           fields[]; MethodInfo          methods[];
         * AttributeInfo       attributes[];
         */

        ByteBuffer header;
        ConstantPoolInfo constantPoolInfo = new ConstantPoolInfo();

        // ------------------------------------------------------------ Constructors


        /**
         * Creates a new instance of ClassFile
         */
        public ClassFile() {
            header = ByteBuffer.allocate(12000);
        }

        // ---------------------------------------------------------- Public Methods


        public void setConstantPoolInfo(ConstantPoolInfo poolInfo) {
            constantPoolInfo = poolInfo;
        }


        /**
         * Read the input channel and initialize instance data structure.
         *
         * @param in a <code>ReadableByteChannel</code> that provides the bytes
         *  of the classfile
         *
         * @return <code>true</code> if the bytes representing this classfile include
         *  one of the annotations we're looking for.
         *
         * @throws IOException if an I/O error occurs while reading the class
         */
        public boolean containsAnnotation(ReadableByteChannel in)
              throws IOException {

            /**
             * this is the .class file layout
             *
             ClassFile {
             u4 magic;
             u2 minor_version;
             u2 major_version;
             u2 constant_pool_count;
             cp_info constant_pool[constant_pool_count-1];
             u2 access_flags;
             u2 this_class;
             u2 super_class;
             u2 interfaces_count;
             u2 interfaces[interfaces_count];
             u2 fields_count;
             field_info fields[fields_count];
             u2 methods_count;
             method_info methods[methods_count];
             u2 attributes_count;
             attribute_info attributes[attributes_count];
             }
             **/
            header.clear();
            long read = (long) in.read(header);
            if (read == -1) {
                return false;
            }
            header.rewind();

            if (header.getInt() != magic) {
                return false;
            }

            minorVersion = header.getShort();
            majorVersion = header.getShort();
            int constantPoolSize = header.getShort();

            return constantPoolInfo
                  .containsAnnotation(constantPoolSize, header, in);

        }

    } // END ClassFile
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜