diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 4af1905cd33..009c9a753e7 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -182,7 +182,7 @@ The `pull-request.yml` workflow runs on every PR and is the gating check: | Error | Cause | Fix | |-------|-------|-----| | `Cannot connect to MongoDB` in tests | Docker not running / Testcontainers can't pull image | Start Docker daemon; or use `-Dmongodb=local` with a local `mongod` | -| `No MorphiaConfig found` | Missing `morphia-config.properties` on classpath | Add the file to `src/test/resources/`, or call `Morphia.createDatastore(client, new ManualMorphiaConfig())` | +| `No MorphiaConfig found` | Missing `morphia-config.properties` on classpath | Add the file to `src/test/resources/`, or call `Morphia.createDatastore(client, dev.morphia.config.MorphiaConfig.load())` | | `MappingException: No usable constructor` | Entity class has no no-arg constructor accessible to Morphia | Add a `protected` or `public` no-arg constructor | | `ClassCastException` with proxies | Lazy-loading proxy and `instanceof` check clash | Check `MorphiaInternals.proxyClassesPresent()` before using proxies, or disable lazy loading | | Tests skipped with `SkipException` | MongoDB version below minimum for a feature | Pass a higher `-Dmongodb=` version | diff --git a/core/pom.xml b/core/pom.xml index 9f1e5686365..7f29488f2ff 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -128,6 +128,13 @@ generate-test-resources + + morphia-annotations-asm + + morphia-annotation-node + + generate-sources + @@ -171,6 +178,27 @@ net.bytebuddy byte-buddy + + io.quarkus.gizmo + gizmo + 1.9.0 + true + + + org.ow2.asm + asm-tree + true + + + org.ow2.asm + asm-util + true + + + org.jboss.forge.roaster + roaster-jdt + true + org.slf4j slf4j-api @@ -180,6 +208,12 @@ spotbugs-annotations + + org.jboss.windup.decompiler + decompiler-fernflower + 6.3.9.Final + test + org.testng testng diff --git a/core/src/main/java/dev/morphia/config/ManualMorphiaConfig.java b/core/src/main/java/dev/morphia/config/ManualMorphiaConfig.java index edda8f41469..c791eb271f8 100644 --- a/core/src/main/java/dev/morphia/config/ManualMorphiaConfig.java +++ b/core/src/main/java/dev/morphia/config/ManualMorphiaConfig.java @@ -17,7 +17,9 @@ import org.bson.codecs.configuration.CodecProvider; +import static dev.morphia.config.MorphiaConfigHelper.dumpConfigurationFile; import static dev.morphia.mapping.DateStorage.UTC; +import static dev.morphia.mapping.DiscriminatorFunction.className; import static dev.morphia.mapping.DiscriminatorFunction.simpleName; import static dev.morphia.mapping.NamingStrategy.camelCase; import static dev.morphia.mapping.NamingStrategy.identity; @@ -32,40 +34,40 @@ @MorphiaInternal @SuppressWarnings("removal") public class ManualMorphiaConfig implements MorphiaConfig { - Boolean applyCaps; - Boolean applyDocumentValidations; - Boolean applyIndexes; - - Optional codecProvider; - - NamingStrategy collectionNaming; - - String database; - - DateStorage dateStorage; - DiscriminatorFunction discriminator; - String discriminatorKey; - Boolean enablePolymorphicQueries; - Boolean ignoreFinals; - MapperType mapper; - List packages; - PropertyDiscovery propertyDiscovery; - List> propertyAnnotationProviders; - NamingStrategy propertyNaming; - QueryFactory queryFactory; - Boolean storeEmpties; - Boolean storeNulls; + private Boolean applyCaps; + private Boolean applyDocumentValidations; + private Boolean applyIndexes; + + private Optional codecProvider; + + private NamingStrategy collectionNaming; + + private String database; + + private DateStorage dateStorage; + private DiscriminatorFunction discriminator; + private String discriminatorKey; + private Boolean enablePolymorphicQueries; + private Boolean ignoreFinals; + private MapperType mapper; + private List packages; + private PropertyDiscovery propertyDiscovery; + private List> propertyAnnotationProviders; + private NamingStrategy propertyNaming; + private QueryFactory queryFactory; + private Boolean storeEmpties; + private Boolean storeNulls; /** * @hidden */ - public ManualMorphiaConfig() { + protected ManualMorphiaConfig() { } /** * @hidden */ - public ManualMorphiaConfig(MorphiaConfig base) { + protected ManualMorphiaConfig(MorphiaConfig base) { applyCaps = base.applyCaps(); applyDocumentValidations = base.applyDocumentValidations(); applyIndexes = base.applyIndexes(); @@ -122,90 +124,243 @@ public Boolean applyCaps() { return orDefault(applyCaps, FALSE); } + @Override + public MorphiaConfig applyCaps(Boolean value) { + var newConfig = new ManualMorphiaConfig(this); + newConfig.applyCaps = value; + return newConfig; + } + + @Override public Boolean applyDocumentValidations() { return orDefault(applyDocumentValidations, FALSE); } + @Override + public MorphiaConfig applyDocumentValidations(Boolean value) { + var newConfig = new ManualMorphiaConfig(this); + newConfig.applyDocumentValidations = value; + return newConfig; + } + @Override public Boolean applyIndexes() { return orDefault(applyIndexes, FALSE); } + @Override + public MorphiaConfig applyIndexes(Boolean value) { + var newConfig = new ManualMorphiaConfig(this); + newConfig.applyIndexes = value; + return newConfig; + } + @Override public Optional codecProvider() { return orDefault(codecProvider, Optional.empty()); } + @Override + public MorphiaConfig codecProvider(CodecProvider value) { + var newConfig = new ManualMorphiaConfig(this); + newConfig.codecProvider = Optional.of(value); + return newConfig; + } + @Override public NamingStrategy collectionNaming() { return orDefault(collectionNaming, camelCase()); } + @Override + public MorphiaConfig collectionNaming(NamingStrategy value) { + var newConfig = new ManualMorphiaConfig(this); + newConfig.collectionNaming = value; + return newConfig; + } + + @Override + public MorphiaConfig database(String value) { + var newConfig = new ManualMorphiaConfig(this); + newConfig.database = value; + return newConfig; + } + @Override public DateStorage dateStorage() { return orDefault(dateStorage, UTC); } + @Override + public MorphiaConfig dateStorage(DateStorage value) { + var newConfig = new ManualMorphiaConfig(this); + newConfig.dateStorage = value; + return newConfig; + } + @Override public DiscriminatorFunction discriminator() { return orDefault(discriminator, simpleName()); } + @Override + public MorphiaConfig discriminator(DiscriminatorFunction value) { + var newConfig = new ManualMorphiaConfig(this); + newConfig.discriminator = value; + return newConfig; + } + @Override public String discriminatorKey() { return orDefault(discriminatorKey, "_t"); } + @Override + public MorphiaConfig discriminatorKey(String value) { + var newConfig = new ManualMorphiaConfig(this); + newConfig.discriminatorKey = value; + return newConfig; + } + @Override public Boolean enablePolymorphicQueries() { return orDefault(enablePolymorphicQueries, FALSE); } + @Override + public MorphiaConfig enablePolymorphicQueries(Boolean value) { + var newConfig = new ManualMorphiaConfig(this); + newConfig.enablePolymorphicQueries = value; + return newConfig; + } + @Override public Boolean ignoreFinals() { return orDefault(ignoreFinals, FALSE); } + @Override + public MorphiaConfig ignoreFinals(Boolean value) { + var newConfig = new ManualMorphiaConfig(this); + newConfig.ignoreFinals = value; + return newConfig; + } + + @Override + public MorphiaConfig legacy() { + ManualMorphiaConfig newConfig = new ManualMorphiaConfig(this); + newConfig.dateStorage = DateStorage.SYSTEM_DEFAULT; + newConfig.discriminatorKey = "className"; + newConfig.discriminator = className(); + newConfig.collectionNaming = identity(); + newConfig.propertyNaming = identity(); + return newConfig; + } + @Override public MapperType mapper() { return orDefault(mapper, MapperType.LEGACY); } + @Override + public MorphiaConfig mapper(MapperType value) { + var newConfig = new ManualMorphiaConfig(this); + newConfig.mapper = value; + return newConfig; + } + @Override public List packages() { return orDefault(packages, List.of()); } + @Override + public MorphiaConfig packages(List value) { + var newConfig = new ManualMorphiaConfig(this); + newConfig.packages = value; + return newConfig; + } + @Override public List> propertyAnnotationProviders() { return orDefault(propertyAnnotationProviders, List.of(new MorphiaPropertyAnnotationProvider())); } + @Override + public MorphiaConfig propertyAnnotationProviders(List> list) { + var newConfig = new ManualMorphiaConfig(this); + newConfig.propertyAnnotationProviders = list; + if (list.isEmpty() || list.stream().noneMatch(p -> p instanceof MorphiaPropertyAnnotationProvider)) { + newConfig.propertyAnnotationProviders.add(new MorphiaPropertyAnnotationProvider()); + } + return newConfig; + } + @Override public PropertyDiscovery propertyDiscovery() { return orDefault(propertyDiscovery, FIELDS); } + @Override + public MorphiaConfig propertyDiscovery(PropertyDiscovery value) { + var newConfig = new ManualMorphiaConfig(this); + newConfig.propertyDiscovery = value; + return newConfig; + } + @Override public NamingStrategy propertyNaming() { return orDefault(propertyNaming, identity()); } + @Override + public MorphiaConfig propertyNaming(NamingStrategy value) { + var newConfig = new ManualMorphiaConfig(this); + newConfig.propertyNaming = value; + return newConfig; + } + @Override public QueryFactory queryFactory() { return orDefault(queryFactory, new DefaultQueryFactory()); } + @Override + public MorphiaConfig queryFactory(QueryFactory value) { + var newConfig = new ManualMorphiaConfig(this); + newConfig.queryFactory = value; + return newConfig; + } + @Override public Boolean storeEmpties() { return orDefault(storeEmpties, FALSE); } + @Override + public MorphiaConfig storeEmpties(Boolean value) { + var newConfig = new ManualMorphiaConfig(this); + newConfig.storeEmpties = value; + return newConfig; + } + @Override public Boolean storeNulls() { return orDefault(storeNulls, FALSE); } + @Override + public MorphiaConfig storeNulls(Boolean value) { + var newConfig = new ManualMorphiaConfig(this); + newConfig.storeNulls = value; + return newConfig; + } + + @Override + public String toConfigFormat(boolean showComplete) { + return dumpConfigurationFile(this, showComplete); + } + protected T orDefault(@Nullable T localValue, T defaultValue) { return localValue != null ? localValue : defaultValue; } diff --git a/core/src/main/java/dev/morphia/config/MorphiaConfig.java b/core/src/main/java/dev/morphia/config/MorphiaConfig.java index c079dc40723..ce497040d11 100644 --- a/core/src/main/java/dev/morphia/config/MorphiaConfig.java +++ b/core/src/main/java/dev/morphia/config/MorphiaConfig.java @@ -30,9 +30,6 @@ import io.smallrye.config.WithConverter; import io.smallrye.config.WithDefault; -import static dev.morphia.config.MorphiaConfigHelper.dumpConfigurationFile; -import static dev.morphia.mapping.DiscriminatorFunction.className; -import static dev.morphia.mapping.NamingStrategy.identity; import static io.smallrye.config.PropertiesConfigSourceLoader.*; import static java.lang.Thread.currentThread; @@ -50,7 +47,7 @@ public interface MorphiaConfig { /** * Tries to load a configuration from the default location. - * + * * @return the loaded config */ static MorphiaConfig load() { @@ -87,12 +84,7 @@ static MorphiaConfig load(String location) { * @return a new instance with the updated configuration * @since 3.0 */ - default MorphiaConfig collectionNaming(NamingStrategy value) { - var newConfig = new ManualMorphiaConfig(this); - - newConfig.collectionNaming = value; - return newConfig; - } + MorphiaConfig collectionNaming(NamingStrategy value); /** * The database name that Morphia should use. This entry is required to be present and is the only necessary configuration element @@ -118,12 +110,7 @@ default MorphiaConfig collectionNaming(NamingStrategy value) { * @return a new instance with the updated configuration * @since 3.0 */ - default MorphiaConfig applyCaps(Boolean value) { - var newConfig = new ManualMorphiaConfig(this); - - newConfig.applyCaps = value; - return newConfig; - } + MorphiaConfig applyCaps(Boolean value); /** * If true, document validations will be enabled for entities/collections with validation mappings. @@ -142,12 +129,7 @@ default MorphiaConfig applyCaps(Boolean value) { * @return a new instance with the updated configuration * @since 3.0 */ - default MorphiaConfig applyDocumentValidations(Boolean value) { - var newConfig = new ManualMorphiaConfig(this); - - newConfig.applyDocumentValidations = value; - return newConfig; - } + MorphiaConfig applyDocumentValidations(Boolean value); /** * If true, mapped indexes will be applied to the database at start up. @@ -164,12 +146,7 @@ default MorphiaConfig applyDocumentValidations(Boolean value) { * @return a new instance with the updated configuration * @since 3.0 */ - default MorphiaConfig applyIndexes(Boolean value) { - var newConfig = new ManualMorphiaConfig(this); - - newConfig.applyIndexes = value; - return newConfig; - } + MorphiaConfig applyIndexes(Boolean value); /** * Specifies a {@code CodecProvider} to supply user defined codecs that Morphia should use. @@ -188,12 +165,7 @@ default MorphiaConfig applyIndexes(Boolean value) { * @return a new instance with the updated configuration * @since 3.0 */ - default MorphiaConfig codecProvider(CodecProvider value) { - var newConfig = new ManualMorphiaConfig(this); - - newConfig.codecProvider = Optional.of(value); - return newConfig; - } + MorphiaConfig codecProvider(CodecProvider value); /** * Sets the naming strategy to be used when generating collection names for entities if name is not explicitly given in the {@code @@ -217,12 +189,7 @@ default MorphiaConfig codecProvider(CodecProvider value) { * @return a new instance with the updated configuration * @since 3.0 */ - default MorphiaConfig database(String value) { - var newConfig = new ManualMorphiaConfig(this); - - newConfig.database = value; - return newConfig; - } + MorphiaConfig database(String value); /** * The date storage configuration Morphia should use for JSR 310 types. @@ -239,12 +206,7 @@ default MorphiaConfig database(String value) { * @return a new instance with the updated configuration * @since 3.0 */ - default MorphiaConfig dateStorage(DateStorage value) { - var newConfig = new ManualMorphiaConfig(this); - - newConfig.dateStorage = value; - return newConfig; - } + MorphiaConfig dateStorage(DateStorage value); /** * The function to use when calculating the discriminator value for an entity @@ -264,12 +226,7 @@ default MorphiaConfig dateStorage(DateStorage value) { * @return a new instance with the updated configuration * @since 3.0 */ - default MorphiaConfig discriminator(DiscriminatorFunction value) { - var newConfig = new ManualMorphiaConfig(this); - - newConfig.discriminator = value; - return newConfig; - } + MorphiaConfig discriminator(DiscriminatorFunction value); /** * The document field name to use when storing discriminator values @@ -286,12 +243,7 @@ default MorphiaConfig discriminator(DiscriminatorFunction value) { * @return a new instance with the updated configuration * @since 3.0 */ - default MorphiaConfig discriminatorKey(String value) { - var newConfig = new ManualMorphiaConfig(this); - - newConfig.discriminatorKey = value; - return newConfig; - } + MorphiaConfig discriminatorKey(String value); /** * Enable polymorphic queries. By default, Morphia will only query for the given type. However, in cases where subtypes are stored @@ -309,12 +261,7 @@ default MorphiaConfig discriminatorKey(String value) { * @return a new instance with the updated configuration * @since 3.0 */ - default MorphiaConfig enablePolymorphicQueries(Boolean value) { - var newConfig = new ManualMorphiaConfig(this); - - newConfig.enablePolymorphicQueries = value; - return newConfig; - } + MorphiaConfig enablePolymorphicQueries(Boolean value); /** * Instructs Morphia to ignore final fields. @@ -331,32 +278,17 @@ default MorphiaConfig enablePolymorphicQueries(Boolean value) { * @return a new instance with the updated configuration * @since 3.0 */ - default MorphiaConfig ignoreFinals(Boolean value) { - var newConfig = new ManualMorphiaConfig(this); - - newConfig.ignoreFinals = value; - return newConfig; - } + MorphiaConfig ignoreFinals(Boolean value); /** * Creates a new configuration based on the current one but updated to reflect the legacy configuration. This configuration is not * changed. - * + * * @return the update configuration * * @since 3.0 */ - default MorphiaConfig legacy() { - ManualMorphiaConfig newConfig = new ManualMorphiaConfig(this); - newConfig.dateStorage = DateStorage.SYSTEM_DEFAULT; - newConfig.discriminatorKey = "className"; - newConfig.discriminator = className(); - newConfig.collectionNaming = identity(); - newConfig.propertyNaming = identity(); - - return newConfig; - - } + MorphiaConfig legacy(); /** * The mapper implementation to use. Defaults to {@link MapperType#LEGACY} (reflection-based). @@ -375,12 +307,7 @@ default MorphiaConfig legacy() { * @return a new instance with the updated configuration * @since 3.0 */ - default MorphiaConfig mapper(MapperType value) { - var newConfig = new ManualMorphiaConfig(this); - - newConfig.mapper = value; - return newConfig; - } + MorphiaConfig mapper(MapperType value); /** * A comma delimited list of packages that Morphia should map. If subpackages of a specific package should also be mapped, simply add @@ -398,12 +325,7 @@ default MorphiaConfig mapper(MapperType value) { * @return a new instance with the updated configuration * @since 3.0 */ - default MorphiaConfig packages(List value) { - var newConfig = new ManualMorphiaConfig(this); - newConfig.packages = value; - - return newConfig; - } + MorphiaConfig packages(List value); /** * Specifies the providers of any external annotations to use as markers for properties for Morphia to consider while mapping. This @@ -440,14 +362,7 @@ default MorphiaConfig packages(List value) { */ @MorphiaInternal @MorphiaExperimental - default MorphiaConfig propertyAnnotationProviders(List> list) { - var newConfig = new ManualMorphiaConfig(this); - newConfig.propertyAnnotationProviders = list; - if (list.isEmpty() || list.stream().noneMatch(p -> p instanceof MorphiaPropertyAnnotationProvider)) { - newConfig.propertyAnnotationProviders.add(new MorphiaPropertyAnnotationProvider()); - } - return newConfig; - } + MorphiaConfig propertyAnnotationProviders(List> list); /** * Determines how properties are discovered. The traditional value is by scanning for fields which involves a bit more reflective @@ -468,12 +383,7 @@ default MorphiaConfig propertyAnnotationProviders(List, Object> providerMap; + private final Mapper mapper; private final CritterClassLoader classLoader; private final boolean runtimeMode; public PropertyFinder(Mapper mapper, CritterClassLoader classLoader, boolean runtimeMode) { + this.mapper = mapper; this.providerMap = new LinkedHashMap<>(); for (var provider : mapper.getConfig().propertyAnnotationProviders()) { providerMap.put(provider.provides(), provider); @@ -34,33 +37,33 @@ public PropertyFinder(Mapper mapper, CritterClassLoader classLoader, boolean run this.runtimeMode = runtimeMode; } - public List find(Class entityType, ClassNode classNode) { + public List find(Class entityType, ClassNode classNode, MorphiaConfig config) { List models = new ArrayList<>(); List methods = discoverPropertyMethods(classNode); if (methods.isEmpty()) { List fields = discoverAllFields(entityType, classNode); if (!runtimeMode) { - classLoader.register(entityType.getName(), CritterGizmoGenerator.INSTANCE.fieldAccessors(entityType, fields)); + classLoader.register(entityType.getName(), CritterGizmoGenerator.fieldAccessors(entityType, fields)); } for (FieldNode field : fields) { if (runtimeMode) { - CritterGizmoGenerator.INSTANCE.varHandleAccessor(entityType, classLoader, field); + CritterGizmoGenerator.varHandleAccessor(entityType, classLoader, field); } else { - CritterGizmoGenerator.INSTANCE.propertyAccessor(entityType, classLoader, field); + CritterGizmoGenerator.propertyAccessor(entityType, classLoader, field); } - models.add(CritterGizmoGenerator.INSTANCE.propertyModelGenerator(entityType, classLoader, field)); + models.add(CritterGizmoGenerator.propertyModelGenerator(config, entityType, classLoader, field)); } } else { if (!runtimeMode) { - classLoader.register(entityType.getName(), CritterGizmoGenerator.INSTANCE.methodAccessors(entityType, methods)); + classLoader.register(entityType.getName(), CritterGizmoGenerator.methodAccessors(entityType, methods)); } for (MethodNode method : methods) { if (runtimeMode) { - CritterGizmoGenerator.INSTANCE.varHandleAccessor(entityType, classLoader, method); + CritterGizmoGenerator.varHandleAccessor(entityType, classLoader, method); } else { - CritterGizmoGenerator.INSTANCE.propertyAccessor(entityType, classLoader, method); + CritterGizmoGenerator.propertyAccessor(entityType, classLoader, method); } - models.add(CritterGizmoGenerator.INSTANCE.propertyModelGenerator(entityType, classLoader, method)); + models.add(CritterGizmoGenerator.propertyModelGenerator(config, entityType, classLoader, method)); } } return models; diff --git a/critter/core/src/main/java/dev/morphia/critter/parser/asm/AddFieldAccessorMethods.java b/core/src/main/java/dev/morphia/critter/parser/asm/AddFieldAccessorMethods.java similarity index 100% rename from critter/core/src/main/java/dev/morphia/critter/parser/asm/AddFieldAccessorMethods.java rename to core/src/main/java/dev/morphia/critter/parser/asm/AddFieldAccessorMethods.java diff --git a/critter/core/src/main/java/dev/morphia/critter/parser/asm/AddMethodAccessorMethods.java b/core/src/main/java/dev/morphia/critter/parser/asm/AddMethodAccessorMethods.java similarity index 100% rename from critter/core/src/main/java/dev/morphia/critter/parser/asm/AddMethodAccessorMethods.java rename to core/src/main/java/dev/morphia/critter/parser/asm/AddMethodAccessorMethods.java diff --git a/critter/core/src/main/java/dev/morphia/critter/parser/asm/BaseGenerator.java b/core/src/main/java/dev/morphia/critter/parser/asm/BaseGenerator.java similarity index 100% rename from critter/core/src/main/java/dev/morphia/critter/parser/asm/BaseGenerator.java rename to core/src/main/java/dev/morphia/critter/parser/asm/BaseGenerator.java diff --git a/critter/core/src/main/java/dev/morphia/critter/parser/gizmo/BaseGizmoGenerator.java b/core/src/main/java/dev/morphia/critter/parser/gizmo/BaseGizmoGenerator.java similarity index 100% rename from critter/core/src/main/java/dev/morphia/critter/parser/gizmo/BaseGizmoGenerator.java rename to core/src/main/java/dev/morphia/critter/parser/gizmo/BaseGizmoGenerator.java diff --git a/core/src/main/java/dev/morphia/critter/parser/gizmo/CritterGizmoGenerator.java b/core/src/main/java/dev/morphia/critter/parser/gizmo/CritterGizmoGenerator.java new file mode 100644 index 00000000000..b76c1828f77 --- /dev/null +++ b/core/src/main/java/dev/morphia/critter/parser/gizmo/CritterGizmoGenerator.java @@ -0,0 +1,87 @@ +package dev.morphia.critter.parser.gizmo; + +import java.io.IOException; +import java.util.List; + +import dev.morphia.config.MorphiaConfig; +import dev.morphia.critter.CritterClassLoader; +import dev.morphia.critter.parser.Generators; +import dev.morphia.critter.parser.PropertyFinder; +import dev.morphia.critter.parser.asm.AddFieldAccessorMethods; +import dev.morphia.critter.parser.asm.AddMethodAccessorMethods; + +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.FieldNode; +import org.objectweb.asm.tree.MethodNode; + +public class CritterGizmoGenerator { + private CritterGizmoGenerator() { + } + + public static GizmoEntityModelGenerator generate(Class type, CritterClassLoader critterClassLoader, + Generators generators, boolean runtimeMode) { + ClassNode classNode = new ClassNode(); + String resourceName = "%s.class".formatted(type.getName().replace('.', '/')); + try (java.io.InputStream inputStream = type.getClassLoader().getResourceAsStream(resourceName)) { + if (inputStream == null) { + throw new IllegalArgumentException("Could not find class file for %s".formatted(type.getName())); + } + new ClassReader(inputStream).accept(classNode, 0); + } catch (IOException e) { + throw new RuntimeException("Failed to read class %s".formatted(type.getName()), e); + } + PropertyFinder propertyFinder = new PropertyFinder(generators.getMapper(), critterClassLoader, runtimeMode); + + return entityModel(type, critterClassLoader, classNode, propertyFinder.find(type, classNode, generators.getConfig()), + generators.getConfig()); + } + + public static GizmoEntityModelGenerator generate(Class type, CritterClassLoader critterClassLoader, + Generators generators) { + return generate(type, critterClassLoader, generators, false); + } + + public static byte[] fieldAccessors(Class entityType, List fields) { + return new AddFieldAccessorMethods(entityType, fields).emit(); + } + + public static byte[] methodAccessors(Class entityType, List methods) { + return new AddMethodAccessorMethods(entityType, methods).emit(); + } + + public static PropertyAccessorGenerator propertyAccessor(Class entityType, CritterClassLoader critterClassLoader, + FieldNode field) { + return new PropertyAccessorGenerator(entityType, critterClassLoader, field).emit(); + } + + public static PropertyAccessorGenerator propertyAccessor(Class entityType, CritterClassLoader critterClassLoader, + MethodNode method) { + return new PropertyAccessorGenerator(entityType, critterClassLoader, method).emit(); + } + + public static VarHandleAccessorGenerator varHandleAccessor(Class entityType, CritterClassLoader critterClassLoader, + FieldNode field) { + return new VarHandleAccessorGenerator(entityType, critterClassLoader, field).emit(); + } + + public static VarHandleAccessorGenerator varHandleAccessor(Class entityType, CritterClassLoader critterClassLoader, + MethodNode method) { + return new VarHandleAccessorGenerator(entityType, critterClassLoader, method).emit(); + } + + public static PropertyModelGenerator propertyModelGenerator(MorphiaConfig config, Class entityType, + CritterClassLoader critterClassLoader, FieldNode field) { + return new PropertyModelGenerator(config, entityType, critterClassLoader, field).emit(); + } + + public static PropertyModelGenerator propertyModelGenerator(MorphiaConfig config, Class entityType, + CritterClassLoader critterClassLoader, MethodNode method) { + return new PropertyModelGenerator(config, entityType, critterClassLoader, method).emit(); + } + + public static GizmoEntityModelGenerator entityModel(Class type, CritterClassLoader critterClassLoader, + ClassNode classNode, List properties, MorphiaConfig config) { + return new GizmoEntityModelGenerator(type, critterClassLoader, classNode, properties, config).emit(); + } +} diff --git a/critter/core/src/main/java/dev/morphia/critter/parser/gizmo/GizmoEntityModelGenerator.java b/core/src/main/java/dev/morphia/critter/parser/gizmo/GizmoEntityModelGenerator.java similarity index 95% rename from critter/core/src/main/java/dev/morphia/critter/parser/gizmo/GizmoEntityModelGenerator.java rename to core/src/main/java/dev/morphia/critter/parser/gizmo/GizmoEntityModelGenerator.java index c0f4cb58926..6419d95102a 100644 --- a/critter/core/src/main/java/dev/morphia/critter/parser/gizmo/GizmoEntityModelGenerator.java +++ b/core/src/main/java/dev/morphia/critter/parser/gizmo/GizmoEntityModelGenerator.java @@ -8,8 +8,8 @@ import dev.morphia.annotations.Entity; import dev.morphia.annotations.internal.AnnotationNodeExtensions; +import dev.morphia.config.MorphiaConfig; import dev.morphia.critter.CritterClassLoader; -import dev.morphia.critter.parser.Generators; import dev.morphia.mapping.Mapper; import dev.morphia.mapping.codec.pojo.EntityModel; import dev.morphia.mapping.codec.pojo.PropertyModel; @@ -29,10 +29,12 @@ public class GizmoEntityModelGenerator extends BaseGizmoGenerator { private final List annotations; private final List morphiaAnnotations; private final Entity entityAnnotation; + private final MorphiaConfig config; public GizmoEntityModelGenerator(Class type, CritterClassLoader critterClassLoader, - ClassNode classNode, List properties) { + ClassNode classNode, List properties, MorphiaConfig config) { super(type, critterClassLoader); + this.config = config; this.classNode = classNode; this.properties = properties; @@ -108,7 +110,7 @@ private void discriminatorKey() { try (MethodCreator mc = getCreator().getMethodCreator("discriminatorKey", String.class)) { String key = entityAnnotation.discriminator(); String result = Mapper.IGNORED_FIELDNAME.equals(key) - ? Generators.INSTANCE.getConfig().discriminatorKey() + ? config.discriminatorKey() : key; mc.returnValue(mc.load(result)); } @@ -116,7 +118,7 @@ private void discriminatorKey() { private void discriminator() { try (MethodCreator mc = getCreator().getMethodCreator("discriminator", String.class)) { - String discriminator = Generators.INSTANCE.getConfig().discriminator() + String discriminator = config.discriminator() .apply(entity, entityAnnotation.discriminator()); mc.returnValue(mc.load(discriminator)); } @@ -126,7 +128,7 @@ private void collectionName() { try (MethodCreator mc = getCreator().getMethodCreator("collectionName", String.class)) { String key = entityAnnotation.value(); String result = Mapper.IGNORED_FIELDNAME.equals(key) - ? Generators.INSTANCE.getConfig().collectionNaming().apply(entity.getSimpleName()) + ? config.collectionNaming().apply(entity.getSimpleName()) : key; mc.returnValue(mc.load(result)); } diff --git a/critter/core/src/main/java/dev/morphia/critter/parser/gizmo/GizmoExtensions.java b/core/src/main/java/dev/morphia/critter/parser/gizmo/GizmoExtensions.java similarity index 100% rename from critter/core/src/main/java/dev/morphia/critter/parser/gizmo/GizmoExtensions.java rename to core/src/main/java/dev/morphia/critter/parser/gizmo/GizmoExtensions.java diff --git a/critter/core/src/main/java/dev/morphia/critter/parser/gizmo/PropertyAccessorGenerator.java b/core/src/main/java/dev/morphia/critter/parser/gizmo/PropertyAccessorGenerator.java similarity index 100% rename from critter/core/src/main/java/dev/morphia/critter/parser/gizmo/PropertyAccessorGenerator.java rename to core/src/main/java/dev/morphia/critter/parser/gizmo/PropertyAccessorGenerator.java diff --git a/critter/core/src/main/java/dev/morphia/critter/parser/gizmo/PropertyModelGenerator.java b/core/src/main/java/dev/morphia/critter/parser/gizmo/PropertyModelGenerator.java similarity index 100% rename from critter/core/src/main/java/dev/morphia/critter/parser/gizmo/PropertyModelGenerator.java rename to core/src/main/java/dev/morphia/critter/parser/gizmo/PropertyModelGenerator.java diff --git a/critter/core/src/main/java/dev/morphia/critter/parser/gizmo/VarHandleAccessorGenerator.java b/core/src/main/java/dev/morphia/critter/parser/gizmo/VarHandleAccessorGenerator.java similarity index 100% rename from critter/core/src/main/java/dev/morphia/critter/parser/gizmo/VarHandleAccessorGenerator.java rename to core/src/main/java/dev/morphia/critter/parser/gizmo/VarHandleAccessorGenerator.java diff --git a/critter/core/src/main/java/dev/morphia/critter/parser/java/CritterParser.java b/core/src/main/java/dev/morphia/critter/parser/java/CritterParser.java similarity index 100% rename from critter/core/src/main/java/dev/morphia/critter/parser/java/CritterParser.java rename to core/src/main/java/dev/morphia/critter/parser/java/CritterParser.java diff --git a/critter/core/src/test/java/dev/morphia/critter/ClassfileOutput.java b/core/src/test/java/dev/morphia/critter/ClassfileOutput.java similarity index 100% rename from critter/core/src/test/java/dev/morphia/critter/ClassfileOutput.java rename to core/src/test/java/dev/morphia/critter/ClassfileOutput.java diff --git a/critter/core/src/test/java/dev/morphia/critter/parser/BaseCritterTest.java b/core/src/test/java/dev/morphia/critter/parser/BaseCritterTest.java similarity index 100% rename from critter/core/src/test/java/dev/morphia/critter/parser/BaseCritterTest.java rename to core/src/test/java/dev/morphia/critter/parser/BaseCritterTest.java diff --git a/critter/core/src/test/java/dev/morphia/critter/parser/GeneratorTest.java b/core/src/test/java/dev/morphia/critter/parser/GeneratorTest.java similarity index 87% rename from critter/core/src/test/java/dev/morphia/critter/parser/GeneratorTest.java rename to core/src/test/java/dev/morphia/critter/parser/GeneratorTest.java index 846fbabbd5a..4948cd15df1 100644 --- a/critter/core/src/test/java/dev/morphia/critter/parser/GeneratorTest.java +++ b/core/src/test/java/dev/morphia/critter/parser/GeneratorTest.java @@ -9,11 +9,13 @@ import java.util.function.Predicate; import java.util.stream.Collectors; +import dev.morphia.config.MorphiaConfig; import dev.morphia.critter.ClassfileOutput; import dev.morphia.critter.CritterClassLoader; import dev.morphia.critter.parser.gizmo.CritterGizmoGenerator; import dev.morphia.critter.parser.gizmo.GizmoEntityModelGenerator; import dev.morphia.critter.sources.Example; +import dev.morphia.mapping.ReflectiveMapper; import dev.morphia.mapping.codec.pojo.critter.CritterEntityModel; import io.github.classgraph.ClassGraph; @@ -38,12 +40,14 @@ public class GeneratorTest { } catch (Exception ignored) { } - GizmoEntityModelGenerator gen = CritterGizmoGenerator.INSTANCE.generate(Example.class, critterClassLoader, false); + MorphiaConfig config = MorphiaConfig.load(); + Generators generators = new Generators(config, new ReflectiveMapper(config)); + GizmoEntityModelGenerator gen = CritterGizmoGenerator.generate(Example.class, critterClassLoader, generators, false); try { entityModel = (CritterEntityModel) critterClassLoader .loadClass(gen.getGeneratedType()) .getConstructors()[0] - .newInstance(Generators.INSTANCE.getMapper()); + .newInstance(generators.getMapper()); } catch (Exception e) { throw new RuntimeException(e); } diff --git a/critter/core/src/test/java/dev/morphia/critter/parser/TestAccessorsMutators.java b/core/src/test/java/dev/morphia/critter/parser/TestAccessorsMutators.java similarity index 100% rename from critter/core/src/test/java/dev/morphia/critter/parser/TestAccessorsMutators.java rename to core/src/test/java/dev/morphia/critter/parser/TestAccessorsMutators.java diff --git a/critter/core/src/test/java/dev/morphia/critter/parser/TestEntityModelGenerator.java b/core/src/test/java/dev/morphia/critter/parser/TestEntityModelGenerator.java similarity index 93% rename from critter/core/src/test/java/dev/morphia/critter/parser/TestEntityModelGenerator.java rename to core/src/test/java/dev/morphia/critter/parser/TestEntityModelGenerator.java index 2f56301ea7b..5d9b42495fc 100644 --- a/critter/core/src/test/java/dev/morphia/critter/parser/TestEntityModelGenerator.java +++ b/core/src/test/java/dev/morphia/critter/parser/TestEntityModelGenerator.java @@ -2,6 +2,7 @@ import java.lang.reflect.Method; +import dev.morphia.config.MorphiaConfig; import dev.morphia.critter.ClassfileOutput; import dev.morphia.critter.CritterClassLoader; import dev.morphia.mapping.Mapper; @@ -18,7 +19,7 @@ public class TestEntityModelGenerator { private static final Logger LOG = LoggerFactory.getLogger(TestEntityModelGenerator.class); private final CritterEntityModel control; - private final Mapper mapper = new ReflectiveMapper(Generators.INSTANCE.getConfig()); + private final Mapper mapper = new ReflectiveMapper(MorphiaConfig.load()); private final CritterClassLoader critterClassLoader = new CritterClassLoader(); public TestEntityModelGenerator() { diff --git a/critter/core/src/test/java/dev/morphia/critter/parser/TestPropertyModelGenerator.java b/core/src/test/java/dev/morphia/critter/parser/TestPropertyModelGenerator.java similarity index 100% rename from critter/core/src/test/java/dev/morphia/critter/parser/TestPropertyModelGenerator.java rename to core/src/test/java/dev/morphia/critter/parser/TestPropertyModelGenerator.java diff --git a/critter/core/src/test/java/dev/morphia/critter/parser/TestVarHandleAccessor.java b/core/src/test/java/dev/morphia/critter/parser/TestVarHandleAccessor.java similarity index 92% rename from critter/core/src/test/java/dev/morphia/critter/parser/TestVarHandleAccessor.java rename to core/src/test/java/dev/morphia/critter/parser/TestVarHandleAccessor.java index 5dbf0349c1c..d15cbfb1b7d 100644 --- a/critter/core/src/test/java/dev/morphia/critter/parser/TestVarHandleAccessor.java +++ b/core/src/test/java/dev/morphia/critter/parser/TestVarHandleAccessor.java @@ -4,10 +4,12 @@ import java.util.List; import java.util.stream.Collectors; +import dev.morphia.config.MorphiaConfig; import dev.morphia.critter.Critter; import dev.morphia.critter.CritterClassLoader; import dev.morphia.critter.parser.gizmo.CritterGizmoGenerator; import dev.morphia.critter.sources.Example; +import dev.morphia.mapping.ReflectiveMapper; import org.bson.codecs.pojo.PropertyAccessor; import org.testng.Assert; @@ -20,7 +22,8 @@ public class TestVarHandleAccessor { @BeforeClass public void setup() { classLoader = new CritterClassLoader(); - CritterGizmoGenerator.INSTANCE.generate(Example.class, classLoader, true); + MorphiaConfig config = dev.morphia.config.MorphiaConfig.load(); + CritterGizmoGenerator.generate(Example.class, classLoader, new Generators(config, new ReflectiveMapper(config)), true); } @Test diff --git a/critter/core/src/test/java/dev/morphia/critter/parser/TypesTest.java b/core/src/test/java/dev/morphia/critter/parser/TypesTest.java similarity index 96% rename from critter/core/src/test/java/dev/morphia/critter/parser/TypesTest.java rename to core/src/test/java/dev/morphia/critter/parser/TypesTest.java index 58d991c1951..b1b9a412409 100644 --- a/critter/core/src/test/java/dev/morphia/critter/parser/TypesTest.java +++ b/core/src/test/java/dev/morphia/critter/parser/TypesTest.java @@ -81,7 +81,7 @@ public Object[][] typeProvider() { @Test(dataProvider = "types") public void asClassConversion(Class expected) { Type type = Type.getType(expected); - Class actual = Generators.INSTANCE.asClass(type, Thread.currentThread().getContextClassLoader()); + Class actual = Generators.asClass(type, Thread.currentThread().getContextClassLoader()); Assert.assertEquals(actual, expected, "Type " + type.getDescriptor() + " should convert to " + expected.getName()); } } diff --git a/critter/core/src/test/java/dev/morphia/critter/parser/gizmo/TestGizmoGeneration.java b/core/src/test/java/dev/morphia/critter/parser/gizmo/TestGizmoGeneration.java similarity index 97% rename from critter/core/src/test/java/dev/morphia/critter/parser/gizmo/TestGizmoGeneration.java rename to core/src/test/java/dev/morphia/critter/parser/gizmo/TestGizmoGeneration.java index cddb2678738..50e8770429f 100644 --- a/critter/core/src/test/java/dev/morphia/critter/parser/gizmo/TestGizmoGeneration.java +++ b/core/src/test/java/dev/morphia/critter/parser/gizmo/TestGizmoGeneration.java @@ -19,12 +19,14 @@ import dev.morphia.annotations.internal.IndexBuilder; import dev.morphia.annotations.internal.IndexOptionsBuilder; import dev.morphia.annotations.internal.IndexesBuilder; +import dev.morphia.config.MorphiaConfig; import dev.morphia.critter.ClassfileOutput; import dev.morphia.critter.CritterClassLoader; import dev.morphia.critter.parser.Generators; import dev.morphia.critter.parser.asm.AddMethodAccessorMethods; import dev.morphia.critter.sources.Example; import dev.morphia.critter.sources.MethodExample; +import dev.morphia.mapping.ReflectiveMapper; import dev.morphia.mapping.codec.pojo.EntityModel; import dev.morphia.mapping.codec.pojo.PropertyModel; import dev.morphia.mapping.codec.pojo.TypeData; @@ -135,7 +137,9 @@ public void testAnnotationBuilding() throws Exception { @Test public void testGizmo() throws Exception { - CritterGizmoGenerator.INSTANCE.generate(Example.class, critterClassLoader, false); + MorphiaConfig config = dev.morphia.config.MorphiaConfig.load(); + Generators generators = new Generators(config, new ReflectiveMapper(config)); + CritterGizmoGenerator.generate(Example.class, critterClassLoader, generators, false); critterClassLoader.loadClass("dev.morphia.critter.sources.__morphia.example.AgeModel"); Class nameModel = critterClassLoader.loadClass("dev.morphia.critter.sources.__morphia.example.NameModel"); invokeAll(PropertyModel.class, nameModel); @@ -145,7 +149,7 @@ public void testGizmo() throws Exception { critterClassLoader.loadClass("dev.morphia.critter.sources.__morphia.example.SalaryAccessor").getConstructor().newInstance(); Class loadClass = critterClassLoader.loadClass("dev.morphia.critter.sources.__morphia.example.ExampleEntityModel"); - EntityModel model = (EntityModel) loadClass.getConstructors()[0].newInstance(Generators.INSTANCE.getMapper()); + EntityModel model = (EntityModel) loadClass.getConstructors()[0].newInstance(generators.getMapper()); validate(model); } diff --git a/critter/core/src/test/java/dev/morphia/critter/sources/Example.java b/core/src/test/java/dev/morphia/critter/sources/Example.java similarity index 100% rename from critter/core/src/test/java/dev/morphia/critter/sources/Example.java rename to core/src/test/java/dev/morphia/critter/sources/Example.java diff --git a/critter/core/src/test/java/dev/morphia/critter/sources/ExampleAgeAccessorTemplate.java b/core/src/test/java/dev/morphia/critter/sources/ExampleAgeAccessorTemplate.java similarity index 100% rename from critter/core/src/test/java/dev/morphia/critter/sources/ExampleAgeAccessorTemplate.java rename to core/src/test/java/dev/morphia/critter/sources/ExampleAgeAccessorTemplate.java diff --git a/critter/core/src/test/java/dev/morphia/critter/sources/ExampleAgePropertyModelTemplate.java b/core/src/test/java/dev/morphia/critter/sources/ExampleAgePropertyModelTemplate.java similarity index 100% rename from critter/core/src/test/java/dev/morphia/critter/sources/ExampleAgePropertyModelTemplate.java rename to core/src/test/java/dev/morphia/critter/sources/ExampleAgePropertyModelTemplate.java diff --git a/critter/core/src/test/java/dev/morphia/critter/sources/ExampleEntityModelTemplate.java b/core/src/test/java/dev/morphia/critter/sources/ExampleEntityModelTemplate.java similarity index 100% rename from critter/core/src/test/java/dev/morphia/critter/sources/ExampleEntityModelTemplate.java rename to core/src/test/java/dev/morphia/critter/sources/ExampleEntityModelTemplate.java diff --git a/critter/core/src/test/java/dev/morphia/critter/sources/ExampleNameAccessorTemplate.java b/core/src/test/java/dev/morphia/critter/sources/ExampleNameAccessorTemplate.java similarity index 100% rename from critter/core/src/test/java/dev/morphia/critter/sources/ExampleNameAccessorTemplate.java rename to core/src/test/java/dev/morphia/critter/sources/ExampleNameAccessorTemplate.java diff --git a/critter/core/src/test/java/dev/morphia/critter/sources/ExampleNamePropertyModelTemplate.java b/core/src/test/java/dev/morphia/critter/sources/ExampleNamePropertyModelTemplate.java similarity index 100% rename from critter/core/src/test/java/dev/morphia/critter/sources/ExampleNamePropertyModelTemplate.java rename to core/src/test/java/dev/morphia/critter/sources/ExampleNamePropertyModelTemplate.java diff --git a/critter/core/src/test/java/dev/morphia/critter/sources/ExampleSalaryAccessorTemplate.java b/core/src/test/java/dev/morphia/critter/sources/ExampleSalaryAccessorTemplate.java similarity index 100% rename from critter/core/src/test/java/dev/morphia/critter/sources/ExampleSalaryAccessorTemplate.java rename to core/src/test/java/dev/morphia/critter/sources/ExampleSalaryAccessorTemplate.java diff --git a/critter/core/src/test/java/dev/morphia/critter/sources/ExampleSalaryPropertyModelTemplate.java b/core/src/test/java/dev/morphia/critter/sources/ExampleSalaryPropertyModelTemplate.java similarity index 100% rename from critter/core/src/test/java/dev/morphia/critter/sources/ExampleSalaryPropertyModelTemplate.java rename to core/src/test/java/dev/morphia/critter/sources/ExampleSalaryPropertyModelTemplate.java diff --git a/critter/core/src/test/java/dev/morphia/critter/sources/MethodExample.java b/core/src/test/java/dev/morphia/critter/sources/MethodExample.java similarity index 100% rename from critter/core/src/test/java/dev/morphia/critter/sources/MethodExample.java rename to core/src/test/java/dev/morphia/critter/sources/MethodExample.java diff --git a/core/src/test/java/dev/morphia/test/config/TestConfig.java b/core/src/test/java/dev/morphia/test/config/TestConfig.java index dbeefcf9173..bb5cae18058 100644 --- a/core/src/test/java/dev/morphia/test/config/TestConfig.java +++ b/core/src/test/java/dev/morphia/test/config/TestConfig.java @@ -8,7 +8,6 @@ import dev.morphia.Datastore; import dev.morphia.Morphia; import dev.morphia.MorphiaDatastore; -import dev.morphia.config.ManualMorphiaConfig; import dev.morphia.config.MorphiaConfig; import dev.morphia.config.MorphiaConfigHelper; import dev.morphia.mapping.MappingException; @@ -48,19 +47,19 @@ public void generateExampleConfigFiles() throws IOException { var docsTarget = new File(root, "docs/modules/ROOT/examples"); try (var writer = new FileWriter(new File(docsTarget, "complete-morphia-config.properties"))) { - var configContents = MorphiaConfigHelper.dumpConfigurationFile(new ManualMorphiaConfig(), true); + var configContents = MorphiaConfigHelper.dumpConfigurationFile(dev.morphia.config.MorphiaConfig.load(), true); writer.write(configContents); writer.flush(); } try (var writer = new FileWriter(new File(docsTarget, "minimal-morphia-config.properties"))) { - var configContents = MorphiaConfigHelper.dumpConfigurationFile(new ManualMorphiaConfig(), false); + var configContents = MorphiaConfigHelper.dumpConfigurationFile(dev.morphia.config.MorphiaConfig.load(), false); writer.write(configContents); writer.flush(); } try (var writer = new FileWriter(new File(docsTarget, "legacy-morphia-config.properties"))) { - var configContents = MorphiaConfigHelper.dumpConfigurationFile(new ManualMorphiaConfig() + var configContents = MorphiaConfigHelper.dumpConfigurationFile(dev.morphia.config.MorphiaConfig.load() .legacy(), false); writer.write(configContents); writer.flush(); diff --git a/critter/core/src/main/java/dev/morphia/critter/parser/gizmo/CritterGizmoGenerator.java b/critter/core/src/main/java/dev/morphia/critter/parser/gizmo/CritterGizmoGenerator.java deleted file mode 100644 index 7c2174d9bac..00000000000 --- a/critter/core/src/main/java/dev/morphia/critter/parser/gizmo/CritterGizmoGenerator.java +++ /dev/null @@ -1,80 +0,0 @@ -package dev.morphia.critter.parser.gizmo; - -import java.io.IOException; -import java.util.List; - -import dev.morphia.critter.CritterClassLoader; -import dev.morphia.critter.parser.Generators; -import dev.morphia.critter.parser.PropertyFinder; -import dev.morphia.critter.parser.asm.AddFieldAccessorMethods; -import dev.morphia.critter.parser.asm.AddMethodAccessorMethods; - -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.FieldNode; -import org.objectweb.asm.tree.MethodNode; - -public class CritterGizmoGenerator { - public static final CritterGizmoGenerator INSTANCE = new CritterGizmoGenerator(); - - private CritterGizmoGenerator() { - } - - public GizmoEntityModelGenerator generate(Class type, CritterClassLoader critterClassLoader, boolean runtimeMode) { - ClassNode classNode = new ClassNode(); - String resourceName = "%s.class".formatted(type.getName().replace('.', '/')); - java.io.InputStream inputStream = type.getClassLoader().getResourceAsStream(resourceName); - if (inputStream == null) { - throw new IllegalArgumentException("Could not find class file for %s".formatted(type.getName())); - } - try { - new ClassReader(inputStream).accept(classNode, 0); - } catch (IOException e) { - throw new RuntimeException("Failed to read class %s".formatted(type.getName()), e); - } - PropertyFinder propertyFinder = new PropertyFinder(Generators.INSTANCE.getMapper(), critterClassLoader, runtimeMode); - - return entityModel(type, critterClassLoader, classNode, propertyFinder.find(type, classNode)); - } - - public GizmoEntityModelGenerator generate(Class type, CritterClassLoader critterClassLoader) { - return generate(type, critterClassLoader, false); - } - - public byte[] fieldAccessors(Class entityType, List fields) { - return new AddFieldAccessorMethods(entityType, fields).emit(); - } - - public byte[] methodAccessors(Class entityType, List methods) { - return new AddMethodAccessorMethods(entityType, methods).emit(); - } - - public PropertyAccessorGenerator propertyAccessor(Class entityType, CritterClassLoader critterClassLoader, FieldNode field) { - return new PropertyAccessorGenerator(entityType, critterClassLoader, field).emit(); - } - - public PropertyAccessorGenerator propertyAccessor(Class entityType, CritterClassLoader critterClassLoader, MethodNode method) { - return new PropertyAccessorGenerator(entityType, critterClassLoader, method).emit(); - } - - public VarHandleAccessorGenerator varHandleAccessor(Class entityType, CritterClassLoader critterClassLoader, FieldNode field) { - return new VarHandleAccessorGenerator(entityType, critterClassLoader, field).emit(); - } - - public VarHandleAccessorGenerator varHandleAccessor(Class entityType, CritterClassLoader critterClassLoader, MethodNode method) { - return new VarHandleAccessorGenerator(entityType, critterClassLoader, method).emit(); - } - - public PropertyModelGenerator propertyModelGenerator(Class entityType, CritterClassLoader critterClassLoader, FieldNode field) { - return new PropertyModelGenerator(Generators.INSTANCE.getConfig(), entityType, critterClassLoader, field).emit(); - } - - public PropertyModelGenerator propertyModelGenerator(Class entityType, CritterClassLoader critterClassLoader, MethodNode method) { - return new PropertyModelGenerator(Generators.INSTANCE.getConfig(), entityType, critterClassLoader, method).emit(); - } - - public GizmoEntityModelGenerator entityModel(Class type, CritterClassLoader critterClassLoader, - ClassNode classNode, List properties) { - return new GizmoEntityModelGenerator(type, critterClassLoader, classNode, properties).emit(); - } -} diff --git a/critter/critter-maven/src/main/kotlin/dev/morphia/critter/maven/CritterProcessor.kt b/critter/critter-maven/src/main/kotlin/dev/morphia/critter/maven/CritterProcessor.kt index 5de1d6f42d7..401e0eca497 100644 --- a/critter/critter-maven/src/main/kotlin/dev/morphia/critter/maven/CritterProcessor.kt +++ b/critter/critter-maven/src/main/kotlin/dev/morphia/critter/maven/CritterProcessor.kt @@ -5,6 +5,7 @@ import dev.morphia.config.MorphiaConfig import dev.morphia.critter.CritterClassLoader import dev.morphia.critter.parser.Generators import dev.morphia.critter.parser.gizmo.CritterGizmoGenerator +import dev.morphia.mapping.ReflectiveMapper import io.github.classgraph.ClassGraph import java.io.File import org.slf4j.Logger @@ -20,12 +21,10 @@ class CritterProcessor( ) { private val logger: Logger = LoggerFactory.getLogger(CritterProcessor::class.java) - private val critterClassLoader = CritterClassLoader() + private val critterClassLoader = CritterClassLoader(classLoader) + private val generators = Generators(config, ReflectiveMapper(config)) fun process() { - // Configure Generators with the loaded MorphiaConfig - Generators.INSTANCE.configFile = findConfigFile() - val entityClasses = findEntityClasses() if (entityClasses.isEmpty()) { @@ -44,17 +43,6 @@ class CritterProcessor( writeGeneratedClasses() } - private fun findConfigFile(): String { - // Check if morphia-config.properties exists in the classes directory - val configFile = File(classesDirectory, "META-INF/morphia-config.properties") - return if (configFile.exists()) { - "META-INF/morphia-config.properties" - } else { - // Return default location - Generators will use defaults if not found - "META-INF/morphia-config.properties" - } - } - private fun findEntityClasses(): List> { val packagesToScan = packages.ifEmpty { @@ -84,7 +72,7 @@ class CritterProcessor( private fun processClass(entityClass: Class<*>) { logger.info("Generating critter code for: ${entityClass.name}") - CritterGizmoGenerator.INSTANCE.generate(entityClass, critterClassLoader, false) + CritterGizmoGenerator.generate(entityClass, critterClassLoader, generators, false) } private fun writeGeneratedClasses() { diff --git a/critter/pom.xml b/critter/pom.xml index 4c08fd018b3..a442d36d109 100644 --- a/critter/pom.xml +++ b/critter/pom.xml @@ -15,8 +15,7 @@ pom - core critter-maven critter-integration-tests - \ No newline at end of file +