Search in sources :

Example 1 with FunctionCreator

use of io.quarkus.gizmo.FunctionCreator in project quarkus by quarkusio.

the class AbstractMethodsAdder method generateFindQueryResultHandling.

protected void generateFindQueryResultHandling(MethodCreator methodCreator, ResultHandle panacheQuery, Integer pageableParameterIndex, ClassInfo repositoryClassInfo, ClassInfo entityClassInfo, DotName returnType, Integer limit, String methodName, DotName customResultType, String originalResultType) {
    ResultHandle page = null;
    if (limit != null) {
        // create a custom page object that will limit the results by the limit size
        page = methodCreator.newInstance(MethodDescriptor.ofConstructor(Page.class, int.class), methodCreator.load(limit));
    } else if (pageableParameterIndex != null) {
        page = methodCreator.invokeStaticMethod(MethodDescriptor.ofMethod(TypesConverter.class, "toPanachePage", Page.class, Pageable.class), methodCreator.getMethodParam(pageableParameterIndex));
    }
    if (page != null) {
        panacheQuery = methodCreator.invokeInterfaceMethod(MethodDescriptor.ofMethod(PanacheQuery.class, "page", PanacheQuery.class, Page.class), panacheQuery, page);
    }
    if (returnType.equals(entityClassInfo.name())) {
        // implement by issuing PanacheQuery.singleResult
        // if there is one result return
        // if there are no results (known due to NoResultException) return null
        // if there are multiple results just let the relevant exception be thrown
        // when limit is specified we don't want to fail when there are multiple results, we just want to return the first one
        String panacheQueryMethodToUse = (limit != null) ? "firstResult" : "singleResult";
        TryBlock tryBlock = methodCreator.tryBlock();
        ResultHandle singleResult = tryBlock.invokeInterfaceMethod(MethodDescriptor.ofMethod(PanacheQuery.class, panacheQueryMethodToUse, Object.class), panacheQuery);
        ResultHandle casted = tryBlock.checkCast(singleResult, entityClassInfo.name().toString());
        tryBlock.returnValue(casted);
        CatchBlockCreator catchBlock = tryBlock.addCatch(NoResultException.class);
        catchBlock.returnValue(catchBlock.loadNull());
    } else if (DotNames.OPTIONAL.equals(returnType)) {
        // implement by issuing PanacheQuery.singleResult
        // if there is one result return an Optional containing it
        // if there are no results (known due to NoResultException) return empty Optional
        // if there are multiple results just let the relevant exception be thrown
        // when limit is specified we don't want to fail when there are multiple results, we just want to return the first one
        String panacheQueryMethodToUse = (limit != null) ? "firstResult" : "singleResult";
        TryBlock tryBlock = methodCreator.tryBlock();
        ResultHandle singleResult = tryBlock.invokeInterfaceMethod(MethodDescriptor.ofMethod(PanacheQuery.class, panacheQueryMethodToUse, Object.class), panacheQuery);
        if (customResultType == null) {
            ResultHandle casted = tryBlock.checkCast(singleResult, entityClassInfo.name().toString());
            ResultHandle optional = tryBlock.invokeStaticMethod(MethodDescriptor.ofMethod(Optional.class, "of", Optional.class, Object.class), casted);
            tryBlock.returnValue(optional);
        } else {
            ResultHandle customResult = tryBlock.invokeStaticMethod(MethodDescriptor.ofMethod(customResultType.toString(), "convert_" + methodName, customResultType.toString(), originalResultType), singleResult);
            ResultHandle optional = tryBlock.invokeStaticMethod(MethodDescriptor.ofMethod(Optional.class, "of", Optional.class, Object.class), customResult);
            tryBlock.returnValue(optional);
        }
        CatchBlockCreator catchBlock = tryBlock.addCatch(NoResultException.class);
        ResultHandle emptyOptional = catchBlock.invokeStaticMethod(MethodDescriptor.ofMethod(Optional.class, "empty", Optional.class));
        catchBlock.returnValue(emptyOptional);
    } else if (DotNames.LIST.equals(returnType) || DotNames.COLLECTION.equals(returnType) || DotNames.SET.equals(returnType) || DotNames.ITERATOR.equals(returnType) || DotNames.SPRING_DATA_PAGE.equals(returnType) || DotNames.SPRING_DATA_SLICE.equals(returnType)) {
        ResultHandle list;
        if (customResultType == null) {
            list = methodCreator.invokeInterfaceMethod(MethodDescriptor.ofMethod(PanacheQuery.class, "list", List.class), panacheQuery);
        } else {
            ResultHandle stream = methodCreator.invokeInterfaceMethod(MethodDescriptor.ofMethod(PanacheQuery.class, "stream", Stream.class), panacheQuery);
            // Function to convert `originResultType` (Object[] or entity class)
            // to the custom type (using the generated static convert method)
            FunctionCreator customResultMappingFunction = methodCreator.createFunction(Function.class);
            BytecodeCreator funcBytecode = customResultMappingFunction.getBytecode();
            ResultHandle obj = funcBytecode.invokeStaticMethod(MethodDescriptor.ofMethod(customResultType.toString(), "convert_" + methodName, customResultType.toString(), originalResultType), funcBytecode.getMethodParam(0));
            funcBytecode.returnValue(obj);
            stream = methodCreator.invokeInterfaceMethod(MethodDescriptor.ofMethod(Stream.class, "map", Stream.class, Function.class), stream, customResultMappingFunction.getInstance());
            // Re-collect the stream into a list
            ResultHandle collector = methodCreator.invokeStaticMethod(MethodDescriptor.ofMethod(Collectors.class, "toList", Collector.class));
            list = methodCreator.invokeInterfaceMethod(MethodDescriptor.ofMethod(Stream.class, "collect", Object.class, Collector.class), stream, collector);
        }
        if (DotNames.ITERATOR.equals(returnType)) {
            ResultHandle iterator = methodCreator.invokeInterfaceMethod(MethodDescriptor.ofMethod(Iterable.class, "iterator", Iterator.class), list);
            methodCreator.returnValue(iterator);
        } else if (DotNames.SET.equals(returnType)) {
            ResultHandle set = methodCreator.newInstance(MethodDescriptor.ofConstructor(LinkedHashSet.class, Collection.class), list);
            methodCreator.returnValue(set);
        } else if (DotNames.SPRING_DATA_PAGE.equals(returnType)) {
            ResultHandle pageResult;
            if (pageableParameterIndex != null) {
                ResultHandle count = methodCreator.invokeInterfaceMethod(MethodDescriptor.ofMethod(PanacheQuery.class, "count", long.class), panacheQuery);
                pageResult = methodCreator.newInstance(MethodDescriptor.ofConstructor(PageImpl.class, List.class, Pageable.class, long.class), list, methodCreator.getMethodParam(pageableParameterIndex), count);
            } else {
                pageResult = methodCreator.newInstance(MethodDescriptor.ofConstructor(PageImpl.class, List.class), list);
            }
            methodCreator.returnValue(pageResult);
        } else if (DotNames.SPRING_DATA_SLICE.equals(returnType)) {
            ResultHandle sliceResult;
            if (pageableParameterIndex != null) {
                ResultHandle hasNextPage = methodCreator.invokeInterfaceMethod(MethodDescriptor.ofMethod(PanacheQuery.class, "hasNextPage", boolean.class), panacheQuery);
                sliceResult = methodCreator.newInstance(MethodDescriptor.ofConstructor(SliceImpl.class, List.class, Pageable.class, boolean.class), list, methodCreator.getMethodParam(pageableParameterIndex), hasNextPage);
            } else {
                sliceResult = methodCreator.newInstance(MethodDescriptor.ofConstructor(SliceImpl.class, List.class), list);
            }
            methodCreator.returnValue(sliceResult);
        }
        methodCreator.returnValue(list);
    } else if (DotNames.STREAM.equals(returnType)) {
        ResultHandle stream = methodCreator.invokeInterfaceMethod(MethodDescriptor.ofMethod(PanacheQuery.class, "stream", Stream.class), panacheQuery);
        methodCreator.returnValue(stream);
    } else if (isHibernateSupportedReturnType(returnType)) {
        ResultHandle singleResult = methodCreator.invokeInterfaceMethod(MethodDescriptor.ofMethod(PanacheQuery.class, "singleResult", Object.class), panacheQuery);
        methodCreator.returnValue(singleResult);
    } else if (customResultType != null) {
        // when limit is specified we don't want to fail when there are multiple results, we just want to return the first one
        String panacheQueryMethodToUse = (limit != null) ? "firstResult" : "singleResult";
        TryBlock tryBlock = methodCreator.tryBlock();
        ResultHandle singleResult = tryBlock.invokeInterfaceMethod(MethodDescriptor.ofMethod(PanacheQuery.class, panacheQueryMethodToUse, Object.class), panacheQuery);
        ResultHandle customResult = tryBlock.invokeStaticMethod(MethodDescriptor.ofMethod(customResultType.toString(), "convert_" + methodName, customResultType.toString(), originalResultType), singleResult);
        tryBlock.returnValue(customResult);
        CatchBlockCreator catchBlock = tryBlock.addCatch(NoResultException.class);
        catchBlock.returnValue(catchBlock.loadNull());
        tryBlock.returnValue(customResult);
    } else {
        throw new IllegalArgumentException("Return type of method " + methodName + " of Repository " + repositoryClassInfo + " does not match find query type");
    }
}
Also used : Collectors(java.util.stream.Collectors) FunctionCreator(io.quarkus.gizmo.FunctionCreator) PanacheQuery(io.quarkus.hibernate.orm.panache.PanacheQuery) Page(io.quarkus.panache.common.Page) TryBlock(io.quarkus.gizmo.TryBlock) BytecodeCreator(io.quarkus.gizmo.BytecodeCreator) NoResultException(javax.persistence.NoResultException) SliceImpl(org.springframework.data.domain.SliceImpl) Pageable(org.springframework.data.domain.Pageable) Collector(java.util.stream.Collector) Iterator(java.util.Iterator) TypesConverter(io.quarkus.spring.data.runtime.TypesConverter) ResultHandle(io.quarkus.gizmo.ResultHandle) Stream(java.util.stream.Stream) List(java.util.List) CatchBlockCreator(io.quarkus.gizmo.CatchBlockCreator)

