Categories
Coding

Eclipse package-info bug solved

I finally found the cause of the Eclipse package-info.java bug I mentioned earlier. I took a look at the .class files generated by IDEA and Eclipse and compared them, first using javap, and then using good old Vim’s built in Hex mode. Using a copy of the class file format specification (updated for Java 5), I was able to decipher the .class files and find a few interesting things.

For starters, here is the class file format:

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];
}

First of all, the constant pool layout seems to be arbitrary, and there doesn’t seem to be any fixed order on where constants appear in the pool versus how they are defined in the source code. This stands to reason, as the constant pool is a lookup table, after all, and it should be irrelevant where they physically appear, as long as they are indexed correctly.

The second issue was actually tracking down what Eclipse and IDEA did differently. I had a feeling that the issue may have resided in the attributes section of the class file, but as it turned out, the error turned out to be in the access_info field of the class file. The access_info field is defined as:


Flag Name

Value

Interpretation


ACC_PUBLIC

0x0001


Declared public; may be accessed from outside its package.


ACC_FINAL

0x0010

Declared final; no subclasses allowed.


ACC_SUPER


0x0020

Treat superclass methods specially when invoked by the invokespecial instruction.


ACC_INTERFACE

0x0200

Is an interface, not a class.

ACC_ABSTRACT


0x0400

Declared abstract; may not be instantiated.

ACC_ANNOTATION


0x0400

Declared as an annotation type

ACC_ENUM


0x0400

Declared as an enum type.

The value of this field was 0x1600 for Eclipse, but 0x0200 for IDEA. The Eclipse value was (I presume) constructed by using ACC_INTERFACE | ACC_ABSTRACT | ACC_SYNTHETIC. The ClassLoader choked when it saw the synthetic attribute. This bug has now been fixed. Oddly, the “bug” is technically correct – the synthetic attribute should be perfectly valid for a package-info class file. Apparently it will be in 6.0.

The strange thing is that the IDEA-generated access_info field is 0x0200 (ACC_INTERFACE), when strictly in accordance with the spec, it should be 0x0600 (ACC_INTERFACE | ACC_ABSTRACT), and technically is erroneous. I’m not sure why the CM does not flag it as such.

The last point I noticed is that the extensible attribute system that Sun built into the class file format was a stroke of genius. This is what supports the JDK 5 annotation system, and has previously allowed vendors to extend the class format in ways never thought possible.

Leave a Reply