Search in sources :

Example 1 with ClassCreator

use of io.quarkus.gizmo.ClassCreator in project camel-quarkus by apache.

the class GrpcProcessor method createBindableServiceBeans.

@BuildStep
void createBindableServiceBeans(BuildProducer<GeneratedBeanBuildItem> generatedBean, BuildProducer<ReflectiveClassBuildItem> reflectiveClass, CombinedIndexBuildItem combinedIndexBuildItem) {
    IndexView index = combinedIndexBuildItem.getIndex();
    Collection<ClassInfo> bindableServiceImpls = index.getAllKnownImplementors(BINDABLE_SERVICE_DOT_NAME);
    // This mimics similar logic in DefaultBindableServiceFactory that uses Javassist ProxyFactory & MethodHandler
    for (ClassInfo service : bindableServiceImpls) {
        if (!Modifier.isAbstract(service.flags())) {
            continue;
        }
        if (service.name().withoutPackagePrefix().startsWith("Mutiny")) {
            /* The generate-code goal of quarkus-maven-plugin generates also Mutiny service that we do not use
                 * Not skipping it here results in randomly registering the Mutiny one or the right one.
                 * In case the Mutiny service one is registered, the client throws something like
                 * io.grpc.StatusRuntimeException: UNIMPLEMENTED */
            continue;
        }
        String superClassName = service.name().toString();
        String generatedClassName = superClassName + "QuarkusMethodHandler";
        // Register the service classes for reflection
        reflectiveClass.produce(new ReflectiveClassBuildItem(true, false, service.name().toString()));
        reflectiveClass.produce(new ReflectiveClassBuildItem(true, false, service.enclosingClass().toString()));
        reflectiveClass.produce(new ReflectiveClassBuildItem(true, false, generatedClassName));
        try (ClassCreator classCreator = ClassCreator.builder().classOutput(new GeneratedBeanGizmoAdaptor(generatedBean)).className(generatedClassName).superClass(superClassName).interfaces(CamelQuarkusBindableService.class).build()) {
            classCreator.addAnnotation(Dependent.class);
            FieldCreator serverMethodHandler = classCreator.getFieldCreator("methodHandler", GrpcMethodHandler.class.getName()).setModifiers(Modifier.PRIVATE);
            // Create constructor
            try (MethodCreator initMethod = classCreator.getMethodCreator("<init>", void.class)) {
                initMethod.setModifiers(Modifier.PUBLIC);
                initMethod.invokeSpecialMethod(MethodDescriptor.ofMethod(superClassName, "<init>", void.class), initMethod.getThis());
                initMethod.returnValue(null);
            }
            // Create setMethodHandler override
            try (MethodCreator setMethodHandlerMethod = classCreator.getMethodCreator("setMethodHandler", void.class, GrpcMethodHandler.class)) {
                setMethodHandlerMethod.setModifiers(Modifier.PUBLIC);
                ResultHandle self = setMethodHandlerMethod.getThis();
                ResultHandle methodHandlerInstance = setMethodHandlerMethod.getMethodParam(0);
                setMethodHandlerMethod.writeInstanceField(serverMethodHandler.getFieldDescriptor(), self, methodHandlerInstance);
                setMethodHandlerMethod.returnValue(null);
            }
            // Override service methods that the gRPC component is interested in
            // E.g methods with one or two parameters where one is of type StreamObserver
            List<MethodInfo> methods = service.methods();
            for (MethodInfo method : methods) {
                if (isCandidateServiceMethod(method)) {
                    String[] params = method.parameters().stream().map(type -> type.name().toString()).toArray(String[]::new);
                    ClassInfo classInfo = index.getClassByName(DotName.createSimple(GrpcMethodHandler.class.getName()));
                    String returnType = method.returnType().name().toString();
                    try (MethodCreator methodCreator = classCreator.getMethodCreator(method.name(), returnType, params)) {
                        method.exceptions().stream().map(type -> type.name().toString()).forEach(methodCreator::addException);
                        if (method.parameters().size() == 1) {
                            ResultHandle returnValue = generateGrpcDelegateMethod(classInfo, serverMethodHandler, methodCreator, method, "handleForConsumerStrategy");
                            methodCreator.returnValue(returnValue);
                        } else if (method.parameters().size() == 2) {
                            generateGrpcDelegateMethod(classInfo, serverMethodHandler, methodCreator, method, "handle");
                            methodCreator.returnValue(null);
                        }
                    }
                }
            }
        }
    }
}
Also used : BindableService(io.grpc.BindableService) ReflectiveClassBuildItem(io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem) AbstractFutureStub(io.grpc.stub.AbstractFutureStub) AbstractBlockingStub(io.grpc.stub.AbstractBlockingStub) MethodCreator(io.quarkus.gizmo.MethodCreator) DotName(org.jboss.jandex.DotName) Type(org.jboss.jandex.Type) ClassCreator(io.quarkus.gizmo.ClassCreator) ClassInfo(org.jboss.jandex.ClassInfo) CombinedIndexBuildItem(io.quarkus.deployment.builditem.CombinedIndexBuildItem) BuildProducer(io.quarkus.deployment.annotations.BuildProducer) GeneratedBeanBuildItem(io.quarkus.arc.deployment.GeneratedBeanBuildItem) BuildStep(io.quarkus.deployment.annotations.BuildStep) MethodInfo(org.jboss.jandex.MethodInfo) StreamObserver(io.grpc.stub.StreamObserver) AdditionalBeanBuildItem(io.quarkus.arc.deployment.AdditionalBeanBuildItem) FeatureBuildItem(io.quarkus.deployment.builditem.FeatureBuildItem) AbstractAsyncStub(io.grpc.stub.AbstractAsyncStub) IndexView(org.jboss.jandex.IndexView) MethodDescriptor(io.quarkus.gizmo.MethodDescriptor) Collection(java.util.Collection) CamelQuarkusBindableService(org.apache.camel.quarkus.grpc.runtime.CamelQuarkusBindableService) List(java.util.List) GeneratedBeanGizmoAdaptor(io.quarkus.arc.deployment.GeneratedBeanGizmoAdaptor) Dependent(javax.enterprise.context.Dependent) FieldCreator(io.quarkus.gizmo.FieldCreator) AbstractStub(io.grpc.stub.AbstractStub) Modifier(java.lang.reflect.Modifier) GrpcMethodHandler(org.apache.camel.component.grpc.server.GrpcMethodHandler) ResultHandle(io.quarkus.gizmo.ResultHandle) QuarkusBindableServiceFactory(org.apache.camel.quarkus.grpc.runtime.QuarkusBindableServiceFactory) IndexView(org.jboss.jandex.IndexView) FieldCreator(io.quarkus.gizmo.FieldCreator) CamelQuarkusBindableService(org.apache.camel.quarkus.grpc.runtime.CamelQuarkusBindableService) GeneratedBeanGizmoAdaptor(io.quarkus.arc.deployment.GeneratedBeanGizmoAdaptor) ClassCreator(io.quarkus.gizmo.ClassCreator) MethodCreator(io.quarkus.gizmo.MethodCreator) ResultHandle(io.quarkus.gizmo.ResultHandle) MethodInfo(org.jboss.jandex.MethodInfo) ReflectiveClassBuildItem(io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem) ClassInfo(org.jboss.jandex.ClassInfo) BuildStep(io.quarkus.deployment.annotations.BuildStep)

