Search in sources :

Example 91 with Parameter

use of java.lang.reflect.Parameter in project ezyhttp by youngmonkeys.

the class RequestHandlerImplementer method makeHandleRequestMethodContent.

@SuppressWarnings("MethodLength")
protected String makeHandleRequestMethodContent() {
    EzyMethod method = getHandleRequestMethod();
    EzyFunction function = new EzyFunction(method).throwsException();
    EzyBody body = function.body();
    int paramCount = 0;
    int headerCount = 0;
    int parameterCount = 0;
    int pathVariableCount = 0;
    int cookieCount = 0;
    Parameter[] parameters = handlerMethod.getParameters();
    for (Parameter parameter : parameters) {
        Class<?> parameterType = parameter.getType();
        Class<?> genericType = getGenericType(parameter);
        String genericTypeClass = genericType != null ? genericType.getName() + ".class" : "null";
        EzyInstruction instruction = new EzyInstruction("\t", "\n").clazz(parameterType).append(" ").append(PARAMETER_PREFIX).append(paramCount).equal();
        boolean hasAnnotation = false;
        RequestParam requestParamAnno = parameter.getAnnotation(RequestParam.class);
        if (requestParamAnno != null) {
            String paramKey = RequestParamAnnotations.getParamKeyString(requestParamAnno, parameterCount);
            String defaultValue = requestParamAnno.defaultValue();
            String getValueExpression = defaultValue.equals(EzyStrings.NULL) ? "arg0.getParameter(" + paramKey + ")" : "arg0.getParameter(" + paramKey + ", " + quote(defaultValue) + ")";
            String valueExpression = "this.deserializeParameter(" + paramKey + ", " + getValueExpression + ", " + parameterType.getTypeName() + ".class" + ", " + genericTypeClass + ")";
            instruction.cast(parameterType, valueExpression);
            ++parameterCount;
            hasAnnotation = true;
        }
        RequestHeader requestHeaderAnno = parameter.getAnnotation(RequestHeader.class);
        if (requestHeaderAnno != null) {
            String headerKey = RequestHeaderAnnotations.getHeaderKeyString(requestHeaderAnno, headerCount);
            String defaultValue = requestHeaderAnno.defaultValue();
            String getValueExpression = defaultValue.equals(EzyStrings.NULL) ? "arg0.getHeader(" + headerKey + ")" : "arg0.getHeader(" + headerKey + ", " + quote(defaultValue) + ")";
            String valueExpression = "this.deserializeHeader(" + headerKey + ", " + getValueExpression + ", " + parameterType.getTypeName() + ".class" + ", " + genericTypeClass + ")";
            instruction.cast(parameterType, valueExpression);
            ++headerCount;
            hasAnnotation = true;
        }
        PathVariable pathVariableAnno = parameter.getAnnotation(PathVariable.class);
        if (pathVariableAnno != null) {
            String varNameKey = PathVariableAnnotations.getVariableNameKeyString(pathVariableAnno, pathVariableCount);
            String valueExpression = "this.deserializePathVariable(" + varNameKey + ", arg0.getPathVariable(" + varNameKey + ")" + ", " + parameterType.getTypeName() + ".class" + ", " + genericTypeClass + ")";
            instruction.cast(parameterType, valueExpression);
            ++pathVariableCount;
            hasAnnotation = true;
        }
        RequestCookie requestCookieAnno = parameter.getAnnotation(RequestCookie.class);
        if (requestCookieAnno != null) {
            String cookieKey = RequestCookieAnnotations.getCookieKeyString(requestCookieAnno, cookieCount);
            String defaultValue = requestCookieAnno.defaultValue();
            String getValueExpression = defaultValue.equals(EzyStrings.NULL) ? "arg0.getCookieValue(" + cookieKey + ")" : "arg0.getCookieValue(" + cookieKey + ", " + quote(defaultValue) + ")";
            String valueExpression = "this.deserializeCookie(" + cookieKey + ", " + getValueExpression + ", " + parameterType.getTypeName() + ".class" + ", " + genericTypeClass + ")";
            instruction.cast(parameterType, valueExpression);
            ++cookieCount;
            hasAnnotation = true;
        }
        RequestBody requestBodyAnno = parameter.getAnnotation(RequestBody.class);
        if (requestBodyAnno != null) {
            instruction.brackets(parameterType).append("this.deserializeBody(").append("arg0, ").clazz(parameterType, true).append(")");
            hasAnnotation = true;
        }
        if (!hasAnnotation) {
            String valueExpression = "arg0";
            if (parameterType != RequestArguments.class) {
                String argumentKey = RequestParameters.getArgumentKeyString(parameter);
                valueExpression = "arg0.getArgument(" + argumentKey + ")";
            }
            instruction.cast(parameterType, valueExpression);
        }
        body.append(instruction);
        ++paramCount;
    }
    EzyInstruction instruction = new EzyInstruction("\t", "\n");
    Class<?> returnType = handlerMethod.getReturnType();
    if (returnType != void.class) {
        instruction.answer();
    }
    StringBuilder answerExpression = new StringBuilder();
    answerExpression.append("this.controller.").append(handlerMethod.getName()).append("(");
    for (int i = 0; i < paramCount; ++i) {
        answerExpression.append(PARAMETER_PREFIX).append(i);
        if (i < paramCount - 1) {
            answerExpression.append(", ");
        }
    }
    answerExpression.append(")");
    if (returnType != void.class) {
        instruction.valueOf(returnType, answerExpression.toString());
    } else {
        instruction.append(answerExpression);
    }
    body.append(instruction);
    if (returnType == void.class) {
        body.append(new EzyInstruction("\t", "\n").append("return null"));
    }
    return function.toString();
}
Also used : EzyBody(com.tvd12.ezyfox.asm.EzyFunction.EzyBody) RequestParam(com.tvd12.ezyhttp.server.core.annotation.RequestParam) RequestCookie(com.tvd12.ezyhttp.server.core.annotation.RequestCookie) EzyInstruction(com.tvd12.ezyfox.asm.EzyInstruction) Parameter(java.lang.reflect.Parameter) RequestHeader(com.tvd12.ezyhttp.server.core.annotation.RequestHeader) EzyFunction(com.tvd12.ezyfox.asm.EzyFunction) EzyMethod(com.tvd12.ezyfox.reflect.EzyMethod) PathVariable(com.tvd12.ezyhttp.server.core.annotation.PathVariable) RequestBody(com.tvd12.ezyhttp.server.core.annotation.RequestBody)

Example 92 with Parameter

use of java.lang.reflect.Parameter in project ezyhttp by youngmonkeys.

the class AbstractHandlerImplementer method appendHandleExceptionMethodArguments.

