aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAhmed El Khazari <ahmed.el.khazari@qt.io>2025-01-31 16:50:48 +0200
committerVille Voutilainen <ville.voutilainen@qt.io>2025-04-15 05:59:30 +0000
commit19767ce3c7407584ae49a4f291e41b0294533a75 (patch)
tree60862a6d90dd37f4548b4fa896d53c6f7373ddf9
parent0c4f42b5a301b5bba1ce30d13edbf58f848981a4 (diff)
Introduce GenerationProcessorAPI for generation workflows
This commit introduces the implementation of the GenerationProcessorAPI, which provides a unified and extensible interface for orchestrating the generation workflows. - Introduced the GenerationProcessorAPI to expose a comprehensive set of methods for: - Initiating generation processes - Configuring generation parameters - Integrated the GenerationProcessorAPIImpl with the underlying Processors and Generators Task-number: QTTA-271 Change-Id: I62af129ad77004b4b4c1df85c4614e97d2cc971d Reviewed-by: Ville Voutilainen <ville.voutilainen@qt.io>
-rw-r--r--compiler/src/main/java/io/github/landerlyoung/jenny/JennyAnnotationProcessor.kt177
-rw-r--r--compiler/src/main/java/io/github/landerlyoung/jenny/JennyProcessorConfiguration.kt106
-rw-r--r--compiler/src/main/java/io/github/landerlyoung/jenny/api/GenerationProcessorAPI.kt42
-rw-r--r--compiler/src/main/java/io/github/landerlyoung/jenny/api/GenerationProcessorAPIImpl.kt41
-rw-r--r--compiler/src/main/java/io/github/landerlyoung/jenny/api/GenerationProcessorFactory.kt14
5 files changed, 285 insertions, 95 deletions
diff --git a/compiler/src/main/java/io/github/landerlyoung/jenny/JennyAnnotationProcessor.kt b/compiler/src/main/java/io/github/landerlyoung/jenny/JennyAnnotationProcessor.kt
index aabbcba..ca17f3e 100644
--- a/compiler/src/main/java/io/github/landerlyoung/jenny/JennyAnnotationProcessor.kt
+++ b/compiler/src/main/java/io/github/landerlyoung/jenny/JennyAnnotationProcessor.kt
@@ -1,132 +1,119 @@
-/**
+/*
+ * Copyright (C) 2024 The Qt Company Ltd.
* Copyright 2016 landerlyoung@gmail.com
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * SPDX-License-Identifier: Apache-2.0
*/
+
package io.github.landerlyoung.jenny
+import io.github.landerlyoung.jenny.api.GenerationProcessorAPI
+import io.github.landerlyoung.jenny.api.GenerationProcessorFactory
+import io.github.landerlyoung.jenny.utils.AnnotationResolver
+
import javax.annotation.processing.AbstractProcessor
-import javax.annotation.processing.Filer
import javax.annotation.processing.Messager
import javax.annotation.processing.ProcessingEnvironment
import javax.annotation.processing.RoundEnvironment
+
import javax.lang.model.SourceVersion
import javax.lang.model.element.TypeElement
import javax.lang.model.type.MirroredTypesException
-import javax.lang.model.util.Elements
import javax.lang.model.util.Types
+
import javax.tools.Diagnostic
-/**
- * Author: landerlyoung@gmail.com
- * Date: 2014-12-16
- * Time: 19:42
- * Life with passion. Code with creativity!
- */
class JennyAnnotationProcessor : AbstractProcessor() {
- private lateinit var mMessager: Messager
- private lateinit var mTypeUtils: Types
- private lateinit var mElementsUtils: Elements
- private lateinit var mFiler: Filer
- private lateinit var mConfigurations: Configurations
+
+ private lateinit var generationProcessor: GenerationProcessorAPI
+ private lateinit var jennyConfigurations: JennyProcessorConfiguration
+
+ private lateinit var messager: Messager
+ private lateinit var typeUtils: Types
@Synchronized
override fun init(processingEnv: ProcessingEnvironment) {
super.init(processingEnv)
- mMessager = processingEnv.messager
- mTypeUtils = processingEnv.typeUtils
- mElementsUtils = processingEnv.elementUtils
- mFiler = processingEnv.filer
- mConfigurations = Configurations.fromOptions(processingEnv.options)
+ messager = processingEnv.messager
+ typeUtils = processingEnv.typeUtils
+ jennyConfigurations = JennyProcessorConfiguration.fromOptions(processingEnv.options)
+
+ messager.printMessage(Diagnostic.Kind.NOTE, "Jenny configured with:${jennyConfigurations}")
- mMessager.printMessage(Diagnostic.Kind.NOTE, "Jenny configured with:${mConfigurations}")
+ generationProcessor = GenerationProcessorFactory.create(jennyConfigurations)
}
override fun process(annotations: Set<TypeElement>, roundEnv: RoundEnvironment): Boolean {
if (roundEnv.errorRaised()
- || roundEnv.processingOver()
- || !annotations.any { it.qualifiedName.toString() in SUPPORTED_ANNOTATIONS }) return false
+ || roundEnv.processingOver()
+ || !annotations.any { it.qualifiedName.toString() in SUPPORTED_ANNOTATIONS }
+ ) return false
try {
- val env = Environment(mMessager, mTypeUtils, mElementsUtils, mFiler, mConfigurations)
-
- generateNativeGlueCode(roundEnv, env)
- val proxyClasses = generateNativeProxy(roundEnv, env)
- generateFusionProxyHeader(env, proxyClasses)
- generateJniHelper(env)
+ generateNativeGlueCode(roundEnv)
+ generateNativeProxy(roundEnv)
} catch (e: Throwable) {
- mMessager.printMessage(Diagnostic.Kind.ERROR, "Jenny failed to process ${e.javaClass.name} ${e.message}")
+ messager.printMessage(Diagnostic.Kind.ERROR, "Jenny failed to process ${e.javaClass.name} ${e.message}")
}
return true
}
- private fun generateNativeGlueCode(roundEnv: RoundEnvironment, env: Environment): List<CppClass> {
- // classify annotations by class
+ private fun generateNativeGlueCode(roundEnv: RoundEnvironment) {
return roundEnv.getElementsAnnotatedWith(NativeClass::class.java)
- .filterIsInstance<TypeElement>()
- .map {
- NativeGlueGenerator(env, it).doGenerate()
- }
+ .filterIsInstance<TypeElement>()
+ .forEach {
+ generationProcessor.setGlueNamespace(jennyConfigurations.glueNamespace)
+ generationProcessor.generateGlue(it)
+ }
}
- private fun generateNativeProxy(roundEnv: RoundEnvironment, env: Environment): List<CppClass> {
- val classes = mutableListOf<CppClass>()
+ private fun generateNativeProxy(roundEnv: RoundEnvironment) {
- classes += roundEnv.getElementsAnnotatedWith(NativeProxy::class.java)
- .map {
- val config = NativeProxyGenerator.NativeProxyConfig(
- (it.getAnnotation(NativeProxy::class.java)
- ?: AnnotationResolver.getDefaultImplementation(NativeProxy::class.java)))
- NativeProxyGenerator(env, it as TypeElement, config).doGenerate()
- }
+ roundEnv.getElementsAnnotatedWith(NativeProxy::class.java)
+ .forEach {
+ val annotation = it.getAnnotation(NativeProxy::class.java)
+ ?: AnnotationResolver.getDefaultImplementation(NativeProxy::class.java)
- classes += (roundEnv.getElementsAnnotatedWith(NativeProxyForClasses::class.java)
- .asSequence()
- .map { it.getAnnotation(NativeProxyForClasses::class.java) }
+ val proxyConfiguration = jennyConfigurations.provideProxyConfiguration().copy(
+ namespace = annotation.namespace,
+ allFields = annotation.allFields,
+ allMethods = annotation.allMethods,
+ onlyPublicMethod = false,
+ )
+ generationProcessor.configureProxy(proxyConfiguration)
+ generationProcessor.generateProxy(it as TypeElement)
+ }
+
+ (roundEnv.getElementsAnnotatedWith(NativeProxyForClasses::class.java)
+ .asSequence()
+ .map { it.getAnnotation(NativeProxyForClasses::class.java) }
+
roundEnv.getElementsAnnotatedWith(NativeProxyForClasses.RepeatContainer::class.java)
- .asSequence()
- .flatMap { it.getAnnotationsByType(NativeProxyForClasses::class.java).asSequence() }
- )
- .toCollection(mutableSetOf())
- .flatMap { annotation ->
- try {
- annotation.classes
- throw AssertionError("unreachable")
- } catch (e: MirroredTypesException) {
- e.typeMirrors
- }.map {
- val clazz = mTypeUtils.asElement(it) as TypeElement
-
- val config = NativeProxyGenerator.NativeProxyConfig(
- allMethods = true, allFields = true, namespace = annotation.namespace, onlyPublic = true)
-
- NativeProxyGenerator(env, clazz, config).doGenerate()
+ .asSequence()
+ .flatMap {
+ it.getAnnotationsByType(NativeProxyForClasses::class.java).asSequence()
}
+ )
+ .toCollection(mutableSetOf())
+ .forEach { annotation ->
+ try {
+ annotation.classes
+ throw AssertionError("unreachable")
+ } catch (e: MirroredTypesException) {
+ e.typeMirrors
+ }.forEach {
+
+ val proxyConfiguration = jennyConfigurations.provideProxyConfiguration().copy(
+ namespace = annotation.namespace,
+ allFields = true,
+ allMethods = true,
+ onlyPublicMethod = true
+ )
+
+ generationProcessor.configureProxy(proxyConfiguration)
+ generationProcessor.generateProxy(typeUtils.asElement(it) as TypeElement)
}
-
- return classes
- }
-
- private fun generateJniHelper(env: Environment) {
- env.createOutputFile(Constants.JENNY_GEN_DIR_PROXY, Constants.JENNY_JNI_HELPER_H_NAME).use {
- it.write(Constants.JENNY_JNI_HELPER_H_CONTENT.toByteArray(Charsets.UTF_8))
- }
- }
-
- private fun generateFusionProxyHeader(env: Environment, proxyClasses: Collection<CppClass>) {
- FusionProxyGenerator(env, proxyClasses).generate()
+ }
}
override fun getSupportedSourceVersion(): SourceVersion {
@@ -138,17 +125,17 @@ class JennyAnnotationProcessor : AbstractProcessor() {
}
override fun getSupportedOptions(): Set<String> {
- return Configurations.ALL_OPTIONS
+ return JennyProcessorConfiguration.configurationOptions
}
companion object {
private val SUPPORTED_ANNOTATIONS: Set<String> = setOf(
- NativeClass::class.java.name,
- NativeCode::class.java.name,
- NativeFieldProxy::class.java.name,
- NativeMethodProxy::class.java.name,
- NativeProxy::class.java.name,
- NativeProxyForClasses::class.java.name
+ NativeClass::class.java.name,
+ NativeCode::class.java.name,
+ NativeFieldProxy::class.java.name,
+ NativeMethodProxy::class.java.name,
+ NativeProxy::class.java.name,
+ NativeProxyForClasses::class.java.name
)
}
}
diff --git a/compiler/src/main/java/io/github/landerlyoung/jenny/JennyProcessorConfiguration.kt b/compiler/src/main/java/io/github/landerlyoung/jenny/JennyProcessorConfiguration.kt
new file mode 100644
index 0000000..f519d4f
--- /dev/null
+++ b/compiler/src/main/java/io/github/landerlyoung/jenny/JennyProcessorConfiguration.kt
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2025 The Qt Company Ltd.
+ * Copyright 2016 landerlyoung@gmail.com
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.github.landerlyoung.jenny
+
+import io.github.landerlyoung.jenny.model.JennyProxyConfiguration
+import io.github.landerlyoung.jenny.provider.ProviderConfiguration
+
+/**
+ * @param outputDirectory full path where the code is generated
+ * @param glueNamespace name space for the C++ glue files (optional)
+ * @param useTemplates flag to set the providers to use templates code
+ * @param templateDirectory full path of custom templates
+ * @param templateBuildDirectory full path of where the compiled templates is generated
+ * @param threadSafe add mutex for C++ proxy files
+ * @param useJniHelper flag to use JniHelper file
+ * @param headerOnlyProxy only header file (.h) is generated
+ * @param errorLoggerFunction Custom Error Logging function
+ * @param fusionProxyHeaderName Custom Fusion header file name
+ */
+
+data class JennyProcessorConfiguration(
+ val outputDirectory: String,
+ val glueNamespace: String = "",
+ val useTemplates: Boolean = true,
+ val useQjniTemplates: Boolean = false,
+ val templateDirectory: String? = null,
+ val templateBuildDirectory: String? = null,
+ val threadSafe: Boolean = true,
+ val useJniHelper: Boolean = false,
+ val headerOnlyProxy: Boolean = false,
+ val errorLoggerFunction: String = "",
+ val fusionProxyHeaderName: String = "",
+) {
+ fun provideProxyConfiguration(): JennyProxyConfiguration {
+ return JennyProxyConfiguration(
+ namespace = "",
+ threadSafe = threadSafe,
+ useJniHelper = useJniHelper,
+ headerOnlyProxy = headerOnlyProxy,
+ allFields = true,
+ allMethods = true,
+ onlyPublicMethod = true,
+ errorLoggingFunction = errorLoggerFunction,
+ fusionProxyHeaderName = fusionProxyHeaderName
+ )
+ }
+
+ fun provideTemplateConfiguration(): ProviderConfiguration {
+ return ProviderConfiguration(useTemplates, useQjniTemplates, templateDirectory, templateBuildDirectory)
+ }
+
+ companion object {
+ private const val PREFIX = "jenny."
+ // Constructing Keys
+
+ /**
+ * external error log function
+ * void (function_type)(JNIEnv* env, const char* error);
+ */
+ private val ERROR_LOGGER_FUNCTION = PREFIX + JennyProcessorConfiguration::errorLoggerFunction.name
+
+ private val OUTPUT_DIRECTORY = PREFIX + JennyProcessorConfiguration::outputDirectory.name
+
+ private val FUSION_PROXY_HEADER_NAME = PREFIX + JennyProcessorConfiguration::fusionProxyHeaderName.name
+
+ private val USE_TEMPLATES = PREFIX + JennyProcessorConfiguration::useTemplates.name
+ private val USE_QJNI_TEMPLATES = PREFIX + JennyProcessorConfiguration::useQjniTemplates.name
+ private val TEMPLATE_DIRECTORY = PREFIX + JennyProcessorConfiguration::templateDirectory.name
+ private val TEMPLATE_BUILD_DIRECTORY = PREFIX + JennyProcessorConfiguration::templateBuildDirectory.name
+
+ private val HEADER_ONLY_PROXY = PREFIX + JennyProcessorConfiguration::headerOnlyProxy.name
+ private val USE_JNI_HELPER = PREFIX + JennyProcessorConfiguration::useJniHelper.name
+ private val THREAD_SAFE = PREFIX + JennyProcessorConfiguration::threadSafe.name
+
+ val configurationOptions: Set<String>
+ get() = setOf(
+ THREAD_SAFE,
+ ERROR_LOGGER_FUNCTION,
+ USE_TEMPLATES,
+ USE_QJNI_TEMPLATES,
+ TEMPLATE_DIRECTORY,
+ TEMPLATE_BUILD_DIRECTORY,
+ OUTPUT_DIRECTORY,
+ FUSION_PROXY_HEADER_NAME,
+ HEADER_ONLY_PROXY,
+ USE_JNI_HELPER,
+ )
+
+ fun fromOptions(options: Map<String, String>) = JennyProcessorConfiguration(
+ outputDirectory = options[OUTPUT_DIRECTORY] ?: "src/main/cpp/gen",
+ useTemplates = options[USE_TEMPLATES] == true.toString(),
+ useQjniTemplates = options[USE_QJNI_TEMPLATES] == true.toString(),
+ templateDirectory = options[TEMPLATE_DIRECTORY],
+ templateBuildDirectory = options[TEMPLATE_BUILD_DIRECTORY],
+ threadSafe = options[THREAD_SAFE] == true.toString(),
+ useJniHelper = options[USE_JNI_HELPER] == true.toString(),
+ headerOnlyProxy = options[HEADER_ONLY_PROXY] == true.toString(),
+ errorLoggerFunction = options[ERROR_LOGGER_FUNCTION] ?: "",
+ fusionProxyHeaderName = options[FUSION_PROXY_HEADER_NAME] ?: "JennyFusionProxy.h"
+ )
+ }
+}
diff --git a/compiler/src/main/java/io/github/landerlyoung/jenny/api/GenerationProcessorAPI.kt b/compiler/src/main/java/io/github/landerlyoung/jenny/api/GenerationProcessorAPI.kt
new file mode 100644
index 0000000..f1d29dd
--- /dev/null
+++ b/compiler/src/main/java/io/github/landerlyoung/jenny/api/GenerationProcessorAPI.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2025 The Qt Company Ltd.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.github.landerlyoung.jenny.api
+
+import io.github.landerlyoung.jenny.JennyProcessorConfiguration
+import io.github.landerlyoung.jenny.model.JennyProxyConfiguration
+
+interface GenerationProcessorAPI {
+ /**
+ * Generates native glue code for the specified class.
+ * @param input the class for which to generate glue code.
+ */
+ fun generateGlue(input: Any)
+
+ /**
+ * Sets the namespace for glue code generation.
+ * @param namespace the namespace to use for glue code.
+ */
+ fun setGlueNamespace(namespace: String)
+
+ /**
+ * Generates proxy code for the specified class.
+ * @param input the class for which to generate proxy code.
+ */
+ fun generateProxy(input: Any)
+
+ /**
+ * Configures proxy generation settings.
+ * @param proxyConfiguration the configuration object for proxy generation.
+ */
+ fun configureProxy(proxyConfiguration: JennyProxyConfiguration)
+
+ /**
+ * Configures processor settings.
+ * @param configuration the configuration object for the processor.
+ */
+ fun configureProcessor(configuration: JennyProcessorConfiguration)
+}
+
diff --git a/compiler/src/main/java/io/github/landerlyoung/jenny/api/GenerationProcessorAPIImpl.kt b/compiler/src/main/java/io/github/landerlyoung/jenny/api/GenerationProcessorAPIImpl.kt
new file mode 100644
index 0000000..d323952
--- /dev/null
+++ b/compiler/src/main/java/io/github/landerlyoung/jenny/api/GenerationProcessorAPIImpl.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2025 The Qt Company Ltd.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.github.landerlyoung.jenny.api
+
+import io.github.landerlyoung.jenny.JennyProcessorConfiguration
+import io.github.landerlyoung.jenny.model.JennyProxyConfiguration
+import io.github.landerlyoung.jenny.processor.NativeGlueProcessor
+import io.github.landerlyoung.jenny.processor.NativeProxyProcessor
+
+internal class GenerationProcessorAPIImpl(
+ jennyProcessorConfiguration: JennyProcessorConfiguration,
+) : GenerationProcessorAPI {
+
+ private val nativeGlueProcessor = NativeGlueProcessor(jennyProcessorConfiguration.outputDirectory)
+
+ private val nativeProxyProcessor = NativeProxyProcessor(
+ outputDirectory = jennyProcessorConfiguration.outputDirectory,
+ providerConfiguration = jennyProcessorConfiguration.provideTemplateConfiguration(),
+ proxyConfiguration = jennyProcessorConfiguration.provideProxyConfiguration()
+ )
+
+ override fun generateGlue(input: Any) = nativeGlueProcessor.process(input)
+
+ override fun setGlueNamespace(namespace: String) = nativeGlueProcessor.setNamespace(namespace)
+
+ override fun generateProxy(input: Any) = nativeProxyProcessor.process(input)
+
+ override fun configureProxy(proxyConfiguration: JennyProxyConfiguration) =
+ nativeProxyProcessor.applyConfiguration(proxyConfiguration)
+
+ override fun configureProcessor(configuration: JennyProcessorConfiguration) {
+ nativeProxyProcessor.apply {
+ applyConfiguration(configuration.provideProxyConfiguration())
+ setOutputTargetPath(configuration.outputDirectory)
+ }
+ nativeGlueProcessor.setOutputTargetPath(configuration.outputDirectory)
+ }
+}
diff --git a/compiler/src/main/java/io/github/landerlyoung/jenny/api/GenerationProcessorFactory.kt b/compiler/src/main/java/io/github/landerlyoung/jenny/api/GenerationProcessorFactory.kt
new file mode 100644
index 0000000..02a0992
--- /dev/null
+++ b/compiler/src/main/java/io/github/landerlyoung/jenny/api/GenerationProcessorFactory.kt
@@ -0,0 +1,14 @@
+/*
+ * Copyright (C) 2025 The Qt Company Ltd.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.github.landerlyoung.jenny.api
+
+import io.github.landerlyoung.jenny.JennyProcessorConfiguration
+
+object GenerationProcessorFactory {
+ fun create(configuration: JennyProcessorConfiguration): GenerationProcessorAPI {
+ return GenerationProcessorAPIImpl(configuration)
+ }
+}