Example 2 with ClassCreator

use of io.quarkus.gizmo.ClassCreator in project camel-quarkus by apache.

the class XalanNativeImageProcessor method installTransformerFactory.

@BuildStep
void installTransformerFactory(BuildProducer<GeneratedNativeImageClassBuildItem> nativeImageClass, BuildProducer<GeneratedResourceBuildItem> generatedResources) {
    final String serviceProviderFileContent = XalanTransformerFactory.class.getName() + "\n";
    /* This is primarily for the JVM mode */
    generatedResources.produce(new GeneratedResourceBuildItem(TRANSFORMER_FACTORY_SERVICE_FILE_PATH, serviceProviderFileContent.getBytes(StandardCharsets.UTF_8)));
    /* A low level way to embed only our service file in the native image.
         * There are at least two META-INF/services/javax.xml.transform.TransformerFactory files
         * in the class path: ours and the one from xalan.jar. As of GraalVM 19.3.1-java8, 19.3.1-java11,
         * 20.0.0-java8 and 20.0.0-java11, there is no way to ensure that ServiceProviderBuildItem
         * or NativeImageResourceBuildItem will pick the service file preferred by us.
         * We are thus forced to use this low level mechanism to ensure that.
         */
    final ClassCreator file = new ClassCreator(new ClassOutput() {

        @Override
        public void write(String s, byte[] bytes) {
            nativeImageClass.produce(new GeneratedNativeImageClassBuildItem(s, bytes));
        }
    }, getClass().getName() + "AutoFeature", null, Object.class.getName(), Feature.class.getName());
    file.addAnnotation("com.oracle.svm.core.annotate.AutomaticFeature");
    final MethodCreator beforeAn = file.getMethodCreator("beforeAnalysis", "V", Feature.BeforeAnalysisAccess.class.getName());
    final TryBlock overallCatch = beforeAn.tryBlock();
    overallCatch.invokeStaticMethod(ofMethod(ResourceUtils.class, "registerResources", void.class, String.class, String.class), overallCatch.load(TRANSFORMER_FACTORY_SERVICE_FILE_PATH), overallCatch.load(serviceProviderFileContent));
    final CatchBlockCreator print = overallCatch.addCatch(Throwable.class);
    print.invokeVirtualMethod(ofMethod(Throwable.class, "printStackTrace", void.class), print.getCaughtException());
    beforeAn.returnValue(null);
    file.close();
}
Also used : GeneratedResourceBuildItem(io.quarkus.deployment.builditem.GeneratedResourceBuildItem) GeneratedNativeImageClassBuildItem(io.quarkus.deployment.builditem.GeneratedNativeImageClassBuildItem) TryBlock(io.quarkus.gizmo.TryBlock) ClassCreator(io.quarkus.gizmo.ClassCreator) Feature(org.graalvm.nativeimage.hosted.Feature) MethodCreator(io.quarkus.gizmo.MethodCreator) ResourceUtils(org.apache.camel.quarkus.core.graal.ResourceUtils) ClassOutput(io.quarkus.gizmo.ClassOutput) XalanTransformerFactory(org.apache.camel.quarkus.support.xalan.XalanTransformerFactory) CatchBlockCreator(io.quarkus.gizmo.CatchBlockCreator) BuildStep(io.quarkus.deployment.annotations.BuildStep)

Example 3 with ClassCreator

use of io.quarkus.gizmo.ClassCreator in project quarkus-github-action by quarkiverse.

the class GitHubActionProcessor method generatePayloadTypeResolver.