Example 2 with FunctionCreator

use of io.quarkus.gizmo.FunctionCreator in project quarkus by quarkusio.

the class BeanGenerator method implementCreateForClassBean.

void implementCreateForClassBean(ClassOutput classOutput, ClassCreator beanCreator, BeanInfo bean, ProviderType providerType, String baseName, Map<InjectionPointInfo, String> injectionPointToProviderSupplierField, Map<InterceptorInfo, String> interceptorToProviderSupplierField, Map<DecoratorInfo, String> decoratorToProviderSupplierField, ReflectionRegistration reflectionRegistration, String targetPackage, boolean isApplicationClass, MethodCreator create) {
    AssignableResultHandle instanceHandle;
    List<Injection> methodInjections = new ArrayList<>();
    List<Injection> fieldInjections = new ArrayList<>();
    for (Injection injection : bean.getInjections()) {
        if (injection.isField()) {
            fieldInjections.add(injection);
        } else if (injection.isMethod() && !injection.isConstructor()) {
            methodInjections.add(injection);
        }
    }
    ResultHandle postConstructsHandle = null;
    ResultHandle aroundConstructsHandle = null;
    Map<InterceptorInfo, ResultHandle> interceptorToWrap = new HashMap<>();
    if (bean.hasLifecycleInterceptors()) {
        // Note that we must share the interceptors instances with the intercepted subclass, if present
        InterceptionInfo postConstructs = bean.getLifecycleInterceptors(InterceptionType.POST_CONSTRUCT);
        InterceptionInfo aroundConstructs = bean.getLifecycleInterceptors(InterceptionType.AROUND_CONSTRUCT);
        // Wrap InjectableInterceptors using InitializedInterceptor
        Set<InterceptorInfo> wraps = new HashSet<>();
        wraps.addAll(aroundConstructs.interceptors);
        wraps.addAll(postConstructs.interceptors);
        // instances of around/post construct interceptors also need to be shared
        // build a map that links InterceptorInfo to ResultHandle and reuse that when creating wrappers
        Map<InterceptorInfo, ResultHandle> interceptorToResultHandle = new HashMap<>();
        for (InterceptorInfo interceptor : wraps) {
            ResultHandle interceptorProviderSupplier = create.readInstanceField(FieldDescriptor.of(beanCreator.getClassName(), interceptorToProviderSupplierField.get(interceptor), Supplier.class.getName()), create.getThis());
            ResultHandle interceptorProvider = create.invokeInterfaceMethod(MethodDescriptors.SUPPLIER_GET, interceptorProviderSupplier);
            ResultHandle childCtxHandle = create.invokeStaticMethod(MethodDescriptors.CREATIONAL_CTX_CHILD, create.getMethodParam(0));
            ResultHandle interceptorInstanceHandle = create.invokeInterfaceMethod(MethodDescriptors.INJECTABLE_REF_PROVIDER_GET, interceptorProvider, childCtxHandle);
            interceptorToResultHandle.put(interceptor, interceptorInstanceHandle);
            ResultHandle wrapHandle = create.invokeStaticMethod(MethodDescriptor.ofMethod(InitializedInterceptor.class, "of", InitializedInterceptor.class, Object.class, InjectableInterceptor.class), interceptorInstanceHandle, interceptorProvider);
            interceptorToWrap.put(interceptor, wrapHandle);
        }
        if (!postConstructs.isEmpty()) {
            // postConstructs = new ArrayList<InterceptorInvocation>()
            postConstructsHandle = create.newInstance(MethodDescriptor.ofConstructor(ArrayList.class));
            for (InterceptorInfo interceptor : postConstructs.interceptors) {
                ResultHandle interceptorSupplierHandle = create.readInstanceField(FieldDescriptor.of(beanCreator.getClassName(), interceptorToProviderSupplierField.get(interceptor), Supplier.class.getName()), create.getThis());
                ResultHandle interceptorHandle = create.invokeInterfaceMethod(MethodDescriptors.SUPPLIER_GET, interceptorSupplierHandle);
                ResultHandle interceptorInvocationHandle = create.invokeStaticMethod(MethodDescriptors.INTERCEPTOR_INVOCATION_POST_CONSTRUCT, interceptorHandle, interceptorToResultHandle.get(interceptor));
                // postConstructs.add(InterceptorInvocation.postConstruct(interceptor,interceptor.get(CreationalContextImpl.child(ctx))))
                create.invokeInterfaceMethod(MethodDescriptors.LIST_ADD, postConstructsHandle, interceptorInvocationHandle);
            }
        }
        if (!aroundConstructs.isEmpty()) {
            // aroundConstructs = new ArrayList<InterceptorInvocation>()
            aroundConstructsHandle = create.newInstance(MethodDescriptor.ofConstructor(ArrayList.class));
            for (InterceptorInfo interceptor : aroundConstructs.interceptors) {
                ResultHandle interceptorSupplierHandle = create.readInstanceField(FieldDescriptor.of(beanCreator.getClassName(), interceptorToProviderSupplierField.get(interceptor), Supplier.class.getName()), create.getThis());
                ResultHandle interceptorHandle = create.invokeInterfaceMethod(MethodDescriptors.SUPPLIER_GET, interceptorSupplierHandle);
                ResultHandle interceptorInvocationHandle = create.invokeStaticMethod(MethodDescriptors.INTERCEPTOR_INVOCATION_AROUND_CONSTRUCT, interceptorHandle, interceptorToResultHandle.get(interceptor));
                // aroundConstructs.add(InterceptorInvocation.aroundConstruct(interceptor,interceptor.get(CreationalContextImpl.child(ctx))))
                create.invokeInterfaceMethod(MethodDescriptors.LIST_ADD, aroundConstructsHandle, interceptorInvocationHandle);
            }
        }
    }
    // AroundConstruct lifecycle callback interceptors
    InterceptionInfo aroundConstructs = bean.getLifecycleInterceptors(InterceptionType.AROUND_CONSTRUCT);
    instanceHandle = create.createVariable(DescriptorUtils.extToInt(providerType.className()));
    if (!aroundConstructs.isEmpty()) {
        Optional<Injection> constructorInjection = bean.getConstructorInjection();
        ResultHandle constructorHandle;
        if (constructorInjection.isPresent()) {
            List<String> paramTypes = new ArrayList<>();
            for (InjectionPointInfo injectionPoint : constructorInjection.get().injectionPoints) {
                paramTypes.add(injectionPoint.getType().name().toString());
            }
            ResultHandle[] paramsHandles = new ResultHandle[2];
            paramsHandles[0] = create.loadClass(providerType.className());
            ResultHandle paramsArray = create.newArray(Class.class, create.load(paramTypes.size()));
            for (ListIterator<String> iterator = paramTypes.listIterator(); iterator.hasNext(); ) {
                create.writeArrayValue(paramsArray, iterator.nextIndex(), create.loadClass(iterator.next()));
            }
            paramsHandles[1] = paramsArray;
            constructorHandle = create.invokeStaticMethod(MethodDescriptors.REFLECTIONS_FIND_CONSTRUCTOR, paramsHandles);
            reflectionRegistration.registerMethod(constructorInjection.get().target.asMethod());
        } else {
            // constructor = Reflections.findConstructor(Foo.class)
            ResultHandle[] paramsHandles = new ResultHandle[2];
            paramsHandles[0] = create.loadClass(providerType.className());
            paramsHandles[1] = create.newArray(Class.class, create.load(0));
            constructorHandle = create.invokeStaticMethod(MethodDescriptors.REFLECTIONS_FIND_CONSTRUCTOR, paramsHandles);
            MethodInfo noArgsConstructor = bean.getTarget().get().asClass().method(Methods.INIT);
            reflectionRegistration.registerMethod(noArgsConstructor);
        }
        List<TransientReference> transientReferences = new ArrayList<>();
        List<ResultHandle> providerHandles = newProviderHandles(bean, beanCreator, create, injectionPointToProviderSupplierField, interceptorToProviderSupplierField, decoratorToProviderSupplierField, interceptorToWrap, transientReferences);
        // Forwarding function
        // Supplier<Object> forward = () -> new SimpleBean_Subclass(ctx,lifecycleInterceptorProvider1)
        FunctionCreator func = create.createFunction(Supplier.class);
        BytecodeCreator funcBytecode = func.getBytecode();
        ResultHandle retHandle = newInstanceHandle(bean, beanCreator, funcBytecode, create, providerType.className(), baseName, providerHandles, reflectionRegistration, isApplicationClass);
        // Destroy injected transient references
        destroyTransientReferences(funcBytecode, transientReferences);
        funcBytecode.returnValue(retHandle);
        // Interceptor bindings
        ResultHandle bindingsArray = create.newArray(Object.class, aroundConstructs.bindings.size());
        int bindingsIndex = 0;
        for (AnnotationInstance binding : aroundConstructs.bindings) {
            // Create annotation literals first
            ClassInfo bindingClass = bean.getDeployment().getInterceptorBinding(binding.name());
            create.writeArrayValue(bindingsArray, bindingsIndex++, annotationLiterals.process(create, classOutput, bindingClass, binding, Types.getPackageName(beanCreator.getClassName())));
        }
        ResultHandle invocationContextHandle = create.invokeStaticMethod(MethodDescriptors.INVOCATION_CONTEXTS_AROUND_CONSTRUCT, constructorHandle, aroundConstructsHandle, func.getInstance(), create.invokeStaticMethod(MethodDescriptors.SETS_OF, bindingsArray));
        TryBlock tryCatch = create.tryBlock();
        CatchBlockCreator exceptionCatch = tryCatch.addCatch(Exception.class);
        // throw new RuntimeException(e)
        exceptionCatch.throwException(RuntimeException.class, "Error invoking aroundConstructs", exceptionCatch.getCaughtException());
        // InvocationContextImpl.aroundConstruct(constructor,aroundConstructs,forward).proceed()
        tryCatch.invokeInterfaceMethod(MethodDescriptors.INVOCATION_CONTEXT_PROCEED, invocationContextHandle);
        // instance = InvocationContext.getTarget()
        tryCatch.assign(instanceHandle, tryCatch.invokeInterfaceMethod(MethodDescriptors.INVOCATION_CONTEXT_GET_TARGET, invocationContextHandle));
    } else {
        List<TransientReference> transientReferences = new ArrayList<>();
        create.assign(instanceHandle, newInstanceHandle(bean, beanCreator, create, create, providerType.className(), baseName, newProviderHandles(bean, beanCreator, create, injectionPointToProviderSupplierField, interceptorToProviderSupplierField, decoratorToProviderSupplierField, interceptorToWrap, transientReferences), reflectionRegistration, isApplicationClass));
        // Destroy injected transient references
        destroyTransientReferences(create, transientReferences);
    }
    // Perform field and initializer injections
    for (Injection fieldInjection : fieldInjections) {
        TryBlock tryBlock = create.tryBlock();
        InjectionPointInfo injectionPoint = fieldInjection.injectionPoints.get(0);
        ResultHandle providerSupplierHandle = tryBlock.readInstanceField(FieldDescriptor.of(beanCreator.getClassName(), injectionPointToProviderSupplierField.get(injectionPoint), Supplier.class.getName()), tryBlock.getThis());
        ResultHandle providerHandle = tryBlock.invokeInterfaceMethod(MethodDescriptors.SUPPLIER_GET, providerSupplierHandle);
        ResultHandle childCtxHandle = tryBlock.invokeStaticMethod(MethodDescriptors.CREATIONAL_CTX_CHILD_CONTEXTUAL, providerHandle, tryBlock.getMethodParam(0));
        ResultHandle referenceHandle = tryBlock.invokeInterfaceMethod(MethodDescriptors.INJECTABLE_REF_PROVIDER_GET, providerHandle, childCtxHandle);
        FieldInfo injectedField = fieldInjection.target.asField();
        if (isReflectionFallbackNeeded(injectedField, targetPackage)) {
            if (Modifier.isPrivate(injectedField.flags())) {
                privateMembers.add(isApplicationClass, String.format("@Inject field %s#%s", fieldInjection.target.asField().declaringClass().name(), fieldInjection.target.asField().name()));
            }
            reflectionRegistration.registerField(injectedField);
            tryBlock.invokeStaticMethod(MethodDescriptors.REFLECTIONS_WRITE_FIELD, tryBlock.loadClass(injectedField.declaringClass().name().toString()), tryBlock.load(injectedField.name()), instanceHandle, referenceHandle);
        } else {
            // We cannot use injectionPoint.getRequiredType() because it might be a resolved parameterize type and we could get NoSuchFieldError
            tryBlock.writeInstanceField(FieldDescriptor.of(injectedField.declaringClass().name().toString(), injectedField.name(), DescriptorUtils.typeToString(injectionPoint.getTarget().asField().type())), instanceHandle, referenceHandle);
        }
        CatchBlockCreator catchBlock = tryBlock.addCatch(RuntimeException.class);
        catchBlock.throwException(RuntimeException.class, "Error injecting " + fieldInjection.target, catchBlock.getCaughtException());
    }
    for (Injection methodInjection : methodInjections) {
        List<TransientReference> transientReferences = new ArrayList<>();
        ResultHandle[] referenceHandles = new ResultHandle[methodInjection.injectionPoints.size()];
        int paramIdx = 0;
        for (InjectionPointInfo injectionPoint : methodInjection.injectionPoints) {
            ResultHandle providerSupplierHandle = create.readInstanceField(FieldDescriptor.of(beanCreator.getClassName(), injectionPointToProviderSupplierField.get(injectionPoint), Supplier.class.getName()), create.getThis());
            ResultHandle providerHandle = create.invokeInterfaceMethod(MethodDescriptors.SUPPLIER_GET, providerSupplierHandle);
            ResultHandle childCtxHandle = create.invokeStaticMethod(MethodDescriptors.CREATIONAL_CTX_CHILD_CONTEXTUAL, providerHandle, create.getMethodParam(0));
            ResultHandle referenceHandle = create.invokeInterfaceMethod(MethodDescriptors.INJECTABLE_REF_PROVIDER_GET, providerHandle, childCtxHandle);
            referenceHandles[paramIdx++] = referenceHandle;
            // We need to destroy dependent beans for @TransientReference injection points
            if (injectionPoint.isDependentTransientReference()) {
                transientReferences.add(new TransientReference(providerHandle, referenceHandle, childCtxHandle));
            }
        }
        MethodInfo initializerMethod = methodInjection.target.asMethod();
        if (isReflectionFallbackNeeded(initializerMethod, targetPackage)) {
            if (Modifier.isPrivate(initializerMethod.flags())) {
                privateMembers.add(isApplicationClass, String.format("@Inject initializer %s#%s()", initializerMethod.declaringClass().name(), initializerMethod.name()));
            }
            ResultHandle paramTypesArray = create.newArray(Class.class, create.load(referenceHandles.length));
            ResultHandle argsArray = create.newArray(Object.class, create.load(referenceHandles.length));
            for (int i = 0; i < referenceHandles.length; i++) {
                create.writeArrayValue(paramTypesArray, i, create.loadClass(initializerMethod.parameters().get(i).name().toString()));
                create.writeArrayValue(argsArray, i, referenceHandles[i]);
            }
            reflectionRegistration.registerMethod(initializerMethod);
            create.invokeStaticMethod(MethodDescriptors.REFLECTIONS_INVOKE_METHOD, create.loadClass(initializerMethod.declaringClass().name().toString()), create.load(methodInjection.target.asMethod().name()), paramTypesArray, instanceHandle, argsArray);
        } else {
            create.invokeVirtualMethod(MethodDescriptor.of(methodInjection.target.asMethod()), instanceHandle, referenceHandles);
        }
        // Destroy injected transient references
        destroyTransientReferences(create, transientReferences);
    }
    // PostConstruct lifecycle callback interceptors
    InterceptionInfo postConstructs = bean.getLifecycleInterceptors(InterceptionType.POST_CONSTRUCT);
    if (!postConstructs.isEmpty()) {
        // Interceptor bindings
        ResultHandle bindingsArray = create.newArray(Object.class, postConstructs.bindings.size());
        int bindingsIndex = 0;
        for (AnnotationInstance binding : postConstructs.bindings) {
            // Create annotation literals first
            ClassInfo bindingClass = bean.getDeployment().getInterceptorBinding(binding.name());
            create.writeArrayValue(bindingsArray, bindingsIndex++, annotationLiterals.process(create, classOutput, bindingClass, binding, Types.getPackageName(beanCreator.getClassName())));
        }
        // InvocationContextImpl.postConstruct(instance,postConstructs).proceed()
        ResultHandle invocationContextHandle = create.invokeStaticMethod(MethodDescriptors.INVOCATION_CONTEXTS_POST_CONSTRUCT, instanceHandle, postConstructsHandle, create.invokeStaticMethod(MethodDescriptors.SETS_OF, bindingsArray));
        TryBlock tryCatch = create.tryBlock();
        CatchBlockCreator exceptionCatch = tryCatch.addCatch(Exception.class);
        // throw new RuntimeException(e)
        exceptionCatch.throwException(RuntimeException.class, "Error invoking postConstructs", exceptionCatch.getCaughtException());
        tryCatch.invokeInterfaceMethod(MethodDescriptor.ofMethod(InvocationContext.class, "proceed", Object.class), invocationContextHandle);
    }
    // PostConstruct callbacks
    if (!bean.isInterceptor()) {
        List<MethodInfo> postConstructCallbacks = Beans.getCallbacks(bean.getTarget().get().asClass(), DotNames.POST_CONSTRUCT, bean.getDeployment().getBeanArchiveIndex());
        for (MethodInfo callback : postConstructCallbacks) {
            if (isReflectionFallbackNeeded(callback, targetPackage)) {
                if (Modifier.isPrivate(callback.flags())) {
                    privateMembers.add(isApplicationClass, String.format("@PostConstruct callback %s#%s()", callback.declaringClass().name(), callback.name()));
                }
                reflectionRegistration.registerMethod(callback);
                create.invokeStaticMethod(MethodDescriptors.REFLECTIONS_INVOKE_METHOD, create.loadClass(callback.declaringClass().name().toString()), create.load(callback.name()), create.newArray(Class.class, create.load(0)), instanceHandle, create.newArray(Object.class, create.load(0)));
            } else {
                create.invokeVirtualMethod(MethodDescriptor.of(callback), instanceHandle);
            }
        }
    }
    create.returnValue(instanceHandle);
}
Also used : FunctionCreator(io.quarkus.gizmo.FunctionCreator) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) TryBlock(io.quarkus.gizmo.TryBlock) InjectableInterceptor(io.quarkus.arc.InjectableInterceptor) ResultHandle(io.quarkus.gizmo.ResultHandle) AssignableResultHandle(io.quarkus.gizmo.AssignableResultHandle) InvocationContext(javax.interceptor.InvocationContext) InitializedInterceptor(io.quarkus.arc.impl.InitializedInterceptor) HashSet(java.util.HashSet) BytecodeCreator(io.quarkus.gizmo.BytecodeCreator) InterceptionInfo(io.quarkus.arc.processor.BeanInfo.InterceptionInfo) AssignableResultHandle(io.quarkus.gizmo.AssignableResultHandle) MethodInfo(org.jboss.jandex.MethodInfo) CatchBlockCreator(io.quarkus.gizmo.CatchBlockCreator) AnnotationInstance(org.jboss.jandex.AnnotationInstance) FieldInfo(org.jboss.jandex.FieldInfo) ClassInfo(org.jboss.jandex.ClassInfo)

