Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement the Mutiny support for MongoDB Panache #7337

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@
import io.quarkus.panache.common.deployment.MetamodelInfo;
import io.quarkus.panache.common.deployment.PanacheEntityEnhancer;

public class ReactivePanacheMongoEntityEnhancer extends PanacheEntityEnhancer<MetamodelInfo<EntityModel<EntityField>>> {
public class AxlePanacheMongoEntityEnhancer extends PanacheEntityEnhancer<MetamodelInfo<EntityModel<EntityField>>> {
public final static String MONGO_OPERATIONS_NAME = ReactiveMongoOperations.class.getName();
public final static String MONGO_OPERATIONS_BINARY_NAME = MONGO_OPERATIONS_NAME.replace('.', '/');

private static final DotName DOTNAME_BSON_IGNORE = DotName.createSimple(BsonIgnore.class.getName());

final Map<String, EntityModel> entities = new HashMap<>();

public ReactivePanacheMongoEntityEnhancer(IndexView index) {
public AxlePanacheMongoEntityEnhancer(IndexView index) {
super(index, PanacheResourceProcessor.DOTNAME_AXLE_PANACHE_ENTITY_BASE);
modelInfo = new MetamodelInfo<>();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@
import io.quarkus.mongodb.panache.axle.ReactivePanacheMongoRepositoryBase;
import io.quarkus.panache.common.deployment.PanacheRepositoryEnhancer;

public class ReactivePanacheMongoRepositoryEnhancer extends PanacheRepositoryEnhancer {
public class AxlePanacheMongoRepositoryEnhancer extends PanacheRepositoryEnhancer {
public final static DotName PANACHE_REPOSITORY_BASE_NAME = DotName
.createSimple(ReactivePanacheMongoRepositoryBase.class.getName());

public final static DotName PANACHE_REPOSITORY_NAME = DotName.createSimple(ReactivePanacheMongoRepository.class.getName());

public ReactivePanacheMongoRepositoryEnhancer(IndexView index) {
public AxlePanacheMongoRepositoryEnhancer(IndexView index) {
super(index, PanacheResourceProcessor.DOTNAME_AXLE_PANACHE_REPOSITORY_BASE);
}

Expand Down Expand Up @@ -45,7 +45,7 @@ protected DotName getPanacheRepositoryBaseDotName() {

@Override
protected String getPanacheOperationsBinaryName() {
return ReactivePanacheMongoEntityEnhancer.MONGO_OPERATIONS_BINARY_NAME;
return AxlePanacheMongoEntityEnhancer.MONGO_OPERATIONS_BINARY_NAME;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package io.quarkus.mongodb.panache.deployment;

import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;

import org.bson.codecs.pojo.annotations.BsonIgnore;
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName;
import org.jboss.jandex.FieldInfo;
import org.jboss.jandex.IndexView;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

import io.quarkus.gizmo.DescriptorUtils;
import io.quarkus.mongodb.panache.reactive.runtime.ReactiveMongoOperations;
import io.quarkus.panache.common.deployment.EntityField;
import io.quarkus.panache.common.deployment.EntityModel;
import io.quarkus.panache.common.deployment.MetamodelInfo;
import io.quarkus.panache.common.deployment.PanacheEntityEnhancer;

public class MutinyPanacheMongoEntityEnhancer extends PanacheEntityEnhancer<MetamodelInfo<EntityModel<EntityField>>> {
public final static String MONGO_OPERATIONS_NAME = ReactiveMongoOperations.class.getName();
public final static String MONGO_OPERATIONS_BINARY_NAME = MONGO_OPERATIONS_NAME.replace('.', '/');

private static final DotName DOTNAME_BSON_IGNORE = DotName.createSimple(BsonIgnore.class.getName());

final Map<String, EntityModel> entities = new HashMap<>();

public MutinyPanacheMongoEntityEnhancer(IndexView index) {
super(index, PanacheResourceProcessor.DOTNAME_MUTINY_PANACHE_ENTITY_BASE);
modelInfo = new MetamodelInfo<>();
}

@Override
public ClassVisitor apply(String className, ClassVisitor outputClassVisitor) {
return new PanacheMongoEntityClassVisitor(className, outputClassVisitor, modelInfo, panacheEntityBaseClassInfo,
indexView.getClassByName(DotName.createSimple(className)));
}

static class PanacheMongoEntityClassVisitor extends PanacheEntityClassVisitor<EntityField> {

public PanacheMongoEntityClassVisitor(String className, ClassVisitor outputClassVisitor,
MetamodelInfo<EntityModel<EntityField>> modelInfo, ClassInfo panacheEntityBaseClassInfo,
ClassInfo entityInfo) {
super(className, outputClassVisitor, modelInfo, panacheEntityBaseClassInfo, entityInfo);
}

@Override
protected void injectModel(MethodVisitor mv) {
mv.visitLdcInsn(thisClass);
}

@Override
protected String getModelDescriptor() {
return "Ljava/lang/Class;";
}

@Override
protected String getPanacheOperationsBinaryName() {
return MONGO_OPERATIONS_BINARY_NAME;
}

@Override
protected void generateAccessorSetField(MethodVisitor mv, EntityField field) {
mv.visitFieldInsn(Opcodes.PUTFIELD, thisClass.getInternalName(), field.name, field.descriptor);
}

@Override
protected void generateAccessorGetField(MethodVisitor mv, EntityField field) {
mv.visitFieldInsn(Opcodes.GETFIELD, thisClass.getInternalName(), field.name, field.descriptor);
}
}

public void collectFields(ClassInfo classInfo) {
EntityModel<EntityField> entityModel = new EntityModel<>(classInfo);
for (FieldInfo fieldInfo : classInfo.fields()) {
String name = fieldInfo.name();
if (Modifier.isPublic(fieldInfo.flags()) && !fieldInfo.hasAnnotation(DOTNAME_BSON_IGNORE)) {
entityModel.addField(new EntityField(name, DescriptorUtils.typeToString(fieldInfo.type())));
}
}
modelInfo.addEntityModel(entityModel);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package io.quarkus.mongodb.panache.deployment;

import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName;
import org.jboss.jandex.IndexView;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;

import io.quarkus.mongodb.panache.reactive.ReactivePanacheMongoRepository;
import io.quarkus.mongodb.panache.reactive.ReactivePanacheMongoRepositoryBase;
import io.quarkus.panache.common.deployment.PanacheRepositoryEnhancer;

public class MutinyPanacheMongoRepositoryEnhancer extends PanacheRepositoryEnhancer {
public static final DotName PANACHE_REPOSITORY_BASE_NAME = DotName
.createSimple(ReactivePanacheMongoRepositoryBase.class.getName());

public static final DotName PANACHE_REPOSITORY_NAME = DotName.createSimple(ReactivePanacheMongoRepository.class.getName());

public MutinyPanacheMongoRepositoryEnhancer(IndexView index) {
super(index, PanacheResourceProcessor.DOTNAME_MUTINY_PANACHE_REPOSITORY_BASE);
}

@Override
public ClassVisitor apply(String className, ClassVisitor outputClassVisitor) {
return new PanacheMongoRepositoryClassVisitor(className, outputClassVisitor, panacheRepositoryBaseClassInfo,
this.indexView);
}

static class PanacheMongoRepositoryClassVisitor extends PanacheRepositoryClassVisitor {

public PanacheMongoRepositoryClassVisitor(String className, ClassVisitor outputClassVisitor,
ClassInfo panacheRepositoryBaseClassInfo, IndexView indexView) {
super(className, outputClassVisitor, panacheRepositoryBaseClassInfo, indexView);
}

@Override
protected DotName getPanacheRepositoryDotName() {
return PANACHE_REPOSITORY_NAME;
}

@Override
protected DotName getPanacheRepositoryBaseDotName() {
return PANACHE_REPOSITORY_BASE_NAME;
}

@Override
protected String getPanacheOperationsBinaryName() {
return MutinyPanacheMongoEntityEnhancer.MONGO_OPERATIONS_BINARY_NAME;
}

@Override
protected void injectModel(MethodVisitor mv) {
// inject Class
mv.visitLdcInsn(entityType);
}

@Override
protected String getModelDescriptor() {
return "Ljava/lang/Class;";
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,16 @@ public class PanacheResourceProcessor {
.createSimple(ReactivePanacheMongoEntityBase.class.getName());
private static final DotName DOTNAME_AXLE_PANACHE_ENTITY = DotName.createSimple(ReactivePanacheMongoEntity.class.getName());

// reactive types: Mutiny
static final DotName DOTNAME_MUTINY_PANACHE_REPOSITORY_BASE = DotName
.createSimple(io.quarkus.mongodb.panache.reactive.ReactivePanacheMongoRepositoryBase.class.getName());
private static final DotName DOTNAME_MUTINY_PANACHE_REPOSITORY = DotName
.createSimple(io.quarkus.mongodb.panache.reactive.ReactivePanacheMongoRepository.class.getName());
static final DotName DOTNAME_MUTINY_PANACHE_ENTITY_BASE = DotName
.createSimple(io.quarkus.mongodb.panache.reactive.ReactivePanacheMongoEntityBase.class.getName());
private static final DotName DOTNAME_MUTINY_PANACHE_ENTITY = DotName
.createSimple(io.quarkus.mongodb.panache.reactive.ReactivePanacheMongoEntity.class.getName());

private static final DotName DOTNAME_OBJECT_ID = DotName.createSimple(ObjectId.class.getName());

private static final DotName DOTNAME_OBJECT = DotName.createSimple(Object.class.getName());
Expand Down Expand Up @@ -304,7 +314,7 @@ void buildAxle(CombinedIndexBuildItem index,
ApplicationIndexBuildItem applicationIndex,
BuildProducer<BytecodeTransformerBuildItem> transformers) throws Exception {

ReactivePanacheMongoRepositoryEnhancer daoEnhancer = new ReactivePanacheMongoRepositoryEnhancer(index.getIndex());
AxlePanacheMongoRepositoryEnhancer daoEnhancer = new AxlePanacheMongoRepositoryEnhancer(index.getIndex());
Set<String> daoClasses = new HashSet<>();
for (ClassInfo classInfo : index.getIndex().getAllKnownImplementors(DOTNAME_AXLE_PANACHE_REPOSITORY_BASE)) {
// Skip PanacheRepository
Expand All @@ -323,7 +333,7 @@ void buildAxle(CombinedIndexBuildItem index,
transformers.produce(new BytecodeTransformerBuildItem(daoClass, daoEnhancer));
}

ReactivePanacheMongoEntityEnhancer modelEnhancer = new ReactivePanacheMongoEntityEnhancer(index.getIndex());
AxlePanacheMongoEntityEnhancer modelEnhancer = new AxlePanacheMongoEntityEnhancer(index.getIndex());
Set<String> modelClasses = new HashSet<>();
// Note that we do this in two passes because for some reason Jandex does not give us subtypes
// of PanacheMongoEntity if we ask for subtypes of PanacheMongoEntityBase
Expand Down Expand Up @@ -352,4 +362,58 @@ void buildAxle(CombinedIndexBuildItem index,
}
}
}

@BuildStep
void buildMutiny(CombinedIndexBuildItem index,
ApplicationIndexBuildItem applicationIndex,
BuildProducer<BytecodeTransformerBuildItem> transformers) {

MutinyPanacheMongoRepositoryEnhancer daoEnhancer = new MutinyPanacheMongoRepositoryEnhancer(index.getIndex());
Set<String> daoClasses = new HashSet<>();
for (ClassInfo classInfo : index.getIndex().getAllKnownImplementors(DOTNAME_MUTINY_PANACHE_REPOSITORY_BASE)) {
// Skip PanacheRepository
if (classInfo.name().equals(DOTNAME_MUTINY_PANACHE_REPOSITORY))
continue;
if (PanacheRepositoryEnhancer.skipRepository(classInfo))
continue;
daoClasses.add(classInfo.name().toString());
}
for (ClassInfo classInfo : index.getIndex().getAllKnownImplementors(DOTNAME_MUTINY_PANACHE_REPOSITORY)) {
if (PanacheRepositoryEnhancer.skipRepository(classInfo))
continue;
daoClasses.add(classInfo.name().toString());
}
for (String daoClass : daoClasses) {
transformers.produce(new BytecodeTransformerBuildItem(daoClass, daoEnhancer));
}

MutinyPanacheMongoEntityEnhancer modelEnhancer = new MutinyPanacheMongoEntityEnhancer(index.getIndex());
Set<String> modelClasses = new HashSet<>();
// Note that we do this in two passes because for some reason Jandex does not give us subtypes
// of PanacheMongoEntity if we ask for subtypes of PanacheMongoEntityBase
for (ClassInfo classInfo : index.getIndex().getAllKnownSubclasses(DOTNAME_MUTINY_PANACHE_ENTITY_BASE)) {
if (classInfo.name().equals(DOTNAME_MUTINY_PANACHE_ENTITY))
continue;
if (modelClasses.add(classInfo.name().toString()))
modelEnhancer.collectFields(classInfo);
}
for (ClassInfo classInfo : index.getIndex().getAllKnownSubclasses(DOTNAME_MUTINY_PANACHE_ENTITY)) {
if (modelClasses.add(classInfo.name().toString()))
modelEnhancer.collectFields(classInfo);
}
for (String modelClass : modelClasses) {
transformers.produce(new BytecodeTransformerBuildItem(modelClass, modelEnhancer));
}

if (!modelEnhancer.entities.isEmpty()) {
PanacheFieldAccessEnhancer panacheFieldAccessEnhancer = new PanacheFieldAccessEnhancer(
modelEnhancer.getModelInfo());
for (ClassInfo classInfo : applicationIndex.getIndex().getKnownClasses()) {
String className = classInfo.name().toString();
if (!modelClasses.contains(className)) {
transformers.produce(new BytecodeTransformerBuildItem(className, panacheFieldAccessEnhancer));
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
* all the useful methods.
*
* @see ReactivePanacheMongoEntityBase
* @deprecated Use {@link io.quarkus.mongodb.panache.reactive.ReactivePanacheMongoRepository} instead.
*/
@Deprecated
public abstract class ReactivePanacheMongoEntity extends ReactivePanacheMongoEntityBase {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
* {@link ReactivePanacheMongoEntity} instead.
*
* @see ReactivePanacheMongoEntity
* @deprecated Use {@link io.quarkus.mongodb.panache.reactive.ReactivePanacheMongoEntityBase} instead.
*/
@Deprecated
public abstract class ReactivePanacheMongoEntityBase {

// Operations
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
* implement {@link ReactivePanacheMongoRepositoryBase} instead.
*
* @param <Entity> The type of entity to operate on
* @deprecated Use {@link io.quarkus.mongodb.panache.reactive.ReactivePanacheMongoRepository} instead.
*/
@Deprecated
public interface ReactivePanacheMongoRepository<Entity> extends ReactivePanacheMongoRepositoryBase<Entity, ObjectId> {

}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@
* @param <Entity> The type of entity to operate on
* @param <Id> The ID type of the entity
* @see ReactivePanacheMongoRepository
* @deprecated Use {@link io.quarkus.mongodb.panache.reactive.ReactivePanacheMongoEntity} instead.
*/
@Deprecated
public interface ReactivePanacheMongoRepositoryBase<Entity, Id> {

// Operations
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
* modified, and instances of this interface can be reused to obtain multiple pages of results.
*
* @param <Entity> The entity type being queried
* @deprecated Use {@link io.quarkus.mongodb.panache.reactive.ReactivePanacheQuery} instead.
*/
@Deprecated
public interface ReactivePanacheQuery<Entity> {

// Builder
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package io.quarkus.mongodb.panache.reactive;

import org.bson.types.ObjectId;

/**
* Represents an entity with a generated ID field {@link #id} of type {@link ObjectId}. If your
* Mongo entities extend this class they gain the ID field and auto-generated accessors
* to all their public fields, as well as all the useful methods from {@link ReactivePanacheMongoEntityBase}.
*
* If you want a custom ID type or strategy, you can directly extend {@link ReactivePanacheMongoEntityBase}
* instead, and write your own ID field. You will still get auto-generated accessors and
* all the useful methods.
*
* @see ReactivePanacheMongoEntityBase
*/
public abstract class ReactivePanacheMongoEntity extends ReactivePanacheMongoEntityBase {

/**
* The auto-generated ID field.
* This field is set by Mongo when this entity is persisted.
*
* @see #persist()
*/
public ObjectId id;

@Override
public String toString() {
return this.getClass().getSimpleName() + "<" + id + ">";
}
}
Loading