diff --git a/extensions/resteasy-reactive/jaxrs-client-reactive/deployment/src/main/java/io/quarkus/jaxrs/client/reactive/deployment/ClassRestClientContext.java b/extensions/resteasy-reactive/jaxrs-client-reactive/deployment/src/main/java/io/quarkus/jaxrs/client/reactive/deployment/ClassRestClientContext.java index 1f2762d529d9f..b7d1f63436dde 100644 --- a/extensions/resteasy-reactive/jaxrs-client-reactive/deployment/src/main/java/io/quarkus/jaxrs/client/reactive/deployment/ClassRestClientContext.java +++ b/extensions/resteasy-reactive/jaxrs-client-reactive/deployment/src/main/java/io/quarkus/jaxrs/client/reactive/deployment/ClassRestClientContext.java @@ -19,6 +19,7 @@ import io.quarkus.gizmo.MethodDescriptor; import io.quarkus.gizmo.ResultHandle; import io.quarkus.jaxrs.client.reactive.runtime.ParameterAnnotationsSupplier; +import io.quarkus.jaxrs.client.reactive.runtime.ParameterDescriptorFromClassSupplier; import io.quarkus.jaxrs.client.reactive.runtime.ParameterGenericTypesSupplier; class ClassRestClientContext implements AutoCloseable { @@ -30,6 +31,9 @@ class ClassRestClientContext implements AutoCloseable { public final Map methodStaticFields = new HashMap<>(); public final Map methodParamAnnotationsStaticFields = new HashMap<>(); public final Map methodGenericParametersStaticFields = new HashMap<>(); + public final Map beanTypesParameterDescriptorsStaticFields = new HashMap<>(); + public final Map classesMap = new HashMap<>(); + private int beanParamIndex = 0; public ClassRestClientContext(String name, BuildProducer generatedClasses, String... interfaces) { @@ -53,12 +57,12 @@ public void close() { } protected FieldDescriptor createJavaMethodField(ClassInfo interfaceClass, MethodInfo method, int methodIndex) { - ResultHandle interfaceClassHandle = clinit.loadClassFromTCCL(interfaceClass.toString()); + ResultHandle interfaceClassHandle = loadClass(interfaceClass.toString()); ResultHandle parameterArray = clinit.newArray(Class.class, method.parametersCount()); for (int i = 0; i < method.parametersCount(); i++) { String parameterClass = method.parameterType(i).name().toString(); - clinit.writeArrayValue(parameterArray, i, clinit.loadClassFromTCCL(parameterClass)); + clinit.writeArrayValue(parameterArray, i, loadClass(parameterClass)); } ResultHandle javaMethodHandle = clinit.invokeVirtualMethod( @@ -125,4 +129,43 @@ protected Supplier getLazyJavaMethodGenericParametersField(int return javaMethodGenericParametersField; }; } + + /** + * Generates "Class.forName(beanClass)" to generate the parameter descriptors. This method will only be created if and only + * if the supplier is used in order to not have a penalty performance. + */ + protected Supplier getLazyBeanParameterDescriptors(String beanClass) { + return () -> { + FieldDescriptor field = beanTypesParameterDescriptorsStaticFields.get(beanClass); + if (field != null) { + return field; + } + + ResultHandle clazz = loadClass(beanClass); + + ResultHandle mapWithAnnotationsHandle = clinit.newInstance(MethodDescriptor.ofConstructor( + ParameterDescriptorFromClassSupplier.class, Class.class), + clazz); + field = FieldDescriptor.of(classCreator.getClassName(), "beanParamDescriptors" + beanParamIndex, Supplier.class); + classCreator.getFieldCreator(field).setModifiers(Modifier.FINAL | Modifier.STATIC); // needs to be package-private because it's used by subresources + clinit.writeStaticField(field, mapWithAnnotationsHandle); + + beanTypesParameterDescriptorsStaticFields.put(beanClass, field); + + beanParamIndex++; + + return field; + }; + } + + private ResultHandle loadClass(String className) { + ResultHandle classType = classesMap.get(className); + if (classType != null) { + return classType; + } + + ResultHandle classFromTCCL = clinit.loadClassFromTCCL(className); + classesMap.put(className, classFromTCCL); + return classFromTCCL; + } } diff --git a/extensions/resteasy-reactive/jaxrs-client-reactive/deployment/src/main/java/io/quarkus/jaxrs/client/reactive/deployment/JaxrsClientReactiveProcessor.java b/extensions/resteasy-reactive/jaxrs-client-reactive/deployment/src/main/java/io/quarkus/jaxrs/client/reactive/deployment/JaxrsClientReactiveProcessor.java index b7aa64fa5d191..3113b9af635e7 100644 --- a/extensions/resteasy-reactive/jaxrs-client-reactive/deployment/src/main/java/io/quarkus/jaxrs/client/reactive/deployment/JaxrsClientReactiveProcessor.java +++ b/extensions/resteasy-reactive/jaxrs-client-reactive/deployment/src/main/java/io/quarkus/jaxrs/client/reactive/deployment/JaxrsClientReactiveProcessor.java @@ -19,6 +19,7 @@ import java.io.Closeable; import java.io.File; import java.io.InputStream; +import java.lang.annotation.Annotation; import java.lang.reflect.Modifier; import java.nio.file.Path; import java.util.AbstractMap; @@ -152,6 +153,7 @@ import io.quarkus.gizmo.TryBlock; import io.quarkus.jaxrs.client.reactive.runtime.ClientResponseBuilderFactory; import io.quarkus.jaxrs.client.reactive.runtime.JaxrsClientReactiveRecorder; +import io.quarkus.jaxrs.client.reactive.runtime.ParameterDescriptorFromClassSupplier; import io.quarkus.jaxrs.client.reactive.runtime.RestClientBase; import io.quarkus.jaxrs.client.reactive.runtime.ToObjectArray; import io.quarkus.jaxrs.client.reactive.runtime.impl.MultipartResponseDataBase; @@ -909,9 +911,8 @@ A more full example of generated client (with sub-resource) can is at the bottom addQueryParam(jandexMethod, methodCreator, methodTarget, param.name, methodCreator.getMethodParam(paramIdx), jandexMethod.parameterType(paramIdx), index, methodCreator.getThis(), - methodCreator.readStaticField(methodGenericParametersField.get()), - methodCreator.readStaticField(methodParamAnnotationsField.get()), - paramIdx)); + getGenericTypeFromArray(methodCreator, methodGenericParametersField, paramIdx), + getAnnotationsFromArray(methodCreator, methodParamAnnotationsField, paramIdx))); } else if (param.parameterType == ParameterType.BEAN || param.parameterType == ParameterType.MULTI_PART_FORM) { // bean params require both, web-target and Invocation.Builder, modifications @@ -930,13 +931,17 @@ A more full example of generated client (with sub-resource) can is at the bottom AssignableResultHandle invocationBuilderRef = handleBeanParamMethod .createVariable(Invocation.Builder.class); handleBeanParamMethod.assign(invocationBuilderRef, handleBeanParamMethod.getMethodParam(0)); + + Supplier beanParamDescriptorsField = classContext + .getLazyBeanParameterDescriptors(beanParam.type); + formParams = addBeanParamData(jandexMethod, methodCreator, handleBeanParamMethod, - invocationBuilderRef, beanParam.getItems(), + invocationBuilderRef, classContext, beanParam.getItems(), methodCreator.getMethodParam(paramIdx), methodTarget, index, restClientInterface.getClassName(), methodCreator.getThis(), handleBeanParamMethod.getThis(), - formParams, methodGenericParametersField, methodParamAnnotationsField, paramIdx, multipart, + formParams, beanParamDescriptorsField, multipart, beanParam.type); handleBeanParamMethod.returnValue(invocationBuilderRef); @@ -945,9 +950,8 @@ A more full example of generated client (with sub-resource) can is at the bottom // methodTarget = methodTarget.resolveTemplate(paramname, paramvalue); addPathParam(methodCreator, methodTarget, param.name, methodCreator.getMethodParam(paramIdx), param.type, methodCreator.getThis(), - methodCreator.readStaticField(methodGenericParametersField.get()), - methodCreator.readStaticField(methodParamAnnotationsField.get()), - paramIdx); + getGenericTypeFromArray(methodCreator, methodGenericParametersField, paramIdx), + getAnnotationsFromArray(methodCreator, methodParamAnnotationsField, paramIdx)); } else if (param.parameterType == ParameterType.BODY) { // just store the index of parameter used to create the body, we'll use it later bodyParameterIdx = paramIdx; @@ -965,8 +969,9 @@ A more full example of generated client (with sub-resource) can is at the bottom handleHeaderMethod.assign(invocationBuilderRef, handleHeaderMethod.getMethodParam(0)); addHeaderParam(handleHeaderMethod, invocationBuilderRef, param.name, handleHeaderMethod.getMethodParam(1), param.type, - handleHeaderMethod.getThis(), methodGenericParametersField.get(), - methodParamAnnotationsField.get(), paramIdx); + handleHeaderMethod.getThis(), + getGenericTypeFromArray(handleHeaderMethod, methodGenericParametersField, paramIdx), + getAnnotationsFromArray(handleHeaderMethod, methodParamAnnotationsField, paramIdx)); handleHeaderMethod.returnValue(invocationBuilderRef); invocationBuilderEnrichers.put(handleHeaderDescriptor, methodCreator.getMethodParam(paramIdx)); } else if (param.parameterType == ParameterType.COOKIE) { @@ -984,7 +989,8 @@ A more full example of generated client (with sub-resource) can is at the bottom addCookieParam(handleCookieMethod, invocationBuilderRef, param.name, handleCookieMethod.getMethodParam(1), param.type, handleCookieMethod.getThis(), - methodGenericParametersField.get(), methodParamAnnotationsField.get(), paramIdx); + getGenericTypeFromArray(handleCookieMethod, methodGenericParametersField, paramIdx), + getAnnotationsFromArray(handleCookieMethod, methodParamAnnotationsField, paramIdx)); handleCookieMethod.returnValue(invocationBuilderRef); invocationBuilderEnrichers.put(handleHeaderDescriptor, methodCreator.getMethodParam(paramIdx)); } else if (param.parameterType == ParameterType.FORM) { @@ -993,9 +999,9 @@ A more full example of generated client (with sub-resource) can is at the bottom addFormParam(methodCreator, param.name, methodCreator.getMethodParam(paramIdx), param.declaredType, param.signature, restClientInterface.getClassName(), methodCreator.getThis(), formParams, - methodCreator.readStaticField(methodGenericParametersField.get()), - methodCreator.readStaticField(methodParamAnnotationsField.get()), - paramIdx, multipart, + getGenericTypeFromArray(methodCreator, methodGenericParametersField, paramIdx), + getAnnotationsFromArray(methodCreator, methodParamAnnotationsField, paramIdx), + multipart, param.mimeType, param.partFileName, jandexMethod.declaringClass().name() + "." + jandexMethod.name()); } @@ -1215,9 +1221,8 @@ private void handleSubResourceMethod(List addPathParam(ownerMethod, webTarget, param.name, paramValue, param.type, client, - ownerMethod.readStaticField(methodGenericParametersField.get()), - ownerMethod.readStaticField(methodParamAnnotationsField.get()), - i); + getGenericTypeFromArray(ownerMethod, methodGenericParametersField, i), + getAnnotationsFromArray(ownerMethod, methodParamAnnotationsField, i)); } } @@ -1322,9 +1327,10 @@ private void handleSubResourceMethod(List addQueryParam(jandexMethod, subMethodCreator, methodTarget, param.name, paramValue, subParamField.type, index, subMethodCreator.readInstanceField(clientField, subMethodCreator.getThis()), - subMethodCreator.readStaticField(subParamField.genericsParametersField.get()), - subMethodCreator.readStaticField(subParamField.paramAnnotationsField.get()), - subParamField.paramIndex)); + getGenericTypeFromArray(subMethodCreator, subParamField.genericsParametersField, + subParamField.paramIndex), + getAnnotationsFromArray(subMethodCreator, subParamField.paramAnnotationsField, + subParamField.paramIndex))); } else if (param.parameterType == ParameterType.BEAN || param.parameterType == ParameterType.MULTI_PART_FORM) { // bean params require both, web-target and Invocation.Builder, modifications @@ -1341,17 +1347,20 @@ private void handleSubResourceMethod(List MethodCreator handleBeanParamMethod = subContext.classCreator.getMethodCreator( handleBeanParamDescriptor).setModifiers(Modifier.PRIVATE); + Supplier beanParamDescriptors = subContext + .getLazyBeanParameterDescriptors(beanParam.type); + AssignableResultHandle invocationBuilderRef = handleBeanParamMethod .createVariable(Invocation.Builder.class); handleBeanParamMethod.assign(invocationBuilderRef, handleBeanParamMethod.getMethodParam(0)); formParams = addBeanParamData(jandexMethod, subMethodCreator, handleBeanParamMethod, - invocationBuilderRef, beanParam.getItems(), + invocationBuilderRef, subContext, beanParam.getItems(), paramValue, methodTarget, index, interfaceClass.name().toString(), subMethodCreator.readInstanceField(clientField, subMethodCreator.getThis()), handleBeanParamMethod.readInstanceField(clientField, handleBeanParamMethod.getThis()), formParams, - methodGenericParametersField, methodParamAnnotationsField, subParamField.paramIndex, + beanParamDescriptors, multipart, beanParam.type); handleBeanParamMethod.returnValue(invocationBuilderRef); @@ -1361,9 +1370,10 @@ private void handleSubResourceMethod(List addPathParam(subMethodCreator, methodTarget, param.name, paramValue, param.type, subMethodCreator.readInstanceField(clientField, subMethodCreator.getThis()), - subMethodCreator.readStaticField(subParamField.genericsParametersField.get()), - subMethodCreator.readStaticField(subParamField.paramAnnotationsField.get()), - subParamField.paramIndex); + getGenericTypeFromArray(subMethodCreator, subParamField.genericsParametersField, + subParamField.paramIndex), + getAnnotationsFromArray(subMethodCreator, subParamField.paramAnnotationsField, + subParamField.paramIndex)); } else if (param.parameterType == ParameterType.BODY) { // just store the index of parameter used to create the body, we'll use it later bodyParameterValue = paramValue; @@ -1384,9 +1394,10 @@ private void handleSubResourceMethod(List handleHeaderMethod.getMethodParam(1), param.type, handleHeaderMethod.readInstanceField(clientField, handleHeaderMethod.getThis()), - subParamField.genericsParametersField.get(), - subParamField.paramAnnotationsField.get(), - subParamField.paramIndex); + getGenericTypeFromArray(handleHeaderMethod, subParamField.genericsParametersField, + subParamField.paramIndex), + getAnnotationsFromArray(handleHeaderMethod, subParamField.paramAnnotationsField, + subParamField.paramIndex)); handleHeaderMethod.returnValue(invocationBuilderRef); invocationBuilderEnrichers.put(handleHeaderDescriptor, paramValue); } else if (param.parameterType == ParameterType.COOKIE) { @@ -1406,9 +1417,10 @@ private void handleSubResourceMethod(List handleCookieMethod.getMethodParam(1), param.type, handleCookieMethod.readInstanceField(clientField, handleCookieMethod.getThis()), - subParamField.genericsParametersField.get(), - subParamField.paramAnnotationsField.get(), - subParamField.paramIndex); + getGenericTypeFromArray(handleCookieMethod, subParamField.genericsParametersField, + subParamField.paramIndex), + getAnnotationsFromArray(handleCookieMethod, subParamField.paramAnnotationsField, + subParamField.paramIndex)); handleCookieMethod.returnValue(invocationBuilderRef); invocationBuilderEnrichers.put(handleCookieDescriptor, paramValue); } else if (param.parameterType == ParameterType.FORM) { @@ -1430,9 +1442,10 @@ private void handleSubResourceMethod(List subMethodCreator.getMethodParam(paramIdx), jandexSubMethod.parameterType(paramIdx), index, subMethodCreator.readInstanceField(clientField, subMethodCreator.getThis()), - subMethodCreator.readStaticField(subMethodGenericParametersField.get()), - subMethodCreator.readStaticField(subMethodParamAnnotationsField.get()), - paramIdx)); + getGenericTypeFromArray(subMethodCreator, subMethodGenericParametersField, + paramIdx), + getAnnotationsFromArray(subMethodCreator, subMethodParamAnnotationsField, + paramIdx))); } else if (param.parameterType == ParameterType.BEAN || param.parameterType == ParameterType.MULTI_PART_FORM) { // bean params require both, web-target and Invocation.Builder, modifications @@ -1445,20 +1458,23 @@ private void handleSubResourceMethod(List subMethod.getName() + "$$" + subMethodIndex + "$$handleBeanParam$$" + paramIdx, Invocation.Builder.class, Invocation.Builder.class, param.type); - MethodCreator handleBeanParamMethod = ownerContext.classCreator.getMethodCreator( + MethodCreator handleBeanParamMethod = subContext.classCreator.getMethodCreator( handleBeanParamDescriptor).setModifiers(Modifier.PRIVATE); + Supplier beanParamDescriptors = subContext + .getLazyBeanParameterDescriptors(beanParam.type); + AssignableResultHandle invocationBuilderRef = handleBeanParamMethod .createVariable(Invocation.Builder.class); handleBeanParamMethod.assign(invocationBuilderRef, handleBeanParamMethod.getMethodParam(0)); formParams = addBeanParamData(jandexMethod, subMethodCreator, handleBeanParamMethod, - invocationBuilderRef, beanParam.getItems(), + invocationBuilderRef, subContext, beanParam.getItems(), subMethodCreator.getMethodParam(paramIdx), methodTarget, index, interfaceClass.name().toString(), subMethodCreator.readInstanceField(clientField, subMethodCreator.getThis()), handleBeanParamMethod.readInstanceField(clientField, handleBeanParamMethod.getThis()), formParams, - subMethodGenericParametersField, subMethodParamAnnotationsField, paramIdx, multipart, + beanParamDescriptors, multipart, beanParam.type); handleBeanParamMethod.returnValue(invocationBuilderRef); @@ -1468,9 +1484,8 @@ private void handleSubResourceMethod(List addPathParam(subMethodCreator, methodTarget, param.name, subMethodCreator.getMethodParam(paramIdx), param.type, subMethodCreator.readInstanceField(clientField, subMethodCreator.getThis()), - subMethodCreator.readStaticField(subMethodGenericParametersField.get()), - subMethodCreator.readStaticField(subMethodParamAnnotationsField.get()), - paramIdx); + getGenericTypeFromArray(subMethodCreator, subMethodGenericParametersField, paramIdx), + getAnnotationsFromArray(subMethodCreator, subMethodParamAnnotationsField, paramIdx)); } else if (param.parameterType == ParameterType.BODY) { // just store the index of parameter used to create the body, we'll use it later bodyParameterValue = subMethodCreator.getMethodParam(paramIdx); @@ -1489,7 +1504,8 @@ private void handleSubResourceMethod(List addHeaderParam(handleHeaderMethod, invocationBuilderRef, param.name, handleHeaderMethod.getMethodParam(1), param.type, handleHeaderMethod.readInstanceField(clientField, handleHeaderMethod.getThis()), - subMethodGenericParametersField.get(), subMethodParamAnnotationsField.get(), paramIdx); + getGenericTypeFromArray(handleHeaderMethod, subMethodGenericParametersField, paramIdx), + getAnnotationsFromArray(handleHeaderMethod, subMethodParamAnnotationsField, paramIdx)); handleHeaderMethod.returnValue(invocationBuilderRef); invocationBuilderEnrichers.put(handleHeaderDescriptor, subMethodCreator.getMethodParam(paramIdx)); } else if (param.parameterType == ParameterType.COOKIE) { @@ -1508,7 +1524,8 @@ private void handleSubResourceMethod(List handleCookieMethod.getMethodParam(1), param.type, handleCookieMethod.readInstanceField(clientField, handleCookieMethod.getThis()), - subMethodGenericParametersField.get(), subMethodParamAnnotationsField.get(), paramIdx); + getGenericTypeFromArray(handleCookieMethod, subMethodGenericParametersField, paramIdx), + getAnnotationsFromArray(handleCookieMethod, subMethodParamAnnotationsField, paramIdx)); handleCookieMethod.returnValue(invocationBuilderRef); invocationBuilderEnrichers.put(handleCookieDescriptor, subMethodCreator.getMethodParam(paramIdx)); } else if (param.parameterType == ParameterType.FORM) { @@ -1635,7 +1652,7 @@ private void handleMultipartField(String formParamName, String partType, String String type, String parameterGenericType, ResultHandle fieldValue, AssignableResultHandle multipartForm, BytecodeCreator methodCreator, - ResultHandle client, String restClientInterfaceClassName, ResultHandle parameterAnnotations, int methodIndex, + ResultHandle client, String restClientInterfaceClassName, ResultHandle parameterAnnotations, ResultHandle genericType, String errorLocation) { BytecodeCreator ifValueNotNull = methodCreator.ifNotNull(fieldValue).trueBranch(); @@ -1679,7 +1696,7 @@ private void handleMultipartField(String formParamName, String partType, String } else { // go via converter ResultHandle convertedFormParam = convertParamToString(ifValueNotNull, client, fieldValue, type, genericType, - parameterAnnotations, methodIndex); + parameterAnnotations); BytecodeCreator parameterIsStringBranch = checkStringParam(ifValueNotNull, convertedFormParam, restClientInterfaceClassName, errorLocation); addString(parameterIsStringBranch, multipartForm, formParamName, null, partFilename, convertedFormParam); @@ -2270,6 +2287,7 @@ private AssignableResultHandle addBeanParamData(MethodInfo jandexMethod, // Invocation.Builder executePut$$enrichInvocationBuilder${noOfBeanParam}(Invocation.Builder) BytecodeCreator invocationBuilderEnricher, AssignableResultHandle invocationBuilder, + ClassRestClientContext classContext, List beanParamItems, ResultHandle param, // can only be used in the current method, not in `invocationBuilderEnricher` @@ -2280,18 +2298,17 @@ private AssignableResultHandle addBeanParamData(MethodInfo jandexMethod, ResultHandle invocationEnricherClient, // this client or containing client if this is a sub-client AssignableResultHandle formParams, - Supplier methodGenericTypeField, - Supplier methodParamAnnotationsField, - int paramIdx, boolean multipart, String beanParamClass) { + Supplier descriptorsField, + boolean multipart, String beanParamClass) { // Form params collector must be initialized at method root level before any inner blocks that may use it if (areFormParamsDefinedIn(beanParamItems)) { formParams = createFormDataIfAbsent(methodCreator, formParams, multipart); } - addSubBeanParamData(jandexMethod, methodCreator, invocationBuilderEnricher, invocationBuilder, beanParamItems, param, - target, + addSubBeanParamData(jandexMethod, methodCreator, invocationBuilderEnricher, invocationBuilder, classContext, + beanParamItems, param, target, index, restClientInterfaceClassName, client, invocationEnricherClient, formParams, - methodGenericTypeField, methodParamAnnotationsField, paramIdx, multipart, beanParamClass); + descriptorsField, multipart, beanParamClass); return formParams; } @@ -2300,6 +2317,7 @@ private void addSubBeanParamData(MethodInfo jandexMethod, BytecodeCreator method // Invocation.Builder executePut$$enrichInvocationBuilder${noOfBeanParam}(Invocation.Builder) BytecodeCreator invocationBuilderEnricher, AssignableResultHandle invocationBuilder, + ClassRestClientContext classContext, List beanParamItems, ResultHandle param, // can only be used in the current method, not in `invocationBuilderEnricher` @@ -2310,9 +2328,8 @@ private void addSubBeanParamData(MethodInfo jandexMethod, BytecodeCreator method // this client or containing client if this is a sub-client ResultHandle invocationEnricherClient, AssignableResultHandle formParams, - Supplier methodGenericTypeField, - Supplier methodParamAnnotationsField, - int paramIdx, boolean multipart, String beanParamClass) { + Supplier beanParamDescriptorField, + boolean multipart, String beanParamClass) { BytecodeCreator creator = methodCreator.ifNotNull(param).trueBranch(); BytecodeCreator invoEnricher = invocationBuilderEnricher.ifNotNull(invocationBuilderEnricher.getMethodParam(1)) .trueBranch(); @@ -2322,10 +2339,12 @@ private void addSubBeanParamData(MethodInfo jandexMethod, BytecodeCreator method case BEAN_PARAM: BeanParamItem beanParamItem = (BeanParamItem) item; ResultHandle beanParamElementHandle = beanParamItem.extract(creator, param); - addSubBeanParamData(jandexMethod, creator, invoEnricher, invocationBuilder, beanParamItem.items(), - beanParamElementHandle, target, index, restClientInterfaceClassName, client, + Supplier newBeanParamDescriptorField = classContext + .getLazyBeanParameterDescriptors(beanParamItem.className()); + addSubBeanParamData(jandexMethod, creator, invoEnricher, invocationBuilder, classContext, + beanParamItem.items(), beanParamElementHandle, target, index, restClientInterfaceClassName, client, invocationEnricherClient, formParams, - methodGenericTypeField, methodParamAnnotationsField, paramIdx, multipart, + newBeanParamDescriptorField, multipart, beanParamItem.className()); break; case QUERY_PARAM: @@ -2335,9 +2354,8 @@ private void addSubBeanParamData(MethodInfo jandexMethod, BytecodeCreator method queryParam.extract(creator, param), queryParam.getValueType(), index, client, - creator.readStaticField(methodGenericTypeField.get()), - creator.readStaticField(methodParamAnnotationsField.get()), - paramIdx)); + getGenericTypeFromParameter(creator, beanParamDescriptorField, item.fieldName()), + getAnnotationsFromParameter(creator, beanParamDescriptorField, item.fieldName()))); break; case COOKIE: CookieParamItem cookieParam = (CookieParamItem) item; @@ -2345,33 +2363,34 @@ private void addSubBeanParamData(MethodInfo jandexMethod, BytecodeCreator method cookieParam.getCookieName(), cookieParam.extract(invoEnricher, invoEnricher.getMethodParam(1)), cookieParam.getParamType(), invocationEnricherClient, - methodGenericTypeField.get(), methodParamAnnotationsField.get(), paramIdx); + getGenericTypeFromParameter(invoEnricher, beanParamDescriptorField, item.fieldName()), + getAnnotationsFromParameter(invoEnricher, beanParamDescriptorField, item.fieldName())); break; case HEADER_PARAM: HeaderParamItem headerParam = (HeaderParamItem) item; addHeaderParam(invoEnricher, invocationBuilder, headerParam.getHeaderName(), headerParam.extract(invoEnricher, invoEnricher.getMethodParam(1)), - headerParam.getParamType(), invocationEnricherClient, methodGenericTypeField.get(), - methodParamAnnotationsField.get(), paramIdx); + headerParam.getParamType(), invocationEnricherClient, + getGenericTypeFromParameter(invoEnricher, beanParamDescriptorField, item.fieldName()), + getAnnotationsFromParameter(invoEnricher, beanParamDescriptorField, item.fieldName())); break; case PATH_PARAM: PathParamItem pathParam = (PathParamItem) item; addPathParam(creator, target, pathParam.getPathParamName(), pathParam.extract(creator, param), pathParam.getParamType(), client, - creator.readStaticField(methodGenericTypeField.get()), - creator.readStaticField(methodParamAnnotationsField.get()), - paramIdx); + getGenericTypeFromParameter(creator, beanParamDescriptorField, item.fieldName()), + getAnnotationsFromParameter(creator, beanParamDescriptorField, item.fieldName())); break; case FORM_PARAM: FormParamItem formParam = (FormParamItem) item; addFormParam(creator, formParam.getFormParamName(), formParam.extract(creator, param), formParam.getParamType(), formParam.getParamSignature(), restClientInterfaceClassName, client, formParams, - creator.readStaticField(methodGenericTypeField.get()), - creator.readStaticField(methodParamAnnotationsField.get()), - paramIdx, multipart, formParam.getMimeType(), formParam.getFileName(), + getGenericTypeFromParameter(creator, beanParamDescriptorField, item.fieldName()), + getAnnotationsFromParameter(creator, beanParamDescriptorField, item.fieldName()), + multipart, formParam.getMimeType(), formParam.getFileName(), beanParamClass + "." + formParam.getSourceName()); break; default: @@ -2380,6 +2399,64 @@ private void addSubBeanParamData(MethodInfo jandexMethod, BytecodeCreator method } } + private ResultHandle getGenericTypeFromParameter(BytecodeCreator creator, Supplier supplier, + String name) { + // Will return Map + ResultHandle map = creator.invokeInterfaceMethod(ofMethod(Supplier.class, "get", Object.class), + creator.readStaticField(supplier.get())); + // Will return ParameterDescriptorFromClassSupplier.ParameterDescriptor; + ResultHandle value = creator.invokeInterfaceMethod(ofMethod(Map.class, "get", Object.class, Object.class), + map, creator.load(name)); + // if (value != null) return value.genericType; + AssignableResultHandle genericType = creator.createVariable(java.lang.reflect.Type.class); + BranchResult ifBranch = creator.ifNotNull(value); + BytecodeCreator ifNotNull = ifBranch.trueBranch(); + ifNotNull.assign(genericType, ifNotNull.readInstanceField( + FieldDescriptor.of(ParameterDescriptorFromClassSupplier.ParameterDescriptor.class, "genericType", + java.lang.reflect.Type.class), + value)); + // if (value == null) return null; + BytecodeCreator ifNull = ifBranch.falseBranch(); + ifNull.assign(genericType, ifNull.loadNull()); + return genericType; + } + + private ResultHandle getGenericTypeFromArray(BytecodeCreator creator, Supplier supplier, + int paramIdx) { + ResultHandle value = creator.invokeInterfaceMethod(ofMethod(Supplier.class, "get", Object.class), + creator.readStaticField(supplier.get())); + return creator.readArrayValue(creator.checkCast(value, java.lang.reflect.Type[].class), paramIdx); + } + + private ResultHandle getAnnotationsFromParameter(BytecodeCreator creator, Supplier supplier, + String name) { + // Will return Map + ResultHandle map = creator.invokeInterfaceMethod(ofMethod(Supplier.class, "get", Object.class), + creator.readStaticField(supplier.get())); + // Will return ParameterDescriptorFromClassSupplier.ParameterDescriptor; + ResultHandle value = creator.invokeInterfaceMethod(ofMethod(Map.class, "get", Object.class, Object.class), + map, creator.load(name)); + // if (value != null) return value.genericType; + AssignableResultHandle annotations = creator.createVariable(Annotation[].class); + BranchResult ifBranch = creator.ifNotNull(value); + BytecodeCreator ifNotNull = ifBranch.trueBranch(); + ifNotNull.assign(annotations, ifNotNull.readInstanceField( + FieldDescriptor.of(ParameterDescriptorFromClassSupplier.ParameterDescriptor.class, "annotations", + Annotation[].class), + value)); + // if (value == null) return null; + BytecodeCreator ifNull = ifBranch.falseBranch(); + ifNull.assign(annotations, ifNull.loadNull()); + return annotations; + } + + private ResultHandle getAnnotationsFromArray(BytecodeCreator creator, Supplier supplier, + int paramIdx) { + ResultHandle value = creator.invokeInterfaceMethod(ofMethod(Supplier.class, "get", Object.class), + creator.readStaticField(supplier.get())); + return creator.readArrayValue(creator.checkCast(value, Annotation[][].class), paramIdx); + } + private boolean areFormParamsDefinedIn(List beanParamItems) { for (Item item : beanParamItems) { switch (item.type()) { @@ -2406,7 +2483,7 @@ private ResultHandle addQueryParam(MethodInfo jandexMethod, BytecodeCreator meth // this client or containing client if we're in a subresource ResultHandle client, ResultHandle genericType, - ResultHandle paramAnnotations, int paramIndex) { + ResultHandle paramAnnotations) { AssignableResultHandle result = methodCreator.createVariable(WebTarget.class); BranchResult isParamNull = methodCreator.ifNull(queryParamHandle); @@ -2453,7 +2530,7 @@ private ResultHandle addQueryParam(MethodInfo jandexMethod, BytecodeCreator meth } // get the new WebTarget addQueryParamToWebTarget(loopCreator, key, result, client, genericType, paramAnnotations, - paramIndex, paramArray, componentType, result); + paramArray, componentType, result); } else { ResultHandle paramArray; String componentType = null; @@ -2481,8 +2558,7 @@ private ResultHandle addQueryParam(MethodInfo jandexMethod, BytecodeCreator meth } addQueryParamToWebTarget(notNullParam, notNullParam.load(paramName), webTarget, client, genericType, - paramAnnotations, paramIndex, - paramArray, componentType, result); + paramAnnotations, paramArray, componentType, result); } isParamNull.trueBranch().assign(result, webTarget); @@ -2521,14 +2597,13 @@ private BranchResult iteratorHasNext(BytecodeCreator creator, ResultHandle itera private void addQueryParamToWebTarget(BytecodeCreator creator, ResultHandle paramName, ResultHandle webTarget, ResultHandle client, ResultHandle genericType, - ResultHandle paramAnnotations, int paramIndex, ResultHandle paramArray, + ResultHandle paramAnnotations, ResultHandle paramArray, String componentType, AssignableResultHandle resultVariable) { ResultHandle convertedParamArray = creator.invokeVirtualMethod( MethodDescriptor.ofMethod(RestClientBase.class, "convertParamArray", Object[].class, Object[].class, - Class.class, Supplier.class, Supplier.class, int.class), - client, paramArray, creator.loadClassFromTCCL(componentType), genericType, paramAnnotations, - creator.load(paramIndex)); + Class.class, java.lang.reflect.Type.class, Annotation[].class), + client, paramArray, creator.loadClassFromTCCL(componentType), genericType, paramAnnotations); creator.assign(resultVariable, creator.invokeInterfaceMethod( MethodDescriptor.ofMethod(WebTarget.class, "queryParam", WebTarget.class, @@ -2563,19 +2638,15 @@ private boolean isMap(Type type, IndexView index) { private void addHeaderParam(BytecodeCreator invoBuilderEnricher, AssignableResultHandle invocationBuilder, String paramName, ResultHandle headerParamHandle, String paramType, ResultHandle client, - FieldDescriptor methodGenericTypeField, FieldDescriptor methodParamAnnotationsField, - int paramIdx) { + ResultHandle genericType, ResultHandle annotations) { BytecodeCreator notNullValue = invoBuilderEnricher.ifNull(headerParamHandle).falseBranch(); - ResultHandle genericType = notNullValue.readStaticField(methodGenericTypeField); - - ResultHandle parameterAnnotations = notNullValue.readStaticField(methodParamAnnotationsField); headerParamHandle = notNullValue.invokeVirtualMethod( MethodDescriptor.ofMethod(RestClientBase.class, "convertParam", Object.class, - Object.class, Class.class, Supplier.class, Supplier.class, int.class), + Object.class, Class.class, java.lang.reflect.Type.class, Annotation[].class), client, headerParamHandle, - notNullValue.loadClassFromTCCL(paramType), genericType, parameterAnnotations, notNullValue.load(paramIdx)); + notNullValue.loadClassFromTCCL(paramType), genericType, annotations); notNullValue.assign(invocationBuilder, notNullValue.invokeInterfaceMethod( @@ -2586,13 +2657,12 @@ private void addHeaderParam(BytecodeCreator invoBuilderEnricher, AssignableResul private void addPathParam(BytecodeCreator methodCreator, AssignableResultHandle methodTarget, String paramName, ResultHandle pathParamHandle, String parameterType, ResultHandle client, - ResultHandle genericType, ResultHandle parameterAnnotations, int paramIndex) { + ResultHandle genericType, ResultHandle parameterAnnotations) { ResultHandle handle = methodCreator.invokeVirtualMethod( MethodDescriptor.ofMethod(RestClientBase.class, "convertParam", Object.class, - Object.class, Class.class, Supplier.class, Supplier.class, int.class), + Object.class, Class.class, java.lang.reflect.Type.class, Annotation[].class), client, pathParamHandle, - methodCreator.loadClassFromTCCL(parameterType), genericType, parameterAnnotations, - methodCreator.load(paramIndex)); + methodCreator.loadClassFromTCCL(parameterType), genericType, parameterAnnotations); methodCreator.assign(methodTarget, methodCreator.invokeInterfaceMethod(WEB_TARGET_RESOLVE_TEMPLATE_METHOD, methodTarget, @@ -2603,17 +2673,17 @@ private void addFormParam(BytecodeCreator methodCreator, String paramName, Resul String parameterType, String parameterGenericType, String restClientInterfaceClassName, ResultHandle client, AssignableResultHandle formParams, ResultHandle genericType, - ResultHandle parameterAnnotations, int methodIndex, boolean multipart, + ResultHandle parameterAnnotations, boolean multipart, String partType, String partFilename, String errorLocation) { if (multipart) { handleMultipartField(paramName, partType, partFilename, parameterType, parameterGenericType, formParamHandle, formParams, methodCreator, - client, restClientInterfaceClassName, parameterAnnotations, methodIndex, genericType, + client, restClientInterfaceClassName, parameterAnnotations, genericType, errorLocation); } else { BytecodeCreator notNullValue = methodCreator.ifNull(formParamHandle).falseBranch(); ResultHandle convertedFormParam = convertParamToString(notNullValue, client, formParamHandle, parameterType, - genericType, parameterAnnotations, methodIndex); + genericType, parameterAnnotations); BytecodeCreator parameterIsStringBranch = checkStringParam(notNullValue, convertedFormParam, restClientInterfaceClassName, errorLocation); parameterIsStringBranch.invokeInterfaceMethod(MULTIVALUED_MAP_ADD, formParams, @@ -2637,30 +2707,25 @@ private BytecodeCreator checkStringParam(BytecodeCreator notNullValue, ResultHan private ResultHandle convertParamToString(BytecodeCreator notNullValue, ResultHandle client, ResultHandle formParamHandle, String parameterType, - ResultHandle genericType, ResultHandle parameterAnnotations, int methodIndex) { + ResultHandle genericType, ResultHandle parameterAnnotations) { return notNullValue.invokeVirtualMethod( MethodDescriptor.ofMethod(RestClientBase.class, "convertParam", Object.class, - Object.class, Class.class, Supplier.class, Supplier.class, int.class), + Object.class, Class.class, java.lang.reflect.Type.class, Annotation[].class), client, formParamHandle, - notNullValue.loadClassFromTCCL(parameterType), genericType, parameterAnnotations, - notNullValue.load(methodIndex)); + notNullValue.loadClassFromTCCL(parameterType), genericType, parameterAnnotations); } private void addCookieParam(BytecodeCreator invoBuilderEnricher, AssignableResultHandle invocationBuilder, String paramName, ResultHandle cookieParamHandle, String paramType, ResultHandle client, - FieldDescriptor methodGenericTypeField, FieldDescriptor methodParamAnnotationsField, int paramIdx) { + ResultHandle genericType, ResultHandle annotations) { BytecodeCreator notNullValue = invoBuilderEnricher.ifNull(cookieParamHandle).falseBranch(); - ResultHandle genericType = notNullValue.readStaticField(methodGenericTypeField); - - ResultHandle parameterAnnotations = notNullValue.readStaticField(methodParamAnnotationsField); - cookieParamHandle = notNullValue.invokeVirtualMethod( MethodDescriptor.ofMethod(RestClientBase.class, "convertParam", Object.class, - Object.class, Class.class, Supplier.class, Supplier.class, int.class), + Object.class, Class.class, java.lang.reflect.Type.class, Annotation[].class), client, cookieParamHandle, - notNullValue.loadClassFromTCCL(paramType), genericType, parameterAnnotations, notNullValue.load(paramIdx)); + notNullValue.loadClassFromTCCL(paramType), genericType, annotations); notNullValue.assign(invocationBuilder, notNullValue.invokeInterfaceMethod( MethodDescriptor.ofMethod(Invocation.Builder.class, "cookie", Invocation.Builder.class, String.class, diff --git a/extensions/resteasy-reactive/jaxrs-client-reactive/runtime/src/main/java/io/quarkus/jaxrs/client/reactive/runtime/ParameterDescriptorFromClassSupplier.java b/extensions/resteasy-reactive/jaxrs-client-reactive/runtime/src/main/java/io/quarkus/jaxrs/client/reactive/runtime/ParameterDescriptorFromClassSupplier.java new file mode 100644 index 0000000000000..72cb181e8f295 --- /dev/null +++ b/extensions/resteasy-reactive/jaxrs-client-reactive/runtime/src/main/java/io/quarkus/jaxrs/client/reactive/runtime/ParameterDescriptorFromClassSupplier.java @@ -0,0 +1,52 @@ +package io.quarkus.jaxrs.client.reactive.runtime; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Supplier; + +public class ParameterDescriptorFromClassSupplier + implements Supplier> { + + private final Class clazz; + private volatile Map value; + + public ParameterDescriptorFromClassSupplier(Class clazz) { + this.clazz = clazz; + } + + @Override + public Map get() { + if (value == null) { + value = new HashMap<>(); + Class currentClass = clazz; + while (currentClass != null && currentClass != Object.class) { + for (Field field : currentClass.getDeclaredFields()) { + ParameterDescriptor descriptor = new ParameterDescriptor(); + descriptor.annotations = field.getAnnotations(); + descriptor.genericType = field.getGenericType(); + value.put(field.getName(), descriptor); + } + + for (Method method : currentClass.getDeclaredMethods()) { + ParameterDescriptor descriptor = new ParameterDescriptor(); + descriptor.annotations = method.getAnnotations(); + descriptor.genericType = method.getGenericReturnType(); + value.put(method.getName(), descriptor); + } + + currentClass = currentClass.getSuperclass(); + } + } + + return value; + } + + public static class ParameterDescriptor { + public Annotation[] annotations; + public Type genericType; + } +} diff --git a/extensions/resteasy-reactive/jaxrs-client-reactive/runtime/src/main/java/io/quarkus/jaxrs/client/reactive/runtime/RestClientBase.java b/extensions/resteasy-reactive/jaxrs-client-reactive/runtime/src/main/java/io/quarkus/jaxrs/client/reactive/runtime/RestClientBase.java index c7f70ad6d0854..45c8aef084b2c 100644 --- a/extensions/resteasy-reactive/jaxrs-client-reactive/runtime/src/main/java/io/quarkus/jaxrs/client/reactive/runtime/RestClientBase.java +++ b/extensions/resteasy-reactive/jaxrs-client-reactive/runtime/src/main/java/io/quarkus/jaxrs/client/reactive/runtime/RestClientBase.java @@ -7,7 +7,6 @@ import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Supplier; import jakarta.ws.rs.ext.ParamConverter; import jakarta.ws.rs.ext.ParamConverterProvider; @@ -122,9 +121,8 @@ public RestClientBase(List providers) { } @SuppressWarnings("unused") // used by generated code - public Object[] convertParamArray(T[] value, Class type, Supplier genericType, - Supplier methodAnnotations, int paramIndex) { - ParamConverter converter = getConverter(type, genericType, methodAnnotations, paramIndex); + public Object[] convertParamArray(T[] value, Class type, Type genericType, Annotation[] annotations) { + ParamConverter converter = getConverter(type, genericType, annotations); if (converter == null) { return value; @@ -139,10 +137,8 @@ public Object[] convertParamArray(T[] value, Class type, Supplier } @SuppressWarnings("unused") // used by generated code - public Object convertParam(T value, Class type, Supplier genericType, - Supplier methodAnnotations, - int paramIndex) { - ParamConverter converter = getConverter(type, genericType, methodAnnotations, paramIndex); + public Object convertParam(T value, Class type, Type genericType, Annotation[] annotations) { + ParamConverter converter = getConverter(type, genericType, annotations); if (converter != null) { return converter.toString(value); } else { @@ -154,30 +150,26 @@ public Object convertParam(T value, Class type, Supplier genericT } } - private ParamConverter getConverter(Class type, Supplier genericType, - Supplier methodAnnotations, - int paramIndex) { + private ParamConverter getConverter(Class type, Type genericType, Annotation[] annotations) { ParamConverterProvider converterProvider = providerForClass.get(type); if (converterProvider == null) { for (ParamConverterProvider provider : paramConverterProviders) { - ParamConverter converter = provider.getConverter(type, genericType.get()[paramIndex], - methodAnnotations.get()[paramIndex]); + ParamConverter converter = provider.getConverter(type, genericType, annotations); if (converter != null) { providerForClass.put(type, provider); return converter; } } // FIXME: this should go in favour of generating them, so we can generate them only if used for dead-code elimination - ParamConverter converter = DEFAULT_PROVIDER.getConverter(type, genericType.get()[paramIndex], - methodAnnotations.get()[paramIndex]); + ParamConverter converter = DEFAULT_PROVIDER.getConverter(type, genericType, annotations); if (converter != null) { providerForClass.put(type, DEFAULT_PROVIDER); return converter; } providerForClass.put(type, NO_PROVIDER); } else if (converterProvider != NO_PROVIDER) { - return converterProvider.getConverter(type, genericType.get()[paramIndex], methodAnnotations.get()[paramIndex]); + return converterProvider.getConverter(type, genericType, annotations); } return null; } diff --git a/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/converter/ParamConverterProviderTest.java b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/converter/ParamConverterProviderTest.java index 535ea3ebe2065..b56ac980cadb0 100644 --- a/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/converter/ParamConverterProviderTest.java +++ b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/converter/ParamConverterProviderTest.java @@ -2,10 +2,16 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.lang.annotation.Annotation; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; import java.lang.reflect.Type; import java.net.URI; +import java.util.Arrays; import jakarta.ws.rs.BeanParam; import jakarta.ws.rs.CookieParam; @@ -74,7 +80,7 @@ void shouldConvertHeaderParams() { void shouldConvertCookieParams() { Client client = RestClientBuilder.newBuilder().baseUri(baseUri) .build(Client.class); - assertThat(client.getWithHeader(Param.FIRST)).isEqualTo("1"); + assertThat(client.getWithCookie(Param.FIRST)).isEqualTo("1"); assertThat(client.sub().getWithCookie(Param.SECOND)).isEqualTo("2"); Bean bean = new Bean(); @@ -93,7 +99,7 @@ interface Client { @GET @Path("/param/{param}") - String get(@PathParam("param") Param param); + String get(@MyAnnotation("myValue") @PathParam("param") Param param); @GET @Path("/param/{param}") @@ -101,7 +107,7 @@ interface Client { @GET @Path("/query") - String getWithQuery(@QueryParam("param") Param param); + String getWithQuery(@MyAnnotation("myValue") @QueryParam("param") Param param); @GET @Path("/query") @@ -109,7 +115,7 @@ interface Client { @GET @Path("/header") - String getWithHeader(@HeaderParam("param") Param param); + String getWithHeader(@MyAnnotation("myValue") @HeaderParam("param") Param param); @GET @Path("/header") @@ -117,7 +123,7 @@ interface Client { @GET @Path("/cookie") - String getWithCookie(@HeaderParam("cookie-param") Param param); + String getWithCookie(@MyAnnotation("myValue") @CookieParam("cookie-param") Param param); @GET @Path("/cookie") @@ -127,28 +133,32 @@ interface Client { interface SubClient { @GET @Path("/param/{param}") - String get(@PathParam("param") Param param); + String get(@MyAnnotation("myValue") @PathParam("param") Param param); @GET @Path("/query") - String getWithQuery(@QueryParam("param") Param param); + String getWithQuery(@MyAnnotation("myValue") @QueryParam("param") Param param); @GET @Path("/header") - String getWithHeader(@HeaderParam("param") Param param); + String getWithHeader(@MyAnnotation("myValue") @HeaderParam("param") Param param); @GET @Path("cookie") - String getWithCookie(@CookieParam("cookie-param") Param param); + String getWithCookie(@MyAnnotation("myValue") @CookieParam("cookie-param") Param param); } public static class Bean { + @MyAnnotation("myValue") @PathParam("param") public Param param; + @MyAnnotation("myValue") @QueryParam("param") public Param queryParam; + @MyAnnotation("myValue") @HeaderParam("param") public Param headerParam; + @MyAnnotation("myValue") @CookieParam("cookie-param") public Param cookieParam; } @@ -158,6 +168,12 @@ enum Param { SECOND } + @Target({ ElementType.FIELD, ElementType.PARAMETER }) + @Retention(RetentionPolicy.RUNTIME) + public @interface MyAnnotation { + String value() default ""; + } + public static class ParamConverter implements ParamConverterProvider { @SuppressWarnings("unchecked") @Override @@ -171,6 +187,9 @@ public jakarta.ws.rs.ext.ParamConverter getConverter(Class rawType, Ty fail("Annotations cannot be null!"); } + assertTrue(Arrays.stream(annotations) + .anyMatch(a -> a instanceof MyAnnotation && ((MyAnnotation) a).value().equals("myValue"))); + if (rawType == Param.class) { return (jakarta.ws.rs.ext.ParamConverter) new jakarta.ws.rs.ext.ParamConverter() { @Override diff --git a/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/BeanParamItem.java b/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/BeanParamItem.java index 4a31a0346ef47..35abc4465f858 100644 --- a/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/BeanParamItem.java +++ b/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/BeanParamItem.java @@ -6,6 +6,12 @@ public class BeanParamItem extends Item { private final List items; private final String className; + public BeanParamItem(String fieldName, List items, String className, ValueExtractor extractor) { + super(fieldName, ItemType.BEAN_PARAM, extractor); + this.items = items; + this.className = className; + } + public String className() { return className; } @@ -13,10 +19,4 @@ public String className() { public List items() { return items; } - - public BeanParamItem(List items, String className, ValueExtractor extractor) { - super(ItemType.BEAN_PARAM, extractor); - this.items = items; - this.className = className; - } } diff --git a/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/BeanParamParser.java b/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/BeanParamParser.java index d14a3f22ced9d..b85ccd9813516 100644 --- a/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/BeanParamParser.java +++ b/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/BeanParamParser.java @@ -61,18 +61,19 @@ private static List parseInternal(ClassInfo beanParamClass, IndexView inde } resultList.addAll(paramItemsForFieldsAndMethods(beanParamClass, QUERY_PARAM, - (annotationValue, fieldInfo) -> new QueryParamItem(annotationValue, + (annotationValue, fieldInfo) -> new QueryParamItem(fieldInfo.name(), annotationValue, new FieldExtractor(null, fieldInfo.name(), fieldInfo.declaringClass().name().toString()), fieldInfo.type()), - (annotationValue, getterMethod) -> new QueryParamItem(annotationValue, new GetterExtractor(getterMethod), + (annotationValue, getterMethod) -> new QueryParamItem(getterMethod.name(), annotationValue, + new GetterExtractor(getterMethod), getterMethod.returnType()))); resultList.addAll(paramItemsForFieldsAndMethods(beanParamClass, REST_QUERY_PARAM, - (annotationValue, fieldInfo) -> new QueryParamItem( + (annotationValue, fieldInfo) -> new QueryParamItem(fieldInfo.name(), annotationValue != null ? annotationValue : fieldInfo.name(), new FieldExtractor(null, fieldInfo.name(), fieldInfo.declaringClass().name().toString()), fieldInfo.type()), - (annotationValue, getterMethod) -> new QueryParamItem( + (annotationValue, getterMethod) -> new QueryParamItem(getterMethod.name(), annotationValue != null ? annotationValue : getterName(getterMethod), new GetterExtractor(getterMethod), getterMethod.returnType()))); @@ -84,7 +85,7 @@ private static List parseInternal(ClassInfo beanParamClass, IndexView inde DotName beanParamClassName = type.asClassType().name(); List subBeanParamItems = parseInternal(index.getClassByName(beanParamClassName), index, processedBeanParamClasses); - return new BeanParamItem(subBeanParamItems, beanParamClassName.toString(), + return new BeanParamItem(fieldInfo.name(), subBeanParamItems, beanParamClassName.toString(), new FieldExtractor(null, fieldInfo.name(), fieldInfo.declaringClass().name().toString())); } else { throw new IllegalArgumentException("BeanParam annotation used on a field that is not an object: " @@ -95,69 +96,71 @@ private static List parseInternal(ClassInfo beanParamClass, IndexView inde Type returnType = getterMethod.returnType(); List items = parseInternal(index.getClassByName(returnType.name()), index, processedBeanParamClasses); - return new BeanParamItem(items, beanParamClass.name().toString(), new GetterExtractor(getterMethod)); + return new BeanParamItem(getterMethod.name(), items, beanParamClass.name().toString(), + new GetterExtractor(getterMethod)); })); resultList.addAll(paramItemsForFieldsAndMethods(beanParamClass, COOKIE_PARAM, - (annotationValue, fieldInfo) -> new CookieParamItem(annotationValue, + (annotationValue, fieldInfo) -> new CookieParamItem(fieldInfo.name(), annotationValue, new FieldExtractor(null, fieldInfo.name(), fieldInfo.declaringClass().name().toString()), fieldInfo.type().name().toString()), - (annotationValue, getterMethod) -> new CookieParamItem(annotationValue, + (annotationValue, getterMethod) -> new CookieParamItem(getterMethod.name(), annotationValue, new GetterExtractor(getterMethod), getterMethod.returnType().name().toString()))); resultList.addAll(paramItemsForFieldsAndMethods(beanParamClass, REST_COOKIE_PARAM, - (annotationValue, fieldInfo) -> new CookieParamItem( + (annotationValue, fieldInfo) -> new CookieParamItem(fieldInfo.name(), annotationValue != null ? annotationValue : fieldInfo.name(), new FieldExtractor(null, fieldInfo.name(), fieldInfo.declaringClass().name().toString()), fieldInfo.type().name().toString()), - (annotationValue, getterMethod) -> new CookieParamItem( + (annotationValue, getterMethod) -> new CookieParamItem(getterMethod.name(), annotationValue != null ? annotationValue : getterName(getterMethod), new GetterExtractor(getterMethod), getterMethod.returnType().name().toString()))); resultList.addAll(paramItemsForFieldsAndMethods(beanParamClass, HEADER_PARAM, - (annotationValue, fieldInfo) -> new HeaderParamItem(annotationValue, + (annotationValue, fieldInfo) -> new HeaderParamItem(fieldInfo.name(), annotationValue, new FieldExtractor(null, fieldInfo.name(), fieldInfo.declaringClass().name().toString()), fieldInfo.type().name().toString()), - (annotationValue, getterMethod) -> new HeaderParamItem(annotationValue, + (annotationValue, getterMethod) -> new HeaderParamItem(getterMethod.name(), annotationValue, new GetterExtractor(getterMethod), getterMethod.returnType().name().toString()))); // @RestHeader with no explicit value are hyphenated resultList.addAll(paramItemsForFieldsAndMethods(beanParamClass, REST_HEADER_PARAM, - (annotationValue, fieldInfo) -> new HeaderParamItem( + (annotationValue, fieldInfo) -> new HeaderParamItem(fieldInfo.name(), annotationValue != null ? annotationValue : StringUtil.hyphenateWithCapitalFirstLetter(fieldInfo.name()), new FieldExtractor(null, fieldInfo.name(), fieldInfo.declaringClass().name().toString()), fieldInfo.type().name().toString()), - (annotationValue, getterMethod) -> new HeaderParamItem( + (annotationValue, getterMethod) -> new HeaderParamItem(getterMethod.name(), annotationValue != null ? annotationValue : StringUtil.hyphenateWithCapitalFirstLetter(getterName(getterMethod)), new GetterExtractor(getterMethod), getterMethod.returnType().name().toString()))); resultList.addAll(paramItemsForFieldsAndMethods(beanParamClass, PATH_PARAM, - (annotationValue, fieldInfo) -> new PathParamItem(annotationValue, fieldInfo.type().name().toString(), + (annotationValue, fieldInfo) -> new PathParamItem(fieldInfo.name(), annotationValue, + fieldInfo.type().name().toString(), new FieldExtractor(null, fieldInfo.name(), fieldInfo.declaringClass().name().toString())), - (annotationValue, getterMethod) -> new PathParamItem(annotationValue, + (annotationValue, getterMethod) -> new PathParamItem(getterMethod.name(), annotationValue, getterMethod.returnType().name().toString(), new GetterExtractor(getterMethod)))); resultList.addAll(paramItemsForFieldsAndMethods(beanParamClass, REST_PATH_PARAM, - (annotationValue, fieldInfo) -> new PathParamItem( + (annotationValue, fieldInfo) -> new PathParamItem(fieldInfo.name(), annotationValue != null ? annotationValue : fieldInfo.name(), fieldInfo.type().name().toString(), new FieldExtractor(null, fieldInfo.name(), fieldInfo.declaringClass().name().toString())), - (annotationValue, getterMethod) -> new PathParamItem( + (annotationValue, getterMethod) -> new PathParamItem(getterMethod.name(), annotationValue != null ? annotationValue : getterName(getterMethod), getterMethod.returnType().name().toString(), new GetterExtractor(getterMethod)))); resultList.addAll(paramItemsForFieldsAndMethods(beanParamClass, FORM_PARAM, - (annotationValue, fieldInfo) -> new FormParamItem(annotationValue, + (annotationValue, fieldInfo) -> new FormParamItem(fieldInfo.name(), annotationValue, fieldInfo.type().name().toString(), AsmUtil.getSignature(fieldInfo.type()), fieldInfo.name(), partType(fieldInfo), fileName(fieldInfo), new FieldExtractor(null, fieldInfo.name(), fieldInfo.declaringClass().name().toString())), - (annotationValue, getterMethod) -> new FormParamItem(annotationValue, + (annotationValue, getterMethod) -> new FormParamItem(getterMethod.name(), annotationValue, getterMethod.returnType().name().toString(), AsmUtil.getSignature(getterMethod.returnType()), getterMethod.name(), @@ -165,13 +168,13 @@ private static List parseInternal(ClassInfo beanParamClass, IndexView inde new GetterExtractor(getterMethod)))); resultList.addAll(paramItemsForFieldsAndMethods(beanParamClass, REST_FORM_PARAM, - (annotationValue, fieldInfo) -> new FormParamItem( + (annotationValue, fieldInfo) -> new FormParamItem(fieldInfo.name(), annotationValue != null ? annotationValue : fieldInfo.name(), fieldInfo.type().name().toString(), AsmUtil.getSignature(fieldInfo.type()), fieldInfo.name(), partType(fieldInfo), fileName(fieldInfo), new FieldExtractor(null, fieldInfo.name(), fieldInfo.declaringClass().name().toString())), - (annotationValue, getterMethod) -> new FormParamItem( + (annotationValue, getterMethod) -> new FormParamItem(getterMethod.name(), annotationValue != null ? annotationValue : getterName(getterMethod), getterMethod.returnType().name().toString(), AsmUtil.getSignature(getterMethod.returnType()), diff --git a/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/CookieParamItem.java b/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/CookieParamItem.java index c865b7dc475e9..ba068e0ad463f 100644 --- a/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/CookieParamItem.java +++ b/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/CookieParamItem.java @@ -4,8 +4,8 @@ public class CookieParamItem extends Item { private final String cookieName; private final String paramType; - public CookieParamItem(String cookieName, ValueExtractor extractor, String paramType) { - super(ItemType.COOKIE, extractor); + public CookieParamItem(String fieldName, String cookieName, ValueExtractor extractor, String paramType) { + super(fieldName, ItemType.COOKIE, extractor); this.cookieName = cookieName; this.paramType = paramType; } diff --git a/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/FormParamItem.java b/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/FormParamItem.java index ebf9f08ccad23..60c2fe9d3ccb0 100644 --- a/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/FormParamItem.java +++ b/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/FormParamItem.java @@ -9,11 +9,11 @@ public class FormParamItem extends Item { private final String fileName; private final String sourceName; - public FormParamItem(String formParamName, String paramType, String paramSignature, + public FormParamItem(String fieldName, String formParamName, String paramType, String paramSignature, String sourceName, String mimeType, String fileName, ValueExtractor valueExtractor) { - super(ItemType.FORM_PARAM, valueExtractor); + super(fieldName, ItemType.FORM_PARAM, valueExtractor); this.formParamName = formParamName; this.paramType = paramType; this.paramSignature = paramSignature; diff --git a/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/HeaderParamItem.java b/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/HeaderParamItem.java index b47110b960d4b..61b417b3865ff 100644 --- a/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/HeaderParamItem.java +++ b/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/HeaderParamItem.java @@ -4,8 +4,8 @@ public class HeaderParamItem extends Item { private final String headerName; private final String paramType; - public HeaderParamItem(String headerName, ValueExtractor extractor, String paramType) { - super(ItemType.HEADER_PARAM, extractor); + public HeaderParamItem(String fieldName, String headerName, ValueExtractor extractor, String paramType) { + super(fieldName, ItemType.HEADER_PARAM, extractor); this.headerName = headerName; this.paramType = paramType; } diff --git a/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/Item.java b/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/Item.java index 4bda26033130d..1ef10511912ad 100644 --- a/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/Item.java +++ b/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/Item.java @@ -5,14 +5,20 @@ public abstract class Item { + private final String fieldName; private final ItemType type; private final ValueExtractor valueExtractor; - public Item(ItemType type, ValueExtractor valueExtractor) { + public Item(String fieldName, ItemType type, ValueExtractor valueExtractor) { + this.fieldName = fieldName; this.type = type; this.valueExtractor = valueExtractor; } + public String fieldName() { + return fieldName; + } + public ItemType type() { return type; } diff --git a/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/PathParamItem.java b/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/PathParamItem.java index 4db45bd16baaf..474052a4f0a39 100644 --- a/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/PathParamItem.java +++ b/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/PathParamItem.java @@ -5,8 +5,8 @@ public class PathParamItem extends Item { private final String pathParamName; private final String paramType; - public PathParamItem(String pathParamName, String paramType, ValueExtractor valueExtractor) { - super(ItemType.PATH_PARAM, valueExtractor); + public PathParamItem(String fieldName, String pathParamName, String paramType, ValueExtractor valueExtractor) { + super(fieldName, ItemType.PATH_PARAM, valueExtractor); this.pathParamName = pathParamName; this.paramType = paramType; } diff --git a/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/QueryParamItem.java b/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/QueryParamItem.java index 8fb3cc58a2e0f..a3b83a979d817 100644 --- a/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/QueryParamItem.java +++ b/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/QueryParamItem.java @@ -7,8 +7,8 @@ public class QueryParamItem extends Item { private final String name; private final Type valueType; - public QueryParamItem(String name, ValueExtractor extractor, Type valueType) { - super(ItemType.QUERY_PARAM, extractor); + public QueryParamItem(String fieldName, String name, ValueExtractor extractor, Type valueType) { + super(fieldName, ItemType.QUERY_PARAM, extractor); this.name = name; this.valueType = valueType; }