in framework/src/main/java/org/apache/felix/framework/util/ClassParser.java [785:1054]
Set<String> parseClassFileData(DataInput in) throws Exception
{
++depth;
boolean crawl = false; // Crawl the byte code if we have a
// collector
int magic = in.readInt();
if (magic != 0xCAFEBABE)
{
throw new IOException("Not a valid class file (no CAFEBABE header)");
}
minor = in.readUnsignedShort(); // minor version
major = in.readUnsignedShort(); // major version
int count = in.readUnsignedShort();
pool = new Object[count];
intPool = new int[count];
CONSTANT[] tags = CONSTANT.values();
process:
for (int poolIndex = 1; poolIndex < count; poolIndex++)
{
int tagValue = in.readUnsignedByte();
if (tagValue >= tags.length)
{
throw new IOException("Unrecognized constant pool tag value " + tagValue);
}
CONSTANT tag = tags[tagValue];
switch (tag)
{
case Zero:
break process;
case Utf8:
constantUtf8(in, poolIndex);
break;
case Integer:
constantInteger(in, poolIndex);
break;
case Float:
constantFloat(in, poolIndex);
break;
// For some insane optimization reason,
// the long and double entries take two slots in the
// constant pool. See 4.4.5
case Long:
constantLong(in, poolIndex);
poolIndex++;
break;
case Double:
constantDouble(in, poolIndex);
poolIndex++;
break;
case Class:
constantClass(in, poolIndex);
break;
case String:
constantString(in, poolIndex);
break;
case Fieldref:
case Methodref:
case InterfaceMethodref:
ref(in, poolIndex);
break;
case NameAndType:
nameAndType(in, poolIndex, tag);
break;
case MethodHandle:
methodHandle(in, poolIndex, tag);
break;
case MethodType:
methodType(in, poolIndex, tag);
break;
case InvokeDynamic:
invokeDynamic(in, poolIndex, tag);
break;
default:
int skip = tag.skip();
if (skip == -1)
{
throw new IOException("Invalid tag " + tag);
}
in.skipBytes(skip);
break;
}
}
pool(pool, intPool);
// All name& type and class constant records contain classParser we must
// treat
// as references, though not API
for (Object o : pool)
{
if (o == null)
{
continue;
}
if (o instanceof Assoc)
{
Assoc assoc = (Assoc) o;
switch (assoc.tag)
{
case Fieldref:
case Methodref:
case InterfaceMethodref:
classConstRef(assoc.a);
break;
case NameAndType:
case MethodType:
referTo(assoc.b, 0); // Descriptor
break;
default:
break;
}
}
}
//
// There is a bug in J8 compiler that leaves an
// orphan class constant. So when we have a CC that
// is not referenced by fieldrefs, method refs, or other
// refs then we need to crawl the byte code.
//
for (Object o : pool)
{
if (o instanceof ClassConstant)
{
ClassConstant cc = (ClassConstant) o;
if (!cc.referred)
{
detectLdc = true;
}
}
}
/*
* Parse after the constant pool, code thanks to Hans Christian
* Falkenberg
*/
accessx = in.readUnsignedShort(); // access
int this_class = in.readUnsignedShort();
className = classParser.getTypeRef((String) pool[intPool[this_class]]);
if (!isModule())
{
referTo(className, Modifier.PUBLIC);
}
int super_class = in.readUnsignedShort();
String superName = (String) pool[intPool[super_class]];
if (superName != null)
{
zuper = classParser.getTypeRef(superName);
}
if (zuper != null)
{
referTo(zuper, accessx);
}
int interfacesCount = in.readUnsignedShort();
if (interfacesCount > 0)
{
interfaces = new TypeRef[interfacesCount];
for (int i = 0; i < interfacesCount; i++)
{
interfaces[i] = classParser.getTypeRef((String) pool[intPool[in.readUnsignedShort()]]);
referTo(interfaces[i], accessx);
}
}
int fieldsCount = in.readUnsignedShort();
for (int i = 0; i < fieldsCount; i++)
{
int access_flags = in.readUnsignedShort(); // skip access flags
int name_index = in.readUnsignedShort();
int descriptor_index = in.readUnsignedShort();
// Java prior to 1.5 used a weird
// static variable to hold the com.X.class
// result construct. If it did not find it
// it would create a variable class$com$X
// that would be used to hold the class
// object gotten with Class.forName ...
// Stupidly, they did not actively use the
// class name for the field type, so bnd
// would not see a reference. We detect
// this case and add an artificial descriptor
String name = pool[name_index].toString(); // name_index
if (name.startsWith("class$") || name.startsWith("$class$"))
{
crawl = true;
}
referTo(descriptor_index, access_flags);
doAttributes(in, ElementType.FIELD, false, access_flags);
}
//
// Check if we have to crawl the code to find
// the ldc(_w) <string constant> invokestatic Class.forName
// if so, calculate the method ref index so we
// can do this efficiently
//
if (crawl)
{
forName = findMethodReference("java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;");
class$ = findMethodReference(className.getBinary(), "class$", "(Ljava/lang/String;)Ljava/lang/Class;");
}
else if (major == 48)
{
forName = findMethodReference("java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;");
if (forName > 0)
{
crawl = true;
class$ = findMethodReference(className.getBinary(), "class$",
"(Ljava/lang/String;)Ljava/lang/Class;");
}
}
// There are some serious changes in the
// class file format. So we do not do any crawling
// it has also become less important
// however, jDK8 has a bug that leaves an orphan ClassConstnat
// so if we have those, we need to also crawl the byte codes.
// if (major >= JAVA.OpenJDK7.major)
crawl |= detectLdc;
//
// Handle the methods
//
int methodCount = in.readUnsignedShort();
for (int i = 0; i < methodCount; i++)
{
int access_flags = in.readUnsignedShort();
int name_index = in.readUnsignedShort();
int descriptor_index = in.readUnsignedShort();
String name = pool[name_index].toString();
String descriptor = pool[descriptor_index].toString();
MethodDef mdef = null;
referTo(descriptor_index, access_flags);
if ("<init>".equals(name))
{
if (Modifier.isPublic(access_flags) && "()V".equals(descriptor))
{
hasDefaultConstructor = true;
}
doAttributes(in, ElementType.CONSTRUCTOR, crawl, access_flags);
}
else
{
doAttributes(in, ElementType.METHOD, crawl, access_flags);
}
}
last = null;
doAttributes(in, ElementType.TYPE, false, accessx);
//
// Parse all the classParser we found
//
reset();
return imports;
}