Example 3 with FunctionCreator

use of io.quarkus.gizmo.FunctionCreator in project quarkus by quarkusio.

the class SubclassGenerator method createInterceptedMethod.

private void createInterceptedMethod(ClassOutput classOutput, BeanInfo bean, MethodInfo method, ClassCreator subclass, String providerTypeName, FieldDescriptor metadataField, FieldDescriptor constructedField, MethodDescriptor forwardMethod, DecoratorInfo decorator) {
    MethodDescriptor originalMethodDescriptor = MethodDescriptor.of(method);
    MethodCreator interceptedMethod = subclass.getMethodCreator(originalMethodDescriptor);
    // Params
    // Object[] params = new Object[] {p1}
    List<Type> parameters = method.parameters();
    ResultHandle paramsHandle;
    if (parameters.isEmpty()) {
        paramsHandle = interceptedMethod.loadNull();
    } else {
        paramsHandle = interceptedMethod.newArray(Object.class, interceptedMethod.load(parameters.size()));
        for (int i = 0; i < parameters.size(); i++) {
            interceptedMethod.writeArrayValue(paramsHandle, i, interceptedMethod.getMethodParam(i));
        }
    }
    // Delegate to super class if not constructed yet
    BytecodeCreator notConstructed = interceptedMethod.ifFalse(interceptedMethod.readInstanceField(constructedField, interceptedMethod.getThis())).trueBranch();
    ResultHandle[] params = new ResultHandle[parameters.size()];
    for (int i = 0; i < parameters.size(); ++i) {
        params[i] = notConstructed.getMethodParam(i);
    }
    if (Modifier.isAbstract(method.flags())) {
        notConstructed.throwException(IllegalStateException.class, "Cannot delegate to an abstract method");
    } else {
        notConstructed.returnValue(notConstructed.invokeVirtualMethod(forwardMethod, notConstructed.getThis(), params));
    }
    ResultHandle decoratorHandle = null;
    if (decorator != null) {
        decoratorHandle = interceptedMethod.readInstanceField(FieldDescriptor.of(subclass.getClassName(), decorator.getIdentifier(), Object.class.getName()), interceptedMethod.getThis());
    }
    // Forwarding function
    // Function<InvocationContext, Object> forward = ctx -> super.foo((java.lang.String)ctx.getParameters()[0])
    FunctionCreator func = interceptedMethod.createFunction(Function.class);
    BytecodeCreator funcBytecode = func.getBytecode();
    ResultHandle ctxHandle = funcBytecode.getMethodParam(0);
    ResultHandle[] superParamHandles;
    if (parameters.isEmpty()) {
        superParamHandles = new ResultHandle[0];
    } else {
        superParamHandles = new ResultHandle[parameters.size()];
        ResultHandle ctxParamsHandle = funcBytecode.invokeInterfaceMethod(MethodDescriptor.ofMethod(InvocationContext.class, "getParameters", Object[].class), ctxHandle);
        // autoboxing is handled inside Gizmo
        for (int i = 0; i < superParamHandles.length; i++) {
            superParamHandles[i] = funcBytecode.readArrayValue(ctxParamsHandle, i);
        }
    }
    // If a decorator is bound then invoke the method upon the decorator instance instead of the generated forwarding method
    if (decorator != null) {
        AssignableResultHandle funDecoratorInstance = funcBytecode.createVariable(Object.class);
        funcBytecode.assign(funDecoratorInstance, decoratorHandle);
        String declaringClass = decorator.getBeanClass().toString();
        if (decorator.isAbstract()) {
            String baseName = DecoratorGenerator.createBaseName(decorator.getTarget().get().asClass());
            String targetPackage = DotNames.packageName(decorator.getProviderType().name());
            declaringClass = generatedNameFromTarget(targetPackage, baseName, DecoratorGenerator.ABSTRACT_IMPL_SUFFIX);
        }
        MethodDescriptor methodDescriptor = MethodDescriptor.ofMethod(declaringClass, originalMethodDescriptor.getName(), originalMethodDescriptor.getReturnType(), originalMethodDescriptor.getParameterTypes());
        funcBytecode.returnValue(funcBytecode.invokeVirtualMethod(methodDescriptor, funDecoratorInstance, superParamHandles));
    } else {
        ResultHandle superResult = funcBytecode.invokeVirtualMethod(forwardMethod, interceptedMethod.getThis(), superParamHandles);
        funcBytecode.returnValue(superResult != null ? superResult : funcBytecode.loadNull());
    }
    for (Type declaredException : method.exceptions()) {
        interceptedMethod.addException(declaredException.name().toString());
    }
    TryBlock tryCatch = interceptedMethod.tryBlock();
    // catch exceptions declared on the original method
    boolean addCatchRuntimeException = true;
    boolean addCatchException = true;
    boolean isKotlin = method.declaringClass().classAnnotation(DotNames.KOTLIN_METADATA_ANNOTATION) != null;
    Set<DotName> declaredExceptions = new LinkedHashSet<>(method.exceptions().size());
    for (Type declaredException : method.exceptions()) {
        declaredExceptions.add(declaredException.name());
    }
    for (DotName declaredException : declaredExceptions) {
        CatchBlockCreator catchDeclaredException = tryCatch.addCatch(declaredException.toString());
        catchDeclaredException.throwException(catchDeclaredException.getCaughtException());
        if (JAVA_LANG_RUNTIME_EXCEPTION.equals(declaredException) || JAVA_LANG_THROWABLE.equals(declaredException)) {
            addCatchRuntimeException = false;
        }
        if (JAVA_LANG_EXCEPTION.equals(declaredException) || JAVA_LANG_THROWABLE.equals(declaredException)) {
            addCatchException = false;
        }
    }
    // catch (RuntimeException e) if not already caught
    if (addCatchRuntimeException) {
        CatchBlockCreator catchRuntimeException = tryCatch.addCatch(RuntimeException.class);
        catchRuntimeException.throwException(catchRuntimeException.getCaughtException());
    }
    // this catch is _not_ included for Kotlin methods because Kotlin has not checked exceptions contract
    if (addCatchException && !isKotlin) {
        CatchBlockCreator catchOtherExceptions = tryCatch.addCatch(Exception.class);
        // and wrap them in a new RuntimeException(e)
        catchOtherExceptions.throwException(ArcUndeclaredThrowableException.class, "Error invoking subclass method", catchOtherExceptions.getCaughtException());
    }
    // InvocationContexts.performAroundInvoke(...)
    ResultHandle methodMetadataHandle = tryCatch.readInstanceField(metadataField, tryCatch.getThis());
    ResultHandle ret = tryCatch.invokeStaticMethod(MethodDescriptors.INVOCATION_CONTEXTS_PERFORM_AROUND_INVOKE, tryCatch.getThis(), tryCatch.readInstanceField(FIELD_METADATA_METHOD, methodMetadataHandle), func.getInstance(), paramsHandle, tryCatch.readInstanceField(FIELD_METADATA_CHAIN, methodMetadataHandle), tryCatch.readInstanceField(FIELD_METADATA_BINDINGS, methodMetadataHandle));
    tryCatch.returnValue(ret);
}
Also used : LinkedHashSet(java.util.LinkedHashSet) FunctionCreator(io.quarkus.gizmo.FunctionCreator) BytecodeCreator(io.quarkus.gizmo.BytecodeCreator) TryBlock(io.quarkus.gizmo.TryBlock) MethodDescriptor(io.quarkus.gizmo.MethodDescriptor) DotName(org.jboss.jandex.DotName) SpecialType(io.quarkus.arc.processor.ResourceOutput.Resource.SpecialType) Type(org.jboss.jandex.Type) InterceptionType(javax.enterprise.inject.spi.InterceptionType) MethodCreator(io.quarkus.gizmo.MethodCreator) ResultHandle(io.quarkus.gizmo.ResultHandle) AssignableResultHandle(io.quarkus.gizmo.AssignableResultHandle) AssignableResultHandle(io.quarkus.gizmo.AssignableResultHandle) CatchBlockCreator(io.quarkus.gizmo.CatchBlockCreator) InvocationContext(javax.interceptor.InvocationContext)

