Skip to content

Commit

Permalink
allow primitive type signatures on fields
Browse files Browse the repository at this point in the history
The grammar for generic signatures in the JVMS is pretty clear that
a signature for a field is a reference type signature. However,
there are class files in the wild that contain a primitive type
signature for a field. This commit makes that acceptable in Jandex,
even though it technically isn't valid bytecode.
  • Loading branch information
Ladicek committed Nov 27, 2023
1 parent 468cd08 commit 34833d6
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,14 @@ Type parseFieldSignature(String signature) {
this.typeParameters = this.elementTypeParameters;
this.pos = 0;

return parseReferenceType();
// the grammar in the JVMS says:
//
// FieldSignature:
// ReferenceTypeSignature
//
// however, there are class files in the wild that contain
// a primitive type signature as a field signature
return parseJavaType();
}

MethodSignature parseMethodSignature(String signature) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package org.jboss.jandex.test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

import java.io.IOException;

import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.FieldInfo;
import org.jboss.jandex.Index;
import org.jboss.jandex.PrimitiveType;
import org.junit.jupiter.api.Test;

import net.bytebuddy.ByteBuddy;
import net.bytebuddy.asm.AsmVisitorWrapper;
import net.bytebuddy.description.field.FieldDescription;
import net.bytebuddy.description.field.FieldList;
import net.bytebuddy.description.method.MethodList;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.implementation.Implementation;
import net.bytebuddy.jar.asm.ClassVisitor;
import net.bytebuddy.jar.asm.FieldVisitor;
import net.bytebuddy.pool.TypePool;
import net.bytebuddy.utility.OpenedClassReader;

public class FieldWithPrimitiveTypeSignatureTest {
private static final String TEST_CLASS = "org.jboss.jandex.test.TestClass";

// the Oracle JDBC driver in version 23.3.0.23.09 contains a class with a field
// whose generic signature encodes a primitive type, which is invalid per JVMS

@Test
public void test() throws IOException {
byte[] bytecode = new ByteBuddy()
.subclass(Object.class)
.name(TEST_CLASS)
.defineField("foo", boolean.class)
.visit(new AsmVisitorWrapper.AbstractBase() {
@Override
public ClassVisitor wrap(TypeDescription instrumentedType, ClassVisitor classVisitor,
Implementation.Context implementationContext, TypePool typePool,
FieldList<FieldDescription.InDefinedShape> fields, MethodList<?> methods,
int writerFlags, int readerFlags) {
return new ClassVisitor(OpenedClassReader.ASM_API, classVisitor) {
@Override
public FieldVisitor visitField(int access, String name, String descriptor, String signature,
Object value) {
if ("foo".equals(name)) {
signature = "Z"; // boolean
}
return super.visitField(access, name, descriptor, signature, value);
}
};
}
})
.make()
.getBytes();
ClassInfo clazz = Index.singleClass(bytecode);

assertEquals(1, clazz.fields().size());
FieldInfo field = clazz.field("foo");
assertNotNull(field);
assertEquals(PrimitiveType.BOOLEAN, field.type());
}
}

0 comments on commit 34833d6

Please sign in to comment.