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:
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.