Skip to content

Commit

Permalink
Add ClassCreator.Builder#signature() that extracts superclass/intefaces
Browse files Browse the repository at this point in the history
  • Loading branch information
mkouba committed Jan 10, 2023
1 parent 5a28fa8 commit b34c2a2
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 22 deletions.
56 changes: 47 additions & 9 deletions src/main/java/io/quarkus/gizmo/ClassCreator.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

import io.quarkus.gizmo.SignatureBuilder.ClassSignatureBuilder;

public class ClassCreator implements AutoCloseable, AnnotatedElement, SignatureElement<ClassCreator> {

public static Builder builder() {
Expand All @@ -65,7 +67,8 @@ public static Builder interfaceBuilder() {
private final Map<MethodDescriptor, MethodDescriptor> superclassAccessors = new LinkedHashMap<>();
private final AtomicInteger accessorCount = new AtomicInteger();

ClassCreator(BytecodeCreatorImpl enclosing, ClassOutput classOutput, String name, String signature, String superClass, int access, String... interfaces) {
ClassCreator(BytecodeCreatorImpl enclosing, ClassOutput classOutput, String name, String signature, String superClass,
int access, String... interfaces) {
this.enclosing = enclosing;
this.classOutput = classOutput;
this.superClass = superClass.replace('.', '/');
Expand Down Expand Up @@ -159,7 +162,8 @@ MethodDescriptor getSupertypeAccessor(MethodDescriptor descriptor, String supert
for (int i = 0; i < params.length; ++i) {
params[i] = ctor.getMethodParam(i);
}
MethodDescriptor superDescriptor = MethodDescriptor.ofMethod(supertype, descriptor.getName(), descriptor.getReturnType(), descriptor.getParameterTypes());
MethodDescriptor superDescriptor = MethodDescriptor.ofMethod(supertype, descriptor.getName(),
descriptor.getReturnType(), descriptor.getParameterTypes());
ResultHandle ret;
if (isInterface) {
ret = ctor.invokeSpecialInterfaceMethod(superDescriptor, ctor.getThis(), params);
Expand All @@ -183,7 +187,7 @@ public void writeTo(ClassOutput classOutput) {
Writer sourceWriter = classOutput.getSourceWriter(className);
ClassVisitor cv;
if (sourceWriter != null) {
cv = new GizmoClassVisitor(Gizmo.ASM_API_VERSION, file, sourceWriter);
cv = new GizmoClassVisitor(Gizmo.ASM_API_VERSION, file, sourceWriter);
} else {
cv = file;
}
Expand All @@ -202,7 +206,7 @@ public void writeTo(ClassOutput classOutput) {
if (requiresCtor) {
// constructor
if (cv instanceof GizmoClassVisitor) {
((GizmoClassVisitor)cv).append("// Auto-generated constructor").newLine();
((GizmoClassVisitor) cv).append("// Auto-generated constructor").newLine();
}
MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, MethodDescriptor.INIT, "()V", null, null);
mv.visitVarInsn(ALOAD, 0); // push `this` to the operand stack
Expand All @@ -220,9 +224,10 @@ public void writeTo(ClassOutput classOutput) {
for (Map.Entry<MethodDescriptor, MethodCreatorImpl> method : methods.entrySet()) {
method.getValue().write(cv);
}
for(AnnotationCreatorImpl annotation : annotations) {
AnnotationVisitor av = cv.visitAnnotation(DescriptorUtils.extToInt(annotation.getAnnotationType()), annotation.getRetentionPolicy() == RetentionPolicy.RUNTIME);
for(Map.Entry<String, Object> e : annotation.getValues().entrySet()) {
for (AnnotationCreatorImpl annotation : annotations) {
AnnotationVisitor av = cv.visitAnnotation(DescriptorUtils.extToInt(annotation.getAnnotationType()),
annotation.getRetentionPolicy() == RetentionPolicy.RUNTIME);
for (Map.Entry<String, Object> e : annotation.getValues().entrySet()) {
AnnotationUtils.visitAnnotationValue(av, e.getKey(), e.getValue());
}
av.visitEnd();
Expand All @@ -234,7 +239,7 @@ public void writeTo(ClassOutput classOutput) {
}

/**
* Finish the class creator. If a class output was configured for this class creator, the class bytes
* Finish the class creator. If a class output was configured for this class creator, the class bytes
* will immediately be written there.
*/
@Override
Expand Down Expand Up @@ -317,6 +322,30 @@ public Builder signature(String signature) {
return this;
}

/**
* The raw types of the superclass and superinterfaces are extracted and passed to {@link #superClass(String)} and
* {@link #interfaces(String...)} respectively.
*
* @param signatureBuilder
* @return self
*/
public Builder signature(ClassSignatureBuilder signatureBuilder) {
ClassSignatureBuilderImpl signatureBuilderImpl = (ClassSignatureBuilderImpl) signatureBuilder;
Type superClass = signatureBuilderImpl.superClass;
if (superClass != null) {
superClass(getRawType(superClass));
}
if (!signatureBuilderImpl.superInterfaces.isEmpty()) {
String[] interfaces = new String[signatureBuilderImpl.superInterfaces.size()];
int idx = 0;
for (Type superInterface : signatureBuilderImpl.superInterfaces) {
interfaces[idx++] = getRawType(superInterface);
}
interfaces(interfaces);
}
return signature(signatureBuilder.build());
}

public Builder superClass(String superClass) {
if ((access & ACC_INTERFACE) != 0
&& !"java.lang.Object".equals(superClass)
Expand Down Expand Up @@ -360,7 +389,16 @@ public Builder interfaces(Class<?>... interfaces) {
public ClassCreator build() {
Objects.requireNonNull(className);
Objects.requireNonNull(superClass);
return new ClassCreator(enclosing, classOutput, className, signature, superClass, access, interfaces.toArray(new String[0]));
return new ClassCreator(enclosing, classOutput, className, signature, superClass, access,
interfaces.toArray(new String[0]));
}

private String getRawType(Type type) {
if (type.isClass()) {
return type.asClass().name;
} else {
return type.asParameterizedType().genericClass.name;
}
}

}
Expand Down
7 changes: 4 additions & 3 deletions src/main/java/io/quarkus/gizmo/ClassSignatureBuilderImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@
import io.quarkus.gizmo.Type.TypeVariable;

class ClassSignatureBuilderImpl implements ClassSignatureBuilder {
private List<TypeVariable> typeParameters = new ArrayList<>();
private Type superClass = ClassType.OBJECT;
private List<Type> superInterfaces = new ArrayList<>();

List<TypeVariable> typeParameters = new ArrayList<>();
Type superClass = ClassType.OBJECT;
List<Type> superInterfaces = new ArrayList<>();

@Override
public String build() {
Expand Down
11 changes: 6 additions & 5 deletions src/main/java/io/quarkus/gizmo/Type.java
Original file line number Diff line number Diff line change
Expand Up @@ -260,8 +260,8 @@ PrimitiveType asPrimitive() {
public static final class ClassType extends Type {
public static final ClassType OBJECT = new ClassType("java/lang/Object", null);

private final String name; // always slash-delimited
private final Type owner;
final String name; // always slash-delimited
final Type owner;

ClassType(String name, Type owner) {
this.name = Objects.requireNonNull(name);
Expand Down Expand Up @@ -344,9 +344,10 @@ ArrayType asArray() {
}

public static final class ParameterizedType extends Type {
private final ClassType genericClass;
private final List<Type> typeArguments;
private final Type owner;

final ClassType genericClass;
final List<Type> typeArguments;
final Type owner;

ParameterizedType(ClassType genericClass, List<Type> typeArguments, Type owner) {
this.genericClass = Objects.requireNonNull(genericClass);
Expand Down
29 changes: 24 additions & 5 deletions src/test/java/io/quarkus/gizmo/SignaturesTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.jboss.jandex.DotName;
import org.junit.Test;

import io.quarkus.gizmo.SignatureBuilder.ClassSignatureBuilder;
import io.quarkus.gizmo.SignaturesTest.Nested.Inner.Inner2;
import io.quarkus.gizmo.SignaturesTest.NestedParam.InnerParam;

Expand Down Expand Up @@ -233,17 +234,19 @@ public void testClassSignatures() {
// }
// }
// }
assertEquals("<X:Ljava/lang/String;Y:Ljava/lang/Integer;>Lio/quarkus/gizmo/test/OuterParam<TX;>.InnerParam<TY;>.InnerInnerRaw.InnerInnerInnerParam<Ljava/lang/String;>;Lio/quarkus/gizmo/test/OuterParam$NestedParam<TV;>;",
assertEquals(
"<X:Ljava/lang/String;Y:Ljava/lang/Integer;>Lio/quarkus/gizmo/test/OuterParam<TX;>.InnerParam<TY;>.InnerInnerRaw.InnerInnerInnerParam<Ljava/lang/String;>;Lio/quarkus/gizmo/test/OuterParam$NestedParam<TV;>;",
SignatureBuilder.forClass()
.addTypeParameter(Type.typeVariable("X", Type.classType(String.class)))
.addTypeParameter(Type.typeVariable("Y", Type.classType(Integer.class)))
.setSuperClass(
Type.parameterizedType(Type.classType("io.quarkus.gizmo.test.OuterParam"), Type.typeVariable("X"))
Type.parameterizedType(Type.classType("io.quarkus.gizmo.test.OuterParam"),
Type.typeVariable("X"))
.innerParameterizedType("InnerParam", Type.typeVariable("Y"))
.innerClass("InnerInnerRaw")
.innerParameterizedType("InnerInnerInnerParam", Type.classType(String.class))
)
.addInterface(Type.parameterizedType(Type.classType("io.quarkus.gizmo.test.OuterParam$NestedParam"), Type.typeVariable("V")))
.innerParameterizedType("InnerInnerInnerParam", Type.classType(String.class)))
.addInterface(Type.parameterizedType(Type.classType("io.quarkus.gizmo.test.OuterParam$NestedParam"),
Type.typeVariable("V")))
.build());

try {
Expand All @@ -254,6 +257,22 @@ public void testClassSignatures() {
}
}

@Test
public void testClassCreatorSignatureBuilder() {
// class Foo<T> extends List<T> implements Serializable, Comparable<T>
ClassSignatureBuilder classSignature = SignatureBuilder.forClass()
.addTypeParameter(Type.typeVariable("T"))
.setSuperClass(Type.parameterizedType(Type.classType(List.class), Type.typeVariable("T")))
.addInterface(Type.classType(Serializable.class))
.addInterface(Type.parameterizedType(Type.classType(Comparable.class), Type.typeVariable("T")));

ClassCreator creator = ClassCreator.builder().signature(classSignature).className("org.acme.Foo").build();
assertEquals("java/util/List", creator.getSuperClass());
assertEquals(2, creator.getInterfaces().length);
assertEquals("java/io/Serializable", creator.getInterfaces()[0]);
assertEquals("java/lang/Comparable", creator.getInterfaces()[1]);
}

public static class Nested {

public class Inner {
Expand Down

0 comments on commit b34c2a2

Please sign in to comment.