protected void appendHandleExceptionMethodArguments(ExceptionHandlerMethod method, EzyInstruction instruction, Class<?> exceptionClass) {
    int paramCount = 0;
    Parameter[] parameters = method.getParameters();
    for (Parameter parameter : parameters) {
        Class<?> parameterType = parameter.getType();
        if (parameterType == RequestArguments.class) {
            instruction.append("arg0");
        } else if (parameterType == HttpServletRequest.class) {
            instruction.append("arg0.getRequest()");
        } else if (parameterType == HttpServletResponse.class) {
            instruction.append("arg0.getResponse()");
        } else if (Throwable.class.isAssignableFrom(parameterType)) {
            instruction.brackets(exceptionClass).append("arg1");
        } else if (parameterType == boolean.class) {
            instruction.append("false");
        } else if (parameterType.isPrimitive()) {
            instruction.append("0");
        } else {
            instruction.append("null");
        }
        if ((paramCount++) < (parameters.length - 1)) {
            instruction.append(", ");
        }
    }
}
Also used : HttpServletRequest(javax.servlet.http.HttpServletRequest) Parameter(java.lang.reflect.Parameter)

Example 93 with Parameter

use of java.lang.reflect.Parameter in project quarkus by quarkusio.

the class BytecodeRecorderImpl method loadComplexObject.

/**
 * Created a {@link DeferredParameter} to load a complex object, such as a javabean or collection. This is basically
 * just an extension of {@link #loadObjectInstanceImpl(Object, Map, Class, boolean)} but it removes some of the more complex
 * code from that method.
 *
 * @param param The object to load
 * @param existing The existing object map
 * @param expectedType The expected type of the object
 * @param relaxedValidation
 * @return
 */
