Skip to content

Commit

Permalink
basic EntityModel generation complete. may expand later.
Browse files Browse the repository at this point in the history
  • Loading branch information
evanchooly committed Oct 15, 2024
1 parent 2ab7438 commit abd9a2a
Show file tree
Hide file tree
Showing 9 changed files with 149 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,13 @@
import dev.morphia.annotations.Entity;
import dev.morphia.annotations.EntityListeners;
import dev.morphia.annotations.ExternalEntity;
import dev.morphia.annotations.Id;
import dev.morphia.annotations.PostLoad;
import dev.morphia.annotations.PostPersist;
import dev.morphia.annotations.PreLoad;
import dev.morphia.annotations.PrePersist;
import dev.morphia.annotations.ShardKeys;
import dev.morphia.annotations.Version;
import dev.morphia.annotations.internal.MorphiaInternal;
import dev.morphia.mapping.InstanceCreatorFactory;
import dev.morphia.mapping.InstanceCreatorFactoryImpl;
Expand Down Expand Up @@ -98,11 +100,11 @@ public EntityModel(Class<?> type) {
throw new MappingException(Sofia.noInnerClasses(type.getName()));
}
this.type = type;
creatorFactory = new InstanceCreatorFactoryImpl(this);
}

public EntityModel(Mapper mapper, Class<?> type) {
this(type);
creatorFactory = new InstanceCreatorFactoryImpl(this);

new MappingUtil(mapper);

Expand Down Expand Up @@ -167,6 +169,13 @@ public boolean addProperty(PropertyModel property) {
var added = propertyModelsByName.putIfAbsent(property.getName(), property) == null;
added &= propertyModelsByMappedName.put(property.getMappedName(), property) == null;

if (added) {
if (property.hasAnnotation(Id.class)) {
idProperty = property;
} else if (property.hasAnnotation(Version.class)) {
versionProperty = property;
}
}
return added;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
package dev.morphia.mapping.codec.pojo.critter;

import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Set;

import dev.morphia.annotations.Entity;
import dev.morphia.mapping.Mapper;
import dev.morphia.mapping.codec.MorphiaInstanceCreator;
import dev.morphia.mapping.codec.pojo.EntityModel;
import dev.morphia.mapping.codec.pojo.PropertyModel;
import dev.morphia.mapping.codec.pojo.TypeData;

/**
* 0
Expand All @@ -29,15 +23,12 @@ public CritterEntityModel(Mapper mapper, Class<?> type) {
}

@Override
public abstract Set<Class<?>> classHierarchy();

@Override
public final void discriminator(String discriminator) {
public final EntityModel collectionName(String collectionName) {
throw new UnsupportedOperationException();
}

@Override
public final EntityModel discriminatorKey(String discriminatorKey) {
public final void discriminator(String discriminator) {
throw new UnsupportedOperationException();
}

Expand All @@ -47,52 +38,19 @@ public final EntityModel discriminatorEnabled(boolean discriminatorEnabled) {
}

@Override
public abstract String collectionName();

@Override
public final EntityModel collectionName(String collectionName) {
public final EntityModel discriminatorKey(String discriminatorKey) {
throw new UnsupportedOperationException();
}

@Override
public abstract List<PropertyModel> getShardKeys();
public abstract String collectionName();

@Override
public abstract String discriminator();

@Override
public abstract String discriminatorKey();

@Override
public abstract Entity getEntityAnnotation();

@Override
public abstract PropertyModel getIdProperty();

@Override
public final void setIdProperty(PropertyModel model) {
throw new UnsupportedOperationException();
}

@Override
public abstract MorphiaInstanceCreator getInstanceCreator();

@Override
public final void setType(Class<?> type) {
throw new UnsupportedOperationException();
}

@Override
public abstract TypeData<?> getTypeData(Class<?> type, TypeData<?> suggested, Type genericType);

@Override
public abstract PropertyModel getVersionProperty();

@Override
public final void setVersionProperty(PropertyModel model) {
throw new UnsupportedOperationException();
}

@Override
public abstract boolean hasLifecycle(Class<? extends Annotation> type);

Expand Down
4 changes: 4 additions & 0 deletions critter/core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@
<artifactId>gizmo</artifactId>
<version>1.8.0</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@ package dev.morphia.critter.parser.gizmo

import dev.morphia.annotations.Entity
import dev.morphia.annotations.internal.AnnotationNodeExtensions.toMorphiaAnnotation
import dev.morphia.critter.parser.Generators.config
import dev.morphia.mapping.Mapper
import dev.morphia.mapping.codec.pojo.EntityModel
import dev.morphia.mapping.codec.pojo.PropertyModel
import dev.morphia.mapping.codec.pojo.critter.CritterEntityModel
import io.quarkus.gizmo.MethodCreator
import io.quarkus.gizmo.MethodDescriptor
import io.quarkus.gizmo.MethodDescriptor.ofMethod
import java.lang.reflect.Modifier
import kotlin.use
import org.objectweb.asm.tree.AnnotationNode
import org.objectweb.asm.tree.ClassNode
Expand All @@ -32,19 +36,62 @@ class GizmoEntityModelGenerator(

creator.use {
ctor()
collectionName()
discriminator()
discriminatorKey()
isAbstract()
isInterface()
useDiscriminator()
}

return this
}

private fun useDiscriminator() {
creator.getMethodCreator("useDiscriminator", "boolean").use {
it.returnValue(it.load(annotation(Entity::class.java)!!.useDiscriminator))
}
}

private fun isInterface() {
creator.getMethodCreator("isInterface", "boolean").use {
it.returnValue(it.load(entity.isInterface))
}
}

private fun isAbstract() {
creator.getMethodCreator("isAbstract", "boolean").use {
it.returnValue(it.load(Modifier.isAbstract(entity.modifiers)))
}
}

private fun discriminatorKey() {
creator.getMethodCreator("discriminatorKey", String::class.java).use {
val key = annotation(Entity::class.java)!!.discriminator
it.returnValue(
it.load(if (key == Mapper.IGNORED_FIELDNAME) config.discriminatorKey() else key)
)
}
}

private fun discriminator() {
creator.getMethodCreator("discriminator", String::class.java).use {
val value = annotation(Entity::class.java)?.value
val name =
if (value != null && value != Mapper.IGNORED_FIELDNAME) value else entity.simpleName
val discriminator =
config.discriminator().apply(entity, annotation(Entity::class.java)!!.discriminator)
it.returnValue(it.load(discriminator))
}
}

it.returnValue(it.load(name))
private fun collectionName() {
creator.getMethodCreator("collectionName", String::class.java).use {
val key = annotation(Entity::class.java)!!.value
it.returnValue(
it.load(
if (key == Mapper.IGNORED_FIELDNAME)
config.collectionNaming().apply(entity.simpleName)
else key
)
)
}
}

Expand All @@ -61,11 +108,31 @@ class GizmoEntityModelGenerator(
constructor.loadClass(entity)
)
constructor.setParameterNames(arrayOf("mapper"))

constructor.invokeVirtualMethod(
ofMethod(generatedType, "setType", "void", Class::class.java),
constructor.`this`,
constructor.loadClass(entity)
)
loadProperties(constructor)
registerAnnotations(constructor)

constructor.returnVoid()
}
}

private fun loadProperties(creator: MethodCreator) {
val addProperty =
ofMethod(generatedType, "addProperty", "boolean", PropertyModel::class.java)
properties.forEach { property ->
val modelCtor =
MethodDescriptor.ofConstructor(property.generatedType, EntityModel::class.java)

val model = creator.newInstance(modelCtor, creator.`this`)
creator.invokeVirtualMethod(addProperty, creator.`this`, model)
}
}

private fun registerAnnotations(constructor: MethodCreator) {
val annotationMethod = ofMethod(generatedType, "annotation", "void", Annotation::class.java)
annotations.forEach { annotation ->
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package dev.morphia.critter.parser.gizmo

import dev.morphia.annotations.internal.AnnotationNodeExtensions.setBuilderValues
import dev.morphia.critter.parser.Generators.asClass
import dev.morphia.critter.parser.methodCase
import dev.morphia.mapping.codec.pojo.TypeData
import io.quarkus.gizmo.FieldDescriptor
import io.quarkus.gizmo.MethodCreator
import io.quarkus.gizmo.MethodDescriptor
Expand Down Expand Up @@ -36,6 +38,22 @@ fun AnnotationNode.annotationBuilder(creator: MethodCreator): ResultHandle {
)
}

fun TypeData<*>.emitTypeData(methodCreator: MethodCreator): ResultHandle {
var array = methodCreator.newArray(TypeData::class.java, typeParameters.size)

typeParameters.forEachIndexed { index, typeParameter ->
methodCreator.writeArrayValue(array, index, typeParameter.emitTypeData(methodCreator))
}
val list = listOf(methodCreator.loadClass(type), array)
val descriptor =
MethodDescriptor.ofConstructor(
TypeData::class.java,
Class::class.java,
"[${Type.getType(TypeData::class.java).descriptor}"
)
return methodCreator.newInstance(descriptor, *list.toTypedArray())
}

fun rawType(type: java.lang.reflect.Type) =
when (type) {
is GenericArrayType -> {
Expand Down Expand Up @@ -114,3 +132,6 @@ fun load(creator: MethodCreator, type: Class<*>, `value`: Any): ResultHandle {
}
}
}

fun Type.typeData(typeParameters: List<TypeData<*>> = listOf()) =
TypeData(asClass(), typeParameters)
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import dev.morphia.annotations.Reference
import dev.morphia.annotations.internal.AnnotationNodeExtensions.toMorphiaAnnotation
import dev.morphia.config.MorphiaConfig
import dev.morphia.critter.conventions.PropertyConvention
import dev.morphia.critter.parser.Generators.asClass
import dev.morphia.critter.parser.Generators.isArray
import dev.morphia.critter.parser.methodCase
import dev.morphia.critter.titleCase
Expand Down Expand Up @@ -339,6 +338,3 @@ fun typeData(input: String): List<TypeData<*>> {
}
return types
}

private fun Type.typeData(typeParameters: List<TypeData<*>> = listOf()) =
TypeData(asClass(), typeParameters)
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import dev.morphia.annotations.Entity;
import dev.morphia.annotations.EntityListeners;
import dev.morphia.annotations.Field;
import dev.morphia.annotations.Id;
import dev.morphia.annotations.Index;
import dev.morphia.annotations.IndexOptions;
import dev.morphia.annotations.Indexes;
Expand All @@ -19,10 +20,14 @@
import dev.morphia.annotations.Transient;
import dev.morphia.mapping.lifecycle.EntityListenerAdapter;

import org.bson.types.ObjectId;

@Entity("examples")
@EntityListeners(EntityListenerAdapter.class)
@Indexes(@Index(fields = @Field(value = "name", weight = 42), options = @IndexOptions(partialFilter = "partial filter", collation = @Collation(caseFirst = CollationCaseFirst.LOWER))))
public class Example {
@Id
private ObjectId id;
@Property(value = "myName")
@AlsoLoad({ "name1", "name2" })
private String name;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import kotlin.reflect.KClass
import org.objectweb.asm.Type
import org.objectweb.asm.tree.AnnotationNode
import org.testng.Assert.assertEquals
import org.testng.Assert.assertFalse
import org.testng.Assert.assertNotNull
import org.testng.Assert.assertTrue
import org.testng.Assert.fail
Expand Down Expand Up @@ -174,7 +175,6 @@ class TestGizmoGeneration {
val constructors = loadClass.constructors
val model: EntityModel = constructors[0].newInstance(mapper) as EntityModel
validate(model)
println("**************** newInstance = ${model}")
}

private fun validate(model: EntityModel) {
Expand Down Expand Up @@ -205,6 +205,17 @@ class TestGizmoGeneration {
)
.build()
)

assertEquals(model.collectionName(), "examples")
assertEquals(model.discriminator(), "Example")
assertEquals(model.discriminatorKey(), "_t")
assertEquals(model.type.name, Example::class.java.name)
assertFalse(model.properties.isEmpty(), "Should have properties")
assertNotNull(model.idProperty, "Should have an ID property")
assertFalse(model.isAbstract(), "Should not be abstract")
assertFalse(model.isInterface(), "Should not be an interface")
assertTrue(model.useDiscriminator(), "Should use the discriminator")
assertTrue(model.classHierarchy().isEmpty(), "Should not have a class hierarchy")
}

private fun invokeAll(type: Class<*>, klass: Class<*>) {
Expand Down
22 changes: 22 additions & 0 deletions critter/core/src/test/resources/logback-test.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<root level="warn"/>

<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{40} - %msg%n</pattern>
</encoder>
</appender>

<logger name="ch.qos" level="error" additivity="true">
<appender-ref ref="STDOUT" />
</logger>

<logger name="dev.morphia" level="error">
<appender-ref ref="STDOUT" />
</logger>

<logger name="dev.morphia.test" level="debug" additivity="false">
<appender-ref ref="STDOUT" />
</logger>
</configuration>

0 comments on commit abd9a2a

Please sign in to comment.