Skip to content

Commit

Permalink
Add method to set parameter names
Browse files Browse the repository at this point in the history
  • Loading branch information
Ladicek committed May 6, 2022
1 parent 1048fce commit 2f124dc
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 0 deletions.
15 changes: 15 additions & 0 deletions src/main/java/io/quarkus/gizmo/MethodCreator.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,19 @@ default MethodCreator addException(Class<?> exception) {

AnnotatedElement getParameterAnnotations(int param);

/**
* Sets names of all this method's parameters. The length of {@code parameterNames}
* must be equal to the number of this method's parameters. Removes previously set
* parameter names if {@code parameterNames} is {@code null}.
* <p>
* It is required to set all parameter names in one go, because parameter names are stored in bytecode
* as a simple sequence, without positions.
* <p>
* When generating a method with mandated or synthetic parameters (such as an inner
* class constructor), remember that these parameters must have names too.
*
* @param parameterNames names of all parameters of this method
*/
void setParameterNames(String[] parameterNames);

}
25 changes: 25 additions & 0 deletions src/main/java/io/quarkus/gizmo/MethodCreatorImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
Expand All @@ -42,6 +43,8 @@ class MethodCreatorImpl extends BytecodeCreatorImpl implements MethodCreator {
private final ClassCreator classCreator;
private String signature;

private String[] parameterNames;

MethodCreatorImpl(BytecodeCreatorImpl enclosing, MethodDescriptor methodDescriptor, String declaringClassName, ClassCreator classCreator) {
super(enclosing, true);
this.methodDescriptor = methodDescriptor;
Expand Down Expand Up @@ -75,6 +78,23 @@ public AnnotatedElement getParameterAnnotations(int param) {
return p;
}

@Override
public void setParameterNames(String[] parameterNames) {
if (parameterNames == null) {
this.parameterNames = null;
return;
}

if (methodDescriptor.getParameterTypes().length != parameterNames.length) {
throw new IllegalArgumentException("Method " + methodDescriptor.getDeclaringClass() + "#"
+ methodDescriptor.getName() + " has " + methodDescriptor.getParameterTypes().length
+ " parameters, but provided parameter names array has " + parameterNames.length + ": "
+ Arrays.toString(parameterNames));
}

this.parameterNames = parameterNames;
}

@Override
public int getModifiers() {
return modifiers;
Expand Down Expand Up @@ -119,6 +139,11 @@ public void write(ClassVisitor file) {
av.visitEnd();
}
}
if (parameterNames != null) {
for (String parameterName : parameterNames) {
visitor.visitParameter(parameterName, 0);
}
}
visitor.visitEnd();
}

Expand Down
59 changes: 59 additions & 0 deletions src/test/java/io/quarkus/gizmo/ParameterNamesTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package io.quarkus.gizmo;

import org.junit.Test;
import org.objectweb.asm.Opcodes;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

public class ParameterNamesTest {
@Test
public void test() throws Exception {
TestClassLoader cl = new TestClassLoader(getClass().getClassLoader());
try (ClassCreator creator = ClassCreator.builder().classOutput(cl).className("com.MyTest").build()) {
try (MethodCreator method = creator.getMethodCreator("staticMethod", void.class, String.class)
.setModifiers(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC)) {
AnnotationCreator annotation = method.getParameterAnnotations(0).addAnnotation(MyAnnotation.class);
annotation.addValue("value", "static method");
annotation.addValue("enumVal", MyEnum.NO);
method.setParameterNames(new String[] {"staticMethodParameter"});
method.returnValue(null);
}

try (MethodCreator method = creator.getMethodCreator("instanceMethod", void.class, String.class)) {
AnnotationCreator annotation = method.getParameterAnnotations(0).addAnnotation(MyAnnotation.class);
annotation.addValue("value", "instance method");
annotation.addValue("enumVal", MyEnum.YES);
method.setParameterNames(new String[] {"instanceMethodParameter"});
method.returnValue(null);
}
}

Class<?> clazz = cl.loadClass("com.MyTest");
{
Method method = clazz.getMethod("staticMethod", String.class);
assertEquals(1, method.getParameterCount());
assertEquals(String.class, method.getParameterTypes()[0]);
Parameter parameter = method.getParameters()[0];
assertTrue(parameter.isAnnotationPresent(MyAnnotation.class));
MyAnnotation annotation = parameter.getAnnotation(MyAnnotation.class);
assertEquals("static method", annotation.value());
assertEquals(MyEnum.NO, annotation.enumVal());
assertEquals("staticMethodParameter", parameter.getName());
}
{
Method method = clazz.getMethod("instanceMethod", String.class);
assertEquals(1, method.getParameterCount());
assertEquals(String.class, method.getParameterTypes()[0]);
Parameter parameter = method.getParameters()[0];
assertTrue(parameter.isAnnotationPresent(MyAnnotation.class));
MyAnnotation annotation = parameter.getAnnotation(MyAnnotation.class);
assertEquals("instance method", annotation.value());
assertEquals(MyEnum.YES, annotation.enumVal());
assertEquals("instanceMethodParameter", parameter.getName());
}
}
}

0 comments on commit 2f124dc

Please sign in to comment.