private static void generatePayloadTypeResolver(ClassOutput beanClassOutput, BuildProducer<ReflectiveClassBuildItem> reflectiveClasses, Collection<EventDefinition> eventDefinitions) {
    String payloadTypeResolverClassName = GitHubEvent.class.getPackageName() + ".PayloadTypeResolverImpl";
    reflectiveClasses.produce(new ReflectiveClassBuildItem(true, true, payloadTypeResolverClassName));
    ClassCreator payloadTypeResolverClassCreator = ClassCreator.builder().classOutput(beanClassOutput).className(payloadTypeResolverClassName).interfaces(PayloadTypeResolver.class).build();
    payloadTypeResolverClassCreator.addAnnotation(Singleton.class);
    Map<String, DotName> payloadTypeMapping = eventDefinitions.stream().collect(Collectors.toMap(ed -> ed.getEvent(), ed -> ed.getPayloadType(), (ed1, ed2) -> ed1));
    MethodCreator getPayloadTypeMethodCreator = payloadTypeResolverClassCreator.getMethodCreator("getPayloadType", Class.class, String.class);
    ResultHandle eventRh = getPayloadTypeMethodCreator.getMethodParam(0);
    for (Entry<String, DotName> payloadTypeMappingEntry : payloadTypeMapping.entrySet()) {
        BytecodeCreator matches = getPayloadTypeMethodCreator.ifTrue(getPayloadTypeMethodCreator.invokeVirtualMethod(MethodDescriptors.OBJECT_EQUALS, getPayloadTypeMethodCreator.load(payloadTypeMappingEntry.getKey()), eventRh)).trueBranch();
        matches.returnValue(matches.loadClass(payloadTypeMappingEntry.getValue().toString()));
    }
    getPayloadTypeMethodCreator.returnValue(getPayloadTypeMethodCreator.loadNull());
    payloadTypeResolverClassCreator.close();
}
Also used : DotNames(io.quarkus.arc.processor.DotNames) GeneratedClassGizmoAdaptor(io.quarkus.deployment.GeneratedClassGizmoAdaptor) Arrays(java.util.Arrays) MethodVisitor(org.objectweb.asm.MethodVisitor) PayloadTypeResolver(io.quarkiverse.githubaction.runtime.PayloadTypeResolver) ClassOutput(io.quarkus.gizmo.ClassOutput) RunTimeConfigurationDefaultBuildItem(io.quarkus.deployment.builditem.RunTimeConfigurationDefaultBuildItem) ClassInfo(org.jboss.jandex.ClassInfo) CombinedIndexBuildItem(io.quarkus.deployment.builditem.CombinedIndexBuildItem) BuildProducer(io.quarkus.deployment.annotations.BuildProducer) GeneratedBeanBuildItem(io.quarkus.arc.deployment.GeneratedBeanBuildItem) MethodInfo(org.jboss.jandex.MethodInfo) Context(io.quarkiverse.githubaction.Context) AdditionalBeanBuildItem(io.quarkus.arc.deployment.AdditionalBeanBuildItem) FeatureBuildItem(io.quarkus.deployment.builditem.FeatureBuildItem) AnnotationLiteral(javax.enterprise.util.AnnotationLiteral) Map(java.util.Map) BytecodeCreator(io.quarkus.gizmo.BytecodeCreator) GHEventPayload(org.kohsuke.github.GHEventPayload) ConfigFileReader(io.quarkiverse.githubaction.runtime.ConfigFileReader) MethodParameterInfo(org.jboss.jandex.MethodParameterInfo) ClassVisitor(org.objectweb.asm.ClassVisitor) GitHub(org.kohsuke.github.GitHub) AnnotationsTransformerBuildItem(io.quarkus.arc.deployment.AnnotationsTransformerBuildItem) ActionDispatchingConfiguration(io.quarkiverse.githubaction.deployment.DispatchingConfiguration.ActionDispatchingConfiguration) AnnotationValue(org.jboss.jandex.AnnotationValue) ReflectiveHierarchyBuildItem(io.quarkus.deployment.builditem.nativeimage.ReflectiveHierarchyBuildItem) EventAnnotationLiteral(io.quarkiverse.githubaction.deployment.DispatchingConfiguration.EventAnnotationLiteral) Collection(java.util.Collection) Set(java.util.Set) ActionLiteral(io.quarkiverse.githubaction.Action.ActionLiteral) BuiltinScope(io.quarkus.arc.processor.BuiltinScope) Collectors(java.util.stream.Collectors) MethodDescriptors(io.quarkus.arc.processor.MethodDescriptors) List(java.util.List) GitHubEvent(io.quarkiverse.githubaction.runtime.GitHubEvent) GitHubApiClassWithBridgeMethodsBuildItem(io.quarkiverse.githubapi.deployment.GitHubApiClassWithBridgeMethodsBuildItem) ActionDispatchingMethod(io.quarkiverse.githubaction.deployment.DispatchingConfiguration.ActionDispatchingMethod) Actions(io.quarkiverse.githubapp.event.Actions) AnnotationInstance(org.jboss.jandex.AnnotationInstance) Modifier(java.lang.reflect.Modifier) Annotation(java.lang.annotation.Annotation) Entry(java.util.Map.Entry) Optional(java.util.Optional) Multiplexer(io.quarkiverse.githubaction.runtime.Multiplexer) HashUtil(io.quarkus.runtime.util.HashUtil) ResultHandle(io.quarkus.gizmo.ResultHandle) ReflectiveClassBuildItem(io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem) Logger(org.jboss.logging.Logger) MethodCreator(io.quarkus.gizmo.MethodCreator) DotName(org.jboss.jandex.DotName) Type(org.jboss.jandex.Type) AnnotatedElement(io.quarkus.gizmo.AnnotatedElement) HashMap(java.util.HashMap) ClassCreator(io.quarkus.gizmo.ClassCreator) Singleton(javax.inject.Singleton) TreeSet(java.util.TreeSet) ArrayList(java.util.ArrayList) EVENT(io.quarkiverse.githubaction.deployment.GitHubActionDotNames.EVENT) Inject(javax.inject.Inject) BuildStep(io.quarkus.deployment.annotations.BuildStep) INJECTABLE_TYPES(io.quarkiverse.githubaction.deployment.GitHubActionDotNames.INJECTABLE_TYPES) Kind(org.jboss.jandex.AnnotationTarget.Kind) EventAnnotation(io.quarkiverse.githubaction.deployment.DispatchingConfiguration.EventAnnotation) Gizmo(io.quarkus.gizmo.Gizmo) PrintStream(java.io.PrintStream) Event(javax.enterprise.event.Event) IndexView(org.jboss.jandex.IndexView) Opcodes(org.objectweb.asm.Opcodes) MethodDescriptor(io.quarkus.gizmo.MethodDescriptor) CONFIG_FILE(io.quarkiverse.githubaction.deployment.GitHubActionDotNames.CONFIG_FILE) GitHubEventHandler(io.quarkiverse.githubaction.runtime.GitHubEventHandler) FieldDescriptor(io.quarkus.gizmo.FieldDescriptor) Action(io.quarkiverse.githubaction.Action) GeneratedBeanGizmoAdaptor(io.quarkus.arc.deployment.GeneratedBeanGizmoAdaptor) ACTION(io.quarkiverse.githubaction.deployment.GitHubActionDotNames.ACTION) GeneratedClassBuildItem(io.quarkus.deployment.builditem.GeneratedClassBuildItem) LaunchModeBuildItem(io.quarkus.deployment.builditem.LaunchModeBuildItem) FieldCreator(io.quarkus.gizmo.FieldCreator) BytecodeTransformerBuildItem(io.quarkus.deployment.builditem.BytecodeTransformerBuildItem) Collections(java.util.Collections) MethodCreator(io.quarkus.gizmo.MethodCreator) PayloadTypeResolver(io.quarkiverse.githubaction.runtime.PayloadTypeResolver) ResultHandle(io.quarkus.gizmo.ResultHandle) BytecodeCreator(io.quarkus.gizmo.BytecodeCreator) GitHubEvent(io.quarkiverse.githubaction.runtime.GitHubEvent) ClassCreator(io.quarkus.gizmo.ClassCreator) DotName(org.jboss.jandex.DotName) ReflectiveClassBuildItem(io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem)

