HHH-17873 handle generic supertypes of repositories
This commit is contained in:
parent
ae56e16b6d
commit
985887964d
|
@ -0,0 +1,23 @@
|
||||||
|
package org.hibernate.processor.test.data.superdao.generic;
|
||||||
|
|
||||||
|
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.generic;
|
||||||
|
|
||||||
|
import jakarta.data.repository.Repository;
|
||||||
|
import org.hibernate.annotations.processing.Find;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface Repo extends SuperRepo<Book,String> {
|
||||||
|
@Find
|
||||||
|
Book get(String isbn);
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
package org.hibernate.processor.test.data.superdao.generic;
|
||||||
|
|
||||||
|
import jakarta.data.page.Page;
|
||||||
|
import jakarta.data.page.PageRequest;
|
||||||
|
import jakarta.data.repository.By;
|
||||||
|
import jakarta.data.repository.Delete;
|
||||||
|
import jakarta.data.repository.Find;
|
||||||
|
import jakarta.data.repository.Save;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
|
||||||
|
public interface SuperRepo<T,K> {
|
||||||
|
|
||||||
|
@Save
|
||||||
|
<S extends T> S save(S entity);
|
||||||
|
|
||||||
|
@Save
|
||||||
|
<S extends T> List<S> saveAll(List<S> entities);
|
||||||
|
|
||||||
|
@Find
|
||||||
|
Optional<T> findById(@By("#id") K id);
|
||||||
|
|
||||||
|
@Find
|
||||||
|
Stream<T> findAll();
|
||||||
|
|
||||||
|
@Find
|
||||||
|
Page<T> findAll(PageRequest<T> pageRequest);
|
||||||
|
|
||||||
|
@Delete
|
||||||
|
void deleteById(@By("#id") K id);
|
||||||
|
|
||||||
|
@Delete
|
||||||
|
void delete(T entity);
|
||||||
|
|
||||||
|
@Delete
|
||||||
|
void deleteAll(List<? extends T> entities);
|
||||||
|
}
|
|
@ -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.generic;
|
||||||
|
|
||||||
|
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 );
|
||||||
|
}
|
||||||
|
}
|
|
@ -365,7 +365,8 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
||||||
if ( isGetterOrSetter( method ) ) {
|
if ( isGetterOrSetter( method ) ) {
|
||||||
gettersAndSettersOfClass.add( method );
|
gettersAndSettersOfClass.add( method );
|
||||||
}
|
}
|
||||||
else if ( containsAnnotation( method, HQL, SQL, FIND ) ) {
|
else if ( element.getTypeParameters().isEmpty()
|
||||||
|
&& containsAnnotation( method, HQL, SQL, FIND ) ) {
|
||||||
queryMethods.add( method );
|
queryMethods.add( method );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -427,32 +428,34 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupSession() {
|
private void setupSession() {
|
||||||
jakartaDataRepository = hasAnnotation( element, JD_REPOSITORY );
|
if ( element.getTypeParameters().isEmpty() ) {
|
||||||
final ExecutableElement getter = findSessionGetter( element );
|
jakartaDataRepository = hasAnnotation( element, JD_REPOSITORY );
|
||||||
if ( getter != null ) {
|
final ExecutableElement getter = findSessionGetter( element );
|
||||||
// Never make a DAO for Panache subtypes
|
if ( getter != null ) {
|
||||||
if ( !isPanacheType( element ) ) {
|
// Never make a DAO for Panache subtypes
|
||||||
|
if ( !isPanacheType( element ) ) {
|
||||||
|
repository = true;
|
||||||
|
sessionType = addDaoConstructor( getter );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// For Panache subtypes, we look at the session type, but no DAO, we want static methods
|
||||||
|
sessionType = getter.getReturnType().toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( element.getKind() == ElementKind.INTERFACE
|
||||||
|
&& ( context.usesQuarkusOrm() || context.usesQuarkusReactive() ) ) {
|
||||||
|
// if we don't have a getter, but we're in Quarkus, we know how to find the default sessions
|
||||||
repository = true;
|
repository = true;
|
||||||
sessionType = addDaoConstructor( getter );
|
sessionType = setupQuarkusDaoConstructor();
|
||||||
}
|
}
|
||||||
else {
|
if ( !repository && jakartaDataRepository ) {
|
||||||
// For Panache subtypes, we look at the session type, but no DAO, we want static methods
|
repository = true;
|
||||||
sessionType = getter.getReturnType().toString();
|
sessionType = HIB_STATELESS_SESSION;
|
||||||
|
addDaoConstructor( null );
|
||||||
|
}
|
||||||
|
if ( jakartaDataRepository && !quarkusInjection ) {
|
||||||
|
addDefaultConstructor();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if ( element.getKind() == ElementKind.INTERFACE
|
|
||||||
&& ( context.usesQuarkusOrm() || context.usesQuarkusReactive() ) ) {
|
|
||||||
// if we don't have a getter, but we're in Quarkus, we know how to find the default sessions
|
|
||||||
repository = true;
|
|
||||||
sessionType = setupQuarkusDaoConstructor();
|
|
||||||
}
|
|
||||||
if ( !repository && jakartaDataRepository ) {
|
|
||||||
repository = true;
|
|
||||||
sessionType = HIB_STATELESS_SESSION;
|
|
||||||
addDaoConstructor( null );
|
|
||||||
}
|
|
||||||
if ( jakartaDataRepository && !quarkusInjection ) {
|
|
||||||
addDefaultConstructor();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -720,7 +723,10 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addQueryMethod(ExecutableElement method) {
|
private void addQueryMethod(ExecutableElement method) {
|
||||||
TypeMirror returnType = method.getReturnType();
|
final ExecutableType methodType =
|
||||||
|
(ExecutableType) context.getTypeUtils()
|
||||||
|
.asMemberOf((DeclaredType) element.asType(), method);
|
||||||
|
final TypeMirror returnType = methodType.getReturnType();
|
||||||
final TypeKind kind = returnType.getKind();
|
final TypeKind kind = returnType.getKind();
|
||||||
if ( kind == TypeKind.VOID || kind == TypeKind.ARRAY || kind.isPrimitive() ) {
|
if ( kind == TypeKind.VOID || kind == TypeKind.ARRAY || kind.isPrimitive() ) {
|
||||||
addQueryMethod( method, returnType, null );
|
addQueryMethod( method, returnType, null );
|
||||||
|
@ -872,7 +878,7 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
||||||
final String operation = lifecycleOperation( method );
|
final String operation = lifecycleOperation( method );
|
||||||
final VariableElement parameter = method.getParameters().get(0);
|
final VariableElement parameter = method.getParameters().get(0);
|
||||||
final TypeMirror declaredParameterType = parameter.asType();
|
final TypeMirror declaredParameterType = parameter.asType();
|
||||||
final TypeMirror parameterType = parameterType( declaredParameterType );
|
final TypeMirror parameterType = parameterType( parameter );
|
||||||
final DeclaredType declaredType = entityType( parameterType );
|
final DeclaredType declaredType = entityType( parameterType );
|
||||||
if ( declaredType == null ) {
|
if ( declaredType == null ) {
|
||||||
context.message( parameter,
|
context.message( parameter,
|
||||||
|
@ -915,6 +921,7 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
||||||
}
|
}
|
||||||
|
|
||||||
private @Nullable DeclaredType entityType(TypeMirror parameterType) {
|
private @Nullable DeclaredType entityType(TypeMirror parameterType) {
|
||||||
|
final Types types = context.getTypeUtils();
|
||||||
switch ( parameterType.getKind() ) {
|
switch ( parameterType.getKind() ) {
|
||||||
case TYPEVAR:
|
case TYPEVAR:
|
||||||
final TypeVariable typeVariable = (TypeVariable) parameterType;
|
final TypeVariable typeVariable = (TypeVariable) parameterType;
|
||||||
|
@ -922,12 +929,11 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
||||||
//INTENTIONAL FALL THROUGH
|
//INTENTIONAL FALL THROUGH
|
||||||
case DECLARED:
|
case DECLARED:
|
||||||
final DeclaredType declaredType = (DeclaredType) parameterType;
|
final DeclaredType declaredType = (DeclaredType) parameterType;
|
||||||
final Types types = context.getTypeUtils();
|
|
||||||
final Elements elements = context.getElementUtils();
|
final Elements elements = context.getElementUtils();
|
||||||
if ( types.isAssignable( declaredType,
|
if ( types.isAssignable( declaredType,
|
||||||
types.erasure( elements.getTypeElement(ITERABLE).asType() ) )
|
types.erasure( elements.getTypeElement(ITERABLE).asType() ) )
|
||||||
&& !declaredType.getTypeArguments().isEmpty() ) {
|
&& !declaredType.getTypeArguments().isEmpty() ) {
|
||||||
final TypeMirror elementType = parameterType( declaredType.getTypeArguments().get(0) );
|
final TypeMirror elementType = types.erasure( declaredType.getTypeArguments().get(0) );
|
||||||
return elementType.getKind() == TypeKind.DECLARED ? (DeclaredType) elementType : null;
|
return elementType.getKind() == TypeKind.DECLARED ? (DeclaredType) elementType : null;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -935,7 +941,7 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
||||||
}
|
}
|
||||||
case ARRAY:
|
case ARRAY:
|
||||||
final ArrayType arrayType = (ArrayType) parameterType;
|
final ArrayType arrayType = (ArrayType) parameterType;
|
||||||
final TypeMirror componentType = parameterType( arrayType.getComponentType() );
|
final TypeMirror componentType = types.erasure( arrayType.getComponentType() );
|
||||||
return componentType.getKind() == TypeKind.DECLARED ? (DeclaredType) componentType : null;
|
return componentType.getKind() == TypeKind.DECLARED ? (DeclaredType) componentType : null;
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
|
@ -1057,7 +1063,7 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
||||||
else {
|
else {
|
||||||
multivalued.add( false );
|
multivalued.add( false );
|
||||||
final Types types = context.getTypeUtils();
|
final Types types = context.getTypeUtils();
|
||||||
final TypeMirror parameterType = parameter.asType();
|
final TypeMirror parameterType = parameterType( parameter );
|
||||||
final String type = parameterType.toString();
|
final String type = parameterType.toString();
|
||||||
boolean pageRequest = type.startsWith(JD_PAGE_REQUEST);
|
boolean pageRequest = type.startsWith(JD_PAGE_REQUEST);
|
||||||
if ( isOrderParam(type) || pageRequest ) {
|
if ( isOrderParam(type) || pageRequest ) {
|
||||||
|
@ -1428,15 +1434,6 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// final String memberType = attributeType.toString();
|
|
||||||
// final String paramType = parameterType.toString();
|
|
||||||
// if ( !isLegalAssignment( paramType, memberType ) ) {
|
|
||||||
// context.message( param,
|
|
||||||
// "matching field has type '" + memberType
|
|
||||||
// + "' in entity class '" + entityType + "'",
|
|
||||||
// Diagnostic.Kind.ERROR );
|
|
||||||
// }
|
|
||||||
|
|
||||||
if ( checkParameterType( entityType, param, memberType( member ) ) ) {
|
if ( checkParameterType( entityType, param, memberType( member ) ) ) {
|
||||||
return FieldType.MULTIVALUED;
|
return FieldType.MULTIVALUED;
|
||||||
}
|
}
|
||||||
|
@ -1485,7 +1482,7 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
||||||
private boolean checkParameterType(TypeElement entityType, VariableElement param, TypeMirror attributeType) {
|
private boolean checkParameterType(TypeElement entityType, VariableElement param, TypeMirror attributeType) {
|
||||||
final Types types = context.getTypeUtils();
|
final Types types = context.getTypeUtils();
|
||||||
if ( entityType.getKind() == CLASS ) { // do no checks if the entity type is a type variable
|
if ( entityType.getKind() == CLASS ) { // do no checks if the entity type is a type variable
|
||||||
TypeMirror parameterType = param.asType();
|
TypeMirror parameterType = parameterType( param );
|
||||||
if ( types.isSameType( parameterType, attributeType ) ) {
|
if ( types.isSameType( parameterType, attributeType ) ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -2088,12 +2085,19 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
||||||
|
|
||||||
private List<String> parameterTypes(ExecutableElement method) {
|
private List<String> parameterTypes(ExecutableElement method) {
|
||||||
return method.getParameters().stream()
|
return method.getParameters().stream()
|
||||||
.map(param -> parameterType(param.asType()).toString())
|
.map(param -> parameterType(param).toString())
|
||||||
.collect(toList());
|
.collect(toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
private TypeMirror parameterType(TypeMirror type) {
|
private TypeMirror parameterType(VariableElement parameter) {
|
||||||
switch (type.getKind()) {
|
final ExecutableElement method =
|
||||||
|
(ExecutableElement) parameter.getEnclosingElement();
|
||||||
|
final ExecutableType methodType =
|
||||||
|
(ExecutableType) context.getTypeUtils()
|
||||||
|
.asMemberOf((DeclaredType) element.asType(), method);
|
||||||
|
final TypeMirror type = methodType.getParameterTypes()
|
||||||
|
.get( method.getParameters().indexOf(parameter) );
|
||||||
|
switch ( type.getKind() ) {
|
||||||
case TYPEVAR:
|
case TYPEVAR:
|
||||||
final TypeVariable typeVariable = (TypeVariable) type;
|
final TypeVariable typeVariable = (TypeVariable) type;
|
||||||
return context.getTypeUtils().erasure(typeVariable);
|
return context.getTypeUtils().erasure(typeVariable);
|
||||||
|
@ -2213,7 +2217,7 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
||||||
if ( returnType != null ) {
|
if ( returnType != null ) {
|
||||||
final Types types = context.getTypeUtils();
|
final Types types = context.getTypeUtils();
|
||||||
for ( VariableElement parameter : method.getParameters() ) {
|
for ( VariableElement parameter : method.getParameters() ) {
|
||||||
final TypeMirror parameterType = parameter.asType();
|
final TypeMirror parameterType = parameterType( parameter );
|
||||||
final TypeMirror typeArgument = getTypeArgument( parameterType );
|
final TypeMirror typeArgument = getTypeArgument( parameterType );
|
||||||
final String type = parameterType.toString();
|
final String type = parameterType.toString();
|
||||||
final boolean pageRequest = type.startsWith(JD_PAGE_REQUEST);
|
final boolean pageRequest = type.startsWith(JD_PAGE_REQUEST);
|
||||||
|
|
|
@ -20,10 +20,10 @@ public class SuperDaoTest extends CompilationTest {
|
||||||
@Test
|
@Test
|
||||||
@WithClasses({ Book.class, SuperDao.class, Dao.class })
|
@WithClasses({ Book.class, SuperDao.class, Dao.class })
|
||||||
public void testQueryMethod() {
|
public void testQueryMethod() {
|
||||||
System.out.println( TestUtil.getMetaModelSourceAsString( SuperDao.class ) );
|
// System.out.println( TestUtil.getMetaModelSourceAsString( SuperDao.class ) );
|
||||||
System.out.println( TestUtil.getMetaModelSourceAsString( Dao.class ) );
|
System.out.println( TestUtil.getMetaModelSourceAsString( Dao.class ) );
|
||||||
assertMetamodelClassGeneratedFor( Book.class );
|
assertMetamodelClassGeneratedFor( Book.class );
|
||||||
assertMetamodelClassGeneratedFor( SuperDao.class );
|
// assertMetamodelClassGeneratedFor( SuperDao.class );
|
||||||
assertMetamodelClassGeneratedFor( Dao.class );
|
assertMetamodelClassGeneratedFor( Dao.class );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
package org.hibernate.processor.test.superdao.generic;
|
||||||
|
|
||||||
|
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.generic;
|
||||||
|
|
||||||
|
import org.hibernate.annotations.processing.Find;
|
||||||
|
|
||||||
|
public interface Dao extends SuperDao<Book,String> {
|
||||||
|
@Find
|
||||||
|
Book getConc(String isbn);
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package org.hibernate.processor.test.superdao.generic;
|
||||||
|
|
||||||
|
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<T,K> {
|
||||||
|
|
||||||
|
EntityManager em();
|
||||||
|
|
||||||
|
@Find
|
||||||
|
T get(K isbn);
|
||||||
|
|
||||||
|
@Find
|
||||||
|
List<T> books1(@Pattern String title);
|
||||||
|
|
||||||
|
@HQL("where title like :title")
|
||||||
|
List<T> 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.generic;
|
||||||
|
|
||||||
|
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