From cadc9fce0ecf623c553ad231296ecfa256dcd551 Mon Sep 17 00:00:00 2001 From: evanchooly Date: Sun, 18 Aug 2024 22:50:42 -0400 Subject: [PATCH] rolling along with gizmo --- .mvn/wrapper/maven-wrapper.properties | 4 +- critter/core/pom.xml | 5 + .../kotlin/dev/morphia/critter/Critter.kt | 4 + .../critter/parser/CritterGizmoGenerator.kt | 29 ++++ .../morphia/critter/parser/PropertyFinder.kt | 19 +-- .../parser/asm/CritterEntityModelGenerator.kt | 4 +- .../asm/CritterPropertyModelGenerator.kt | 2 +- .../parser/asm/EntityAccessorGenerator.kt | 2 +- .../morphia/critter/parser/asm/Generators.kt | 5 - .../parser/gizmo/BaseGizmoGenerator.kt | 13 ++ .../parser/gizmo/GizmoEntityModelGenerator.kt | 4 + .../gizmo/GizmoPropertyAccessorGenerator.kt | 97 ++++++++++++ .../gizmo/GizmoPropertyModelGenerator.kt | 139 ++++++++++++++++++ .../critter/parser/java/CritterClassLoader.kt | 8 + .../morphia/critter/parser/GeneratorTest.kt | 5 +- .../critter/parser/TestAccessorsMutators.kt | 2 +- .../parser/gizmo/TestGizmoGeneration.kt | 64 ++++++++ mvnw.cmd | 0 util/pom.xml | 2 + 19 files changed, 381 insertions(+), 27 deletions(-) create mode 100644 critter/core/src/main/kotlin/dev/morphia/critter/parser/CritterGizmoGenerator.kt create mode 100644 critter/core/src/main/kotlin/dev/morphia/critter/parser/gizmo/BaseGizmoGenerator.kt create mode 100644 critter/core/src/main/kotlin/dev/morphia/critter/parser/gizmo/GizmoEntityModelGenerator.kt create mode 100644 critter/core/src/main/kotlin/dev/morphia/critter/parser/gizmo/GizmoPropertyAccessorGenerator.kt create mode 100644 critter/core/src/main/kotlin/dev/morphia/critter/parser/gizmo/GizmoPropertyModelGenerator.kt create mode 100644 critter/core/src/test/kotlin/dev/morphia/critter/parser/gizmo/TestGizmoGeneration.kt mode change 100755 => 100644 mvnw.cmd diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index f82b3e67635..72d6eaa6529 100644 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -14,5 +14,5 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/4.0.0-alpha-13/apache-maven-4.0.0-alpha-13-bin.zip -wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/4.0.0-beta-3/apache-maven-4.0.0-beta-3-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar diff --git a/critter/core/pom.xml b/critter/core/pom.xml index c24cee74b44..a1fd1fe6325 100644 --- a/critter/core/pom.xml +++ b/critter/core/pom.xml @@ -72,6 +72,11 @@ 2.29.0.Final compile + + io.quarkus.gizmo + gizmo + 1.8.0 + diff --git a/critter/core/src/main/kotlin/dev/morphia/critter/Critter.kt b/critter/core/src/main/kotlin/dev/morphia/critter/Critter.kt index d8fcb5580f9..f513d28fc99 100644 --- a/critter/core/src/main/kotlin/dev/morphia/critter/Critter.kt +++ b/critter/core/src/main/kotlin/dev/morphia/critter/Critter.kt @@ -11,6 +11,10 @@ import java.io.File class Critter(val root: File) { companion object { var outputDirectory = File("target/generated-sources/morphia") + + fun critterPackage(entity: Class<*>): String { + return "${entity.packageName}.__morphia.${entity.simpleName.lowercase()}" + } } private val outputDir = File(root, "target") diff --git a/critter/core/src/main/kotlin/dev/morphia/critter/parser/CritterGizmoGenerator.kt b/critter/core/src/main/kotlin/dev/morphia/critter/parser/CritterGizmoGenerator.kt new file mode 100644 index 00000000000..42f142b0b81 --- /dev/null +++ b/critter/core/src/main/kotlin/dev/morphia/critter/parser/CritterGizmoGenerator.kt @@ -0,0 +1,29 @@ +package dev.morphia.critter.parser + +import dev.morphia.critter.CritterEntityModel +import dev.morphia.critter.parser.gizmo.GizmoEntityModelGenerator +import dev.morphia.critter.parser.java.CritterClassLoader +import dev.morphia.critter.parser.java.CritterParser.critterClassLoader +import dev.morphia.mapping.Mapper +import org.objectweb.asm.ClassReader +import org.objectweb.asm.tree.ClassNode + +class CritterGizmoGenerator(val classLoader: CritterClassLoader, val mapper: Mapper) { + val propertyFinder = PropertyFinder(mapper, classLoader) + + fun generate(type: Class<*>): CritterEntityModel? { + val classNode = ClassNode() + ClassReader(type.name).accept(classNode, 0) + val propertyNames = propertyFinder.find(type, classNode) + + return null // entityModel(type, propertyNames) + } + + private fun entityModel(type: Class<*>, propertyNames: List): CritterEntityModel { + val entityModelGenerator = GizmoEntityModelGenerator(type, propertyNames) + return critterClassLoader + .loadClass(entityModelGenerator.generatedType) + .getConstructor(Mapper::class.java) + .newInstance(mapper) as CritterEntityModel + } +} diff --git a/critter/core/src/main/kotlin/dev/morphia/critter/parser/PropertyFinder.kt b/critter/core/src/main/kotlin/dev/morphia/critter/parser/PropertyFinder.kt index f4e74d64046..9fe0f4f3e1a 100644 --- a/critter/core/src/main/kotlin/dev/morphia/critter/parser/PropertyFinder.kt +++ b/critter/core/src/main/kotlin/dev/morphia/critter/parser/PropertyFinder.kt @@ -2,8 +2,8 @@ package dev.morphia.critter.parser import dev.morphia.config.PropertyAnnotationProvider import dev.morphia.critter.parser.asm.AddFieldAccessorMethods -import dev.morphia.critter.parser.asm.CritterPropertyModelGenerator -import dev.morphia.critter.parser.asm.EntityAccessorGenerator +import dev.morphia.critter.parser.gizmo.GizmoPropertyAccessorGenerator +import dev.morphia.critter.parser.gizmo.GizmoPropertyModelGenerator import dev.morphia.critter.parser.java.CritterClassLoader import dev.morphia.critter.parser.java.CritterParser import dev.morphia.mapping.Mapper @@ -28,16 +28,11 @@ class PropertyFinder(mapper: Mapper, val classLoader: CritterClassLoader) { AddFieldAccessorMethods(entityType, fields).emit() ) fields.forEach { field -> - val accessorGenerator = EntityAccessorGenerator(entityType, field) - classLoader.register( - accessorGenerator.generatedType.className, - accessorGenerator.emit() - ) - - val propertyModelGenerator = CritterPropertyModelGenerator(entityType, field) - val className = propertyModelGenerator.generatedType.className - classLoader.register(className, propertyModelGenerator.emit()) - models += className + val accessorGenerator = GizmoPropertyAccessorGenerator(entityType, field) + accessorGenerator.emit() + val propertyModelGenerator = GizmoPropertyModelGenerator(entityType, field) + propertyModelGenerator.emit() + models += propertyModelGenerator.generatedType } } diff --git a/critter/core/src/main/kotlin/dev/morphia/critter/parser/asm/CritterEntityModelGenerator.kt b/critter/core/src/main/kotlin/dev/morphia/critter/parser/asm/CritterEntityModelGenerator.kt index 8efa4540004..76c3021fe30 100644 --- a/critter/core/src/main/kotlin/dev/morphia/critter/parser/asm/CritterEntityModelGenerator.kt +++ b/critter/core/src/main/kotlin/dev/morphia/critter/parser/asm/CritterEntityModelGenerator.kt @@ -1,8 +1,8 @@ package dev.morphia.critter.parser.asm import dev.morphia.annotations.Entity +import dev.morphia.critter.Critter.Companion.critterPackage import dev.morphia.critter.CritterEntityModel -import dev.morphia.critter.parser.asm.Generators.critterPackage import java.lang.reflect.InvocationHandler import java.lang.reflect.Method import java.lang.reflect.Modifier @@ -19,7 +19,7 @@ class CritterEntityModelGenerator(val entity: Class<*>, val models: List } init { - val generatorName = "${critterPackage(entity)}${entity.simpleName}EntityModel" + val generatorName = "${critterPackage(entity)}.${entity.simpleName}EntityModel" generatedType = Type.getType("L${generatorName};") } diff --git a/critter/core/src/main/kotlin/dev/morphia/critter/parser/asm/CritterPropertyModelGenerator.kt b/critter/core/src/main/kotlin/dev/morphia/critter/parser/asm/CritterPropertyModelGenerator.kt index 388232a3d2c..8f04b89111f 100644 --- a/critter/core/src/main/kotlin/dev/morphia/critter/parser/asm/CritterPropertyModelGenerator.kt +++ b/critter/core/src/main/kotlin/dev/morphia/critter/parser/asm/CritterPropertyModelGenerator.kt @@ -1,7 +1,7 @@ package dev.morphia.critter.parser.asm +import dev.morphia.critter.Critter.Companion.critterPackage import dev.morphia.critter.identifierCase -import dev.morphia.critter.parser.asm.Generators.critterPackage import dev.morphia.critter.titleCase import dev.morphia.mapping.codec.pojo.critter.CritterPropertyModel import org.objectweb.asm.FieldVisitor diff --git a/critter/core/src/main/kotlin/dev/morphia/critter/parser/asm/EntityAccessorGenerator.kt b/critter/core/src/main/kotlin/dev/morphia/critter/parser/asm/EntityAccessorGenerator.kt index f6dbcbdf915..d531d4c1262 100644 --- a/critter/core/src/main/kotlin/dev/morphia/critter/parser/asm/EntityAccessorGenerator.kt +++ b/critter/core/src/main/kotlin/dev/morphia/critter/parser/asm/EntityAccessorGenerator.kt @@ -1,6 +1,6 @@ package dev.morphia.critter.parser.asm -import dev.morphia.critter.parser.asm.Generators.critterPackage +import dev.morphia.critter.Critter.Companion.critterPackage import dev.morphia.critter.parser.asm.Generators.wrap import dev.morphia.critter.titleCase import org.objectweb.asm.Label diff --git a/critter/core/src/main/kotlin/dev/morphia/critter/parser/asm/Generators.kt b/critter/core/src/main/kotlin/dev/morphia/critter/parser/asm/Generators.kt index 505b7e392bd..e840ff9a3e2 100644 --- a/critter/core/src/main/kotlin/dev/morphia/critter/parser/asm/Generators.kt +++ b/critter/core/src/main/kotlin/dev/morphia/critter/parser/asm/Generators.kt @@ -8,11 +8,6 @@ object Generators { var config = MorphiaConfig.load() var convention = MorphiaDefaultsConvention() - fun critterPackage(entity: Class<*>): String { - val name = "${entity.packageName}/__morphia/${entity.simpleName.lowercase()}/" - return name.replace('.', '/') - } - fun wrap(fieldType: Type): Type { return when (fieldType) { Type.VOID_TYPE -> Type.getType(Void::class.java) diff --git a/critter/core/src/main/kotlin/dev/morphia/critter/parser/gizmo/BaseGizmoGenerator.kt b/critter/core/src/main/kotlin/dev/morphia/critter/parser/gizmo/BaseGizmoGenerator.kt new file mode 100644 index 00000000000..8fb1fea85cb --- /dev/null +++ b/critter/core/src/main/kotlin/dev/morphia/critter/parser/gizmo/BaseGizmoGenerator.kt @@ -0,0 +1,13 @@ +package dev.morphia.critter.parser.gizmo + +import dev.morphia.critter.Critter.Companion.critterPackage + +open class BaseGizmoGenerator(val entity: Class<*>) { + val baseName: String + lateinit var generatedType: String + + init { + val `package` = critterPackage(entity) + baseName = `package` + } +} diff --git a/critter/core/src/main/kotlin/dev/morphia/critter/parser/gizmo/GizmoEntityModelGenerator.kt b/critter/core/src/main/kotlin/dev/morphia/critter/parser/gizmo/GizmoEntityModelGenerator.kt new file mode 100644 index 00000000000..ead756e46d7 --- /dev/null +++ b/critter/core/src/main/kotlin/dev/morphia/critter/parser/gizmo/GizmoEntityModelGenerator.kt @@ -0,0 +1,4 @@ +package dev.morphia.critter.parser.gizmo + +class GizmoEntityModelGenerator(type: Class<*>, propertyNames: List) : + BaseGizmoGenerator(type) {} diff --git a/critter/core/src/main/kotlin/dev/morphia/critter/parser/gizmo/GizmoPropertyAccessorGenerator.kt b/critter/core/src/main/kotlin/dev/morphia/critter/parser/gizmo/GizmoPropertyAccessorGenerator.kt new file mode 100644 index 00000000000..70282acfcff --- /dev/null +++ b/critter/core/src/main/kotlin/dev/morphia/critter/parser/gizmo/GizmoPropertyAccessorGenerator.kt @@ -0,0 +1,97 @@ +package dev.morphia.critter.parser.gizmo + +import dev.morphia.critter.parser.java.CritterParser.critterClassLoader +import dev.morphia.critter.titleCase +import io.quarkus.gizmo.ClassCreator +import io.quarkus.gizmo.MethodDescriptor.ofConstructor +import io.quarkus.gizmo.MethodDescriptor.ofMethod +import io.quarkus.gizmo.SignatureBuilder.* +import io.quarkus.gizmo.Type.* +import org.bson.codecs.pojo.PropertyAccessor +import org.objectweb.asm.Type.getReturnType +import org.objectweb.asm.Type.getType +import org.objectweb.asm.tree.FieldNode +import org.objectweb.asm.tree.MethodNode + +class GizmoPropertyAccessorGenerator : BaseGizmoGenerator { + constructor(entity: Class<*>, field: FieldNode) : super(entity) { + propertyName = field.name + propertyType = getType(field.desc).className + generatedType = "${baseName}.${propertyName.titleCase()}Accessor" + } + + constructor(entity: Class<*>, method: MethodNode) : super(entity) { + propertyName = method.name + propertyType = getReturnType(method.signature).className + generatedType = "${baseName}.${propertyName.titleCase()}Accessor" + } + + lateinit var creator: ClassCreator + val propertyName: String + val propertyType: String + + fun emit() { + creator = + ClassCreator.builder() + .signature( + forClass() + .addInterface( + parameterizedType( + classType(PropertyAccessor::class.java), + classType(propertyType) + ) + ) + ) + .classOutput { name, data -> + critterClassLoader.register(name.replace('/', '.'), data) + } + .className(generatedType) + .build() + + ctor() + get() + set() + creator.close() + } + + private fun get() { + val method = + creator.getMethodCreator(ofMethod(generatedType, "get", propertyType, entity.name)) + method.signature = + forMethod() + .addTypeParameter(typeVariable("S")) + .setReturnType(classType(propertyType)) + .addParameterType(classType(entity)) + .build() + method.setParameterNames(arrayOf("model")) + val toInvoke = ofMethod(entity, "__read${propertyName.titleCase()}", propertyType) + method.returnValue(method.invokeVirtualMethod(toInvoke, method.getMethodParam(0))) + } + + private fun set() { + val method = + creator.getMethodCreator( + ofMethod(generatedType, "set", "void", entity.name, propertyType) + ) + method.signature = + forMethod() + .addTypeParameter(typeVariable("S")) + .setReturnType(voidType()) + .addParameterType(classType(entity)) + .addParameterType(classType(propertyType)) + .build() + method.setParameterNames(arrayOf("model", "value")) + + val toInvoke = ofMethod(entity, "__write${propertyName.titleCase()}", "void", propertyType) + method.invokeVirtualMethod(toInvoke, method.getMethodParam(0), method.getMethodParam(1)) + method.returnValue(null) + } + + private fun ctor() { + val constructor = creator.getConstructorCreator(*arrayOf()) + constructor.invokeSpecialMethod(ofConstructor(Object::class.java), constructor.`this`) + constructor.returnVoid() + + constructor.close() + } +} diff --git a/critter/core/src/main/kotlin/dev/morphia/critter/parser/gizmo/GizmoPropertyModelGenerator.kt b/critter/core/src/main/kotlin/dev/morphia/critter/parser/gizmo/GizmoPropertyModelGenerator.kt new file mode 100644 index 00000000000..5409a4343ff --- /dev/null +++ b/critter/core/src/main/kotlin/dev/morphia/critter/parser/gizmo/GizmoPropertyModelGenerator.kt @@ -0,0 +1,139 @@ +package dev.morphia.critter.parser.gizmo + +import dev.morphia.critter.parser.java.CritterParser.critterClassLoader +import dev.morphia.critter.parser.ksp.extensions.methodCase +import dev.morphia.critter.titleCase +import dev.morphia.mapping.codec.pojo.EntityModel +import dev.morphia.mapping.codec.pojo.PropertyModel +import dev.morphia.mapping.codec.pojo.critter.CritterPropertyModel +import io.quarkus.gizmo.ClassCreator +import io.quarkus.gizmo.MethodCreator +import io.quarkus.gizmo.MethodDescriptor +import io.quarkus.gizmo.ResultHandle +import org.bson.codecs.pojo.PropertyAccessor +import org.objectweb.asm.Type +import org.objectweb.asm.Type.getType +import org.objectweb.asm.tree.AnnotationNode +import org.objectweb.asm.tree.FieldNode + +class GizmoPropertyModelGenerator : BaseGizmoGenerator { + + constructor(entity: Class<*>, field: FieldNode) : super(entity) { + propertyName = field.name.titleCase() + generatedType = "${baseName}.${propertyName}Model" + accessorType = "${baseName}.${propertyName}Accessor" + annotations = field.visibleAnnotations ?: listOf() + } + + val propertyName: String + val accessorType: String + lateinit var creator: ClassCreator + lateinit var annotations: List + + fun emit() { + creator = + ClassCreator.builder() + .classOutput { name, data -> + critterClassLoader.register(name.replace('/', '.'), data) + } + .className(generatedType) + .superClass(CritterPropertyModel::class.java) + .build() + + ctor() + getAccessor() + + creator.close() + } + + private fun ctor() { + val constructor = creator.getConstructorCreator(EntityModel::class.java) + constructor.invokeSpecialMethod( + MethodDescriptor.ofConstructor(PropertyModel::class.java, EntityModel::class.java), + constructor.`this`, + constructor.getMethodParam(0) + ) + constructor.setParameterNames(arrayOf("model")) + + registerAnnotations(constructor) + + constructor.close() + } + + private fun registerAnnotations(constructor: MethodCreator) { + val annotationMethod = + MethodDescriptor.ofMethod( + PropertyModel::class.java.name, + "annotation", + PropertyModel::class.java.name, + Annotation::class.java + ) + annotations.forEach { annotation -> + constructor.invokeVirtualMethod( + annotationMethod, + constructor.`this`, + annotationBuilder(constructor, annotation) + ) + } + } + + private fun annotationBuilder( + constructor: MethodCreator, + annotation: AnnotationNode + ): ResultHandle { + val type = getType(annotation.desc) + val classType = type.className.substringAfterLast('.') + val builderType = Type.getType("L${type.className}Builder;") + val builder = + MethodDescriptor.ofMethod( + builderType.className, + "${classType.methodCase()}Builder", + builderType.className + ) + + var local = constructor.invokeStaticMethod(builder) + val values = annotation.values?.windowed(2, 2) ?: emptyList() + values.forEach { value -> + val method = + MethodDescriptor.ofMethod( + builderType.className, + value[0] as String, + builderType.className, + value[1].javaClass + ) + constructor.invokeVirtualMethod(method, local, load(constructor, value[1])) + } + + return local + } + + private fun load(constructor: MethodCreator, value: Any): ResultHandle { + return when (value) { + is String -> constructor.load(value) + is Int -> constructor.load(value) + is Long -> constructor.load(value) + is Boolean -> constructor.load(value) + is List<*> -> { + val toTypedArray = value.map { load(constructor, it!!) }.toTypedArray() + constructor.marshalAsArray(value[0]!!.javaClass, *toTypedArray) + } + else -> TODO("${value.javaClass} is not yet supported") + } + } + + private fun getAccessor() { + val field = creator.getFieldCreator("accessor", accessorType) + val method = + creator.getMethodCreator( + MethodDescriptor.ofMethod( + creator.className, + "getAccessor", + PropertyAccessor::class.java.name + ) + ) + + method.returnValue(method.readInstanceField(field.fieldDescriptor, method.`this`)) + + method.close() + } +} diff --git a/critter/core/src/main/kotlin/dev/morphia/critter/parser/java/CritterClassLoader.kt b/critter/core/src/main/kotlin/dev/morphia/critter/parser/java/CritterClassLoader.kt index 1119628022d..e526a9f24b3 100644 --- a/critter/core/src/main/kotlin/dev/morphia/critter/parser/java/CritterClassLoader.kt +++ b/critter/core/src/main/kotlin/dev/morphia/critter/parser/java/CritterClassLoader.kt @@ -19,6 +19,14 @@ class CritterClassLoader(parent: ClassLoader?) : ChildFirst(parent, mapOf()) { dump(name) } + override fun loadClass(name: String?): Class<*> { + try { + return super.loadClass(name) + } catch (e: ClassNotFoundException) { + throw ClassNotFoundException("Known class names: ${typeDefinitions.keys}", e) + } + } + fun dump(name: String, mappings: Map = mapOf()) { File(output).mkdirs() val outputFolder = File(output, File(name.replace('.', '/')).parent) diff --git a/critter/core/src/test/kotlin/dev/morphia/critter/parser/GeneratorTest.kt b/critter/core/src/test/kotlin/dev/morphia/critter/parser/GeneratorTest.kt index 863490ffbad..ed325730123 100644 --- a/critter/core/src/test/kotlin/dev/morphia/critter/parser/GeneratorTest.kt +++ b/critter/core/src/test/kotlin/dev/morphia/critter/parser/GeneratorTest.kt @@ -4,14 +4,13 @@ import dev.morphia.critter.CritterEntityModel import dev.morphia.critter.parser.asm.Generators import dev.morphia.critter.parser.java.CritterParser.asmify import dev.morphia.critter.parser.java.CritterParser.critterClassLoader -import dev.morphia.critter.sources.Example import dev.morphia.mapping.Mapper import io.github.classgraph.ClassGraph import java.lang.reflect.Modifier import org.objectweb.asm.Type object GeneratorTest { - var entityModel: CritterEntityModel + lateinit var entityModel: CritterEntityModel val mapper = Mapper(Generators.config) val critterAsmGenerator = CritterAsmGenerator(critterClassLoader, mapper) @@ -28,7 +27,7 @@ object GeneratorTest { } } - entityModel = critterAsmGenerator.generate(Example::class.java) + // entityModel = critterAsmGenerator.generate(Example::class.java) } fun methodNames(clazz: Class<*>): Array> { diff --git a/critter/core/src/test/kotlin/dev/morphia/critter/parser/TestAccessorsMutators.kt b/critter/core/src/test/kotlin/dev/morphia/critter/parser/TestAccessorsMutators.kt index 888b0310d2e..ca15804a185 100644 --- a/critter/core/src/test/kotlin/dev/morphia/critter/parser/TestAccessorsMutators.kt +++ b/critter/core/src/test/kotlin/dev/morphia/critter/parser/TestAccessorsMutators.kt @@ -1,6 +1,6 @@ package dev.morphia.critter.parser -import dev.morphia.critter.parser.asm.Generators.critterPackage +import dev.morphia.critter.Critter.Companion.critterPackage import dev.morphia.critter.parser.java.CritterClassLoader import dev.morphia.critter.parser.java.CritterParser.critterClassLoader import dev.morphia.critter.sources.Example diff --git a/critter/core/src/test/kotlin/dev/morphia/critter/parser/gizmo/TestGizmoGeneration.kt b/critter/core/src/test/kotlin/dev/morphia/critter/parser/gizmo/TestGizmoGeneration.kt new file mode 100644 index 00000000000..8b1c201a6aa --- /dev/null +++ b/critter/core/src/test/kotlin/dev/morphia/critter/parser/gizmo/TestGizmoGeneration.kt @@ -0,0 +1,64 @@ +package dev.morphia.critter.parser.gizmo + +import dev.morphia.critter.parser.CritterGizmoGenerator +import dev.morphia.critter.parser.GeneratorTest +import dev.morphia.critter.parser.java.CritterParser.critterClassLoader +import dev.morphia.critter.sources.Example +import dev.morphia.mapping.codec.pojo.EntityModel +import dev.morphia.mapping.codec.pojo.PropertyModel +import io.quarkus.gizmo.ClassCreator +import io.quarkus.gizmo.ClassOutput +import io.quarkus.gizmo.MethodDescriptor +import org.bson.codecs.pojo.PropertyAccessor +import org.testng.annotations.Test + +class TestGizmoGeneration { + private val classOutput = ClassOutput { name, data -> + critterClassLoader.register(name.replace('/', '.'), data) + } + + @Test + fun testGizmo() { + val generator = CritterGizmoGenerator(critterClassLoader, GeneratorTest.mapper) + generator.generate(Example::class.java) + critterClassLoader.loadClass("dev.morphia.critter.sources.__morphia.example.AgeModel") + critterClassLoader.loadClass("dev.morphia.critter.sources.__morphia.example.NameModel") + critterClassLoader.loadClass("dev.morphia.critter.sources.__morphia.example.SalaryModel") + critterClassLoader + .loadClass("dev.morphia.critter.sources.__morphia.example.AgeAccessor") + .getConstructor() + .newInstance() + critterClassLoader + .loadClass("dev.morphia.critter.sources.__morphia.example.NameAccessor") + .getConstructor() + .newInstance() + critterClassLoader + .loadClass("dev.morphia.critter.sources.__morphia.example.SalaryAccessor") + .getConstructor() + .newInstance() + } + + private fun getAccessor(creator: ClassCreator) { + val field = creator.getFieldCreator("accessor", PropertyAccessor::class.java) + val method = + creator.getMethodCreator( + MethodDescriptor.ofMethod( + creator.className, + "getAccessor", + PropertyAccessor::class.java.name + ) + ) + + method.returnValue(method.readInstanceField(field.fieldDescriptor, method.`this`)) + } + + private fun ctor(creator: ClassCreator) { + val constructor = creator.getConstructorCreator(EntityModel::class.java) + constructor.invokeSpecialMethod( + MethodDescriptor.ofConstructor(PropertyModel::class.java, EntityModel::class.java), + constructor.`this`, + constructor.getMethodParam(0) + ) + constructor.returnVoid() + } +} diff --git a/mvnw.cmd b/mvnw.cmd old mode 100755 new mode 100644 diff --git a/util/pom.xml b/util/pom.xml index 330f220933a..f3a330c3e59 100644 --- a/util/pom.xml +++ b/util/pom.xml @@ -14,5 +14,7 @@ true true + 17 + 17