Example 4 with ClassCreator

use of io.quarkus.gizmo.ClassCreator in project quarkus-github-action by quarkiverse.

the class GitHubActionProcessor method generateMultiplexers.

/**
 * Multiplexers listen to the sync events emitted by the main class.
 * <p>
 * They are subclasses of the application classes registering actions or listening to GitHub events through our annotations.
 * <p>
 * They are useful for several purposes:
 * <ul>
 * <li>A single application method can listen to multiple event types: the event types are qualifiers and CDI wouldn't allow
 * that (only events matching all the qualifiers would be received by the application method). That's why this class is
 * called a multiplexer: it will generate one method per event type and each generated method will delegate to the original
 * method.</li>
 * <li>The multiplexer also handles the resolution of payloads, config files...</li>
 * <li>We can inject a properly configured instance of GitHub or DynamicGraphQLClient into the method.</li>
 * </ul>
 */
private static void generateMultiplexers(ClassOutput beanClassOutput, DispatchingConfiguration dispatchingConfiguration, BuildProducer<ReflectiveClassBuildItem> reflectiveClasses) {
    for (Entry<DotName, TreeSet<ActionDispatchingMethod>> actionDispatchingMethodsEntry : dispatchingConfiguration.getMethods().entrySet()) {
        DotName declaringClassName = actionDispatchingMethodsEntry.getKey();
        TreeSet<ActionDispatchingMethod> actionDispatchingMethods = actionDispatchingMethodsEntry.getValue();
        ClassInfo declaringClass = actionDispatchingMethods.iterator().next().getMethod().declaringClass();
        reflectiveClasses.produce(new ReflectiveClassBuildItem(true, true, declaringClassName.toString()));
        String multiplexerClassName = declaringClassName + "_Multiplexer";
        reflectiveClasses.produce(new ReflectiveClassBuildItem(true, true, multiplexerClassName));
        ClassCreator multiplexerClassCreator = ClassCreator.builder().classOutput(beanClassOutput).className(multiplexerClassName).superClass(declaringClassName.toString()).build();
        multiplexerClassCreator.addAnnotation(Multiplexer.class);
        if (!BuiltinScope.isDeclaredOn(declaringClass)) {
            multiplexerClassCreator.addAnnotation(Singleton.class);
        }
        for (AnnotationInstance classAnnotation : declaringClass.classAnnotations()) {
            multiplexerClassCreator.addAnnotation(classAnnotation);
        }
        // Copy the constructors
        for (MethodInfo originalConstructor : declaringClass.constructors()) {
            MethodCreator constructorCreator = multiplexerClassCreator.getMethodCreator(MethodDescriptor.ofConstructor(multiplexerClassName, originalConstructor.parameters().stream().map(t -> t.name().toString()).toArray(String[]::new)));
            List<AnnotationInstance> originalMethodAnnotations = originalConstructor.annotations().stream().filter(ai -> ai.target().kind() == Kind.METHOD).collect(Collectors.toList());
            for (AnnotationInstance originalMethodAnnotation : originalMethodAnnotations) {
                constructorCreator.addAnnotation(originalMethodAnnotation);
            }
            Map<Short, List<AnnotationInstance>> originalConstructorParameterAnnotationMapping = originalConstructor.annotations().stream().filter(ai -> ai.target().kind() == Kind.METHOD_PARAMETER).collect(Collectors.groupingBy(ai -> ai.target().asMethodParameter().position()));
            List<ResultHandle> parametersRh = new ArrayList<>();
            for (short i = 0; i < originalConstructor.parameters().size(); i++) {
                parametersRh.add(constructorCreator.getMethodParam(i));
                AnnotatedElement parameterAnnotations = constructorCreator.getParameterAnnotations(i);
                List<AnnotationInstance> originalConstructorParameterAnnotations = originalConstructorParameterAnnotationMapping.getOrDefault(i, Collections.emptyList());
                for (AnnotationInstance originalConstructorParameterAnnotation : originalConstructorParameterAnnotations) {
                    parameterAnnotations.addAnnotation(originalConstructorParameterAnnotation);
                }
            }
            constructorCreator.invokeSpecialMethod(MethodDescriptor.of(originalConstructor), constructorCreator.getThis(), parametersRh.toArray(ResultHandle[]::new));
            constructorCreator.returnValue(null);
        }
        // Generate the multiplexed event dispatching methods
        for (ActionDispatchingMethod actionDispatchingMethod : actionDispatchingMethods) {
            String name = actionDispatchingMethod.getName();
            AnnotationInstance eventSubscriberInstance = actionDispatchingMethod.getEventSubscriberInstance();
            MethodInfo originalMethod = actionDispatchingMethod.getMethod();
            Map<Short, List<AnnotationInstance>> originalMethodParameterAnnotationMapping = originalMethod.annotations().stream().filter(ai -> ai.target().kind() == Kind.METHOD_PARAMETER).collect(Collectors.groupingBy(ai -> ai.target().asMethodParameter().position()));
            // if the method already has an @Observes or @ObservesAsync annotation
            if (originalMethod.hasAnnotation(DotNames.OBSERVES) || originalMethod.hasAnnotation(DotNames.OBSERVES_ASYNC)) {
                LOG.warn("Methods listening to GitHub actions may not be annotated with @Observes or @ObservesAsync. Offending method: " + originalMethod.declaringClass().name() + "#" + originalMethod);
            }
            List<String> parameterTypes = new ArrayList<>();
            List<Type> originalMethodParameterTypes = originalMethod.parameters();
            // detect the parameter that is a payload
            short payloadParameterPosition = -1;
            if (eventSubscriberInstance != null) {
                for (short i = 0; i < originalMethodParameterTypes.size(); i++) {
                    List<AnnotationInstance> parameterAnnotations = originalMethodParameterAnnotationMapping.getOrDefault(i, Collections.emptyList());
                    if (parameterAnnotations.stream().anyMatch(ai -> ai.name().equals(eventSubscriberInstance.name()))) {
                        payloadParameterPosition = i;
                        break;
                    }
                }
            }
            short j = 0;
            Map<Short, Short> parameterMapping = new HashMap<>();
            for (short i = 0; i < originalMethodParameterTypes.size(); i++) {
                List<AnnotationInstance> originalMethodAnnotations = originalMethodParameterAnnotationMapping.getOrDefault(i, Collections.emptyList());
                if (originalMethodAnnotations.stream().anyMatch(ai -> CONFIG_FILE.equals(ai.name())) || INJECTABLE_TYPES.contains(originalMethodParameterTypes.get(i).name()) || i == payloadParameterPosition) {
                    // if the parameter is annotated with @ConfigFile, is of an injectable type or is the payload, we skip it
                    continue;
                }
                parameterTypes.add(originalMethodParameterTypes.get(i).name().toString());
                parameterMapping.put(i, j);
                j++;
            }
            int configFileReaderParameterPosition = -1;
            if (originalMethod.hasAnnotation(CONFIG_FILE)) {
                parameterTypes.add(ConfigFileReader.class.getName());
                configFileReaderParameterPosition = j;
                j++;
            }
            parameterTypes.add(GitHubEvent.class.getName());
            int gitHubEventParameterPosition = j;
            MethodCreator methodCreator = multiplexerClassCreator.getMethodCreator(originalMethod.name() + "_" + HashUtil.sha1(originalMethod.toString() + "_" + (eventSubscriberInstance != null ? eventSubscriberInstance.toString() : EventDefinition.ALL)), originalMethod.returnType().name().toString(), parameterTypes.toArray());
            for (Type exceptionType : originalMethod.exceptions()) {
                methodCreator.addException(exceptionType.name().toString());
            }
            ResultHandle[] parameterValues = new ResultHandle[originalMethod.parameters().size()];
            // copy annotations except for @ConfigFile
            for (short i = 0; i < originalMethodParameterTypes.size(); i++) {
                List<AnnotationInstance> parameterAnnotations = originalMethodParameterAnnotationMapping.getOrDefault(i, Collections.emptyList());
                if (parameterAnnotations.isEmpty()) {
                    continue;
                }
                // Elements that are not in the mapping are ignored
                Short generatedParameterIndex = parameterMapping.get(i);
                if (generatedParameterIndex == null) {
                    continue;
                }
                AnnotatedElement generatedParameterAnnotations = methodCreator.getParameterAnnotations(generatedParameterIndex);
                for (AnnotationInstance annotationInstance : parameterAnnotations) {
                    generatedParameterAnnotations.addAnnotation(annotationInstance);
                }
            }
            // add annotations to the GitHubEvent parameter
            AnnotatedElement gitHubEventParameterAnnotations = methodCreator.getParameterAnnotations(gitHubEventParameterPosition);
            gitHubEventParameterAnnotations.addAnnotation(DotNames.OBSERVES.toString());
            gitHubEventParameterAnnotations.addAnnotation(Action.class).addValue("value", name);
            if (eventSubscriberInstance != null) {
                gitHubEventParameterAnnotations.addAnnotation(eventSubscriberInstance);
            }
            ResultHandle gitHubEventRh = methodCreator.getMethodParam(gitHubEventParameterPosition);
            // generate the code of the method
            for (short originalMethodParameterIndex = 0; originalMethodParameterIndex < originalMethodParameterTypes.size(); originalMethodParameterIndex++) {
                List<AnnotationInstance> parameterAnnotations = originalMethodParameterAnnotationMapping.getOrDefault(originalMethodParameterIndex, Collections.emptyList());
                Short multiplexerMethodParameterIndex = parameterMapping.get(originalMethodParameterIndex);
                if (originalMethodParameterIndex == payloadParameterPosition) {
                    parameterValues[originalMethodParameterIndex] = methodCreator.invokeVirtualMethod(MethodDescriptor.ofMethod(GitHubEvent.class, "getPayload", GHEventPayload.class), gitHubEventRh);
                } else if (INJECTABLE_TYPES.contains(originalMethodParameterTypes.get(originalMethodParameterIndex).name())) {
                    DotName injectableType = originalMethodParameterTypes.get(originalMethodParameterIndex).name();
                    parameterValues[originalMethodParameterIndex] = methodCreator.invokeVirtualMethod(MethodDescriptor.ofMethod(GitHubEvent.class, "get" + injectableType.withoutPackagePrefix(), injectableType.toString()), gitHubEventRh);
                } else if (parameterAnnotations.stream().anyMatch(ai -> ai.name().equals(CONFIG_FILE))) {
                    AnnotationInstance configFileAnnotationInstance = parameterAnnotations.stream().filter(ai -> ai.name().equals(CONFIG_FILE)).findFirst().get();
                    String configObjectType = originalMethodParameterTypes.get(originalMethodParameterIndex).name().toString();
                    boolean isOptional = false;
                    if (Optional.class.getName().equals(configObjectType)) {
                        if (originalMethodParameterTypes.get(originalMethodParameterIndex).kind() != Type.Kind.PARAMETERIZED_TYPE) {
                            throw new IllegalStateException("Optional is used but not parameterized for method " + originalMethod.declaringClass().name() + "#" + originalMethod);
                        }
                        isOptional = true;
                        configObjectType = originalMethodParameterTypes.get(originalMethodParameterIndex).asParameterizedType().arguments().get(0).name().toString();
                    }
                    ResultHandle gitHubRh = methodCreator.invokeVirtualMethod(MethodDescriptor.ofMethod(GitHubEvent.class, "getGitHub", GitHub.class), gitHubEventRh);
                    ResultHandle contextRh = methodCreator.invokeVirtualMethod(MethodDescriptor.ofMethod(GitHubEvent.class, "getContext", Context.class), gitHubEventRh);
                    ResultHandle repositoryRh = methodCreator.invokeInterfaceMethod(MethodDescriptor.ofMethod(Context.class, "getGitHubRepository", String.class), contextRh);
                    ResultHandle configFileReaderRh = methodCreator.getMethodParam(configFileReaderParameterPosition);
                    ResultHandle configObject = methodCreator.invokeVirtualMethod(MethodDescriptor.ofMethod(ConfigFileReader.class, "getConfigObject", Object.class, GitHub.class, String.class, String.class, Class.class), configFileReaderRh, gitHubRh, repositoryRh, methodCreator.load(configFileAnnotationInstance.value().asString()), methodCreator.loadClass(configObjectType));
                    configObject = methodCreator.checkCast(configObject, configObjectType);
                    if (isOptional) {
                        configObject = methodCreator.invokeStaticMethod(MethodDescriptor.ofMethod(Optional.class, "ofNullable", Optional.class, Object.class), configObject);
                    }
                    parameterValues[originalMethodParameterIndex] = configObject;
                } else {
                    parameterValues[originalMethodParameterIndex] = methodCreator.getMethodParam(multiplexerMethodParameterIndex);
                }
            }
            ResultHandle returnValue = methodCreator.invokeVirtualMethod(originalMethod, methodCreator.getThis(), parameterValues);
            methodCreator.returnValue(returnValue);
        }
        multiplexerClassCreator.close();
    }
}
Also used : DotNames(io.quarkus.arc.processor.DotNames) GeneratedClassGizmoAdaptor(io.quarkus.deployment.GeneratedClassGizmoAdaptor) Arrays(java.util.Arrays) MethodVisitor(org.objectweb.asm.MethodVisitor) PayloadTypeResolver(io.quarkiverse.githubaction.runtime.PayloadTypeResolver) ClassOutput(io.quarkus.gizmo.ClassOutput) RunTimeConfigurationDefaultBuildItem(io.quarkus.deployment.builditem.RunTimeConfigurationDefaultBuildItem) ClassInfo(org.jboss.jandex.ClassInfo) CombinedIndexBuildItem(io.quarkus.deployment.builditem.CombinedIndexBuildItem) BuildProducer(io.quarkus.deployment.annotations.BuildProducer) GeneratedBeanBuildItem(io.quarkus.arc.deployment.GeneratedBeanBuildItem) MethodInfo(org.jboss.jandex.MethodInfo) Context(io.quarkiverse.githubaction.Context) AdditionalBeanBuildItem(io.quarkus.arc.deployment.AdditionalBeanBuildItem) FeatureBuildItem(io.quarkus.deployment.builditem.FeatureBuildItem) AnnotationLiteral(javax.enterprise.util.AnnotationLiteral) Map(java.util.Map) BytecodeCreator(io.quarkus.gizmo.BytecodeCreator) GHEventPayload(org.kohsuke.github.GHEventPayload) ConfigFileReader(io.quarkiverse.githubaction.runtime.ConfigFileReader) MethodParameterInfo(org.jboss.jandex.MethodParameterInfo) ClassVisitor(org.objectweb.asm.ClassVisitor) GitHub(org.kohsuke.github.GitHub) AnnotationsTransformerBuildItem(io.quarkus.arc.deployment.AnnotationsTransformerBuildItem) ActionDispatchingConfiguration(io.quarkiverse.githubaction.deployment.DispatchingConfiguration.ActionDispatchingConfiguration) AnnotationValue(org.jboss.jandex.AnnotationValue) ReflectiveHierarchyBuildItem(io.quarkus.deployment.builditem.nativeimage.ReflectiveHierarchyBuildItem) EventAnnotationLiteral(io.quarkiverse.githubaction.deployment.DispatchingConfiguration.EventAnnotationLiteral) Collection(java.util.Collection) Set(java.util.Set) ActionLiteral(io.quarkiverse.githubaction.Action.ActionLiteral) BuiltinScope(io.quarkus.arc.processor.BuiltinScope) Collectors(java.util.stream.Collectors) MethodDescriptors(io.quarkus.arc.processor.MethodDescriptors) List(java.util.List) GitHubEvent(io.quarkiverse.githubaction.runtime.GitHubEvent) GitHubApiClassWithBridgeMethodsBuildItem(io.quarkiverse.githubapi.deployment.GitHubApiClassWithBridgeMethodsBuildItem) ActionDispatchingMethod(io.quarkiverse.githubaction.deployment.DispatchingConfiguration.ActionDispatchingMethod) Actions(io.quarkiverse.githubapp.event.Actions) AnnotationInstance(org.jboss.jandex.AnnotationInstance) Modifier(java.lang.reflect.Modifier) Annotation(java.lang.annotation.Annotation) Entry(java.util.Map.Entry) Optional(java.util.Optional) Multiplexer(io.quarkiverse.githubaction.runtime.Multiplexer) HashUtil(io.quarkus.runtime.util.HashUtil) ResultHandle(io.quarkus.gizmo.ResultHandle) ReflectiveClassBuildItem(io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem) Logger(org.jboss.logging.Logger) MethodCreator(io.quarkus.gizmo.MethodCreator) DotName(org.jboss.jandex.DotName) Type(org.jboss.jandex.Type) AnnotatedElement(io.quarkus.gizmo.AnnotatedElement) HashMap(java.util.HashMap) ClassCreator(io.quarkus.gizmo.ClassCreator) Singleton(javax.inject.Singleton) TreeSet(java.util.TreeSet) ArrayList(java.util.ArrayList) EVENT(io.quarkiverse.githubaction.deployment.GitHubActionDotNames.EVENT) Inject(javax.inject.Inject) BuildStep(io.quarkus.deployment.annotations.BuildStep) INJECTABLE_TYPES(io.quarkiverse.githubaction.deployment.GitHubActionDotNames.INJECTABLE_TYPES) Kind(org.jboss.jandex.AnnotationTarget.Kind) EventAnnotation(io.quarkiverse.githubaction.deployment.DispatchingConfiguration.EventAnnotation) Gizmo(io.quarkus.gizmo.Gizmo) PrintStream(java.io.PrintStream) Event(javax.enterprise.event.Event) IndexView(org.jboss.jandex.IndexView) Opcodes(org.objectweb.asm.Opcodes) MethodDescriptor(io.quarkus.gizmo.MethodDescriptor) CONFIG_FILE(io.quarkiverse.githubaction.deployment.GitHubActionDotNames.CONFIG_FILE) GitHubEventHandler(io.quarkiverse.githubaction.runtime.GitHubEventHandler) FieldDescriptor(io.quarkus.gizmo.FieldDescriptor) Action(io.quarkiverse.githubaction.Action) GeneratedBeanGizmoAdaptor(io.quarkus.arc.deployment.GeneratedBeanGizmoAdaptor) ACTION(io.quarkiverse.githubaction.deployment.GitHubActionDotNames.ACTION) GeneratedClassBuildItem(io.quarkus.deployment.builditem.GeneratedClassBuildItem) LaunchModeBuildItem(io.quarkus.deployment.builditem.LaunchModeBuildItem) FieldCreator(io.quarkus.gizmo.FieldCreator) BytecodeTransformerBuildItem(io.quarkus.deployment.builditem.BytecodeTransformerBuildItem) Collections(java.util.Collections) Action(io.quarkiverse.githubaction.Action) HashMap(java.util.HashMap) GitHub(org.kohsuke.github.GitHub) ArrayList(java.util.ArrayList) AnnotatedElement(io.quarkus.gizmo.AnnotatedElement) DotName(org.jboss.jandex.DotName) ClassCreator(io.quarkus.gizmo.ClassCreator) TreeSet(java.util.TreeSet) ActionDispatchingMethod(io.quarkiverse.githubaction.deployment.DispatchingConfiguration.ActionDispatchingMethod) List(java.util.List) ArrayList(java.util.ArrayList) ResultHandle(io.quarkus.gizmo.ResultHandle) Context(io.quarkiverse.githubaction.Context) Optional(java.util.Optional) GitHubEvent(io.quarkiverse.githubaction.runtime.GitHubEvent) Type(org.jboss.jandex.Type) MethodCreator(io.quarkus.gizmo.MethodCreator) ConfigFileReader(io.quarkiverse.githubaction.runtime.ConfigFileReader) MethodInfo(org.jboss.jandex.MethodInfo) ReflectiveClassBuildItem(io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem) AnnotationInstance(org.jboss.jandex.AnnotationInstance) ClassInfo(org.jboss.jandex.ClassInfo)

