HHH-17873 initial impl of repository inheritance
needed for Jakarta Data, and useful limited to single inheritance for now
This commit is contained in:
parent
2e6ac15aab
commit
394d0c8ab2
|
@ -0,0 +1,23 @@
|
|||
package org.hibernate.processor.test.data.superdao;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import org.hibernate.annotations.NaturalId;
|
||||
import org.hibernate.processor.test.hqlsql.Publisher;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
|
||||
@Entity
|
||||
public class Book {
|
||||
@Id String isbn;
|
||||
@NaturalId String title;
|
||||
String text;
|
||||
@NaturalId String authorName;
|
||||
@ManyToOne
|
||||
Publisher publisher;
|
||||
BigDecimal price;
|
||||
int pages;
|
||||
LocalDate publicationDate;
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package org.hibernate.processor.test.data.superdao;
|
||||
|
||||
import jakarta.data.repository.Repository;
|
||||
import org.hibernate.annotations.processing.Find;
|
||||
|
||||
@Repository
|
||||
public interface Repo extends SuperRepo {
|
||||
@Find
|
||||
Book get(String isbn);
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package org.hibernate.processor.test.data.superdao;
|
||||
|
||||
import jakarta.data.repository.Repository;
|
||||
import org.hibernate.annotations.processing.Find;
|
||||
import org.hibernate.annotations.processing.HQL;
|
||||
import org.hibernate.annotations.processing.Pattern;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface SuperRepo {
|
||||
@Find
|
||||
List<Book> books1(@Pattern String title);
|
||||
|
||||
@HQL("where title like :title")
|
||||
List<Book> books2(String title);
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.processor.test.data.superdao;
|
||||
|
||||
import org.hibernate.processor.test.util.CompilationTest;
|
||||
import org.hibernate.processor.test.util.TestUtil;
|
||||
import org.hibernate.processor.test.util.WithClasses;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.processor.test.util.TestUtil.assertMetamodelClassGeneratedFor;
|
||||
|
||||
/**
|
||||
* @author Gavin King
|
||||
*/
|
||||
public class SuperRepoTest extends CompilationTest {
|
||||
@Test
|
||||
@WithClasses({ Book.class, SuperRepo.class, Repo.class })
|
||||
public void testQueryMethod() {
|
||||
System.out.println( TestUtil.getMetaModelSourceAsString( SuperRepo.class ) );
|
||||
System.out.println( TestUtil.getMetaModelSourceAsString( Repo.class ) );
|
||||
assertMetamodelClassGeneratedFor( Book.class );
|
||||
assertMetamodelClassGeneratedFor( SuperRepo.class );
|
||||
assertMetamodelClassGeneratedFor( Repo.class );
|
||||
}
|
||||
}
|
|
@ -137,6 +137,11 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
*/
|
||||
private boolean repository = false;
|
||||
|
||||
/**
|
||||
* A repository type that this repository inherits.
|
||||
*/
|
||||
private @Nullable TypeMirror superRepository;
|
||||
|
||||
/**
|
||||
* The type of the "session getter" method of a DAO-style repository.
|
||||
*/
|
||||
|
@ -215,8 +220,21 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
|
||||
@Override
|
||||
public @Nullable String getSupertypeName() {
|
||||
if ( repository ) {
|
||||
if ( superRepository == null ) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
final DeclaredType declaredType = (DeclaredType) superRepository;
|
||||
final TypeElement typeElement = (TypeElement) declaredType.asElement();
|
||||
// the import should already have been added earlier
|
||||
return importType( typeElement.getQualifiedName().toString() );
|
||||
}
|
||||
}
|
||||
else {
|
||||
return findMappedSuperClass( this, context );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getPackageName() {
|
||||
|
@ -354,6 +372,13 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
|
||||
setupSession();
|
||||
|
||||
if ( repository ) {
|
||||
superRepository = findSuperRepository( element );
|
||||
if ( superRepository != null ) {
|
||||
importType( superRepository.toString() );
|
||||
}
|
||||
}
|
||||
|
||||
if ( managed && !jakartaDataStaticModel ) {
|
||||
putMember( "class", new AnnotationMetaType(this) );
|
||||
}
|
||||
|
@ -427,6 +452,30 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
}
|
||||
}
|
||||
|
||||
private @Nullable TypeMirror findSuperRepository(TypeElement type) {
|
||||
for ( TypeMirror superinterface : type.getInterfaces() ) {
|
||||
if ( superinterface.getKind() == TypeKind.DECLARED ) {
|
||||
final DeclaredType declaredType = (DeclaredType) superinterface;
|
||||
final TypeElement typeElement = (TypeElement) declaredType.asElement();
|
||||
if ( hasAnnotation( typeElement, JD_REPOSITORY ) ) {
|
||||
return superinterface;
|
||||
}
|
||||
else if ( typeElement.getEnclosedElements().stream()
|
||||
.anyMatch( member -> hasAnnotation( member,
|
||||
HQL, SQL, JD_QUERY, FIND, JD_FIND, JD_INSERT, JD_UPDATE, JD_DELETE, JD_SAVE ) ) ) {
|
||||
return superinterface;
|
||||
}
|
||||
else {
|
||||
final TypeMirror ret = findSuperRepository( typeElement );
|
||||
if ( ret != null ) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private @Nullable ExecutableElement findSessionGetter(TypeElement type) {
|
||||
if ( !hasAnnotation( type, ENTITY, MAPPED_SUPERCLASS, EMBEDDABLE )
|
||||
|| isPanacheType( type ) ) {
|
||||
|
@ -438,7 +487,7 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
final TypeMirror superclass = type.getSuperclass();
|
||||
if ( superclass.getKind() == TypeKind.DECLARED ) {
|
||||
final DeclaredType declaredType = (DeclaredType) superclass;
|
||||
ExecutableElement ret = findSessionGetter( (TypeElement) declaredType.asElement() );
|
||||
final ExecutableElement ret = findSessionGetter( (TypeElement) declaredType.asElement() );
|
||||
if ( ret != null ) {
|
||||
return ret;
|
||||
}
|
||||
|
@ -446,7 +495,7 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
for ( TypeMirror superinterface : type.getInterfaces() ) {
|
||||
if ( superinterface.getKind() == TypeKind.DECLARED ) {
|
||||
final DeclaredType declaredType = (DeclaredType) superinterface;
|
||||
ExecutableElement ret = findSessionGetter( (TypeElement) declaredType.asElement() );
|
||||
final ExecutableElement ret = findSessionGetter( (TypeElement) declaredType.asElement() );
|
||||
if ( ret != null ) {
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -57,8 +57,10 @@ public class DefaultConstructor implements MetaAttribute {
|
|||
|
||||
@Override
|
||||
public String getAttributeDeclarationString() {
|
||||
StringBuilder declaration = new StringBuilder();
|
||||
declaration.append('\n');
|
||||
final StringBuilder declaration = new StringBuilder();
|
||||
declaration
|
||||
.append('\n');
|
||||
if ( annotationMetaEntity.getSupertypeName() == null ) {
|
||||
declaration
|
||||
.append("@")
|
||||
.append(annotationMetaEntity.importType("jakarta.persistence.PersistenceUnit"));
|
||||
|
@ -74,12 +76,6 @@ public class DefaultConstructor implements MetaAttribute {
|
|||
.append(" ")
|
||||
.append(sessionVariableName)
|
||||
.append("Factory;\n\n");
|
||||
inject( declaration );
|
||||
declaration
|
||||
.append(constructorName)
|
||||
.append("(")
|
||||
.append(") {")
|
||||
.append("\n}\n\n");
|
||||
declaration.append('@')
|
||||
.append(annotationMetaEntity.importType("jakarta.annotation.PostConstruct"))
|
||||
.append("\nprivate void openSession() {")
|
||||
|
@ -97,6 +93,13 @@ public class DefaultConstructor implements MetaAttribute {
|
|||
.append("\n\t")
|
||||
.append(sessionVariableName)
|
||||
.append(".close();")
|
||||
.append("\n}\n\n");
|
||||
}
|
||||
inject( declaration );
|
||||
declaration
|
||||
.append(constructorName)
|
||||
.append("(")
|
||||
.append(") {")
|
||||
.append("\n}");
|
||||
return declaration.toString();
|
||||
}
|
||||
|
|
|
@ -66,9 +66,12 @@ public class RepositoryConstructor implements MetaAttribute {
|
|||
|
||||
@Override
|
||||
public String getAttributeDeclarationString() {
|
||||
StringBuilder declaration = new StringBuilder();
|
||||
final StringBuilder declaration = new StringBuilder();
|
||||
declaration
|
||||
.append("\nprivate ");
|
||||
.append('\n');
|
||||
if ( annotationMetaEntity.getSupertypeName() == null ) {
|
||||
declaration
|
||||
.append("protected ");
|
||||
if ( !dataRepository ) {
|
||||
// don't mark the field final
|
||||
// because it will be initialized
|
||||
|
@ -81,8 +84,8 @@ public class RepositoryConstructor implements MetaAttribute {
|
|||
.append(annotationMetaEntity.importType(sessionTypeName))
|
||||
.append(" ")
|
||||
.append(sessionVariableName)
|
||||
.append(";")
|
||||
.append("\n\n");
|
||||
.append(";\n\n");
|
||||
}
|
||||
inject( declaration );
|
||||
declaration
|
||||
.append("public ")
|
||||
|
@ -94,13 +97,25 @@ public class RepositoryConstructor implements MetaAttribute {
|
|||
.append(annotationMetaEntity.importType(sessionTypeName))
|
||||
.append(" ")
|
||||
.append(sessionVariableName)
|
||||
.append(") {")
|
||||
.append("\n\tthis.")
|
||||
.append(") {\n");
|
||||
if ( annotationMetaEntity.getSupertypeName() != null ) {
|
||||
declaration
|
||||
.append("\tsuper(")
|
||||
.append(sessionVariableName)
|
||||
.append(");\n");
|
||||
}
|
||||
else {
|
||||
declaration
|
||||
.append("\tthis.")
|
||||
.append(sessionVariableName)
|
||||
.append(" = ")
|
||||
.append(sessionVariableName)
|
||||
.append(";")
|
||||
.append("\n}")
|
||||
.append(";\n");
|
||||
}
|
||||
declaration
|
||||
.append("}");
|
||||
if ( annotationMetaEntity.getSupertypeName() == null ) {
|
||||
declaration
|
||||
.append("\n\n");
|
||||
if (addOverrideAnnotation) {
|
||||
declaration.append("@Override\n");
|
||||
|
@ -115,8 +130,8 @@ public class RepositoryConstructor implements MetaAttribute {
|
|||
.append("() {")
|
||||
.append("\n\treturn ")
|
||||
.append(sessionVariableName)
|
||||
.append(";")
|
||||
.append("\n}");
|
||||
.append(";\n}");
|
||||
}
|
||||
return declaration.toString();
|
||||
}
|
||||
|
||||
|
|
|
@ -612,17 +612,18 @@ public final class TypeUtils {
|
|||
}
|
||||
|
||||
public static @Nullable String findMappedSuperClass(Metamodel entity, Context context) {
|
||||
Element element = entity.getElement();
|
||||
final Element element = entity.getElement();
|
||||
if ( element instanceof TypeElement ) {
|
||||
TypeMirror superClass = ((TypeElement) element).getSuperclass();
|
||||
final TypeElement typeElement = (TypeElement) element;
|
||||
TypeMirror superClass = typeElement.getSuperclass();
|
||||
//superclass of Object is of NoType which returns some other kind
|
||||
while ( superClass.getKind() == TypeKind.DECLARED ) {
|
||||
final Element superClassElement = ( (DeclaredType) superClass ).asElement();
|
||||
String superClassName = ( (TypeElement) superClassElement ).getQualifiedName().toString();
|
||||
final DeclaredType declaredType = (DeclaredType) superClass;
|
||||
final TypeElement superClassElement = (TypeElement) declaredType.asElement();
|
||||
if ( extendsSuperMetaModel( superClassElement, entity.isMetaComplete(), context ) ) {
|
||||
return superClassName;
|
||||
return superClassElement.getQualifiedName().toString();
|
||||
}
|
||||
superClass = ( (TypeElement) superClassElement ).getSuperclass();
|
||||
superClass = superClassElement.getSuperclass();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
@ -643,21 +644,14 @@ public final class TypeUtils {
|
|||
*/
|
||||
private static boolean extendsSuperMetaModel(Element superClassElement, boolean entityMetaComplete, Context context) {
|
||||
// if we processed the superclass in the same run we definitely need to extend
|
||||
String superClassName = ( (TypeElement) superClassElement ).getQualifiedName().toString();
|
||||
if ( context.containsMetaEntity( superClassName )
|
||||
|| context.containsMetaEmbeddable( superClassName ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final TypeElement typeElement = (TypeElement) superClassElement;
|
||||
final String superClassName = typeElement.getQualifiedName().toString();
|
||||
return context.containsMetaEntity( superClassName )
|
||||
|| context.containsMetaEmbeddable( superClassName )
|
||||
// to allow for the case that the metamodel class for the super entity is for example contained in another
|
||||
// jar file we use reflection. However, we need to consider the fact that there is xml configuration
|
||||
// and annotations should be ignored
|
||||
if ( !entityMetaComplete
|
||||
&& containsAnnotation( superClassElement, Constants.ENTITY, Constants.MAPPED_SUPERCLASS ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|| !entityMetaComplete && containsAnnotation( superClassElement, ENTITY, MAPPED_SUPERCLASS );
|
||||
}
|
||||
|
||||
static class EmbeddedAttributeVisitor extends SimpleTypeVisitor8<@Nullable String, Element> {
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
package org.hibernate.processor.test.superdao;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import org.hibernate.annotations.NaturalId;
|
||||
import org.hibernate.processor.test.hqlsql.Publisher;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
|
||||
@Entity
|
||||
public class Book {
|
||||
@Id String isbn;
|
||||
@NaturalId String title;
|
||||
String text;
|
||||
@NaturalId String authorName;
|
||||
@ManyToOne
|
||||
Publisher publisher;
|
||||
BigDecimal price;
|
||||
int pages;
|
||||
LocalDate publicationDate;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package org.hibernate.processor.test.superdao;
|
||||
|
||||
import org.hibernate.annotations.processing.Find;
|
||||
|
||||
public interface Dao extends SuperDao {
|
||||
@Find
|
||||
Book get(String isbn);
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package org.hibernate.processor.test.superdao;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
import org.hibernate.annotations.processing.Find;
|
||||
import org.hibernate.annotations.processing.HQL;
|
||||
import org.hibernate.annotations.processing.Pattern;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface SuperDao {
|
||||
|
||||
EntityManager em();
|
||||
|
||||
|
||||
@Find
|
||||
List<Book> books1(@Pattern String title);
|
||||
|
||||
@HQL("where title like :title")
|
||||
List<Book> books2(String title);
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.processor.test.superdao;
|
||||
|
||||
import org.hibernate.processor.test.util.CompilationTest;
|
||||
import org.hibernate.processor.test.util.TestUtil;
|
||||
import org.hibernate.processor.test.util.WithClasses;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.processor.test.util.TestUtil.assertMetamodelClassGeneratedFor;
|
||||
|
||||
/**
|
||||
* @author Gavin King
|
||||
*/
|
||||
public class SuperDaoTest extends CompilationTest {
|
||||
@Test
|
||||
@WithClasses({ Book.class, SuperDao.class, Dao.class })
|
||||
public void testQueryMethod() {
|
||||
System.out.println( TestUtil.getMetaModelSourceAsString( SuperDao.class ) );
|
||||
System.out.println( TestUtil.getMetaModelSourceAsString( Dao.class ) );
|
||||
assertMetamodelClassGeneratedFor( Book.class );
|
||||
assertMetamodelClassGeneratedFor( SuperDao.class );
|
||||
assertMetamodelClassGeneratedFor( Dao.class );
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue