Hi Trevor, I think ClassFile.of is good for this particular purpose. There is nothing in the header parsing that the default class file handling options is not suitable for.
-Chen ________________________________ From: core-libs-dev <[email protected]> on behalf of Trevor Bond <[email protected]> Sent: Wednesday, November 5, 2025 9:56 PM To: [email protected] <[email protected]> Subject: Questions regarding JDK-8350938 (ResourceParsingClassHierarchyResolver) Hi all, I'm new to contributing to OpenJDK and have been working with Dan Smith as a mentor. I've been looking at JDK-8350938, which suggests refactoring ResourceParsingClassHierarchyResolver to avoid inflating all UTF8 constant pool entries by using ClassReaderImpl. ClassReaderImpl stores constant pool offsets and later lazily reads/inflates UTF8 entries as needed, so it seems to make sense to use here as a performance enhancement. I have an initial prototype that removes manual parsing in getClassInfo() and instead constructs a ClassReaderImpl and uses its helper methods to return the needed class information. One question before I try to move forward with contributing: - ClassReaderImpl takes a ClassFile context. I used ClassFile.of() (a ClassFile context with default options). Is this the correct usage here, or should the resolver provide a more specific context? I am also open to and would appreciate any other ideas or feedback on this implementation. I’ve included the small patch below for reference. Thanks for your help, Trevor diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassHierarchyImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassHierarchyImpl.java index 5be14f42baa..463845ce612 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassHierarchyImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassHierarchyImpl.java @@ -30,7 +30,10 @@ import java.io.IOException; import java.io.InputStream; import java.io.UncheckedIOException; +import java.lang.classfile.ClassFile; import java.lang.classfile.ClassHierarchyResolver; +import java.lang.classfile.ClassReader; +import java.lang.classfile.constantpool.ClassEntry; import java.lang.constant.ClassDesc; import java.util.Collection; import java.util.HashMap; @@ -164,31 +167,12 @@ public ResourceParsingClassHierarchyResolver(Function<ClassDesc, InputStream> cl public ClassHierarchyResolver.ClassHierarchyInfo getClassInfo(ClassDesc classDesc) { var ci = streamProvider.apply(classDesc); if (ci == null) return null; - try (var in = new DataInputStream(new BufferedInputStream(ci))) { - in.skipBytes(8); - int cpLength = in.readUnsignedShort(); - String[] cpStrings = new String[cpLength]; - int[] cpClasses = new int[cpLength]; - for (int i = 1; i < cpLength; i++) { - int tag; - switch (tag = in.readUnsignedByte()) { - case TAG_UTF8 -> cpStrings[i] = in.readUTF(); - case TAG_CLASS -> cpClasses[i] = in.readUnsignedShort(); - case TAG_STRING, TAG_METHOD_TYPE, TAG_MODULE, TAG_PACKAGE -> in.skipBytes(2); - case TAG_METHOD_HANDLE -> in.skipBytes(3); - case TAG_INTEGER, TAG_FLOAT, TAG_FIELDREF, TAG_METHODREF, TAG_INTERFACE_METHODREF, - TAG_NAME_AND_TYPE, TAG_DYNAMIC, TAG_INVOKE_DYNAMIC -> in.skipBytes(4); - case TAG_LONG, TAG_DOUBLE -> { - in.skipBytes(8); - i++; - } - default -> throw new IllegalStateException("Bad tag (" + tag + ") at index (" + i + ")"); - } - } - boolean isInterface = (in.readUnsignedShort() & ACC_INTERFACE) != 0; - in.skipBytes(2); - int superIndex = in.readUnsignedShort(); - var superClass = superIndex > 0 ? ClassDesc.ofInternalName(cpStrings[cpClasses[superIndex]]) : null; + try (ci) { + ClassReader reader = new ClassReaderImpl(ci.readAllBytes(), (ClassFileImpl) ClassFile.of()); + boolean isInterface = (reader.flags() & ACC_INTERFACE) != 0; + ClassDesc superClass = reader.superclassEntry() + .map(ClassEntry::asSymbol) + .orElse(null); return new ClassHierarchyInfoImpl(superClass, isInterface); } catch (IOException ioe) { throw new UncheckedIOException(ioe);