Example 5 with ClassCreator

use of io.quarkus.gizmo.ClassCreator in project quarkus-logging-logback by quarkiverse.

the class LoggingLogbackProcessor method init.

@Record(ExecutionTime.STATIC_INIT)
@BuildStep
void init(LogbackRecorder recorder, RecorderContext context, BuildProducer<RunTimeConfigurationDefaultBuildItem> runTimeConfigurationDefaultBuildItemBuildProducer, BuildProducer<GeneratedClassBuildItem> generatedClasses, OutputTargetBuildItem outputTargetBuildItem, CurateOutcomeBuildItem curateOutcomeBuildItem, ShutdownContextBuildItem shutdownContextBuildItem) throws Exception {
    // first check the versions
    doVersionCheck();
    URL url = getUrl();
    if (url == null) {
        return;
    }
    context.registerSubstitution(StartEvent.class, StartSub.class, (Class) EventSubstitution.class);
    context.registerSubstitution(BodyEvent.class, BodySub.class, (Class) EventSubstitution.class);
    context.registerSubstitution(EndEvent.class, EndSub.class, (Class) EventSubstitution.class);
    final AtomicReference<List<SaxEvent>> events = new AtomicReference<>();
    JoranConfigurator configurator = new JoranConfigurator() {

        @Override
        public void doConfigure(List<SaxEvent> eventList) throws JoranException {
            events.set(eventList);
        }
    };
    configurator.setContext(new LoggerContext());
    configurator.doConfigure(url);
    List<String> loggerPath = Arrays.asList("configuration", "logger");
    List<String> rootPath = Arrays.asList("configuration", "root");
    String rootLevel = null;
    Map<String, String> levels = new HashMap<>();
    Set<String> allClasses = new HashSet<>();
    for (SaxEvent i : events.get()) {
        if (i instanceof StartEvent) {
            StartEvent s = ((StartEvent) i);
            if (Objects.equals(loggerPath, s.elementPath.getCopyOfPartList())) {
                String level = s.attributes.getValue("level");
                if (level != null) {
                    levels.put(s.attributes.getValue("name"), level);
                }
            } else if (Objects.equals(rootPath, s.elementPath.getCopyOfPartList())) {
                String level = s.attributes.getValue("level");
                if (level != null) {
                    rootLevel = level;
                }
            }
            int classIndex = s.attributes.getIndex("class");
            if (classIndex != -1) {
                allClasses.add(s.attributes.getValue(classIndex));
            }
        }
    }
    boolean disableConsole = false;
    Set<String> delayedClasses = new HashSet<>();
    for (String i : allClasses) {
        if (i.equals("ch.qos.logback.core.ConsoleAppender")) {
            disableConsole = true;
        }
        try {
            Class<?> c = Thread.currentThread().getContextClassLoader().loadClass(i);
            if (LifeCycle.class.isAssignableFrom(c)) {
                delayedClasses.add(i);
            }
        } catch (ClassNotFoundException exception) {
            throw new RuntimeException(exception);
        }
    }
    if (disableConsole) {
        runTimeConfigurationDefaultBuildItemBuildProducer.produce(new RunTimeConfigurationDefaultBuildItem("quarkus.log.console.enable", "false"));
    }
    for (String i : delayedClasses) {
        try (ClassCreator c = new ClassCreator(new GeneratedClassGizmoAdaptor(generatedClasses, (Function<String, String>) s -> s.substring(s.length() - LogbackRecorder.DELAYED.length())), i + LogbackRecorder.DELAYED, null, i, DelayedStart.class.getName())) {
            MethodCreator start = c.getMethodCreator("start", void.class);
            start.invokeStaticMethod(MethodDescriptor.ofMethod(LogbackRecorder.class, "addDelayed", void.class, DelayedStart.class), start.getThis());
            start.returnValue(null);
            MethodCreator method = c.getMethodCreator("doQuarkusDelayedStart", void.class);
            method.invokeSpecialMethod(MethodDescriptor.ofMethod(i, "start", void.class), method.getThis());
            method.returnValue(null);
        }
    }
    if (rootLevel != null) {
        runTimeConfigurationDefaultBuildItemBuildProducer.produce(new RunTimeConfigurationDefaultBuildItem("quarkus.log.level", rootLevel));
    }
    for (Map.Entry<String, String> e : levels.entrySet()) {
        runTimeConfigurationDefaultBuildItemBuildProducer.produce(new RunTimeConfigurationDefaultBuildItem("quarkus.log.category.\"" + e.getKey() + "\".level", e.getValue()));
    }
    Map<String, String> buildProperties = new HashMap<>(outputTargetBuildItem.getBuildSystemProperties().entrySet().stream().collect(Collectors.toMap(Object::toString, Object::toString)));
    buildProperties.put(PROJECT_VERSION, curateOutcomeBuildItem.getEffectiveModel().getAppArtifact().getVersion());
    recorder.init(events.get(), delayedClasses, shutdownContextBuildItem, buildProperties);
}
Also used : DelayedStart(io.quarkiverse.logback.runtime.DelayedStart) HashMap(java.util.HashMap) ClassCreator(io.quarkus.gizmo.ClassCreator) URL(java.net.URL) LogbackRecorder(io.quarkiverse.logback.runtime.LogbackRecorder) Function(java.util.function.Function) JoranConfigurator(ch.qos.logback.classic.joran.JoranConfigurator) StartEvent(ch.qos.logback.core.joran.event.StartEvent) List(java.util.List) EventSubstitution(io.quarkiverse.logback.runtime.events.EventSubstitution) HashSet(java.util.HashSet) AtomicReference(java.util.concurrent.atomic.AtomicReference) LoggerContext(ch.qos.logback.classic.LoggerContext) GeneratedClassGizmoAdaptor(io.quarkus.deployment.GeneratedClassGizmoAdaptor) MethodCreator(io.quarkus.gizmo.MethodCreator) SaxEvent(ch.qos.logback.core.joran.event.SaxEvent) RunTimeConfigurationDefaultBuildItem(io.quarkus.deployment.builditem.RunTimeConfigurationDefaultBuildItem) Map(java.util.Map) HashMap(java.util.HashMap) Record(io.quarkus.deployment.annotations.Record) BuildStep(io.quarkus.deployment.annotations.BuildStep)

