Skip to content

Commit 623cbf8

Browse files
committed
Generate repository accessors in the metamodel of Panache2 entities
Comes with 4 out of the box: - managed/blocking (generated) - managed/reactive (generated if reactive-common is in the CP) - stateless/blocking (generated) - stateless/reactive (generated if reactive-common is in the CP) - whatever nested repositories from the entity -- and if they implement one of the first four, we use this instead of the generated one
1 parent dbcbc50 commit 623cbf8

File tree

3 files changed

+294
-0
lines changed

3 files changed

+294
-0
lines changed

tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AnnotationMetaEntity.java

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,10 @@ && containsAnnotation( method, HQL, SQL, FIND ) ) {
468468
addPersistentMembers( gettersAndSettersOfClass, AccessType.PROPERTY );
469469

470470
addIdClassIfNeeded( fieldsOfClass, gettersAndSettersOfClass );
471+
472+
if( hasAnnotation( element, ENTITY) && isPanache2Type(element) && !jakartaDataStaticModel ) {
473+
addRepositoryMembers( element );
474+
}
471475
}
472476

473477
addAuxiliaryMembers();
@@ -521,6 +525,38 @@ private void addIdClassIfNeeded(List<VariableElement> fields, List<ExecutableEle
521525
}
522526
}
523527

