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 ) ) {
|
||||
gettersAndSettersOfClass.add( method );
|
||||
}
|
||||
else if ( containsAnnotation( method, HQL, SQL, FIND ) ) {
|
||||
else if ( element.getTypeParameters().isEmpty()
|
||||
&& containsAnnotation( method, HQL, SQL, FIND ) ) {
|
||||
queryMethods.add( method );
|
||||
}
|
||||
}
|
||||
|
@ -427,32 +428,34 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
}
|
||||
|
||||
private void setupSession() {
|
||||
jakartaDataRepository = hasAnnotation( element, JD_REPOSITORY );
|
||||
final ExecutableElement getter = findSessionGetter( element );
|
||||
if ( getter != null ) {
|
||||
// Never make a DAO for Panache subtypes
|
||||
if ( !isPanacheType( element ) ) {
|
||||
if ( element.getTypeParameters().isEmpty() ) {
|
||||
jakartaDataRepository = hasAnnotation( element, JD_REPOSITORY );
|
||||
final ExecutableElement getter = findSessionGetter( element );
|
||||
if ( getter != null ) {
|
||||
// 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;
|
||||
sessionType = addDaoConstructor( getter );
|
||||
sessionType = setupQuarkusDaoConstructor();
|
||||
}
|
||||
else {
|
||||
// For Panache subtypes, we look at the session type, but no DAO, we want static methods
|
||||
sessionType = getter.getReturnType().toString();
|
||||
if ( !repository && jakartaDataRepository ) {
|
||||
repository = true;
|
||||
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) {
|
||||
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();
|
||||
if ( kind == TypeKind.VOID || kind == TypeKind.ARRAY || kind.isPrimitive() ) {
|
||||
addQueryMethod( method, returnType, null );
|
||||
|
@ -872,7 +878,7 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
final String operation = lifecycleOperation( method );
|
||||
final VariableElement parameter = method.getParameters().get(0);
|
||||
final TypeMirror declaredParameterType = parameter.asType();
|
||||
final TypeMirror parameterType = parameterType( declaredParameterType );
|
||||
final TypeMirror parameterType = parameterType( parameter );
|
||||
final DeclaredType declaredType = entityType( parameterType );
|
||||
if ( declaredType == null ) {
|
||||
context.message( parameter,
|
||||
|
@ -915,6 +921,7 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
}
|
||||
|
||||
private @Nullable DeclaredType entityType(TypeMirror parameterType) {
|
||||
final Types types = context.getTypeUtils();
|
||||
switch ( parameterType.getKind() ) {
|
||||
case TYPEVAR:
|
||||
final TypeVariable typeVariable = (TypeVariable) parameterType;
|
||||
|
@ -922,12 +929,11 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
//INTENTIONAL FALL THROUGH
|
||||
case DECLARED:
|
||||
final DeclaredType declaredType = (DeclaredType) parameterType;
|
||||
final Types types = context.getTypeUtils();
|
||||
final Elements elements = context.getElementUtils();
|
||||
if ( types.isAssignable( declaredType,
|
||||
types.erasure( elements.getTypeElement(ITERABLE).asType() ) )
|
||||
&& !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;
|
||||
}
|
||||
else {
|
||||
|
@ -935,7 +941,7 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
}
|
||||
case ARRAY:
|
||||
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;
|
||||
default:
|
||||
return null;
|
||||
|
@ -1057,7 +1063,7 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
else {
|
||||
multivalued.add( false );
|
||||
final Types types = context.getTypeUtils();
|
||||
final TypeMirror parameterType = parameter.asType();
|
||||
final TypeMirror parameterType = parameterType( parameter );
|
||||
final String type = parameterType.toString();
|
||||
boolean pageRequest = type.startsWith(JD_PAGE_REQUEST);
|
||||
if ( isOrderParam(type) || pageRequest ) {
|
||||
|
@ -1428,15 +1434,6 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
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 ) ) ) {
|
||||
return FieldType.MULTIVALUED;
|
||||
}
|
||||
|
@ -1485,7 +1482,7 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
private boolean checkParameterType(TypeElement entityType, VariableElement param, TypeMirror attributeType) {
|
||||
final Types types = context.getTypeUtils();
|
||||
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 ) ) {
|
||||
return false;
|
||||
}
|
||||
|
@ -2088,12 +2085,19 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
|
||||
private List<String> parameterTypes(ExecutableElement method) {
|
||||
return method.getParameters().stream()
|
||||
.map(param -> parameterType(param.asType()).toString())
|
||||
.map(param -> parameterType(param).toString())
|
||||
.collect(toList());
|
||||
}
|
||||
|
||||
private TypeMirror parameterType(TypeMirror type) {
|
||||
switch (type.getKind()) {
|
||||
private TypeMirror parameterType(VariableElement parameter) {
|
||||
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:
|
||||
final TypeVariable typeVariable = (TypeVariable) type;
|
||||
return context.getTypeUtils().erasure(typeVariable);
|
||||
|
@ -2213,7 +2217,7 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
if ( returnType != null ) {
|
||||
final Types types = context.getTypeUtils();
|
||||
for ( VariableElement parameter : method.getParameters() ) {
|
||||
final TypeMirror parameterType = parameter.asType();
|
||||
final TypeMirror parameterType = parameterType( parameter );
|
||||
final TypeMirror typeArgument = getTypeArgument( parameterType );
|
||||
final String type = parameterType.toString();
|
||||
final boolean pageRequest = type.startsWith(JD_PAGE_REQUEST);
|
||||
|
|
|
@ -20,10 +20,10 @@ 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( SuperDao.class ) );
|
||||
System.out.println( TestUtil.getMetaModelSourceAsString( Dao.class ) );
|
||||
assertMetamodelClassGeneratedFor( Book.class );
|
||||
assertMetamodelClassGeneratedFor( SuperDao.class );
|
||||
// assertMetamodelClassGeneratedFor( SuperDao.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