Example 4 with FunctionCreator

use of io.quarkus.gizmo.FunctionCreator in project quarkus by quarkusio.

the class ExtensionMethodGenerator method implementResolve.

private void implementResolve(ClassCreator valueResolver, ClassInfo declaringClass, MethodInfo method, String matchName, FieldDescriptor patternField, Parameters params) {
    MethodCreator resolve = valueResolver.getMethodCreator("resolve", CompletionStage.class, EvalContext.class).setModifiers(ACC_PUBLIC);
    ResultHandle evalContext = resolve.getMethodParam(0);
    ResultHandle base = resolve.invokeInterfaceMethod(Descriptors.GET_BASE, evalContext);
    boolean matchAnyOrRegex = patternField != null || matchName.equals(TemplateExtension.ANY);
    boolean returnsCompletionStage = method.returnType().kind() != Kind.PRIMITIVE && ValueResolverGenerator.hasCompletionStageInTypeClosure(index.getClassByName(method.returnType().name()), index);
    ResultHandle ret;
    if (!params.needsEvaluation()) {
        // No parameter needs to be evaluated
        ResultHandle[] args = new ResultHandle[params.size()];
        for (int i = 0; i < params.size(); i++) {
            Param param = params.get(i);
            if (param.kind == ParamKind.BASE) {
                args[i] = base;
            } else if (param.kind == ParamKind.NAME) {
                args[i] = resolve.invokeInterfaceMethod(Descriptors.GET_NAME, evalContext);
            } else if (param.kind == ParamKind.ATTR) {
                args[i] = resolve.invokeInterfaceMethod(Descriptors.GET_ATTRIBUTE, evalContext, resolve.load(param.name));
            }
        }
        // Invoke the extension method
        ResultHandle result = resolve.invokeStaticMethod(MethodDescriptor.ofMethod(declaringClass.name().toString(), method.name(), method.returnType().name().toString(), params.parameterTypesAsStringArray()), args);
        if (returnsCompletionStage) {
            ret = result;
        } else {
            ret = resolve.invokeStaticMethod(Descriptors.COMPLETED_STAGE, result);
        }
    } else {
        ret = resolve.newInstance(MethodDescriptor.ofConstructor(CompletableFuture.class));
        // Evaluate params first
        ResultHandle name = resolve.invokeInterfaceMethod(Descriptors.GET_NAME, evalContext);
        // The CompletionStage upon which we invoke whenComplete()
        ResultHandle evaluatedParamsHandle = resolve.invokeStaticMethod(Descriptors.EVALUATED_PARAMS_EVALUATE, evalContext);
        ResultHandle paramsReadyHandle = resolve.readInstanceField(Descriptors.EVALUATED_PARAMS_STAGE, evaluatedParamsHandle);
        // Function that is called when params are evaluated
        FunctionCreator whenCompleteFun = resolve.createFunction(BiConsumer.class);
        resolve.invokeInterfaceMethod(Descriptors.CF_WHEN_COMPLETE, paramsReadyHandle, whenCompleteFun.getInstance());
        BytecodeCreator whenComplete = whenCompleteFun.getBytecode();
        AssignableResultHandle whenBase = whenComplete.createVariable(Object.class);
        whenComplete.assign(whenBase, base);
        AssignableResultHandle whenName = null;
        if (matchAnyOrRegex) {
            whenName = whenComplete.createVariable(String.class);
            whenComplete.assign(whenName, name);
        }
        AssignableResultHandle whenRet = whenComplete.createVariable(CompletableFuture.class);
        whenComplete.assign(whenRet, ret);
        AssignableResultHandle whenEvaluatedParams = whenComplete.createVariable(EvaluatedParams.class);
        whenComplete.assign(whenEvaluatedParams, evaluatedParamsHandle);
        AssignableResultHandle whenEvalContext = whenComplete.createVariable(EvalContext.class);
        whenComplete.assign(whenEvalContext, evalContext);
        BranchResult throwableIsNull = whenComplete.ifNull(whenComplete.getMethodParam(1));
        BytecodeCreator success = throwableIsNull.trueBranch();
        boolean isVarArgs = ValueResolverGenerator.isVarArgs(method);
        // Check type parameters and return NO_RESULT if failed
        List<Param> evaluated = params.evaluated();
        ResultHandle paramTypesHandle = success.newArray(Class.class, evaluated.size());
        int idx = 0;
        for (Param p : evaluated) {
            success.writeArrayValue(paramTypesHandle, idx++, ValueResolverGenerator.loadParamType(success, p.type));
        }
        BytecodeCreator typeMatchFailed = success.ifNonZero(success.invokeVirtualMethod(Descriptors.EVALUATED_PARAMS_PARAM_TYPES_MATCH, whenEvaluatedParams, success.load(isVarArgs), paramTypesHandle)).falseBranch();
        typeMatchFailed.invokeVirtualMethod(Descriptors.COMPLETABLE_FUTURE_COMPLETE, whenRet, typeMatchFailed.invokeStaticMethod(Descriptors.NOT_FOUND_FROM_EC, whenEvalContext));
        typeMatchFailed.returnValue(null);
        // try
        TryBlock tryCatch = success.tryBlock();
        // catch (Throwable e)
        CatchBlockCreator exception = tryCatch.addCatch(Throwable.class);
        // CompletableFuture.completeExceptionally(Throwable)
        exception.invokeVirtualMethod(Descriptors.COMPLETABLE_FUTURE_COMPLETE_EXCEPTIONALLY, whenRet, exception.getCaughtException());
        // Collect the params
        ResultHandle[] args = new ResultHandle[params.size()];
        int evalIdx = 0;
        int lastIdx = params.size() - 1;
        for (int i = 0; i < params.size(); i++) {
            Param param = params.get(i);
            if (param.kind == ParamKind.BASE) {
                args[i] = whenBase;
            } else if (param.kind == ParamKind.NAME) {
                args[i] = whenName;
            } else if (param.kind == ParamKind.ATTR) {
                args[i] = tryCatch.invokeInterfaceMethod(Descriptors.GET_ATTRIBUTE, whenEvalContext, tryCatch.load(param.name));
            } else {
                if (isVarArgs && i == lastIdx) {
                    // Last param is varargs
                    Type varargsParam = params.get(lastIdx).type;
                    ResultHandle componentType = tryCatch.loadClassFromTCCL(varargsParam.asArrayType().component().name().toString());
                    ResultHandle varargsResults = tryCatch.invokeVirtualMethod(Descriptors.EVALUATED_PARAMS_GET_VARARGS_RESULTS, evaluatedParamsHandle, tryCatch.load(evaluated.size()), componentType);
                    args[i] = varargsResults;
                } else {
                    args[i] = tryCatch.invokeVirtualMethod(Descriptors.EVALUATED_PARAMS_GET_RESULT, whenEvaluatedParams, tryCatch.load(evalIdx++));
                }
            }
        }
        // Invoke the extension method
        ResultHandle invokeRet = tryCatch.invokeStaticMethod(MethodDescriptor.ofMethod(declaringClass.name().toString(), method.name(), method.returnType().name().toString(), params.parameterTypesAsStringArray()), args);
        tryCatch.invokeVirtualMethod(Descriptors.COMPLETABLE_FUTURE_COMPLETE, whenRet, invokeRet);
        BytecodeCreator failure = throwableIsNull.falseBranch();
        failure.invokeVirtualMethod(Descriptors.COMPLETABLE_FUTURE_COMPLETE_EXCEPTIONALLY, whenRet, whenComplete.getMethodParam(1));
        whenComplete.returnValue(null);
    }
    resolve.returnValue(ret);
}
Also used : FunctionCreator(io.quarkus.gizmo.FunctionCreator) EvalContext(io.quarkus.qute.EvalContext) BytecodeCreator(io.quarkus.gizmo.BytecodeCreator) TryBlock(io.quarkus.gizmo.TryBlock) BranchResult(io.quarkus.gizmo.BranchResult) Type(org.jboss.jandex.Type) MethodCreator(io.quarkus.gizmo.MethodCreator) ResultHandle(io.quarkus.gizmo.ResultHandle) AssignableResultHandle(io.quarkus.gizmo.AssignableResultHandle) AssignableResultHandle(io.quarkus.gizmo.AssignableResultHandle) CatchBlockCreator(io.quarkus.gizmo.CatchBlockCreator) CompletionStage(java.util.concurrent.CompletionStage)