528+
private void addRepositoryMembers(TypeElement element) {
529+
Element managedBlockingRepository = null;
530+
Element statelessBlockingRepository = null;
531+
Element managedReactiveRepository = null;
532+
Element statelessReactiveRepository = null;
533+
for ( Element enclosedElement : element.getEnclosedElements() ) {
534+
if ( enclosedElement.getKind() == ElementKind.INTERFACE ) {
535+
members.put( enclosedElement.getSimpleName().toString(), new CDIAccessorMetaAttribute( this, enclosedElement ) );
536+
if ( implementsInterface( (TypeElement) enclosedElement, Constants.PANACHE2_MANAGED_BLOCKING_REPOSITORY_BASE ) ) {
537+
managedBlockingRepository = enclosedElement;
538+
} else if ( implementsInterface( (TypeElement) enclosedElement, Constants.PANACHE2_STATELESS_BLOCKING_REPOSITORY_BASE ) ) {
539+
statelessBlockingRepository = enclosedElement;
540+
} else if ( implementsInterface( (TypeElement) enclosedElement, Constants.PANACHE2_MANAGED_REACTIVE_REPOSITORY_BASE ) ) {
541+
managedReactiveRepository = enclosedElement;
542+
} else if ( implementsInterface( (TypeElement) enclosedElement, Constants.PANACHE2_STATELESS_REACTIVE_REPOSITORY_BASE ) ) {
543+
statelessReactiveRepository = enclosedElement;
544+
}
545+
}
546+
}
547+
if ( quarkusInjection ) {
548+
// FIXME: perhaps import id type?
549+
TypeMirror idType = findIdType();
550+
addAccessors(managedBlockingRepository, idType, "managedBlocking", PANACHE2_MANAGED_BLOCKING_REPOSITORY_BASE);
551+
addAccessors(statelessBlockingRepository, idType, "statelessBlocking", PANACHE2_STATELESS_BLOCKING_REPOSITORY_BASE);
552+
// Only add those if HR is in the classpath, otherwise it causes a compilation issue
553+
if( context.usesQuarkusReactiveCommon() ) {
554+
addAccessors(managedReactiveRepository, idType, "managedReactive", PANACHE2_MANAGED_REACTIVE_REPOSITORY_BASE);
555+
addAccessors(statelessReactiveRepository, idType, "statelessReactive", PANACHE2_STATELESS_REACTIVE_REPOSITORY_BASE);
556+
}
557+
}
558+
}
559+
524560
private List<MetaAttribute> getIdMemberNames(List<VariableElement> fields, List<ExecutableElement> methods) {
525561
final List<MetaAttribute> components = new ArrayList<>();
526562
for ( var field : fields ) {
@@ -648,6 +684,66 @@ private boolean isEquivalentPrimitiveType(TypeMirror type, TypeMirror match) {
648684
&& isSameType( context.getTypeUtils().boxedClass( ((PrimitiveType) type) ).asType(), match );
649685
}
650686

687+
private void addAccessors(@Nullable Element repositoryType, @Nullable TypeMirror idType,
688+
String repositoryAccessor, String repositorySuperType) {
689+
TypeElement finalPrimaryEntity = primaryEntity;
690+
if ( repositoryType != null ) {
691+
members.put( repositoryAccessor, new CDIAccessorMetaAttribute( this, repositoryAccessor, repositoryType.getSimpleName().toString() ) );
692+
} else if ( idType != null && finalPrimaryEntity != null ) {
693+
String repositoryTypeName = "Panache"+repositoryAccessor.substring(0,1).toUpperCase()+repositoryAccessor.substring(1)+"Repository";
694+
members.put( repositoryAccessor, new CDIAccessorMetaAttribute( this, repositoryAccessor, repositoryTypeName ) );
695+
members.put( repositoryAccessor + "Repository", new CDITypeMetaAttribute( this, repositoryTypeName, repositorySuperType +"<"+ finalPrimaryEntity.getSimpleName()+", "+ idType.toString()+">" ) );
696+
}
697+
}
698+
699+
private @Nullable TypeMirror findIdType() {
700+
Element idMember = findIdMember();
701+
TypeElement primaryEntityForTest = primaryEntity;
702+
if ( idMember != null && primaryEntityForTest != null ) {
703+
TypeMirror typedIdMember = this.context.getTypeUtils().asMemberOf((DeclaredType) primaryEntityForTest.asType(), idMember);
704+
TypeMirror idType = null;
705+
switch(typedIdMember.getKind()) {
706+
case ARRAY:
707+
case DECLARED:
708+
case BOOLEAN:
709+
case BYTE:
710+
case CHAR:
711+
case SHORT:
712+
case INT:
713+
case LONG:
714+
case FLOAT:
715+
case DOUBLE:
716+
return typedIdMember;
717+
case EXECUTABLE:
718+
return ((ExecutableType) typedIdMember).getReturnType();
719+
default:
720+
message( element,
721+
"Unhandled id member kind: "+typedIdMember+" for id "+idMember,
722+
Diagnostic.Kind.ERROR );
723+
return null;
724+
}
725+
}
726+
return null;
727+
}
728+
729+
private @Nullable Element findIdMember() {
730+
if ( primaryEntity == null ) {
731+
message( element,
732+
"No primary entity defined to find id member",
733+
Diagnostic.Kind.ERROR );
734+
return null;
735+
}
736+
for ( Element member : context.getAllMembers( primaryEntity ) ) {
737+
if ( hasAnnotation( member, ID, EMBEDDED_ID ) ) {
738+
return member;
739+
}
740+
}
741+
message( element,
742+
"Could not find any member annotated with @Id or @EmbeddedId",
743+
Diagnostic.Kind.ERROR );
744+
return null;
745+
}
746+
651747
private boolean checkEntities(List<ExecutableElement> lifecycleMethods, boolean hibernateRepo) {
652748
boolean foundPersistenceEntity = false;
653749
VariableElement nonPersistenceParameter = null;
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.processor.annotation;
6+
7+
import javax.lang.model.element.Element;
8+
9+
import org.hibernate.processor.model.MetaAttribute;
10+
import org.hibernate.processor.model.Metamodel;
11+
import org.hibernate.processor.util.StringUtil;
12+
13+
public class CDIAccessorMetaAttribute implements MetaAttribute {
14+
15+
private AnnotationMetaEntity annotationMetaEntity;
16+
private String propertyName;
17+
private String typeName;
18+
19+
public CDIAccessorMetaAttribute(AnnotationMetaEntity annotationMetaEntity, Element repositoryElement) {
20+
this.annotationMetaEntity = annotationMetaEntity;
21+
// turn the name into lowercase
22+
String name = repositoryElement.getSimpleName().toString();
23+
// FIXME: this is wrong for types like STEFQueries
24+
this.propertyName = StringUtil.decapitalize( name );
25+
this.typeName = name;
26+
}
27+
28+
public CDIAccessorMetaAttribute(AnnotationMetaEntity annotationMetaEntity, String propertyName, String className) {
29+
this.annotationMetaEntity = annotationMetaEntity;
30+
this.propertyName = propertyName;
31+
this.typeName = className;
32+
}
33+
34+
@Override
35+
public boolean hasTypedAttribute() {
36+
return true;
37+
}
38+
39+
@Override
40+
public boolean hasStringAttribute() {
41+
return false;
42+
}
43+
44+
@Override
45+
public String getAttributeDeclarationString() {
46+
final StringBuilder declaration = new StringBuilder();
47+
modifiers( declaration );
48+
preamble( declaration );
49+
returnCDI( declaration );
50+
closingBrace( declaration );
51+
return declaration.toString();
52+
}
53+
54+
private void returnCDI(StringBuilder declaration) {
55+
annotationMetaEntity.importType("jakarta.enterprise.inject.spi.CDI");
56+
declaration
57+
.append("\treturn CDI.current().select(")
58+
.append(typeName)
59+
.append(".class).get();\n");
60+
}
61+
62+
void closingBrace(StringBuilder declaration) {
63+
declaration.append("}");
64+
}
65+
66+
void preamble(StringBuilder declaration) {
67+
declaration
68+
.append(typeName)
69+
.append(" ")
70+
.append( getPropertyName() );
71+
declaration
72+
.append("() {\n");
73+
}
74+
75+
@Override
76+
public String getAttributeNameDeclarationString() {
77+
return "";
78+
}
79+
80+
@Override
81+
public String getMetaType() {
82+
throw new UnsupportedOperationException("operation not supported");
83+
}
84+
85+
@Override
86+
public String getPropertyName() {
87+
return propertyName;
88+
}
89+
90+
@Override
91+
public String getTypeDeclaration() {
92+
return "";
93+
}
94+
95+
void modifiers(StringBuilder declaration) {
96+
declaration
97+
.append("\npublic static ");
98+
}
99+
100+
101+
@Override
102+
public Metamodel getHostingEntity() {
103+
return annotationMetaEntity;
104+
}
105+
106+
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.processor.annotation;
6+
7+
import org.hibernate.processor.HibernateProcessor;
8+
import org.hibernate.processor.model.MetaAttribute;
9+
import org.hibernate.processor.model.Metamodel;
10+
11+
public class CDITypeMetaAttribute implements MetaAttribute {
12+
13+
private AnnotationMetaEntity annotationMetaEntity;
14+
private String typeName;
15+
private Object superTypeName;
16+
17+
public CDITypeMetaAttribute(AnnotationMetaEntity annotationMetaEntity, String className, String superTypeName) {
18+
this.annotationMetaEntity = annotationMetaEntity;
19+
this.superTypeName = superTypeName;
20+
this.typeName = className;
21+
}
22+
23+
@Override
24+
public boolean hasTypedAttribute() {
25+
return true;
26+
}
27+
28+
@Override
29+
public boolean hasStringAttribute() {
30+
return false;
31+
}
32+
33+
@Override
34+
public String getAttributeDeclarationString() {
35+
final StringBuilder declaration = new StringBuilder();
36+
modifiers( declaration );
37+
preamble( declaration );
38+
closingBrace( declaration );
39+
return declaration.toString();
40+
}
41+
42+
void closingBrace(StringBuilder declaration) {
43+
declaration.append("}");
44+
}
45+
46+
void preamble(StringBuilder declaration) {
47+
declaration
48+
.append("class ")
49+
.append(typeName)
50+
.append(" implements ")
51+
.append( superTypeName );
52+
declaration
53+
.append(" {\n");
54+
}
55+
56+
@Override
57+
public String getAttributeNameDeclarationString() {
58+
return "";
59+
}
60+
61+
@Override
62+
public String getMetaType() {
63+
throw new UnsupportedOperationException("operation not supported");
64+
}
65+
66+
@Override
67+
public String getPropertyName() {
68+
return "";
69+
}
70+
71+
@Override
72+
public String getTypeDeclaration() {
73+
return "";
74+
}
75+
76+
void modifiers(StringBuilder declaration) {
77+
annotationMetaEntity.importType("jakarta.annotation.Generated");
78+
annotationMetaEntity.importType("jakarta.enterprise.context.Dependent");
79+
declaration
80+
.append("\n@Dependent\n")
81+
.append("@Generated(\""+HibernateProcessor.class.getName()+"\")\n");
82+
declaration
83+
.append("public static ");
84+
}
85+
86+
87+
@Override
88+
public Metamodel getHostingEntity() {
89+
return annotationMetaEntity;
90+
}
91+
92+
}

0 commit comments

Comments
 (0)