From 692bd490814ef8ef64af575d380761e26d8d782b Mon Sep 17 00:00:00 2001 From: Martin Kouba Date: Mon, 27 Aug 2018 09:02:04 +0200 Subject: [PATCH] Gizmo ClassCreator - make it possible to set class signature + builder --- .../protean/gizmo/BytecodeCreatorImpl.java | 2 +- .../org/jboss/protean/gizmo/ClassCreator.java | 90 ++++++++++++++++--- .../jboss/protean/gizmo/ArrayTestCase.java | 4 +- .../gizmo/ExceptionThrowingTestCase.java | 2 +- .../protean/gizmo/FieldModifiersTest.java | 2 +- .../jboss/protean/gizmo/FunctionTestCase.java | 6 +- .../protean/gizmo/LoadClassTestCase.java | 2 +- .../jboss/protean/gizmo/LoadNullTestCase.java | 2 +- .../org/jboss/protean/gizmo/SampleTest.java | 6 +- .../jboss/protean/gizmo/TryCatchTestCase.java | 4 +- 10 files changed, 92 insertions(+), 28 deletions(-) diff --git a/gizmo/src/main/java/org/jboss/protean/gizmo/BytecodeCreatorImpl.java b/gizmo/src/main/java/org/jboss/protean/gizmo/BytecodeCreatorImpl.java index feb539f26a491..4b355efcf7c0a 100644 --- a/gizmo/src/main/java/org/jboss/protean/gizmo/BytecodeCreatorImpl.java +++ b/gizmo/src/main/java/org/jboss/protean/gizmo/BytecodeCreatorImpl.java @@ -687,7 +687,7 @@ public FunctionCreator createFunction(Class functionalInterface) { final String functionName = declaringClassName + FUNCTION + functionCount.incrementAndGet(); ResultHandle ret = new ResultHandle(type, this); - ClassCreator cc = new ClassCreator(classOutput, functionName, Object.class, functionalInterface); + ClassCreator cc = ClassCreator.builder().classOutput(classOutput).className(functionName).interfaces(functionalInterface).build(); MethodCreatorImpl mc = (MethodCreatorImpl) cc.getMethodCreator(functionMethod.getName(), functionMethod.getReturnType(), functionMethod.getParameterTypes()); FunctionCreatorImpl fc = new FunctionCreatorImpl(ret, functionName, cc, mc, this); operations.add(new Operation() { diff --git a/gizmo/src/main/java/org/jboss/protean/gizmo/ClassCreator.java b/gizmo/src/main/java/org/jboss/protean/gizmo/ClassCreator.java index fb2fcc6f61731..8c06e329f7f4f 100644 --- a/gizmo/src/main/java/org/jboss/protean/gizmo/ClassCreator.java +++ b/gizmo/src/main/java/org/jboss/protean/gizmo/ClassCreator.java @@ -7,8 +7,11 @@ import static org.objectweb.asm.Opcodes.INVOKESPECIAL; import static org.objectweb.asm.Opcodes.RETURN; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.Objects; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; @@ -16,24 +19,19 @@ public class ClassCreator implements AutoCloseable { + public static Builder builder() { + return new Builder(); + } + private final ClassOutput classOutput; private final String superClass; private final String[] interfaces; private final Map methods = new HashMap<>(); private final Map fields = new HashMap<>(); private final String className; + private final String signature; - public ClassCreator(ClassOutput classOutput, String name, Class superClass, Class... interfaces) { - this.classOutput = classOutput; - this.superClass = superClass.getName().replace(".", "/"); - this.interfaces = new String[interfaces.length]; - for (int i = 0; i < interfaces.length; ++i) { - this.interfaces[i] = interfaces[i].getName().replace(".", "/"); - } - this.className = name.replace(".", "/"); - } - - public ClassCreator(ClassOutput classOutput, String name, String superClass, String... interfaces) { + public ClassCreator(ClassOutput classOutput, String name, String signature, String superClass, String... interfaces) { this.classOutput = classOutput; this.superClass = superClass.replace(".", "/"); this.interfaces = new String[interfaces.length]; @@ -41,6 +39,7 @@ public ClassCreator(ClassOutput classOutput, String name, String superClass, Str this.interfaces[i] = interfaces[i].replace(".", "/"); } this.className = name.replace(".", "/"); + this.signature = signature; } public MethodCreator getMethodCreator(MethodDescriptor methodDescriptor) { @@ -99,7 +98,7 @@ public void close() { for (int i = 0; i < interfaces.length; ++i) { interfaces[i] = this.interfaces[i]; } - file.visit(Opcodes.V1_8, ACC_PUBLIC | ACC_SUPER | ACC_SYNTHETIC, className, null, superClass, interfaces); + file.visit(Opcodes.V1_8, ACC_PUBLIC | ACC_SUPER | ACC_SYNTHETIC, className, signature, superClass, interfaces); boolean requiresCtor = true; for (MethodDescriptor m : methods.keySet()) { @@ -132,4 +131,69 @@ public void close() { classOutput.write(className, file.toByteArray()); } -} + + public static class Builder { + + private ClassOutput classOutput; + + private String className; + + private String signature; + + private String superClass; + + private final List interfaces; + + Builder() { + superClass(Object.class); + this.interfaces = new ArrayList<>(); + } + + public Builder classOutput(ClassOutput classOutput) { + this.classOutput = classOutput; + return this; + } + + public Builder className(String className) { + this.className = className; + return this; + } + + public Builder signature(String signature) { + this.signature = signature; + return this; + } + + public Builder superClass(String superClass) { + this.superClass = superClass; + return this; + } + + public Builder superClass(Class superClass) { + return superClass(superClass.getName()); + } + + public Builder interfaces(String... interfaces) { + for (String val : interfaces) { + this.interfaces.add(val); + } + return this; + } + + public Builder interfaces(Class... interfaces) { + for (Class val : interfaces) { + this.interfaces.add(val.getName()); + } + return this; + } + + public ClassCreator build() { + Objects.requireNonNull(className); + Objects.requireNonNull(classOutput); + Objects.requireNonNull(superClass); + return new ClassCreator(classOutput, className, signature, superClass, interfaces.toArray(new String[0])); + } + + } + +} \ No newline at end of file diff --git a/gizmo/src/test/java/org/jboss/protean/gizmo/ArrayTestCase.java b/gizmo/src/test/java/org/jboss/protean/gizmo/ArrayTestCase.java index f6fa975196560..9e73aa1308b24 100644 --- a/gizmo/src/test/java/org/jboss/protean/gizmo/ArrayTestCase.java +++ b/gizmo/src/test/java/org/jboss/protean/gizmo/ArrayTestCase.java @@ -10,7 +10,7 @@ public class ArrayTestCase { @Test public void testNewArray() throws Exception { TestClassLoader cl = new TestClassLoader(getClass().getClassLoader()); - try (ClassCreator creator = new ClassCreator(cl, "com.MyTest", Object.class, Supplier.class)) { + try (ClassCreator creator = ClassCreator.builder().classOutput(cl).className("com.MyTest").interfaces(Supplier.class).build()) { MethodCreator method = creator.getMethodCreator("get", Object.class); ResultHandle arrayHandle = method.newArray(String.class, method.load(10)); method.returnValue(arrayHandle); @@ -27,7 +27,7 @@ public void testNewArray() throws Exception { @Test public void testWriteArray() throws Exception { TestClassLoader cl = new TestClassLoader(getClass().getClassLoader()); - try (ClassCreator creator = new ClassCreator(cl, "com.MyTest", Object.class, Supplier.class)) { + try (ClassCreator creator = ClassCreator.builder().classOutput(cl).className("com.MyTest").interfaces(Supplier.class).build()) { MethodCreator method = creator.getMethodCreator("get", Object.class); ResultHandle arrayHandle = method.newArray(String.class, method.load(1)); method.writeArrayValue(arrayHandle, method.load(0), method.load("hello")); diff --git a/gizmo/src/test/java/org/jboss/protean/gizmo/ExceptionThrowingTestCase.java b/gizmo/src/test/java/org/jboss/protean/gizmo/ExceptionThrowingTestCase.java index 0702ef56549c9..2ed5f10099569 100644 --- a/gizmo/src/test/java/org/jboss/protean/gizmo/ExceptionThrowingTestCase.java +++ b/gizmo/src/test/java/org/jboss/protean/gizmo/ExceptionThrowingTestCase.java @@ -9,7 +9,7 @@ public class ExceptionThrowingTestCase { @Test public void testThrowException() throws Exception { TestClassLoader cl = new TestClassLoader(getClass().getClassLoader()); - try (ClassCreator creator = new ClassCreator(cl, "com.MyTest", Object.class, MyInterface.class)) { + try (ClassCreator creator = ClassCreator.builder().classOutput(cl).className("com.MyTest").interfaces(MyInterface.class).build()) { MethodCreator method = creator.getMethodCreator("transform", String.class, "java.lang.String"); method.throwException(IllegalStateException.class, "ERROR"); } diff --git a/gizmo/src/test/java/org/jboss/protean/gizmo/FieldModifiersTest.java b/gizmo/src/test/java/org/jboss/protean/gizmo/FieldModifiersTest.java index 4662d2e52b6d6..ad11ea95f8106 100644 --- a/gizmo/src/test/java/org/jboss/protean/gizmo/FieldModifiersTest.java +++ b/gizmo/src/test/java/org/jboss/protean/gizmo/FieldModifiersTest.java @@ -15,7 +15,7 @@ public class FieldModifiersTest { @Test public void testFieldModifiers() throws Exception { TestClassLoader cl = new TestClassLoader(getClass().getClassLoader()); - try (ClassCreator creator = new ClassCreator(cl, "com/MyTest", Object.class)) { + try (ClassCreator creator = ClassCreator.builder().classOutput(cl).className("com.MyTest").build()) { creator.getFieldCreator("foo", DescriptorUtils.classToStringRepresentation(String.class)); creator.getFieldCreator("list", DescriptorUtils.classToStringRepresentation(List.class)).setModifiers(ACC_FINAL | ACC_PROTECTED); } diff --git a/gizmo/src/test/java/org/jboss/protean/gizmo/FunctionTestCase.java b/gizmo/src/test/java/org/jboss/protean/gizmo/FunctionTestCase.java index 68a0c2d0a9e43..049c50903009c 100644 --- a/gizmo/src/test/java/org/jboss/protean/gizmo/FunctionTestCase.java +++ b/gizmo/src/test/java/org/jboss/protean/gizmo/FunctionTestCase.java @@ -11,7 +11,7 @@ public class FunctionTestCase { @Test public void testSimpleFunction() throws Exception { TestClassLoader cl = new TestClassLoader(getClass().getClassLoader()); - try (ClassCreator creator = new ClassCreator(cl, "com/MyTest", Object.class, MyInterface.class)) { + try (ClassCreator creator = ClassCreator.builder().classOutput(cl).className("com.MyTest").interfaces(MyInterface.class).build()) { MethodCreator method = creator.getMethodCreator("transform", String.class, String.class); //create a function that appends '-func' to its input @@ -33,7 +33,7 @@ public void testSimpleFunction() throws Exception { @Test public void testSimpleFunctionWithCapture() throws Exception { TestClassLoader cl = new TestClassLoader(getClass().getClassLoader()); - try (ClassCreator creator = new ClassCreator(cl, "com/MyTest", Object.class, MyInterface.class)) { + try (ClassCreator creator = ClassCreator.builder().classOutput(cl).className("com.MyTest").interfaces(MyInterface.class).build()) { MethodCreator method = creator.getMethodCreator("transform", String.class, String.class); //create a function that appends '-func' to its input @@ -55,7 +55,7 @@ public void testSimpleFunctionWithCapture() throws Exception { @Test public void testInvokeSuperMethodFromFunction() throws Exception { TestClassLoader cl = new TestClassLoader(getClass().getClassLoader()); - try (ClassCreator creator = new ClassCreator(cl, "com/MyTest", Superclass.class)) { + try (ClassCreator creator = ClassCreator.builder().classOutput(cl).className("com.MyTest").superClass(Superclass.class).build()) { MethodCreator method = creator.getMethodCreator("getMessage", String.class); //create a function that calls super appends '-func' to its input diff --git a/gizmo/src/test/java/org/jboss/protean/gizmo/LoadClassTestCase.java b/gizmo/src/test/java/org/jboss/protean/gizmo/LoadClassTestCase.java index 072f792c81fe5..e6aab780f94ec 100644 --- a/gizmo/src/test/java/org/jboss/protean/gizmo/LoadClassTestCase.java +++ b/gizmo/src/test/java/org/jboss/protean/gizmo/LoadClassTestCase.java @@ -10,7 +10,7 @@ public class LoadClassTestCase { @Test public void testLoadClass() throws Exception { TestClassLoader cl = new TestClassLoader(getClass().getClassLoader()); - try (ClassCreator creator = new ClassCreator(cl, "com.MyTest", Object.class, Supplier.class)) { + try (ClassCreator creator = ClassCreator.builder().classOutput(cl).className("com.MyTest").interfaces(Supplier.class).build()) { MethodCreator method = creator.getMethodCreator("get", Object.class); ResultHandle stringHandle = method.loadClass(String.class); method.returnValue(stringHandle); diff --git a/gizmo/src/test/java/org/jboss/protean/gizmo/LoadNullTestCase.java b/gizmo/src/test/java/org/jboss/protean/gizmo/LoadNullTestCase.java index 9420ca0f38ae7..42e417dcec5cf 100644 --- a/gizmo/src/test/java/org/jboss/protean/gizmo/LoadNullTestCase.java +++ b/gizmo/src/test/java/org/jboss/protean/gizmo/LoadNullTestCase.java @@ -11,7 +11,7 @@ public class LoadNullTestCase { @Test public void testLoadNull() throws Exception { TestClassLoader cl = new TestClassLoader(getClass().getClassLoader()); - try (ClassCreator creator = new ClassCreator(cl, "com.MyTest", Object.class, Supplier.class)) { + try (ClassCreator creator = ClassCreator.builder().classOutput(cl).className("com.MyTest").interfaces(Supplier.class).build()) { MethodCreator method = creator.getMethodCreator("get", Object.class); method.returnValue(method.loadNull()); } diff --git a/gizmo/src/test/java/org/jboss/protean/gizmo/SampleTest.java b/gizmo/src/test/java/org/jboss/protean/gizmo/SampleTest.java index 503e4aa2ac98d..7615febaf5e84 100644 --- a/gizmo/src/test/java/org/jboss/protean/gizmo/SampleTest.java +++ b/gizmo/src/test/java/org/jboss/protean/gizmo/SampleTest.java @@ -8,7 +8,7 @@ public class SampleTest { @Test public void testSimpleGetMessage() throws Exception { TestClassLoader cl = new TestClassLoader(getClass().getClassLoader()); - try (ClassCreator creator = new ClassCreator(cl, "com/MyTest", Object.class, MyInterface.class)) { + try (ClassCreator creator = ClassCreator.builder().classOutput(cl).className("com.MyTest").interfaces(MyInterface.class).build()) { MethodCreator method = creator.getMethodCreator("transform", String.class, String.class); ResultHandle message = method.invokeStaticMethod(MethodDescriptor.ofMethod(MessageClass.class.getName(), "getMessage", "Ljava/lang/String;")); method.returnValue(message); @@ -22,7 +22,7 @@ public void testSimpleGetMessage() throws Exception { @Test public void testStringTransform() throws Exception { TestClassLoader cl = new TestClassLoader(getClass().getClassLoader()); - try (ClassCreator creator = new ClassCreator(cl, "com/MyTest", Object.class, MyInterface.class)) { + try (ClassCreator creator = ClassCreator.builder().classOutput(cl).className("com.MyTest").interfaces(MyInterface.class).build()) { MethodCreator method = creator.getMethodCreator("transform", String.class, String.class); ResultHandle message = method.invokeStaticMethod(MethodDescriptor.ofMethod(MessageClass.class.getName(), "getMessage", "Ljava/lang/String;")); ResultHandle constant = method.load(":CONST:"); @@ -40,7 +40,7 @@ public void testStringTransform() throws Exception { @Test public void testIfStatement() throws Exception { TestClassLoader cl = new TestClassLoader(getClass().getClassLoader()); - try (ClassCreator creator = new ClassCreator(cl, "com/MyTest", Object.class, MyInterface.class)) { + try (ClassCreator creator = ClassCreator.builder().classOutput(cl).className("com.MyTest").interfaces(MyInterface.class).build()) { MethodCreator method = creator.getMethodCreator("transform", String.class, String.class); ResultHandle equalsResult = method.invokeVirtualMethod(MethodDescriptor.ofMethod(Object.class, "equals", boolean.class, Object.class), method.getMethodParam(0), method.load("TEST")); BranchResult branch = method.ifNonZero(equalsResult); diff --git a/gizmo/src/test/java/org/jboss/protean/gizmo/TryCatchTestCase.java b/gizmo/src/test/java/org/jboss/protean/gizmo/TryCatchTestCase.java index 3298aaea70ff5..9e9bbd6137366 100644 --- a/gizmo/src/test/java/org/jboss/protean/gizmo/TryCatchTestCase.java +++ b/gizmo/src/test/java/org/jboss/protean/gizmo/TryCatchTestCase.java @@ -8,7 +8,7 @@ public class TryCatchTestCase { @Test public void testTryCatch() throws Exception { TestClassLoader cl = new TestClassLoader(getClass().getClassLoader()); - try (ClassCreator creator = new ClassCreator(cl, "com/MyTest", Object.class, MyInterface.class)) { + try (ClassCreator creator = ClassCreator.builder().classOutput(cl).className("com.MyTest").interfaces(MyInterface.class).build()) { MethodCreator method = creator.getMethodCreator("transform", String.class, String.class); ExceptionTable table = method.addTryCatch(); BytecodeCreator illegalState = table.addCatchClause(IllegalStateException.class); @@ -26,7 +26,7 @@ public void testTryCatch() throws Exception { @Test public void testTryCatchEmptyCatchBlock() throws Exception { TestClassLoader cl = new TestClassLoader(getClass().getClassLoader()); - try (ClassCreator creator = new ClassCreator(cl, "com/MyTest", Object.class, MyInterface.class)) { + try (ClassCreator creator = ClassCreator.builder().classOutput(cl).className("com.MyTest").interfaces(MyInterface.class).build()) { MethodCreator method = creator.getMethodCreator("transform", String.class, String.class); ResultHandle existingVal = method.load("complete"); ExceptionTable table = method.addTryCatch();