Example 5 with FunctionCreator

use of io.quarkus.gizmo.FunctionCreator in project quarkus by quarkusio.

the class ValueResolverGenerator method matchMethod.

private void matchMethod(MethodInfo method, ClassInfo clazz, MethodCreator resolve, ResultHandle base, ResultHandle name, ResultHandle params, ResultHandle paramsCount, ResultHandle evalContext) {
    List<Type> methodParams = method.parameters();
    LOGGER.debugf("Method added %s", method);
    BytecodeCreator matchScope = createMatchScope(resolve, method.name(), methodParams.size(), method.returnType(), name, params, paramsCount);
    // Invoke the method
    ResultHandle ret;
    boolean hasCompletionStage = !skipMemberType(method.returnType()) && hasCompletionStageInTypeClosure(index.getClassByName(method.returnType().name()), index);
    // Evaluate the params first
    ret = matchScope.newInstance(MethodDescriptor.ofConstructor(CompletableFuture.class));
    // The CompletionStage upon which we invoke whenComplete()
    ResultHandle evaluatedParams = matchScope.invokeStaticMethod(Descriptors.EVALUATED_PARAMS_EVALUATE, evalContext);
    ResultHandle paramsReady = matchScope.readInstanceField(Descriptors.EVALUATED_PARAMS_STAGE, evaluatedParams);
    FunctionCreator whenCompleteFun = matchScope.createFunction(BiConsumer.class);
    matchScope.invokeInterfaceMethod(Descriptors.CF_WHEN_COMPLETE, paramsReady, whenCompleteFun.getInstance());
    BytecodeCreator whenComplete = whenCompleteFun.getBytecode();
    // TODO workaround for https://github.com/quarkusio/gizmo/issues/6
    AssignableResultHandle whenBase = whenComplete.createVariable(Object.class);
    whenComplete.assign(whenBase, base);
    AssignableResultHandle whenRet = whenComplete.createVariable(CompletableFuture.class);
    whenComplete.assign(whenRet, ret);
    AssignableResultHandle whenEvaluatedParams = whenComplete.createVariable(EvaluatedParams.class);
    whenComplete.assign(whenEvaluatedParams, evaluatedParams);
    AssignableResultHandle whenEvalContext = whenComplete.createVariable(EvalContext.class);
    whenComplete.assign(whenEvalContext, evalContext);
    BranchResult throwableIsNull = whenComplete.ifNull(whenComplete.getMethodParam(1));
    // complete
    BytecodeCreator success = throwableIsNull.trueBranch();
    // Check type parameters and return NO_RESULT if failed
    List<Type> parameterTypes = method.parameters();
    ResultHandle paramTypesHandle = success.newArray(Class.class, parameterTypes.size());
    int idx = 0;
    for (Type parameterType : parameterTypes) {
        success.writeArrayValue(paramTypesHandle, idx++, loadParamType(success, parameterType));
    }
    BytecodeCreator typeMatchFailed = success.ifNonZero(success.invokeVirtualMethod(Descriptors.EVALUATED_PARAMS_PARAM_TYPES_MATCH, whenEvaluatedParams, success.load(isVarArgs(method)), paramTypesHandle)).falseBranch();
    typeMatchFailed.invokeVirtualMethod(Descriptors.COMPLETABLE_FUTURE_COMPLETE, whenRet, typeMatchFailed.invokeStaticMethod(Descriptors.NOT_FOUND_FROM_EC, whenEvalContext));
    typeMatchFailed.returnValue(null);
    ResultHandle[] paramsHandle = new ResultHandle[methodParams.size()];
    if (methodParams.size() == 1) {
        paramsHandle[0] = whenComplete.getMethodParam(0);
    } else {
        for (int i = 0; i < methodParams.size(); i++) {
            paramsHandle[i] = success.invokeVirtualMethod(Descriptors.EVALUATED_PARAMS_GET_RESULT, evaluatedParams, success.load(i));
        }
    }
    AssignableResultHandle invokeRet = success.createVariable(Object.class);
    // try
    TryBlock tryCatch = success.tryBlock();
    // catch (Throwable e)
    CatchBlockCreator exception = tryCatch.addCatch(Throwable.class);
    // CompletableFuture.completeExceptionally(Throwable)
    exception.invokeVirtualMethod(Descriptors.COMPLETABLE_FUTURE_COMPLETE_EXCEPTIONALLY, whenRet, exception.getCaughtException());
    if (Modifier.isStatic(method.flags())) {
        if (Modifier.isInterface(clazz.flags())) {
            tryCatch.assign(invokeRet, tryCatch.invokeStaticInterfaceMethod(MethodDescriptor.of(method), paramsHandle));
        } else {
            tryCatch.assign(invokeRet, tryCatch.invokeStaticMethod(MethodDescriptor.of(method), paramsHandle));
        }
    } else {
        if (Modifier.isInterface(clazz.flags())) {
            tryCatch.assign(invokeRet, tryCatch.invokeInterfaceMethod(MethodDescriptor.of(method), whenBase, paramsHandle));
        } else {
            tryCatch.assign(invokeRet, tryCatch.invokeVirtualMethod(MethodDescriptor.of(method), whenBase, paramsHandle));
        }
    }
    if (hasCompletionStage) {
        FunctionCreator invokeWhenCompleteFun = tryCatch.createFunction(BiConsumer.class);
        tryCatch.invokeInterfaceMethod(Descriptors.CF_WHEN_COMPLETE, invokeRet, invokeWhenCompleteFun.getInstance());
        BytecodeCreator invokeWhenComplete = invokeWhenCompleteFun.getBytecode();
        // TODO workaround for https://github.com/quarkusio/gizmo/issues/6
        AssignableResultHandle invokeWhenRet = invokeWhenComplete.createVariable(CompletableFuture.class);
        invokeWhenComplete.assign(invokeWhenRet, whenRet);
        BranchResult invokeThrowableIsNull = invokeWhenComplete.ifNull(invokeWhenComplete.getMethodParam(1));
        BytecodeCreator invokeSuccess = invokeThrowableIsNull.trueBranch();
        invokeSuccess.invokeVirtualMethod(Descriptors.COMPLETABLE_FUTURE_COMPLETE, invokeWhenRet, invokeWhenComplete.getMethodParam(0));
        BytecodeCreator invokeFailure = invokeThrowableIsNull.falseBranch();
        invokeFailure.invokeVirtualMethod(Descriptors.COMPLETABLE_FUTURE_COMPLETE_EXCEPTIONALLY, invokeWhenRet, invokeWhenComplete.getMethodParam(1));
        invokeWhenComplete.returnValue(null);
    } else {
        tryCatch.invokeVirtualMethod(Descriptors.COMPLETABLE_FUTURE_COMPLETE, whenRet, invokeRet);
    }
    // CompletableFuture.completeExceptionally(Throwable)
    BytecodeCreator failure = throwableIsNull.falseBranch();
    failure.invokeVirtualMethod(Descriptors.COMPLETABLE_FUTURE_COMPLETE_EXCEPTIONALLY, whenRet, whenComplete.getMethodParam(1));
    whenComplete.returnValue(null);
    matchScope.returnValue(ret);
}
Also used : BranchResult(io.quarkus.gizmo.BranchResult) Type(org.jboss.jandex.Type) PrimitiveType(org.jboss.jandex.PrimitiveType) FunctionCreator(io.quarkus.gizmo.FunctionCreator) BytecodeCreator(io.quarkus.gizmo.BytecodeCreator) ResultHandle(io.quarkus.gizmo.ResultHandle) AssignableResultHandle(io.quarkus.gizmo.AssignableResultHandle) AssignableResultHandle(io.quarkus.gizmo.AssignableResultHandle) TryBlock(io.quarkus.gizmo.TryBlock) CatchBlockCreator(io.quarkus.gizmo.CatchBlockCreator)

