Skip to content

Commit

Permalink
Refactor to use new SignatureBuilder API by Gizmo in REST Data Panache
Browse files Browse the repository at this point in the history
From quarkusio/gizmo#147, we can use the latest SignatureBuilder API.
To use the new SignatureBuilder API, I had to deal with the gizmo type class, so more changes than expected were necessary.
  • Loading branch information
Sgitario committed Jan 24, 2023
1 parent d7643f9 commit 88f8c3e
Show file tree
Hide file tree
Showing 8 changed files with 98 additions and 88 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package io.quarkus.rest.data.panache.deployment.methods;

import static io.quarkus.gizmo.MethodDescriptor.ofMethod;
import static io.quarkus.rest.data.panache.deployment.utils.SignatureMethodCreator.ofType;
import static io.quarkus.rest.data.panache.deployment.utils.SignatureMethodCreator.param;
import static io.quarkus.rest.data.panache.deployment.utils.SignatureMethodCreator.responseType;
import static io.quarkus.rest.data.panache.deployment.utils.SignatureMethodCreator.uniType;

import javax.validation.Valid;
import javax.ws.rs.core.Response;
Expand Down Expand Up @@ -102,9 +104,8 @@ public AddMethodImplementor(Capabilities capabilities) {
protected void implementInternal(ClassCreator classCreator, ResourceMetadata resourceMetadata,
ResourceProperties resourceProperties, FieldDescriptor resourceField) {
MethodCreator methodCreator = SignatureMethodCreator.getMethodCreator(METHOD_NAME, classCreator,
isNotReactivePanache() ? ofType(Response.class) : ofType(Uni.class, resourceMetadata.getEntityType()),
resourceMetadata.getEntityType(), UriInfo.class);
methodCreator.setParameterNames(new String[] { "entity", "uriInfo" });
isNotReactivePanache() ? responseType() : uniType(resourceMetadata.getEntityType()),
param("entity", resourceMetadata.getEntityType()), param("uriInfo", UriInfo.class));

// Add method annotations
addPathAnnotation(methodCreator, resourceProperties.getPath(RESOURCE_METHOD_NAME));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package io.quarkus.rest.data.panache.deployment.methods;

import static io.quarkus.gizmo.MethodDescriptor.ofMethod;
import static io.quarkus.rest.data.panache.deployment.utils.SignatureMethodCreator.ofType;
import static io.quarkus.rest.data.panache.deployment.utils.SignatureMethodCreator.responseType;
import static io.quarkus.rest.data.panache.deployment.utils.SignatureMethodCreator.uniType;

import javax.ws.rs.core.Response;

Expand Down Expand Up @@ -74,7 +75,7 @@ protected void implementInternal(ClassCreator classCreator, ResourceMetadata res
ResourceProperties resourceProperties, FieldDescriptor resourceField) {
// Method parameters: sort strings, page index, page size, uri info
MethodCreator methodCreator = SignatureMethodCreator.getMethodCreator(RESOURCE_METHOD_NAME, classCreator,
isNotReactivePanache() ? ofType(Response.class) : ofType(Uni.class, Long.class));
isNotReactivePanache() ? responseType() : uniType(Long.class));

// Add method annotations
addGetAnnotation(methodCreator);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package io.quarkus.rest.data.panache.deployment.methods;

import static io.quarkus.gizmo.MethodDescriptor.ofMethod;
import static io.quarkus.rest.data.panache.deployment.utils.SignatureMethodCreator.ofType;
import static io.quarkus.rest.data.panache.deployment.utils.SignatureMethodCreator.param;
import static io.quarkus.rest.data.panache.deployment.utils.SignatureMethodCreator.responseType;
import static io.quarkus.rest.data.panache.deployment.utils.SignatureMethodCreator.uniType;

import javax.ws.rs.core.Response;

Expand Down Expand Up @@ -82,9 +84,8 @@ public DeleteMethodImplementor(Capabilities capabilities) {
protected void implementInternal(ClassCreator classCreator, ResourceMetadata resourceMetadata,
ResourceProperties resourceProperties, FieldDescriptor resourceField) {
MethodCreator methodCreator = SignatureMethodCreator.getMethodCreator(METHOD_NAME, classCreator,
isNotReactivePanache() ? ofType(Response.class) : ofType(Uni.class, resourceMetadata.getEntityType()),
resourceMetadata.getIdType());
methodCreator.setParameterNames(new String[] { "id" });
isNotReactivePanache() ? responseType() : uniType(resourceMetadata.getEntityType()),
param("id", resourceMetadata.getIdType()));

// Add method annotations
addPathAnnotation(methodCreator, appendToPath(resourceProperties.getPath(RESOURCE_METHOD_NAME), "{id}"));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package io.quarkus.rest.data.panache.deployment.methods;

import static io.quarkus.gizmo.MethodDescriptor.ofMethod;
import static io.quarkus.rest.data.panache.deployment.utils.SignatureMethodCreator.ofType;
import static io.quarkus.rest.data.panache.deployment.utils.SignatureMethodCreator.param;
import static io.quarkus.rest.data.panache.deployment.utils.SignatureMethodCreator.responseType;
import static io.quarkus.rest.data.panache.deployment.utils.SignatureMethodCreator.uniType;

import javax.ws.rs.core.Response;

Expand Down Expand Up @@ -84,9 +86,8 @@ public GetMethodImplementor(Capabilities capabilities) {
protected void implementInternal(ClassCreator classCreator, ResourceMetadata resourceMetadata,
ResourceProperties resourceProperties, FieldDescriptor resourceField) {
MethodCreator methodCreator = SignatureMethodCreator.getMethodCreator(METHOD_NAME, classCreator,
isNotReactivePanache() ? ofType(Response.class) : ofType(Uni.class, resourceMetadata.getEntityType()),
resourceMetadata.getIdType());
methodCreator.setParameterNames(new String[] { "id" });
isNotReactivePanache() ? responseType() : uniType(resourceMetadata.getEntityType()),
param("id", resourceMetadata.getIdType()));

// Add method annotations
addPathAnnotation(methodCreator, appendToPath(resourceProperties.getPath(RESOURCE_METHOD_NAME), "{id}"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@
import static io.quarkus.arc.processor.DotNames.STRING;
import static io.quarkus.gizmo.MethodDescriptor.ofConstructor;
import static io.quarkus.gizmo.MethodDescriptor.ofMethod;
import static io.quarkus.gizmo.Type.intType;
import static io.quarkus.rest.data.panache.deployment.utils.PaginationImplementor.DEFAULT_PAGE_INDEX;
import static io.quarkus.rest.data.panache.deployment.utils.PaginationImplementor.DEFAULT_PAGE_SIZE;
import static io.quarkus.rest.data.panache.deployment.utils.SignatureMethodCreator.ofType;
import static io.quarkus.rest.data.panache.deployment.utils.SignatureMethodCreator.param;
import static io.quarkus.rest.data.panache.deployment.utils.SignatureMethodCreator.responseType;
import static io.quarkus.rest.data.panache.deployment.utils.SignatureMethodCreator.uniType;

import java.util.ArrayList;
import java.util.Collection;
Expand Down Expand Up @@ -173,14 +175,14 @@ private void implementPaged(ClassCreator classCreator, ResourceMetadata resource
Collection<SignatureMethodCreator.Parameter> compatibleFieldsForQuery = getFieldsToQuery(resourceMetadata);
List<SignatureMethodCreator.Parameter> parameters = new ArrayList<>();
parameters.add(param("sort", List.class));
parameters.add(param("page", int.class));
parameters.add(param("size", int.class));
parameters.add(param("page", int.class, intType()));
parameters.add(param("size", int.class, intType()));
parameters.add(param("uriInfo", UriInfo.class));
parameters.add(param("namedQuery", String.class));
parameters.addAll(compatibleFieldsForQuery);
MethodCreator methodCreator = SignatureMethodCreator.getMethodCreator(getMethodName(), classCreator,
isNotReactivePanache() ? ofType(Response.class) : ofType(Uni.class, resourceMetadata.getEntityType()),
parameters);
isNotReactivePanache() ? responseType() : uniType(resourceMetadata.getEntityType()),
parameters.toArray(new SignatureMethodCreator.Parameter[0]));

// Add method annotations
addGetAnnotation(methodCreator);
Expand Down Expand Up @@ -265,8 +267,8 @@ private void implementNotPaged(ClassCreator classCreator, ResourceMetadata resou
parameters.add(param("namedQuery", String.class));
parameters.addAll(compatibleFieldsForQuery);
MethodCreator methodCreator = SignatureMethodCreator.getMethodCreator(getMethodName(), classCreator,
isNotReactivePanache() ? ofType(Response.class) : ofType(Uni.class, resourceMetadata.getEntityType()),
parameters);
isNotReactivePanache() ? responseType() : uniType(resourceMetadata.getEntityType()),
parameters.toArray(new SignatureMethodCreator.Parameter[0]));

// Add method annotations
addGetAnnotation(methodCreator);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import io.quarkus.gizmo.ClassCreator;
import io.quarkus.gizmo.FieldDescriptor;
import io.quarkus.gizmo.TryBlock;
import io.quarkus.gizmo.Type;
import io.quarkus.rest.data.panache.RestDataPanacheException;
import io.quarkus.rest.data.panache.deployment.ResourceMetadata;
import io.quarkus.rest.data.panache.deployment.properties.ResourceProperties;
Expand Down Expand Up @@ -235,6 +236,19 @@ protected boolean isNotReactivePanache() {
return !capabilities.isPresent(Capability.HIBERNATE_REACTIVE);
}

public static Type toType(Object object) {
if (object instanceof Type) {
return (Type) object;
} else if (object instanceof String) {
return Type.classType((String) object);
} else if (object instanceof Class) {
return Type.classType((Class<?>) object);
}

throw new IllegalArgumentException("Unsupported object of type " + object.getClass()
+ ". Supported types are Type, String and Class");
}

private static Class<?> toClass(String className) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
try {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package io.quarkus.rest.data.panache.deployment.methods;

import static io.quarkus.gizmo.MethodDescriptor.ofMethod;
import static io.quarkus.rest.data.panache.deployment.utils.SignatureMethodCreator.ofType;
import static io.quarkus.rest.data.panache.deployment.utils.SignatureMethodCreator.param;
import static io.quarkus.rest.data.panache.deployment.utils.SignatureMethodCreator.responseType;
import static io.quarkus.rest.data.panache.deployment.utils.SignatureMethodCreator.uniType;

import java.lang.annotation.Annotation;
import java.util.function.Supplier;
Expand Down Expand Up @@ -134,9 +136,10 @@ public UpdateMethodImplementor(Capabilities capabilities) {
protected void implementInternal(ClassCreator classCreator, ResourceMetadata resourceMetadata,
ResourceProperties resourceProperties, FieldDescriptor resourceField) {
MethodCreator methodCreator = SignatureMethodCreator.getMethodCreator(METHOD_NAME, classCreator,
isNotReactivePanache() ? ofType(Response.class) : ofType(Uni.class, resourceMetadata.getEntityType()),
resourceMetadata.getIdType(), resourceMetadata.getEntityType(), UriInfo.class);
methodCreator.setParameterNames(new String[] { "id", "entity", "uriInfo" });
isNotReactivePanache() ? responseType() : uniType(resourceMetadata.getEntityType()),
param("id", resourceMetadata.getIdType()),
param("entity", resourceMetadata.getEntityType()),
param("uriInfo", UriInfo.class));

// Add method annotations
addPathAnnotation(methodCreator, appendToPath(resourceProperties.getPath(RESOURCE_UPDATE_METHOD_NAME), "{id}"));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
package io.quarkus.rest.data.panache.deployment.utils;

import static io.quarkus.gizmo.Type.classType;
import static io.quarkus.gizmo.Type.parameterizedType;
import static io.quarkus.rest.data.panache.deployment.methods.StandardMethodImplementor.toType;

import java.util.ArrayList;
import java.util.List;

import javax.ws.rs.core.Response;

import io.quarkus.gizmo.ClassCreator;
import io.quarkus.gizmo.DescriptorUtils;
import io.quarkus.gizmo.MethodCreator;
import io.quarkus.gizmo.SignatureBuilder;
import io.quarkus.gizmo.Type;
import io.smallrye.mutiny.Uni;

public final class SignatureMethodCreator {

private static final Type RESPONSE_TYPE = Type.classType(Response.class);

/**
* Creates a method using a signature (which allows declaring parameterized types like lists).
*
Expand All @@ -20,94 +30,71 @@ public final class SignatureMethodCreator {
* version of the method you want to see the signature.
*/
public static MethodCreator getMethodCreator(String methodName, ClassCreator classCreator, ReturnType returnType,
List<Parameter> parameters) {
List<Object> paramTypes = new ArrayList<>();
Parameter... parameters) {
List<Type> paramTypes = new ArrayList<>();
List<String> paramNames = new ArrayList<>();
List<Object> paramClasses = new ArrayList<>();
for (Parameter param : parameters) {
paramNames.add(param.name);
paramTypes.add(param.type);
paramClasses.add(param.clazz);
}
MethodCreator methodCreator = getMethodCreator(methodName, classCreator, returnType, paramTypes.toArray(new Object[0]));
methodCreator.setParameterNames(paramNames.toArray(new String[0]));
return methodCreator;
}

/**
* Creates a method using a signature (which allows declaring parameterized types like lists).
*
* For example, for the method: "List<String> list(List<String> sort, int size, int other, String uri)"
* It will use the following signature the generated the method:
* "(Ljava/util/List<Ljava/lang/String;>;IILjava/lang/String;)Ljava/util/List<Ljava/lang/String;>;".
*
* One useful utility to verify the method signatures is using "javap -v Test.class" where the Test java class is a compiled
* version of the method you want to see the signature.
*/
public static MethodCreator getMethodCreator(String methodName, ClassCreator classCreator, ReturnType returnType,
Object... parameters) {
MethodCreator methodCreator = classCreator.getMethodCreator(methodName, returnType.type, parameters);

StringBuilder signatureBuilder = new StringBuilder();
// Params first within parenthesis. If method is: "void method(Integer a)", it should return "(Ljava/lang/Integer;)":
signatureBuilder.append("(");
parametersToSignature(signatureBuilder, parameters);

signatureBuilder.append(")");

// Then, result type. If method is: "List<String> method(Integer a)",
// it should return "Ljava/util/List<Ljava/lang/String;>;"
signatureBuilder.append(stringToSignature(returnType.type.getName()));
if (returnType.parameterTypes.length > 0) {
signatureBuilder.append("<");
parametersToSignature(signatureBuilder, returnType.parameterTypes);
signatureBuilder.append(">");
}

signatureBuilder.append(";");

methodCreator.setSignature(signatureBuilder.toString());
MethodCreator methodCreator = classCreator.getMethodCreator(methodName, returnType.classType,
paramClasses.toArray(new Object[0]));
SignatureBuilder.MethodSignatureBuilder signatureBuilder = SignatureBuilder.forMethod()
.setReturnType(returnType.type);
paramTypes.forEach(signatureBuilder::addParameterType);
methodCreator.setSignature(signatureBuilder.build());
methodCreator.setParameterNames(paramNames.toArray(new String[0]));

return methodCreator;
}

private static void parametersToSignature(StringBuilder signatureBuilder, Object[] parameters) {
for (Object parameter : parameters) {
if (parameter instanceof Class) {
signatureBuilder.append(DescriptorUtils.classToStringRepresentation((Class<?>) parameter));
} else if (parameter instanceof String) {
signatureBuilder.append(stringToSignature((String) parameter) + ";");
}
}
}

private static String stringToSignature(String className) {
return "L" + className.replace('.', '/');
}

public static ReturnType ofType(Class<?> type, Object... parameterTypes) {
ReturnType returnType = new ReturnType();
returnType.type = type;
returnType.parameterTypes = parameterTypes;
return returnType;
public static Parameter param(String name, Object type) {
return param(name, type, toType(type));
}

public static Parameter param(String name, Object type) {
public static Parameter param(String name, Object clazz, Type type) {
Parameter parameter = new Parameter();
parameter.name = name;
parameter.clazz = clazz;
parameter.type = type;

return parameter;
}

public static class Parameter {
private String name;
private Object type;
private Type type;
private Object clazz;

public String getName() {
return name;
}
}

public static class ReturnType {
private Class<?> type;
private Object[] parameterTypes;
private Class<?> classType;
private Type type;
}

public static ReturnType responseType() {
ReturnType returnType = new ReturnType();
returnType.classType = Response.class;
returnType.type = RESPONSE_TYPE;
return returnType;
}

public static ReturnType uniType(Object... arguments) {
ReturnType returnType = new ReturnType();
Type[] typeArguments = new Type[arguments.length];
for (int index = 0; index < arguments.length; index++) {
typeArguments[index] = toType(arguments[index]);
}

returnType.classType = Uni.class;
returnType.type = parameterizedType(classType(Uni.class), typeArguments);
return returnType;
}
}

0 comments on commit 88f8c3e

Please sign in to comment.