-
Notifications
You must be signed in to change notification settings - Fork 455
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
7276f6a
commit cadc9fc
Showing
19 changed files
with
381 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
29 changes: 29 additions & 0 deletions
29
critter/core/src/main/kotlin/dev/morphia/critter/parser/CritterGizmoGenerator.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<String>): CritterEntityModel { | ||
val entityModelGenerator = GizmoEntityModelGenerator(type, propertyNames) | ||
return critterClassLoader | ||
.loadClass(entityModelGenerator.generatedType) | ||
.getConstructor(Mapper::class.java) | ||
.newInstance(mapper) as CritterEntityModel | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
critter/core/src/main/kotlin/dev/morphia/critter/parser/asm/CritterPropertyModelGenerator.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
critter/core/src/main/kotlin/dev/morphia/critter/parser/asm/EntityAccessorGenerator.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
13 changes: 13 additions & 0 deletions
13
critter/core/src/main/kotlin/dev/morphia/critter/parser/gizmo/BaseGizmoGenerator.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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` | ||
} | ||
} |
4 changes: 4 additions & 0 deletions
4
critter/core/src/main/kotlin/dev/morphia/critter/parser/gizmo/GizmoEntityModelGenerator.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
package dev.morphia.critter.parser.gizmo | ||
|
||
class GizmoEntityModelGenerator(type: Class<*>, propertyNames: List<String>) : | ||
BaseGizmoGenerator(type) {} |
97 changes: 97 additions & 0 deletions
97
...r/core/src/main/kotlin/dev/morphia/critter/parser/gizmo/GizmoPropertyAccessorGenerator.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<String>()) | ||
constructor.invokeSpecialMethod(ofConstructor(Object::class.java), constructor.`this`) | ||
constructor.returnVoid() | ||
|
||
constructor.close() | ||
} | ||
} |
139 changes: 139 additions & 0 deletions
139
critter/core/src/main/kotlin/dev/morphia/critter/parser/gizmo/GizmoPropertyModelGenerator.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<AnnotationNode> | ||
|
||
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() | ||
} | ||
} |
Oops, something went wrong.