private DeferredParameter loadComplexObject(Object param, Map<Object, DeferredParameter> existing, Class<?> expectedType, boolean relaxedValidation) {
    // a list of steps that are performed on the object after it has been created
    // we need to create all these first, to ensure the required objects have already
    // been deserialized
    List<SerializationStep> setupSteps = new ArrayList<>();
    List<SerializationStep> ctorSetupSteps = new ArrayList<>();
    boolean relaxedOk = false;
    if (param instanceof Collection) {
        // if this is a collection we want to serialize every element
        for (Object i : (Collection) param) {
            DeferredParameter val = i != null ? loadObjectInstance(i, existing, i.getClass(), relaxedValidation) : loadObjectInstance(null, existing, Object.class, relaxedValidation);
            setupSteps.add(new SerializationStep() {

                @Override
                public void handle(MethodContext context, MethodCreator method, DeferredArrayStoreParameter out) {
                    // each step can happen in a new method, so it is safe to do this
                    method.invokeInterfaceMethod(COLLECTION_ADD, context.loadDeferred(out), context.loadDeferred(val));
                }

                @Override
                public void prepare(MethodContext context) {
                    // handle the value serialization
                    val.prepare(context);
                }
            });
        }
        relaxedOk = true;
    }
    if (param instanceof Map) {
        // map works the same as collection
        for (Map.Entry<?, ?> i : ((Map<?, ?>) param).entrySet()) {
            DeferredParameter key = loadObjectInstance(i.getKey(), existing, i.getKey().getClass(), relaxedValidation);
            DeferredParameter val = i.getValue() != null ? loadObjectInstance(i.getValue(), existing, i.getValue().getClass(), relaxedValidation) : loadObjectInstance(null, existing, Object.class, relaxedValidation);
            setupSteps.add(new SerializationStep() {

                @Override
                public void handle(MethodContext context, MethodCreator method, DeferredArrayStoreParameter out) {
                    method.invokeInterfaceMethod(MAP_PUT, context.loadDeferred(out), context.loadDeferred(key), context.loadDeferred(val));
                }

                @Override
                public void prepare(MethodContext context) {
                    key.prepare(context);
                    val.prepare(context);
                }
            });
        }
        relaxedOk = true;
    }
    // check how the object is constructed
    NonDefaultConstructorHolder nonDefaultConstructorHolder = null;
    DeferredParameter[] nonDefaultConstructorHandles = null;
    // used to resolve the parameter position for @RecordableConstructor
    Map<String, Integer> constructorParamNameMap = new HashMap<>();
    if (nonDefaultConstructors.containsKey(param.getClass())) {
        nonDefaultConstructorHolder = nonDefaultConstructors.get(param.getClass());
        List<Object> params = nonDefaultConstructorHolder.paramGenerator.apply(param);
        if (params.size() != nonDefaultConstructorHolder.constructor.getParameterCount()) {
            throw new RuntimeException("Unable to serialize " + param + " as the wrong number of parameters were generated for " + nonDefaultConstructorHolder.constructor);
        }
        int count = 0;
        nonDefaultConstructorHandles = new DeferredParameter[params.size()];
        Class<?>[] parameterTypes = nonDefaultConstructorHolder.constructor.getParameterTypes();
        for (int i = 0; i < params.size(); i++) {
            Object obj = params.get(i);
            nonDefaultConstructorHandles[i] = loadObjectInstance(obj, existing, parameterTypes[count++], relaxedValidation);
        }
    } else if (classesToUseRecorableConstructor.contains(param.getClass())) {
        Constructor<?> current = null;
        int count = 0;
        for (var c : param.getClass().getConstructors()) {
            if (current == null || current.getParameterCount() < c.getParameterCount()) {
                current = c;
                count = 0;
            } else if (current != null && current.getParameterCount() == c.getParameterCount()) {
                count++;
            }
        }
        if (current == null || count > 0) {
            throw new RuntimeException("Unable to determine the recordable constructor to use for " + param.getClass());
        }
        nonDefaultConstructorHolder = new NonDefaultConstructorHolder(current, null);
        nonDefaultConstructorHandles = new DeferredParameter[current.getParameterCount()];
        if (current.getParameterCount() > 0) {
            Parameter[] parameters = current.getParameters();
            for (int i = 0; i < current.getParameterCount(); ++i) {
                String name = parameters[i].getName();
                constructorParamNameMap.put(name, i);
            }
        }
    } else {
        for (Constructor<?> ctor : param.getClass().getConstructors()) {
            if (ctor.isAnnotationPresent(RecordableConstructor.class)) {
                nonDefaultConstructorHolder = new NonDefaultConstructorHolder(ctor, null);
                nonDefaultConstructorHandles = new DeferredParameter[ctor.getParameterCount()];
                if (ctor.getParameterCount() > 0) {
                    Parameter[] ctorParameters = ctor.getParameters();
                    for (int i = 0; i < ctor.getParameterCount(); ++i) {
                        String name = ctorParameters[i].getName();
                        constructorParamNameMap.put(name, i);
                    }
                }
                break;
            }
        }
    }
    Set<String> handledProperties = new HashSet<>();
    Property[] desc = PropertyUtils.getPropertyDescriptors(param);
    for (Property i : desc) {
        if (!i.getDeclaringClass().getPackageName().startsWith("java.")) {
            // check if the getter is ignored
            if ((i.getReadMethod() != null) && (i.getReadMethod().getAnnotation(IgnoreProperty.class) != null)) {
                continue;
            }
            // check if the matching field is ignored
            try {
                if (param.getClass().getDeclaredField(i.getName()).getAnnotation(IgnoreProperty.class) != null) {
                    continue;
                }
            } catch (NoSuchFieldException ignored) {
            }
        }
        Integer ctorParamIndex = constructorParamNameMap.remove(i.name);
        if (i.getReadMethod() != null && i.getWriteMethod() == null && ctorParamIndex == null) {
            try {
                // read only prop, we may still be able to do stuff with it if it is a collection
                if (Collection.class.isAssignableFrom(i.getPropertyType())) {
                    // special case, a collection with only a read method
                    // we assume we can just add to the connection
                    handledProperties.add(i.getName());
                    Collection propertyValue = (Collection) i.read(param);
                    if (propertyValue != null && !propertyValue.isEmpty()) {
                        List<DeferredParameter> params = new ArrayList<>();
                        for (Object c : propertyValue) {
                            DeferredParameter toAdd = loadObjectInstance(c, existing, Object.class, relaxedValidation);
                            params.add(toAdd);
                        }
                        setupSteps.add(new SerializationStep() {

                            @Override
                            public void handle(MethodContext context, MethodCreator method, DeferredArrayStoreParameter out) {
                                // get the collection
                                ResultHandle prop = method.invokeVirtualMethod(MethodDescriptor.ofMethod(i.getReadMethod()), context.loadDeferred(out));
                                for (DeferredParameter i : params) {
                                    // add the parameter
                                    // TODO: this is not guareded against large collections, probably not an issue in practice
                                    method.invokeInterfaceMethod(COLLECTION_ADD, prop, context.loadDeferred(i));
                                }
                            }

                            @Override
                            public void prepare(MethodContext context) {
                                for (DeferredParameter i : params) {
                                    i.prepare(context);
                                }
                            }
                        });
                    }
                } else if (Map.class.isAssignableFrom(i.getPropertyType())) {
                    // special case, a map with only a read method
                    // we assume we can just add to the map
                    // similar to how collection works above
                    handledProperties.add(i.getName());
                    Map<Object, Object> propertyValue = (Map<Object, Object>) i.read(param);
                    if (propertyValue != null && !propertyValue.isEmpty()) {
                        Map<DeferredParameter, DeferredParameter> def = new LinkedHashMap<>();
                        for (Map.Entry<Object, Object> entry : propertyValue.entrySet()) {
                            DeferredParameter key = loadObjectInstance(entry.getKey(), existing, Object.class, relaxedValidation);
                            DeferredParameter val = loadObjectInstance(entry.getValue(), existing, Object.class, relaxedValidation);
                            def.put(key, val);
                        }
                        setupSteps.add(new SerializationStep() {

                            @Override
                            public void handle(MethodContext context, MethodCreator method, DeferredArrayStoreParameter out) {
                                ResultHandle prop = method.invokeVirtualMethod(MethodDescriptor.ofMethod(i.getReadMethod()), context.loadDeferred(out));
                                for (Map.Entry<DeferredParameter, DeferredParameter> e : def.entrySet()) {
                                    method.invokeInterfaceMethod(MAP_PUT, prop, context.loadDeferred(e.getKey()), context.loadDeferred(e.getValue()));
                                }
                            }

                            @Override
                            public void prepare(MethodContext context) {
                                for (Map.Entry<DeferredParameter, DeferredParameter> e : def.entrySet()) {
                                    e.getKey().prepare(context);
                                    e.getValue().prepare(context);
                                }
                            }
                        });
                    }
                } else if (!relaxedValidation && !i.getName().equals("class") && !relaxedOk && nonDefaultConstructorHolder == null) {
                    // check if there is actually a field with the name
                    try {
                        i.getReadMethod().getDeclaringClass().getDeclaredField(i.getName());
                        throw new RuntimeException("Cannot serialise field '" + i.getName() + "' on object '" + param + "' as the property is read only");
                    } catch (NoSuchFieldException e) {
                    // if there is no underlying field then we ignore the property
                    }
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        } else if (i.getReadMethod() != null && (i.getWriteMethod() != null || ctorParamIndex != null)) {
            // normal javabean property
            try {
                handledProperties.add(i.getName());
                Object propertyValue = i.read(param);
                if (propertyValue == null && ctorParamIndex == null) {
                    // TODO: is this a valid assumption? Should we check this by creating an instance?
                    continue;
                }
                Class propertyType = i.getPropertyType();
                if (ctorParamIndex == null) {
                    Class<?> getterReturnType = i.getReadMethod().getReturnType();
                    Class<?> setterParameterType = i.getWriteMethod().getParameterTypes()[0];
                    if (getterReturnType != setterParameterType) {
                        if (relaxedValidation) {
                            for (Method m : param.getClass().getMethods()) {
                                if (m.getName().equals(i.getWriteMethod().getName())) {
                                    if (m.getParameterCount() > 0) {
                                        Class<?>[] parameterTypes = m.getParameterTypes();
                                        if (parameterTypes[0].isAssignableFrom(param.getClass())) {
                                            propertyType = parameterTypes[0];
                                            break;
                                        }
                                    }
                                }
                            }
                        } else {
                            throw new RuntimeException("Cannot serialise field '" + i.getName() + "' on object '" + param + "' of type '" + param.getClass().getName() + "' as getter and setter are of different types. Getter type is '" + getterReturnType.getName() + "' while setter type is '" + setterParameterType.getName() + "'.");
                        }
                    }
                }
                DeferredParameter val = loadObjectInstance(propertyValue, existing, i.getPropertyType(), relaxedValidation);
                if (ctorParamIndex != null) {
                    nonDefaultConstructorHandles[ctorParamIndex] = val;
                    ctorSetupSteps.add(new SerializationStep() {

                        @Override
                        public void handle(MethodContext context, MethodCreator method, DeferredArrayStoreParameter out) {
                        }

                        @Override
                        public void prepare(MethodContext context) {
                            val.prepare(context);
                        }
                    });
                } else {
                    Class finalPropertyType = propertyType;
                    setupSteps.add(new SerializationStep() {

                        @Override
                        public void handle(MethodContext context, MethodCreator method, DeferredArrayStoreParameter out) {
                            ResultHandle object = context.loadDeferred(out);
                            ResultHandle resultVal = context.loadDeferred(val);
                            method.invokeVirtualMethod(ofMethod(param.getClass(), i.getWriteMethod().getName(), i.getWriteMethod().getReturnType(), finalPropertyType), object, resultVal);
                        }

                        @Override
                        public void prepare(MethodContext context) {
                            val.prepare(context);
                        }
                    });
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
    // now handle accessible fields
    for (Field field : param.getClass().getFields()) {
        // check if the field is ignored
        if (field.getAnnotation(IgnoreProperty.class) != null) {
            continue;
        }
        if (!handledProperties.contains(field.getName())) {
            Integer ctorParamIndex = constructorParamNameMap.remove(field.getName());
            if ((ctorParamIndex != null || !Modifier.isFinal(field.getModifiers())) && !Modifier.isStatic(field.getModifiers())) {
                try {
                    DeferredParameter val = loadObjectInstance(field.get(param), existing, field.getType(), relaxedValidation);
                    if (ctorParamIndex != null) {
                        nonDefaultConstructorHandles[ctorParamIndex] = val;
                        ctorSetupSteps.add(new SerializationStep() {

                            @Override
                            public void handle(MethodContext context, MethodCreator method, DeferredArrayStoreParameter out) {
                            }

                            @Override
                            public void prepare(MethodContext context) {
                                val.prepare(context);
                            }
                        });
                    } else {
                        setupSteps.add(new SerializationStep() {

                            @Override
                            public void handle(MethodContext context, MethodCreator method, DeferredArrayStoreParameter out) {
                                method.writeInstanceField(FieldDescriptor.of(param.getClass(), field.getName(), field.getType()), context.loadDeferred(out), context.loadDeferred(val));
                            }

                            @Override
                            public void prepare(MethodContext context) {
                                val.prepare(context);
                            }
                        });
                    }
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
    if (!constructorParamNameMap.isEmpty()) {
        throw new RuntimeException("Could not find parameters for constructor " + nonDefaultConstructorHolder.constructor + " could not read field values " + constructorParamNameMap.keySet());
    }
    NonDefaultConstructorHolder finalNonDefaultConstructorHolder = nonDefaultConstructorHolder;
    DeferredParameter[] finalCtorHandles = nonDefaultConstructorHandles;
    // create a deferred value to represet the object itself. This allows the creation to be split
    // over multiple methods, which is important if this is a large object
    DeferredArrayStoreParameter objectValue = new DeferredArrayStoreParameter(param, expectedType) {

        @Override
        ResultHandle createValue(MethodContext context, MethodCreator method, ResultHandle array) {
            ResultHandle out;
            // do the creation
            if (finalNonDefaultConstructorHolder != null) {
                out = method.newInstance(ofConstructor(finalNonDefaultConstructorHolder.constructor.getDeclaringClass(), finalNonDefaultConstructorHolder.constructor.getParameterTypes()), Arrays.stream(finalCtorHandles).map(m -> context.loadDeferred(m)).toArray(ResultHandle[]::new));
            } else {
                if (List.class.isAssignableFrom(param.getClass()) && expectedType == List.class) {
                    // list is a common special case, so let's handle it
                    List listParam = (List) param;
                    if (listParam.isEmpty()) {
                        out = method.newInstance(ofConstructor(ArrayList.class));
                    } else {
                        out = method.newInstance(ofConstructor(ArrayList.class, int.class), method.load(listParam.size()));
                    }
                } else {
                    try {
                        param.getClass().getDeclaredConstructor();
                        out = method.newInstance(ofConstructor(param.getClass()));
                    } catch (NoSuchMethodException e) {
                        // fallback for collection types, such as unmodifiableMap
                        if (SortedMap.class.isAssignableFrom(expectedType)) {
                            out = method.newInstance(ofConstructor(TreeMap.class));
                        } else if (Map.class.isAssignableFrom(expectedType)) {
                            out = method.newInstance(ofConstructor(LinkedHashMap.class));
                        } else if (List.class.isAssignableFrom(expectedType)) {
                            out = method.newInstance(ofConstructor(ArrayList.class));
                        } else if (SortedSet.class.isAssignableFrom(expectedType)) {
                            out = method.newInstance(ofConstructor(TreeSet.class));
                        } else if (Set.class.isAssignableFrom(expectedType)) {
                            out = method.newInstance(ofConstructor(LinkedHashSet.class));
                        } else {
                            throw new RuntimeException("Unable to serialize objects of type " + param.getClass() + " to bytecode as it has no default constructor");
                        }
                    }
                }
            }
            return out;
        }
    };
    // now return the actual deferred parameter that represents the result of construction
    return new DeferredArrayStoreParameter(param, expectedType) {

        @Override
        void doPrepare(MethodContext context) {
            // first create the actial object
            for (SerializationStep i : ctorSetupSteps) {
                i.prepare(context);
            }
            objectValue.prepare(context);
            for (SerializationStep i : setupSteps) {
                // then prepare the steps (i.e. creating the values to be placed into this object)
                i.prepare(context);
                // now actually run the steps (i.e. actually stick the values into the object)
                context.writeInstruction(new InstructionGroup() {

                    @Override
                    public void write(MethodContext context, MethodCreator method, ResultHandle array) {
                        i.handle(context, method, objectValue);
                    }
                });
            }
            super.doPrepare(context);
        }

        @Override
        ResultHandle createValue(MethodContext context, MethodCreator method, ResultHandle array) {
            // just return the already created object
            return context.loadDeferred(objectValue);
        }
    };
}
Also used : Arrays(java.util.Arrays) Array(java.lang.reflect.Array) SortedSet(java.util.SortedSet) ListIterator(java.util.ListIterator) URL(java.net.URL) ClassOutput(io.quarkus.gizmo.ClassOutput) ClassInfo(org.jboss.jandex.ClassInfo) MethodInfo(org.jboss.jandex.MethodInfo) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) RecordableConstructor(io.quarkus.runtime.annotations.RecordableConstructor) Duration(java.time.Duration) Map(java.util.Map) BytecodeCreator(io.quarkus.gizmo.BytecodeCreator) StartupContext(io.quarkus.runtime.StartupContext) Method(java.lang.reflect.Method) AnnotationValue(org.jboss.jandex.AnnotationValue) Assert(org.wildfly.common.Assert) IdentityHashMap(java.util.IdentityHashMap) ProxyConfiguration(io.quarkus.deployment.proxy.ProxyConfiguration) Collection(java.util.Collection) Property(io.quarkus.deployment.recording.PropertyUtils.Property) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) Set(java.util.Set) NavigableSet(java.util.NavigableSet) QuarkusClassLoader(io.quarkus.bootstrap.classloading.QuarkusClassLoader) Collectors(java.util.stream.Collectors) ProxyFactory(io.quarkus.deployment.proxy.ProxyFactory) List(java.util.List) RelaxedValidation(io.quarkus.runtime.annotations.RelaxedValidation) Modifier(java.lang.reflect.Modifier) Annotation(java.lang.annotation.Annotation) Optional(java.util.Optional) IgnoreProperty(io.quarkus.runtime.annotations.IgnoreProperty) ArrayType(org.jboss.jandex.ArrayType) ResultHandle(io.quarkus.gizmo.ResultHandle) SortedMap(java.util.SortedMap) TryBlock(io.quarkus.gizmo.TryBlock) MethodDescriptor.ofConstructor(io.quarkus.gizmo.MethodDescriptor.ofConstructor) CatchBlockCreator(io.quarkus.gizmo.CatchBlockCreator) Proxy(java.lang.reflect.Proxy) MethodCreator(io.quarkus.gizmo.MethodCreator) Type(org.jboss.jandex.Type) HashMap(java.util.HashMap) MethodDescriptor.ofMethod(io.quarkus.gizmo.MethodDescriptor.ofMethod) ClassCreator(io.quarkus.gizmo.ClassCreator) Constructor(java.lang.reflect.Constructor) Function(java.util.function.Function) TreeSet(java.util.TreeSet) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) LinkedHashMap(java.util.LinkedHashMap) Inject(javax.inject.Inject) Parameter(java.lang.reflect.Parameter) RuntimeValue(io.quarkus.runtime.RuntimeValue) AssignableResultHandle(io.quarkus.gizmo.AssignableResultHandle) StartupTask(io.quarkus.runtime.StartupTask) LinkedHashSet(java.util.LinkedHashSet) MethodDescriptor(io.quarkus.gizmo.MethodDescriptor) MalformedURLException(java.net.MalformedURLException) Field(java.lang.reflect.Field) FieldDescriptor(io.quarkus.gizmo.FieldDescriptor) AbstractMap(java.util.AbstractMap) ParameterizedType(java.lang.reflect.ParameterizedType) TreeMap(java.util.TreeMap) Closeable(java.io.Closeable) InvocationHandler(java.lang.reflect.InvocationHandler) AnnotationProxy(io.quarkus.deployment.recording.AnnotationProxyProvider.AnnotationProxy) ObjectSubstitution(io.quarkus.runtime.ObjectSubstitution) Collections(java.util.Collections) LinkedHashSet(java.util.LinkedHashSet) IdentityHashMap(java.util.IdentityHashMap) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) ArrayList(java.util.ArrayList) List(java.util.List) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet) Method(java.lang.reflect.Method) MethodDescriptor.ofMethod(io.quarkus.gizmo.MethodDescriptor.ofMethod) IgnoreProperty(io.quarkus.runtime.annotations.IgnoreProperty) SortedMap(java.util.SortedMap) Collection(java.util.Collection) Map(java.util.Map) IdentityHashMap(java.util.IdentityHashMap) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) SortedMap(java.util.SortedMap) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) AbstractMap(java.util.AbstractMap) TreeMap(java.util.TreeMap) SortedSet(java.util.SortedSet) Set(java.util.Set) NavigableSet(java.util.NavigableSet) TreeSet(java.util.TreeSet) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet) Field(java.lang.reflect.Field) ResultHandle(io.quarkus.gizmo.ResultHandle) AssignableResultHandle(io.quarkus.gizmo.AssignableResultHandle) Property(io.quarkus.deployment.recording.PropertyUtils.Property) IgnoreProperty(io.quarkus.runtime.annotations.IgnoreProperty) RecordableConstructor(io.quarkus.runtime.annotations.RecordableConstructor) MethodDescriptor.ofConstructor(io.quarkus.gizmo.MethodDescriptor.ofConstructor) Constructor(java.lang.reflect.Constructor) TreeMap(java.util.TreeMap) MalformedURLException(java.net.MalformedURLException) RecordableConstructor(io.quarkus.runtime.annotations.RecordableConstructor) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) MethodCreator(io.quarkus.gizmo.MethodCreator)

Example 94 with Parameter

use of java.lang.reflect.Parameter in project quarkus by quarkusio.

the class BytecodeRecorderImpl method loadObjectInstanceImpl.

/**
 * Returns a representation of a serialized parameter.
 */
private DeferredParameter loadObjectInstanceImpl(Object param, Map<Object, DeferredParameter> existing, Class<?> expectedType, boolean relaxedValidation) {
    // null is easy
    if (param == null) {
        return new DeferredParameter() {

            @Override
            ResultHandle doLoad(MethodContext creator, MethodCreator method, ResultHandle array) {
                return method.loadNull();
            }
        };
    }
    // check the loaded object support (i.e. config) to see if this is a config item
    DeferredParameter loadedObject = findLoaded(param);
    if (loadedObject != null) {
        return loadedObject;
    }
    // Handle empty collections as returned by the Collections object
    loadedObject = handleCollectionsObjects(param, existing, relaxedValidation);
    if (loadedObject != null) {
        return loadedObject;
    }
    // but some are quite complex when dealing with objects and collections
    if (substitutions.containsKey(param.getClass()) || substitutions.containsKey(expectedType)) {
        // check for substitution types, if present we invoke recursively on the substitution
        SubstitutionHolder holder = substitutions.get(param.getClass());
        if (holder == null) {
            holder = substitutions.get(expectedType);
        }
        try {
            ObjectSubstitution substitution = holder.sub.getDeclaredConstructor().newInstance();
            Object res = substitution.serialize(param);
            DeferredParameter serialized = loadObjectInstance(res, existing, holder.to, relaxedValidation);
            SubstitutionHolder finalHolder = holder;
            return new DeferredArrayStoreParameter(param, expectedType) {

                @Override
                void doPrepare(MethodContext context) {
                    serialized.prepare(context);
                    super.doPrepare(context);
                }

                @Override
                ResultHandle createValue(MethodContext creator, MethodCreator method, ResultHandle array) {
                    ResultHandle subInstance = method.newInstance(MethodDescriptor.ofConstructor(finalHolder.sub));
                    return method.invokeInterfaceMethod(ofMethod(ObjectSubstitution.class, "deserialize", Object.class, Object.class), subInstance, creator.loadDeferred(serialized));
                }
            };
        } catch (Exception e) {
            throw new RuntimeException("Failed to substitute " + param, e);
        }
    } else if (param instanceof Optional) {
        Optional val = (Optional) param;
        if (val.isPresent()) {
            DeferredParameter res = loadObjectInstance(val.get(), existing, Object.class, relaxedValidation);
            return new DeferredArrayStoreParameter(param, expectedType) {

                @Override
                void doPrepare(MethodContext context) {
                    res.prepare(context);
                    super.doPrepare(context);
                }

                @Override
                ResultHandle createValue(MethodContext context, MethodCreator method, ResultHandle array) {
                    // so we need to use 'ofNullable' and not 'of' here.
                    return method.invokeStaticMethod(ofMethod(Optional.class, "ofNullable", Optional.class, Object.class), context.loadDeferred(res));
                }
            };
        } else {
            return new DeferredArrayStoreParameter(param, expectedType) {

                @Override
                ResultHandle createValue(MethodContext context, MethodCreator method, ResultHandle array) {
                    return method.invokeStaticMethod(ofMethod(Optional.class, "empty", Optional.class));
                }
            };
        }
    } else if (param instanceof String) {
        if (((String) param).length() > 65535) {
            throw new RuntimeException("String too large to record: " + param);
        }
        return new DeferredParameter() {

            @Override
            ResultHandle doLoad(MethodContext context, MethodCreator method, ResultHandle array) {
                return method.load((String) param);
            }
        };
    } else if (param instanceof URL) {
        String url = ((URL) param).toExternalForm();
        return new DeferredParameter() {

            @Override
            ResultHandle doLoad(MethodContext context, MethodCreator method, ResultHandle array) {
                AssignableResultHandle value = method.createVariable(URL.class);
                try (TryBlock et = method.tryBlock()) {
                    et.assign(value, et.newInstance(MethodDescriptor.ofConstructor(URL.class, String.class), et.load(url)));
                    try (CatchBlockCreator malformed = et.addCatch(MalformedURLException.class)) {
                        malformed.throwException(RuntimeException.class, "Malformed URL", malformed.getCaughtException());
                    }
                }
                return value;
            }
        };
    } else if (param instanceof Enum) {
        Enum e = (Enum) param;
        return new DeferredParameter() {

            @Override
            ResultHandle doLoad(MethodContext context, MethodCreator method, ResultHandle array) {
                ResultHandle nm = method.load(e.name());
                return method.invokeStaticMethod(ofMethod(e.getDeclaringClass(), "valueOf", e.getDeclaringClass(), String.class), nm);
            }
        };
    } else if (param instanceof ReturnedProxy) {
        // if this is a proxy we just grab the value from the StartupContext
        ReturnedProxy rp = (ReturnedProxy) param;
        if (!rp.__static$$init() && staticInit) {
            throw new RuntimeException("Invalid proxy passed to recorder. " + rp + " was created in a runtime recorder method, while this recorder is for a static init method. The object will not have been created at the time this method is run.");
        }
        String proxyId = rp.__returned$proxy$key();
        // we just load it from the startup context
        return new DeferredParameter() {

            @Override
            ResultHandle doLoad(MethodContext context, MethodCreator method, ResultHandle array) {
                return method.invokeVirtualMethod(ofMethod(StartupContext.class, "getValue", Object.class, String.class), method.getMethodParam(0), method.load(proxyId));
            }
        };
    } else if (param instanceof Duration) {
        return new DeferredParameter() {

            @Override
            ResultHandle doLoad(MethodContext context, MethodCreator method, ResultHandle array) {
                return method.invokeStaticMethod(ofMethod(Duration.class, "parse", Duration.class, CharSequence.class), method.load(param.toString()));
            }
        };
    } else if (param instanceof Class<?>) {
        if (!((Class) param).isPrimitive()) {
            // Only try to load the class by name if it is not a primitive class
            String name = classProxies.get(param);
            if (name == null) {
                name = ((Class) param).getName();
            }
            String finalName = name;
            return new DeferredParameter() {

                @Override
                ResultHandle doLoad(MethodContext context, MethodCreator method, ResultHandle array) {
                    ResultHandle currentThread = method.invokeStaticMethod(ofMethod(Thread.class, "currentThread", Thread.class));
                    ResultHandle tccl = method.invokeVirtualMethod(ofMethod(Thread.class, "getContextClassLoader", ClassLoader.class), currentThread);
                    return method.invokeStaticMethod(ofMethod(Class.class, "forName", Class.class, String.class, boolean.class, ClassLoader.class), method.load(finalName), method.load(true), tccl);
                }
            };
        } else {
            // Else load the primitive type by reference; double.class => Class var9 = Double.TYPE;
            return new DeferredParameter() {

                @Override
                ResultHandle doLoad(MethodContext context, MethodCreator method, ResultHandle array) {
                    return method.loadClassFromTCCL((Class) param);
                }
            };
        }
    } else if (expectedType == boolean.class || expectedType == Boolean.class || param instanceof Boolean) {
        return new DeferredParameter() {

            @Override
            ResultHandle doLoad(MethodContext context, MethodCreator method, ResultHandle array) {
                return method.load((boolean) param);
            }
        };
    } else if (expectedType == int.class || expectedType == Integer.class || param instanceof Integer) {
        return new DeferredParameter() {

            @Override
            ResultHandle doLoad(MethodContext context, MethodCreator method, ResultHandle array) {
                return method.load((int) param);
            }
        };
    } else if (expectedType == short.class || expectedType == Short.class || param instanceof Short) {
        return new DeferredParameter() {

            @Override
            ResultHandle doLoad(MethodContext context, MethodCreator method, ResultHandle array) {
                return method.load((short) param);
            }
        };
    } else if (expectedType == byte.class || expectedType == Byte.class || param instanceof Byte) {
        return new DeferredParameter() {

            @Override
            ResultHandle doLoad(MethodContext context, MethodCreator method, ResultHandle array) {
                return method.load((byte) param);
            }
        };
    } else if (expectedType == char.class || expectedType == Character.class || param instanceof Character) {
        return new DeferredParameter() {

            @Override
            ResultHandle doLoad(MethodContext context, MethodCreator method, ResultHandle array) {
                return method.load((char) param);
            }
        };
    } else if (expectedType == long.class || expectedType == Long.class || param instanceof Long) {
        return new DeferredParameter() {

            @Override
            ResultHandle doLoad(MethodContext context, MethodCreator method, ResultHandle array) {
                return method.load((long) param);
            }
        };
    } else if (expectedType == float.class || expectedType == Float.class || param instanceof Float) {
        return new DeferredParameter() {

            @Override
            ResultHandle doLoad(MethodContext context, MethodCreator method, ResultHandle array) {
                return method.load((float) param);
            }
        };
    } else if (expectedType == double.class || expectedType == Double.class || param instanceof Double) {
        return new DeferredParameter() {

            @Override
            ResultHandle doLoad(MethodContext context, MethodCreator method, ResultHandle array) {
                return method.load((double) param);
            }
        };
    } else if (expectedType.isArray()) {
        int length = Array.getLength(param);
        DeferredParameter[] components = new DeferredParameter[length];
        for (int i = 0; i < length; ++i) {
            DeferredParameter component = loadObjectInstance(Array.get(param, i), existing, expectedType.getComponentType(), relaxedValidation);
            components[i] = component;
        }
        return new DeferredArrayStoreParameter(param, expectedType) {

            @Override
            void doPrepare(MethodContext context) {
                for (int i = 0; i < length; ++i) {
                    components[i].prepare(context);
                }
                super.doPrepare(context);
            }

            @Override
            ResultHandle createValue(MethodContext context, MethodCreator method, ResultHandle array) {
                // TODO large arrays can still generate a fair bit of bytecode, and there appears to be a gizmo issue that prevents casting to an array
                // fix this later
                ResultHandle out = method.newArray(expectedType.getComponentType(), length);
                for (int i = 0; i < length; ++i) {
                    method.writeArrayValue(out, i, context.loadDeferred(components[i]));
                }
                return out;
            }
        };
    } else if (param instanceof AnnotationProxy) {
        // new com.foo.MyAnnotation_Proxy_AnnotationLiteral("foo")
        AnnotationProxy annotationProxy = (AnnotationProxy) param;
        List<MethodInfo> constructorParams = annotationProxy.getAnnotationClass().methods().stream().filter(m -> !m.name().equals("<clinit>") && !m.name().equals("<init>")).collect(Collectors.toList());
        Map<String, AnnotationValue> annotationValues = annotationProxy.getAnnotationInstance().values().stream().collect(Collectors.toMap(AnnotationValue::name, Function.identity()));
        DeferredParameter[] constructorParamsHandles = new DeferredParameter[constructorParams.size()];
        for (ListIterator<MethodInfo> iterator = constructorParams.listIterator(); iterator.hasNext(); ) {
            MethodInfo valueMethod = iterator.next();
            Object explicitValue = annotationProxy.getValues().get(valueMethod.name());
            if (explicitValue != null) {
                constructorParamsHandles[iterator.previousIndex()] = loadObjectInstance(explicitValue, existing, explicitValue.getClass(), relaxedValidation);
            } else {
                AnnotationValue value = annotationValues.get(valueMethod.name());
                if (value == null) {
                    // method.invokeInterfaceMethod(MAP_PUT, valuesHandle, method.load(entry.getKey()), loadObjectInstance(method, entry.getValue(),
                    // returnValueResults, entry.getValue().getClass()));
                    Object defaultValue = annotationProxy.getDefaultValues().get(valueMethod.name());
                    if (defaultValue != null) {
                        constructorParamsHandles[iterator.previousIndex()] = loadObjectInstance(defaultValue, existing, defaultValue.getClass(), relaxedValidation);
                        continue;
                    }
                    if (value == null) {
                        value = valueMethod.defaultValue();
                    }
                }
                if (value == null) {
                    throw new NullPointerException("Value not set for " + param);
                }
                DeferredParameter retValue = loadValue(value, annotationProxy.getAnnotationClass(), valueMethod);
                constructorParamsHandles[iterator.previousIndex()] = retValue;
            }
        }
        return new DeferredArrayStoreParameter(annotationProxy.getAnnotationLiteralType()) {

            @Override
            ResultHandle createValue(MethodContext context, MethodCreator method, ResultHandle array) {
                MethodDescriptor constructor = MethodDescriptor.ofConstructor(annotationProxy.getAnnotationLiteralType(), constructorParams.stream().map(m -> m.returnType().name().toString()).toArray());
                ResultHandle[] args = new ResultHandle[constructorParamsHandles.length];
                for (int i = 0; i < constructorParamsHandles.length; i++) {
                    DeferredParameter deferredParameter = constructorParamsHandles[i];
                    if (deferredParameter instanceof DeferredArrayStoreParameter) {
                        DeferredArrayStoreParameter arrayParam = (DeferredArrayStoreParameter) deferredParameter;
                        arrayParam.doPrepare(context);
                    }
                    args[i] = context.loadDeferred(deferredParameter);
                }
                return method.newInstance(constructor, args);
            }
        };
    } else {
        return loadComplexObject(param, existing, expectedType, relaxedValidation);
    }
}
Also used : Arrays(java.util.Arrays) Array(java.lang.reflect.Array) SortedSet(java.util.SortedSet) ListIterator(java.util.ListIterator) URL(java.net.URL) ClassOutput(io.quarkus.gizmo.ClassOutput) ClassInfo(org.jboss.jandex.ClassInfo) MethodInfo(org.jboss.jandex.MethodInfo) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) RecordableConstructor(io.quarkus.runtime.annotations.RecordableConstructor) Duration(java.time.Duration) Map(java.util.Map) BytecodeCreator(io.quarkus.gizmo.BytecodeCreator) StartupContext(io.quarkus.runtime.StartupContext) Method(java.lang.reflect.Method) AnnotationValue(org.jboss.jandex.AnnotationValue) Assert(org.wildfly.common.Assert) IdentityHashMap(java.util.IdentityHashMap) ProxyConfiguration(io.quarkus.deployment.proxy.ProxyConfiguration) Collection(java.util.Collection) Property(io.quarkus.deployment.recording.PropertyUtils.Property) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) Set(java.util.Set) NavigableSet(java.util.NavigableSet) QuarkusClassLoader(io.quarkus.bootstrap.classloading.QuarkusClassLoader) Collectors(java.util.stream.Collectors) ProxyFactory(io.quarkus.deployment.proxy.ProxyFactory) List(java.util.List) RelaxedValidation(io.quarkus.runtime.annotations.RelaxedValidation) Modifier(java.lang.reflect.Modifier) Annotation(java.lang.annotation.Annotation) Optional(java.util.Optional) IgnoreProperty(io.quarkus.runtime.annotations.IgnoreProperty) ArrayType(org.jboss.jandex.ArrayType) ResultHandle(io.quarkus.gizmo.ResultHandle) SortedMap(java.util.SortedMap) TryBlock(io.quarkus.gizmo.TryBlock) MethodDescriptor.ofConstructor(io.quarkus.gizmo.MethodDescriptor.ofConstructor) CatchBlockCreator(io.quarkus.gizmo.CatchBlockCreator) Proxy(java.lang.reflect.Proxy) MethodCreator(io.quarkus.gizmo.MethodCreator) Type(org.jboss.jandex.Type) HashMap(java.util.HashMap) MethodDescriptor.ofMethod(io.quarkus.gizmo.MethodDescriptor.ofMethod) ClassCreator(io.quarkus.gizmo.ClassCreator) Constructor(java.lang.reflect.Constructor) Function(java.util.function.Function) TreeSet(java.util.TreeSet) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) LinkedHashMap(java.util.LinkedHashMap) Inject(javax.inject.Inject) Parameter(java.lang.reflect.Parameter) RuntimeValue(io.quarkus.runtime.RuntimeValue) AssignableResultHandle(io.quarkus.gizmo.AssignableResultHandle) StartupTask(io.quarkus.runtime.StartupTask) LinkedHashSet(java.util.LinkedHashSet) MethodDescriptor(io.quarkus.gizmo.MethodDescriptor) MalformedURLException(java.net.MalformedURLException) Field(java.lang.reflect.Field) FieldDescriptor(io.quarkus.gizmo.FieldDescriptor) AbstractMap(java.util.AbstractMap) ParameterizedType(java.lang.reflect.ParameterizedType) TreeMap(java.util.TreeMap) Closeable(java.io.Closeable) InvocationHandler(java.lang.reflect.InvocationHandler) AnnotationProxy(io.quarkus.deployment.recording.AnnotationProxyProvider.AnnotationProxy) ObjectSubstitution(io.quarkus.runtime.ObjectSubstitution) Collections(java.util.Collections) MalformedURLException(java.net.MalformedURLException) TryBlock(io.quarkus.gizmo.TryBlock) URL(java.net.URL) AnnotationProxy(io.quarkus.deployment.recording.AnnotationProxyProvider.AnnotationProxy) ObjectSubstitution(io.quarkus.runtime.ObjectSubstitution) ResultHandle(io.quarkus.gizmo.ResultHandle) AssignableResultHandle(io.quarkus.gizmo.AssignableResultHandle) List(java.util.List) ArrayList(java.util.ArrayList) Optional(java.util.Optional) Duration(java.time.Duration) ListIterator(java.util.ListIterator) MethodDescriptor(io.quarkus.gizmo.MethodDescriptor) MalformedURLException(java.net.MalformedURLException) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) MethodCreator(io.quarkus.gizmo.MethodCreator) AnnotationValue(org.jboss.jandex.AnnotationValue) AssignableResultHandle(io.quarkus.gizmo.AssignableResultHandle) MethodInfo(org.jboss.jandex.MethodInfo) CatchBlockCreator(io.quarkus.gizmo.CatchBlockCreator) Map(java.util.Map) IdentityHashMap(java.util.IdentityHashMap) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) SortedMap(java.util.SortedMap) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) AbstractMap(java.util.AbstractMap) TreeMap(java.util.TreeMap)