Aggregations

BytecodeCreator (io.quarkus.gizmo.BytecodeCreator)14 FunctionCreator (io.quarkus.gizmo.FunctionCreator)14 ResultHandle (io.quarkus.gizmo.ResultHandle)12 AssignableResultHandle (io.quarkus.gizmo.AssignableResultHandle)9 BranchResult (io.quarkus.gizmo.BranchResult)7 CatchBlockCreator (io.quarkus.gizmo.CatchBlockCreator)7 TryBlock (io.quarkus.gizmo.TryBlock)7 Type (org.jboss.jandex.Type)6 MethodCreator (io.quarkus.gizmo.MethodCreator)3 Uni (io.smallrye.mutiny.Uni)3 InvocationContext (javax.interceptor.InvocationContext)3 MethodInfo (org.jboss.jandex.MethodInfo)3 CompletableFuture (java.util.concurrent.CompletableFuture)2 BiFunction (java.util.function.BiFunction)2 Function (java.util.function.Function)2 InterceptionType (javax.enterprise.inject.spi.InterceptionType)2 PrimitiveType (org.jboss.jandex.PrimitiveType)2 CurrentRequestManager (org.jboss.resteasy.reactive.server.core.CurrentRequestManager)2 ResteasyReactiveRequestContext (org.jboss.resteasy.reactive.server.core.ResteasyReactiveRequestContext)2 InjectableInterceptor (io.quarkus.arc.InjectableInterceptor)1