From c9b6986f69bc63141756afbc85b82a892df663fd Mon Sep 17 00:00:00 2001 From: Gavin King Date: Fri, 20 Dec 2024 19:45:18 +0100 Subject: [PATCH] implement support for Jakarta Data events (no events for reactive repos) --- .../org/hibernate/processor/ClassWriter.java | 6 ++ .../java/org/hibernate/processor/Context.java | 9 ++ .../processor/HibernateProcessor.java | 4 + .../annotation/AnnotationMetaEntity.java | 5 + .../processor/annotation/LifecycleMethod.java | 102 ++++++++++++++---- .../hibernate/processor/model/Metamodel.java | 4 + 6 files changed, 107 insertions(+), 23 deletions(-) diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/ClassWriter.java b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/ClassWriter.java index 2bbb09dcc0..4766b91ca0 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/ClassWriter.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/ClassWriter.java @@ -108,6 +108,12 @@ private static StringBuffer generateBody(Metamodel entity, Context context) { pw.println(); + // TODO: move this! + if ( context.addDependentAnnotation() && context.isDataEventPackageAvailable() + && entity.isImplementation() && !entity.isReactive() ) { + pw.println("\t@Inject private Event> event;\n"); + } + final List members = entity.getMembers(); for ( MetaAttribute metaMember : members ) { if ( metaMember instanceof InnerClassMetaAttribute innerClass ) { diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/Context.java b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/Context.java index fc14378ee2..ca357a3d7b 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/Context.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/Context.java @@ -92,6 +92,7 @@ public final class Context { private AccessType persistenceUnitDefaultAccessType; private boolean generateJakartaDataStaticMetamodel; private boolean quarkusInjection; + private boolean dataEventPackageAvailable; // keep track of all classes for which model have been generated private final Set generatedModelClasses = new HashSet<>(); @@ -224,6 +225,14 @@ public void setQuarkusInjection(boolean quarkusInjection) { this.quarkusInjection = quarkusInjection; } + public boolean isDataEventPackageAvailable() { + return dataEventPackageAvailable; + } + + public void setDataEventPackageAvailable(boolean dataEventPackageAvailable) { + this.dataEventPackageAvailable = dataEventPackageAvailable; + } + public Elements getElementUtils() { return processingEnvironment.getElementUtils(); } diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/HibernateProcessor.java b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/HibernateProcessor.java index b926c5d72e..af3f276da5 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/HibernateProcessor.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/HibernateProcessor.java @@ -243,6 +243,9 @@ private boolean handleSettings(ProcessingEnvironment environment) { final PackageElement quarkusOrmPackage = context.getProcessingEnvironment().getElementUtils() .getPackageElement( "io.quarkus.hibernate.orm" ); + final PackageElement dataEventPackage = + context.getProcessingEnvironment().getElementUtils() + .getPackageElement( "jakarta.data.event" ); PackageElement quarkusOrmPanachePackage = context.getProcessingEnvironment().getElementUtils() @@ -265,6 +268,7 @@ && packagePresent(quarkusOrmPanachePackage) ) { context.setAddGeneratedAnnotation( packagePresent(jakartaAnnotationPackage) ); context.setAddDependentAnnotation( packagePresent(jakartaContextPackage) ); context.setAddTransactionScopedAnnotation( packagePresent(jakartaTransactionsPackage) ); + context.setDataEventPackageAvailable( packagePresent(dataEventPackage) ); context.setQuarkusInjection( packagePresent(quarkusOrmPackage) ); context.setUsesQuarkusOrm( packagePresent(quarkusOrmPanachePackage) ); context.setUsesQuarkusReactive( packagePresent(quarkusReactivePanachePackage) ); diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AnnotationMetaEntity.java b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AnnotationMetaEntity.java index 765530d53d..dacec6a3f3 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AnnotationMetaEntity.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AnnotationMetaEntity.java @@ -685,6 +685,11 @@ boolean needsDefaultConstructor() { return null; } + @Override + public boolean isReactive() { + return usingReactiveSession(sessionType); + } + private boolean isPanacheType(TypeElement type) { return context.usesQuarkusOrm() && isOrmPanacheType( type ) || context.usesQuarkusReactive() && isReactivePanacheType( type ); diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/LifecycleMethod.java b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/LifecycleMethod.java index 27fdac7989..080f4f2c4d 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/LifecycleMethod.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/LifecycleMethod.java @@ -7,6 +7,9 @@ import javax.lang.model.element.ExecutableElement; +import java.util.Set; + +import static java.lang.Character.toUpperCase; import static org.hibernate.processor.util.Constants.LIST; import static org.hibernate.processor.util.Constants.UNI; @@ -60,21 +63,24 @@ public boolean hasStringAttribute() { return false; } + private String capitalize(String string) { + return toUpperCase(string.charAt(0)) + string.substring(1); + } + + static final Set eventTypes = Set.of("insert", "update", "delete"); + @Override public String getAttributeDeclarationString() { StringBuilder declaration = new StringBuilder(); preamble(declaration); nullCheck(declaration, parameterName); + preEvent(declaration); if ( !isReactive() ) { declaration.append( "\ttry {\n" ); } delegateCall(declaration); - returnArgument(declaration); + returnArgumentReactively(declaration); if ( !isReactive() ) { - if ( returnArgument ) { - declaration - .append( ";\n" ); - } declaration.append( "\t}\n" ); } convertExceptions( declaration ); @@ -82,10 +88,77 @@ public String getAttributeDeclarationString() { declaration .append( ";\n" ); } + postEvent(declaration); + returnArgument(declaration); declaration.append("}"); return declaration.toString(); } + private void postEvent(StringBuilder declaration) { + if ( annotationMetaEntity.getContext().isDataEventPackageAvailable() + && annotationMetaEntity.getContext().addDependentAnnotation() + && eventTypes.contains( operationName ) + && !isReactive() ) { + final String postEventType = "Post" + capitalize( operationName ) + "Event"; + annotationMetaEntity.importType( "jakarta.data.event." + postEventType ); + declaration + .append( "\tevent.select(new TypeLiteral<" ) + .append( postEventType ) + .append( "<" ) + .append( annotationMetaEntity.importType( entity ) ) + .append( ">>(){})\n\t\t\t.fire(new " ) + .append( postEventType ) + .append( "<>(" ) + .append( parameterName ) + .append( "));\n" ); + } + } + + private void preEvent(StringBuilder declaration) { + if ( annotationMetaEntity.getContext().isDataEventPackageAvailable() + && annotationMetaEntity.getContext().addDependentAnnotation() + && eventTypes.contains( operationName ) + && !isReactive()) { + final String preEventType = "Pre" + capitalize( operationName ) + "Event"; + annotationMetaEntity.importType( "jakarta.data.event." + preEventType ); + annotationMetaEntity.importType( "jakarta.data.event.LifecycleEvent" ); + annotationMetaEntity.importType( "jakarta.enterprise.util.TypeLiteral" ); + annotationMetaEntity.importType( "jakarta.enterprise.event.Event" ); + annotationMetaEntity.importType( "jakarta.inject.Inject" ); + declaration + .append( "\tevent.select(new TypeLiteral<" ) + .append( preEventType ) + .append( "<" ) + .append( annotationMetaEntity.importType( entity ) ) + .append( ">>(){})\n\t\t\t.fire(new " ) + .append( preEventType ) + .append( "<>(" ) + .append( parameterName ) + .append( "));\n" ); + } + } + + private void returnArgument(StringBuilder declaration) { + if ( returnArgument && !isReactive() ) { + declaration + .append( "\treturn " ) + .append( parameterName ) + .append( ";\n" ); + } + } + + private void returnArgumentReactively(StringBuilder declaration) { + if ( isReactive() ) { + if ( returnArgument ) { + declaration + .append( "\n\t\t\t.replaceWith(") + .append(parameterName) + .append(")"); + } + } + } + + private void convertExceptions(StringBuilder declaration) { if ( operationName.equals("insert") ) { handle( declaration, @@ -102,23 +175,6 @@ private void convertExceptions(StringBuilder declaration) { "jakarta.data.exceptions.DataException"); } - private void returnArgument(StringBuilder declaration) { - if ( returnArgument ) { - if ( isReactive() ) { - declaration - .append( "\n\t\t\t" ) - .append(".replaceWith(") - .append(parameterName) - .append(")"); - } - else { - declaration - .append("\t\treturn ") - .append(parameterName); - } - } - } - private void delegateCall(StringBuilder declaration) { if ( isReactive() ) { // TODO: handle the case of an iterable parameter @@ -179,7 +235,7 @@ private void argument(StringBuilder declaration) { if ( isReactive() ) { declaration .append("All") - .append("(") + .append("((Object[]) ") .append(parameterName) .append(")"); } diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/model/Metamodel.java b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/model/Metamodel.java index 49cdfb09e6..4408e4def0 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/model/Metamodel.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/model/Metamodel.java @@ -60,4 +60,8 @@ public interface Metamodel extends ImportContext { List inheritedAnnotations(); String javadoc(); + + default boolean isReactive() { + return false; + } }