Example 95 with Parameter

use of java.lang.reflect.Parameter in project quarkus by quarkusio.

the class ProxyFactory method doDefineClass.

private void doDefineClass() {
    try (ClassCreator cc = classBuilder.build()) {
        FieldDescriptor invocationHandlerField = cc.getFieldCreator("invocationHandler", InvocationHandler.class).setModifiers(Modifier.PRIVATE).getFieldDescriptor();
        try (MethodCreator ctor = cc.getMethodCreator(MethodDescriptor.ofConstructor(proxyName))) {
            ctor.invokeSpecialMethod(MethodDescriptor.ofConstructor(this.superClassName), ctor.getThis());
            ctor.writeInstanceField(invocationHandlerField, ctor.getThis(), ctor.loadNull());
            ctor.returnValue(null);
        }
        Class<?>[] parameterTypes = injectConstructor.getParameterTypes();
        List<Class<?>> args = new ArrayList<>();
        args.add(InvocationHandler.class);
        args.addAll(Arrays.asList(parameterTypes));
        try (MethodCreator ctor = cc.getMethodCreator(MethodDescriptor.ofConstructor(proxyName, args.toArray(Class[]::new)))) {
            List<ResultHandle> params = new ArrayList<>();
            for (int i = 0; i < injectConstructor.getParameterCount(); ++i) {
                params.add(ctor.getMethodParam(i + 1));
            }
            ctor.invokeSpecialMethod(MethodDescriptor.ofConstructor(injectConstructor.getDeclaringClass(), parameterTypes), ctor.getThis(), params.toArray(ResultHandle[]::new));
            ctor.writeInstanceField(invocationHandlerField, ctor.getThis(), ctor.getMethodParam(0));
            ctor.returnValue(null);
        }
        // proxy each method by forwarding to InvocationHandler
        for (Method methodInfo : methods) {
            try (MethodCreator mc = cc.getMethodCreator(toMethodDescriptor(methodInfo)).setModifiers(Modifier.PUBLIC)) {
                // method = clazz.getDeclaredMethod(...)
                ResultHandle getDeclaredMethodParamsArray = mc.newArray(Class.class, methodInfo.getParameterCount());
                if (methodInfo.getParameterCount() > 0) {
                    Parameter[] methodInfoParameters = methodInfo.getParameters();
                    for (int i = 0; i < methodInfo.getParameterCount(); i++) {
                        ResultHandle paramClass = mc.loadClassFromTCCL(methodInfoParameters[i].getType());
                        mc.writeArrayValue(getDeclaredMethodParamsArray, i, paramClass);
                    }
                }
                ResultHandle method = mc.invokeVirtualMethod(MethodDescriptor.ofMethod(Class.class, "getDeclaredMethod", Method.class, String.class, Class[].class), mc.loadClassFromTCCL(methodInfo.getDeclaringClass()), mc.load(methodInfo.getName()), getDeclaredMethodParamsArray);
                // result = invocationHandler.invoke(...)
                ResultHandle invokeParamsArray = mc.newArray(Object.class, methodInfo.getParameterCount());
                for (int i = 0; i < methodInfo.getParameterCount(); i++) {
                    mc.writeArrayValue(invokeParamsArray, i, mc.getMethodParam(i));
                }
                ResultHandle result = mc.invokeInterfaceMethod(MethodDescriptor.ofMethod(InvocationHandler.class, "invoke", Object.class, Object.class, Method.class, Object[].class), mc.readInstanceField(invocationHandlerField, mc.getThis()), mc.getThis(), method, invokeParamsArray);
                if (void.class.equals(methodInfo.getReturnType())) {
                    mc.returnValue(null);
                } else {
                    mc.returnValue(result);
                }
            }
        }
    }
}
Also used : ArrayList(java.util.ArrayList) Method(java.lang.reflect.Method) ClassCreator(io.quarkus.gizmo.ClassCreator) InvocationHandler(java.lang.reflect.InvocationHandler) FieldDescriptor(io.quarkus.gizmo.FieldDescriptor) MethodCreator(io.quarkus.gizmo.MethodCreator) Parameter(java.lang.reflect.Parameter) ResultHandle(io.quarkus.gizmo.ResultHandle)

Aggregations

Parameter (java.lang.reflect.Parameter)771 Method (java.lang.reflect.Method)276 ArrayList (java.util.ArrayList)142 Annotation (java.lang.annotation.Annotation)95 List (java.util.List)90 Type (java.lang.reflect.Type)77 HashMap (java.util.HashMap)75 Map (java.util.Map)72 Constructor (java.lang.reflect.Constructor)60 Test (org.junit.jupiter.api.Test)57 Arrays (java.util.Arrays)53 InvocationTargetException (java.lang.reflect.InvocationTargetException)52 Executable (java.lang.reflect.Executable)50 Field (java.lang.reflect.Field)45 Collectors (java.util.stream.Collectors)45 ParameterizedType (java.lang.reflect.ParameterizedType)42 Optional (java.util.Optional)42 Test (org.junit.Test)42 Set (java.util.Set)37 Modifier (java.lang.reflect.Modifier)29