Aggregations

ClassCreator (io.quarkus.gizmo.ClassCreator)10 MethodCreator (io.quarkus.gizmo.MethodCreator)10 BuildStep (io.quarkus.deployment.annotations.BuildStep)6 ReflectiveClassBuildItem (io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem)6 FieldCreator (io.quarkus.gizmo.FieldCreator)6 ResultHandle (io.quarkus.gizmo.ResultHandle)6 List (java.util.List)5 ActionDispatchingConfiguration (io.quarkiverse.githubaction.deployment.DispatchingConfiguration.ActionDispatchingConfiguration)4 ActionLiteral (io.quarkiverse.githubaction.Action.ActionLiteral)3 EventAnnotation (io.quarkiverse.githubaction.deployment.DispatchingConfiguration.EventAnnotation)3 EventAnnotationLiteral (io.quarkiverse.githubaction.deployment.DispatchingConfiguration.EventAnnotationLiteral)3 GitHubEventHandler (io.quarkiverse.githubaction.runtime.GitHubEventHandler)3 GitHubApiClassWithBridgeMethodsBuildItem (io.quarkiverse.githubapi.deployment.GitHubApiClassWithBridgeMethodsBuildItem)3 EventDispatchingConfiguration (io.quarkiverse.githubapp.deployment.DispatchingConfiguration.EventDispatchingConfiguration)3 AdditionalBeanBuildItem (io.quarkus.arc.deployment.AdditionalBeanBuildItem)3 GeneratedBeanBuildItem (io.quarkus.arc.deployment.GeneratedBeanBuildItem)3 GeneratedBeanGizmoAdaptor (io.quarkus.arc.deployment.GeneratedBeanGizmoAdaptor)3 BuildProducer (io.quarkus.deployment.annotations.BuildProducer)3 CombinedIndexBuildItem (io.quarkus.deployment.builditem.CombinedIndexBuildItem)3 FeatureBuildItem (io.quarkus.deployment.builditem.FeatureBuildItem)3