diff --git a/tooling/metamodel-generator/src/jakartaData/java/org/hibernate/processor/test/data/BookAuthorRepository.java b/tooling/metamodel-generator/src/jakartaData/java/org/hibernate/processor/test/data/BookAuthorRepository.java index 564c2d0c4d..40dc0dc68b 100644 --- a/tooling/metamodel-generator/src/jakartaData/java/org/hibernate/processor/test/data/BookAuthorRepository.java +++ b/tooling/metamodel-generator/src/jakartaData/java/org/hibernate/processor/test/data/BookAuthorRepository.java @@ -30,6 +30,12 @@ public interface BookAuthorRepository { StatelessSession session(); + @Delete + int deleteByIdIn(String[] isbn); + + @Delete + void deleteById(String isbn); + @Insert void insertBooks0(Book[] books); diff --git a/tooling/metamodel-generator/src/jakartaData/java/org/hibernate/processor/test/data/eg/Bookshop.java b/tooling/metamodel-generator/src/jakartaData/java/org/hibernate/processor/test/data/eg/Bookshop.java new file mode 100644 index 0000000000..85bc9eed28 --- /dev/null +++ b/tooling/metamodel-generator/src/jakartaData/java/org/hibernate/processor/test/data/eg/Bookshop.java @@ -0,0 +1,13 @@ +package org.hibernate.processor.test.data.eg; + +import jakarta.data.repository.CrudRepository; +import jakarta.data.repository.Find; +import jakarta.data.repository.Repository; + +import java.util.List; + +@Repository +public interface Bookshop extends CrudRepository { + @Find + List byPublisher(String publisher_name); +} diff --git a/tooling/metamodel-generator/src/jakartaData/java/org/hibernate/processor/test/data/eg/Library.java b/tooling/metamodel-generator/src/jakartaData/java/org/hibernate/processor/test/data/eg/Library.java index dd87487b06..6085292c02 100644 --- a/tooling/metamodel-generator/src/jakartaData/java/org/hibernate/processor/test/data/eg/Library.java +++ b/tooling/metamodel-generator/src/jakartaData/java/org/hibernate/processor/test/data/eg/Library.java @@ -1,5 +1,8 @@ package org.hibernate.processor.test.data.eg; +import jakarta.data.Limit; +import jakarta.data.Order; +import jakarta.data.Sort; import jakarta.data.page.CursoredPage; import jakarta.data.page.PageRequest; import jakarta.data.repository.By; @@ -25,18 +28,22 @@ public interface Library { List books(@By("isbn") List isbns); @Find - Book books(String title, LocalDate publicationDate); + Book book(String title, LocalDate publicationDate); + + @Find + List publications(Type type, Sort sort); @Find @OrderBy("title") List booksByPublisher(String publisher_name); @Query("where title like :titlePattern") + @OrderBy("title") List booksByTitle(String titlePattern); // not required by Jakarta Data record BookWithAuthor(Book book, Author author) {} - @Query("select b, a from Book b join b.authors a") + @Query("select b, a from Book b join b.authors a order by b.isbn, a.ssn") List booksWithAuthors(); @Insert @@ -69,14 +76,20 @@ public interface Library { @Update void update(Author author); + @Save + void save(Publisher publisher); + + @Delete + void delete(Publisher publisher); + @Find @OrderBy("isbn") CursoredPage allBooks(PageRequest pageRequest); @Find @OrderBy("name") - @OrderBy("address.city") //not working currently - List authors(); + @OrderBy("address.city") + List allAuthors(Order order, Limit limit); @Find List authorsByCity(@By("address.city") String city); diff --git a/tooling/metamodel-generator/src/jakartaData/java/org/hibernate/processor/test/data/superdao/generic/SuperRepo.java b/tooling/metamodel-generator/src/jakartaData/java/org/hibernate/processor/test/data/superdao/generic/SuperRepo.java index df6e251957..83b4f13843 100644 --- a/tooling/metamodel-generator/src/jakartaData/java/org/hibernate/processor/test/data/superdao/generic/SuperRepo.java +++ b/tooling/metamodel-generator/src/jakartaData/java/org/hibernate/processor/test/data/superdao/generic/SuperRepo.java @@ -29,8 +29,8 @@ public interface SuperRepo { @Find Page findAll(PageRequest pageRequest); - @Delete - void deleteById(@By("#id") K id); +// @Delete +// void deleteById(@By("#id") K id); @Delete void delete(T entity); diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AbstractCriteriaMethod.java b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AbstractCriteriaMethod.java new file mode 100644 index 0000000000..f875b4b1b2 --- /dev/null +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AbstractCriteriaMethod.java @@ -0,0 +1,198 @@ +/* + * 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 . + */ +package org.hibernate.processor.annotation; + +import java.util.List; +import java.util.StringTokenizer; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +import static org.hibernate.processor.util.TypeUtils.isPrimitive; + +/** + * @author Gavin King + */ +public abstract class AbstractCriteriaMethod extends AbstractFinderMethod { + + private final List multivalued; + private final List paramPatterns; + + public AbstractCriteriaMethod( + AnnotationMetaEntity annotationMetaEntity, + String methodName, String entity, + boolean belongsToDao, + String sessionType, String sessionName, + List fetchProfiles, + List paramNames, + List paramTypes, + List orderBys, + boolean addNonnullAnnotation, + boolean convertToDataExceptions, + List multivalued, + List paramPatterns) { + super(annotationMetaEntity, methodName, entity, belongsToDao, sessionType, sessionName, fetchProfiles, + paramNames, paramTypes, orderBys, addNonnullAnnotation, convertToDataExceptions); + this.multivalued = multivalued; + this.paramPatterns = paramPatterns; + } + + @Override + public String getAttributeDeclarationString() { + final List paramTypes = parameterTypes(); + final StringBuilder declaration = new StringBuilder(); + comment( declaration ); + modifiers( declaration ); + preamble( declaration, returnType(), paramTypes ); + chainSession( declaration ); + nullChecks( paramTypes, declaration ); + createBuilder(declaration); + createCriteriaQuery( declaration ); + where( declaration, paramTypes ); +// orderBy( paramTypes, declaration ); + executeQuery( declaration, paramTypes ); + convertExceptions( declaration ); + chainSessionEnd( false, declaration ); + closingBrace( declaration ); + return declaration.toString(); + } + + abstract void executeQuery(StringBuilder declaration, List paramTypes); + + abstract void createCriteriaQuery(StringBuilder declaration); + + abstract String returnType(); + + @Override + void createQuery(StringBuilder declaration) { + declaration + .append(localSessionName()) + .append(".createQuery(_query)\n"); + } + + private void createBuilder(StringBuilder declaration) { + declaration + .append("\tvar _builder = ") + .append(localSessionName()) + .append(isUsingEntityManager() + ? ".getEntityManagerFactory()" + : ".getFactory()") + .append(".getCriteriaBuilder();\n"); + } + + void nullChecks(List paramTypes, StringBuilder declaration) { + for ( int i = 0; i< paramNames.size(); i++ ) { + final String paramName = paramNames.get(i); + final String paramType = paramTypes.get(i); + if ( !isNullable(i) && !isPrimitive(paramType) ) { + nullCheck( declaration, paramName ); + } + } + } + + private static void nullCheck(StringBuilder declaration, String paramName) { + declaration + .append("\tif (") + .append(paramName.replace('.', '$')) + .append(" == null) throw new IllegalArgumentException(\"Null ") + .append(paramName) + .append("\");\n"); + } + + void where(StringBuilder declaration, List paramTypes) { + declaration + .append("\t_query.where("); + boolean first = true; + for ( int i = 0; i < paramNames.size(); i ++ ) { + final String paramName = paramNames.get(i); + final String paramType = paramTypes.get(i); + if ( !isSpecialParam(paramType) ) { + if ( first ) { + first = false; + } + else { + declaration + .append(", "); + } + condition(declaration, i, paramName, paramType ); + } + } + declaration + .append("\n\t);"); + } + + private void condition(StringBuilder declaration, int i, String paramName, String paramType) { + declaration + .append("\n\t\t\t"); + final String parameterName = paramName.replace('.', '$'); + if ( isNullable(i) && !isPrimitive(paramType) ) { + declaration + .append(parameterName) + .append("==null") + .append("\n\t\t\t\t? ") + .append("_entity"); + path( declaration, paramName ); + declaration + .append(".isNull()") + .append("\n\t\t\t\t: "); + } + if ( multivalued.get(i) ) { + declaration + .append("_entity"); + path( declaration, paramName ); + declaration + .append(".in("); + if ( paramType.endsWith("[]") ) { + declaration + .append("(Object[]) ") + //TODO: only safe if we are binding literals as parameters!!! + .append(parameterName); + + } + else { + declaration + .append(annotationMetaEntity.staticImport(StreamSupport.class.getName(), "stream")) + .append('(') + //TODO: only safe if we are binding literals as parameters!!! + .append(parameterName) + .append(".spliterator(), false).collect(") // ugh, very ugly! + .append(annotationMetaEntity.staticImport(Collectors.class.getName(), "toList")) + .append("())"); + } + declaration + .append(")"); + } + else { + //TODO: change to use Expression.equalTo() in JPA 3.2 + declaration + .append("_builder.") + .append(paramPatterns.get(i) ? "like" : "equal") + .append("(_entity"); + path( declaration, paramName ); + declaration + .append(", ") + //TODO: only safe if we are binding literals as parameters!!! + .append(parameterName) + .append(')'); + } + } + + private void path(StringBuilder declaration, String paramName) { + final StringTokenizer tokens = new StringTokenizer(paramName, "."); + String typeName = entity; + while ( typeName!= null && tokens.hasMoreTokens() ) { + final String memberName = tokens.nextToken(); + declaration + .append(".get(") + .append(annotationMetaEntity.importType(typeName + '_')) + .append('.') + .append(memberName) + .append(')'); + typeName = annotationMetaEntity.getMemberType(typeName, memberName); + } + } + +} diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AbstractQueryMethod.java b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AbstractQueryMethod.java index 8bbac93640..cd82ae9e5b 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AbstractQueryMethod.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AbstractQueryMethod.java @@ -97,7 +97,7 @@ public abstract class AbstractQueryMethod implements MetaAttribute { return type.endsWith("...") ? stripped + "..." : stripped; } - void preamble(StringBuilder declaration, StringBuilder returnType, List paramTypes) { + void preamble(StringBuilder declaration, String returnType, List paramTypes) { declaration .append(returnType) .append(" ") 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 5208b68758..7e9c820eac 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 @@ -149,6 +149,11 @@ public class AnnotationMetaEntity extends AnnotationMeta { private final Map memberTypes = new HashMap<>(); + /** + * The primary entity type for a repository + */ + private @Nullable TypeElement primaryEntity; + public AnnotationMetaEntity( TypeElement element, Context context, boolean managed, boolean jakartaDataStaticMetamodel) { @@ -349,10 +354,20 @@ public class AnnotationMetaEntity extends AnnotationMeta { if ( containsAnnotation( method, HQL, SQL, JD_QUERY, FIND, JD_FIND ) ) { queryMethods.add( method ); } - else if ( containsAnnotation( method, JD_INSERT, JD_UPDATE, JD_DELETE, JD_SAVE ) ) { + else if ( containsAnnotation( method, JD_INSERT, JD_UPDATE, JD_SAVE ) ) { lifecycleMethods.add( method ); } + else if ( hasAnnotation( method, JD_DELETE) ) { + if ( isDeleteLifecycle(method) ) { + lifecycleMethods.add( method ); + } + else { + queryMethods.add( method ); + } + } } + + primaryEntity = primaryEntity( lifecycleMethods ); } else { determineAccessTypeForHierarchy( element, context ); @@ -393,6 +408,43 @@ public class AnnotationMetaEntity extends AnnotationMeta { initialized = true; } + private @Nullable TypeElement primaryEntity(List lifecycleMethods) { + for (TypeMirror typeMirror : element.getInterfaces()) { + final DeclaredType declaredType = (DeclaredType) typeMirror; + final TypeElement typeElement = (TypeElement) declaredType.asElement(); + final Name name = typeElement.getQualifiedName(); + if ( declaredType.getTypeArguments().size() == 2 + && (name.contentEquals(BASIC_REPOSITORY) + || name.contentEquals(CRUD_REPOSITORY) + || name.contentEquals(DATA_REPOSITORY)) ) { + final TypeMirror entityType = declaredType.getTypeArguments().get(0); + if ( entityType.getKind() == TypeKind.DECLARED ) { + final DeclaredType entityDeclared = (DeclaredType) entityType; + return (TypeElement) entityDeclared.asElement(); + } + } + } + TypeElement result = null; + final Types types = context.getTypeUtils(); + for ( ExecutableElement element : lifecycleMethods ) { + if ( element.getParameters().size()==1 ) { + final VariableElement param = element.getParameters().get(0); + final DeclaredType declaredType = entityType( parameterType(param) ); + if ( declaredType != null ) { + if ( result == null ) { + result = (TypeElement) declaredType.asElement(); + } + else { + if ( !types.isSameType( result.asType(), declaredType ) ) { + return null; + } + } + } + } + } + return result; + } + private void addMethods(TypeElement element, List methodsOfClass) { //TODO just use Elements.getAllMembers(element) here! for ( TypeMirror typeMirror : element.getInterfaces() ) { @@ -870,13 +922,24 @@ public class AnnotationMetaEntity extends AnnotationMeta { private void addLifecycleMethods(List queryMethods) { for ( ExecutableElement method : queryMethods) { if ( method.getModifiers().contains(Modifier.ABSTRACT) ) { - if ( hasAnnotation( method, JD_INSERT, JD_UPDATE, JD_DELETE, JD_SAVE ) ) { - addLifecycleMethod( method ); - } + addLifecycleMethod( method ); } } } + private boolean isDeleteLifecycle(ExecutableElement method) { + if ( method.getParameters().size() == 1 ) { + final VariableElement parameter = method.getParameters().get(0); + final DeclaredType declaredType = entityType( parameterType(parameter) ); + return declaredType != null + && containsAnnotation( declaredType.asElement(), ENTITY ); + + } + else { + return false; + } + } + private void addQueryMethods(List queryMethods) { for ( ExecutableElement method : queryMethods) { final Set modifiers = method.getModifiers(); @@ -1018,6 +1081,9 @@ public class AnnotationMetaEntity extends AnnotationMeta { if ( hasAnnotation( method, FIND, JD_FIND ) ) { addFinderMethod( method, returnType, containerType ); } + else if ( hasAnnotation( method, JD_DELETE ) ) { + createCriteriaDelete( method, returnType ); + } } private void addLifecycleMethod(ExecutableElement method) { @@ -1285,6 +1351,50 @@ public class AnnotationMetaEntity extends AnnotationMeta { ); } + private void createCriteriaDelete( + ExecutableElement method, @Nullable TypeMirror returnType) { + final TypeElement entity = primaryEntity; + if ( entity == null) { + context.message( method, "repository does not have a well-defined primary entity type", + Diagnostic.Kind.ERROR); + } + else { + final String methodName = method.getSimpleName().toString(); + final List paramNames = parameterNames( method, entity ); + final List paramTypes = parameterTypes( method ); + final List paramPatterns = parameterPatterns( method ); + final String[] sessionType = sessionTypeFromParameters( paramNames, paramTypes ); + final String methodKey = methodName + paramTypes; + final List multivalued = new ArrayList<>(); + for ( VariableElement parameter : method.getParameters() ) { + if ( isFinderParameterMappingToAttribute( parameter ) ) { + multivalued.add( validateFinderParameter( entity, parameter ) == FieldType.MULTIVALUED ); + } + else { + multivalued.add( false ); + } + } + putMember( methodKey, + new CriteriaDeleteMethod( + this, + methodName, + entity.getQualifiedName().toString(), + returnType==null ? "void" : returnType.toString(), + paramNames, + paramTypes, + parameterNullability(method, entity), + multivalued, + paramPatterns, + repository, + sessionType[0], + sessionType[1], + context.addNonnullAnnotation(), + jakartaDataRepository + ) + ); + } + } + private void wrongTypeArgError(String entity, VariableElement parameter, boolean pageRequest) { context.message(parameter, (pageRequest diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/CriteriaDeleteMethod.java b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/CriteriaDeleteMethod.java new file mode 100644 index 0000000000..2136a04595 --- /dev/null +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/CriteriaDeleteMethod.java @@ -0,0 +1,87 @@ +/* + * 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 . + */ +package org.hibernate.processor.annotation; + +import java.util.List; + +import static java.util.Collections.emptyList; + +/** + * @author Gavin King + */ +public class CriteriaDeleteMethod extends AbstractCriteriaMethod { + + private final List paramNullability; + private final String returnType; + + CriteriaDeleteMethod( + AnnotationMetaEntity annotationMetaEntity, + String methodName, String entity, String returnType, + List paramNames, + List paramTypes, + List paramNullability, + List multivalued, + List paramPatterns, + boolean belongsToDao, + String sessionType, + String sessionName, + boolean addNonnullAnnotation, + boolean dataRepository) { + super( annotationMetaEntity, methodName, entity, belongsToDao, sessionType, sessionName, emptyList(), + paramNames, paramTypes, emptyList(), addNonnullAnnotation, dataRepository, multivalued, paramPatterns ); + this.paramNullability = paramNullability; + this.returnType = returnType; + } + + @Override + public boolean isNullable(int index) { + return paramNullability.get(index); + } + + @Override + boolean singleResult() { + return true; + } + + @Override + String returnType() { + return returnType; + } + + @Override + void executeQuery(StringBuilder declaration, List paramTypes) { + tryReturn(declaration); + createQuery( declaration ); + execute( declaration ); + } + + void tryReturn(StringBuilder declaration) { + declaration + .append("\n\ttry {\n\t\t"); + if ( !"void".equals(returnType) ) { + declaration + .append("return "); + } + } + + private void execute(StringBuilder declaration) { + declaration + .append("\t\t\t.executeUpdate();\n"); + } + + @Override + void createCriteriaQuery(StringBuilder declaration) { + declaration + .append("\tvar _query = _builder.createCriteriaDelete(") + .append(annotationMetaEntity.importType(entity)) + .append(".class);\n") + .append("\tvar _entity = _query.from(") + .append(annotationMetaEntity.importType(entity)) + .append(".class);\n"); + } + +} diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/CriteriaFinderMethod.java b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/CriteriaFinderMethod.java index 5da23bd839..e05b7a5be6 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/CriteriaFinderMethod.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/CriteriaFinderMethod.java @@ -11,22 +11,16 @@ import org.hibernate.AssertionFailure; import org.hibernate.processor.util.Constants; import java.util.List; -import java.util.StringTokenizer; -import java.util.stream.Collectors; -import java.util.stream.StreamSupport; import static org.hibernate.processor.util.Constants.LIST; -import static org.hibernate.processor.util.TypeUtils.isPrimitive; /** * @author Gavin King */ -public class CriteriaFinderMethod extends AbstractFinderMethod { +public class CriteriaFinderMethod extends AbstractCriteriaMethod { private final @Nullable String containerType; private final List paramNullability; - private final List multivalued; - private final List paramPatterns; CriteriaFinderMethod( AnnotationMetaEntity annotationMetaEntity, @@ -44,11 +38,9 @@ public class CriteriaFinderMethod extends AbstractFinderMethod { boolean addNonnullAnnotation, boolean dataRepository) { super( annotationMetaEntity, methodName, entity, belongsToDao, sessionType, sessionName, fetchProfiles, - paramNames, paramTypes, orderBys, addNonnullAnnotation, dataRepository ); + paramNames, paramTypes, orderBys, addNonnullAnnotation, dataRepository, multivalued, paramPatterns ); this.containerType = containerType; this.paramNullability = paramNullability; - this.multivalued = multivalued; - this.paramPatterns = paramPatterns; } @Override @@ -62,25 +54,7 @@ public class CriteriaFinderMethod extends AbstractFinderMethod { } @Override - public String getAttributeDeclarationString() { - final List paramTypes = parameterTypes(); - final StringBuilder declaration = new StringBuilder(); - comment( declaration ); - modifiers( declaration ); - preamble( declaration, returnType(), paramTypes ); - chainSession( declaration ); - nullChecks( paramTypes, declaration ); - createCriteriaQuery( declaration ); - where( declaration, paramTypes ); -// orderBy( paramTypes, declaration ); - executeQuery( declaration, paramTypes ); - convertExceptions( declaration ); - chainSessionEnd( false, declaration ); - closingBrace( declaration ); - return declaration.toString(); - } - - private void executeQuery(StringBuilder declaration, List paramTypes) { + void executeQuery(StringBuilder declaration, List paramTypes) { declaration .append('\n'); collectOrdering( declaration, paramTypes ); @@ -110,27 +84,15 @@ public class CriteriaFinderMethod extends AbstractFinderMethod { return unwrapped; } - @Override - void createQuery(StringBuilder declaration) { - declaration - .append(localSessionName()) - .append(".createQuery(_query)\n"); - } - private void execute(StringBuilder declaration, List paramTypes, boolean unwrapped) { final boolean mustUnwrap = containerType != null && containerType.startsWith("org.hibernate"); executeSelect( declaration, paramTypes, containerType, unwrapped, mustUnwrap ); } - private void createCriteriaQuery(StringBuilder declaration) { + @Override + void createCriteriaQuery(StringBuilder declaration) { declaration - .append("\tvar _builder = ") - .append(localSessionName()) - .append(isUsingEntityManager() - ? ".getEntityManagerFactory()" - : ".getFactory()") - .append(".getCriteriaBuilder();\n") .append("\tvar _query = _builder.createQuery(") .append(annotationMetaEntity.importType(entity)) .append(".class);\n") @@ -139,119 +101,8 @@ public class CriteriaFinderMethod extends AbstractFinderMethod { .append(".class);\n"); } - private void nullChecks(List paramTypes, StringBuilder declaration) { - for ( int i = 0; i< paramNames.size(); i++ ) { - final String paramName = paramNames.get(i); - final String paramType = paramTypes.get(i); - if ( !isNullable(i) && !isPrimitive(paramType) ) { - nullCheck( declaration, paramName ); - } - } - } - - private static void nullCheck(StringBuilder declaration, String paramName) { - declaration - .append("\tif (") - .append(paramName.replace('.', '$')) - .append(" == null) throw new IllegalArgumentException(\"Null ") - .append(paramName) - .append("\");\n"); - } - - private void where(StringBuilder declaration, List paramTypes) { - declaration - .append("\t_query.where("); - boolean first = true; - for ( int i = 0; i < paramNames.size(); i ++ ) { - final String paramName = paramNames.get(i); - final String paramType = paramTypes.get(i); - if ( !isSpecialParam(paramType) ) { - if ( first ) { - first = false; - } - else { - declaration - .append(", "); - } - condition(declaration, i, paramName, paramType ); - } - } - declaration - .append("\n\t);"); - } - - private void condition(StringBuilder declaration, int i, String paramName, String paramType) { - declaration - .append("\n\t\t\t"); - final String parameterName = paramName.replace('.', '$'); - if ( isNullable(i) && !isPrimitive(paramType) ) { - declaration - .append(parameterName) - .append("==null") - .append("\n\t\t\t\t? ") - .append("_entity"); - path( declaration, paramName ); - declaration - .append(".isNull()") - .append("\n\t\t\t\t: "); - } - if ( multivalued.get(i) ) { - declaration - .append("_entity"); - path( declaration, paramName ); - declaration - .append(".in("); - if ( paramType.endsWith("[]") ) { - declaration - .append("(Object[]) ") - //TODO: only safe if we are binding literals as parameters!!! - .append(parameterName); - - } - else { - declaration - .append(annotationMetaEntity.staticImport(StreamSupport.class.getName(), "stream")) - .append('(') - //TODO: only safe if we are binding literals as parameters!!! - .append(parameterName) - .append(".spliterator(), false).collect(") // ugh, very ugly! - .append(annotationMetaEntity.staticImport(Collectors.class.getName(), "toList")) - .append("())"); - } - declaration - .append(")"); - } - else { - //TODO: change to use Expression.equalTo() in JPA 3.2 - declaration - .append("_builder.") - .append(paramPatterns.get(i) ? "like" : "equal") - .append("(_entity"); - path( declaration, paramName ); - declaration - .append(", ") - //TODO: only safe if we are binding literals as parameters!!! - .append(parameterName) - .append(')'); - } - } - - private void path(StringBuilder declaration, String paramName) { - final StringTokenizer tokens = new StringTokenizer(paramName, "."); - String typeName = entity; - while ( typeName!= null && tokens.hasMoreTokens() ) { - final String memberName = tokens.nextToken(); - declaration - .append(".get(") - .append(annotationMetaEntity.importType(typeName + '_')) - .append('.') - .append(memberName) - .append(')'); - typeName = annotationMetaEntity.getMemberType(typeName, memberName); - } - } - - private StringBuilder returnType() { + @Override + String returnType() { final StringBuilder type = new StringBuilder(); if ( "[]".equals(containerType) ) { if ( returnTypeName == null ) { @@ -276,6 +127,6 @@ public class CriteriaFinderMethod extends AbstractFinderMethod { type.append('>'); } } - return type; + return type.toString(); } } diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/QueryMethod.java b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/QueryMethod.java index d689056571..382c8f7b7d 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/QueryMethod.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/QueryMethod.java @@ -80,7 +80,7 @@ public class QueryMethod extends AbstractQueryMethod { @Override public String getAttributeDeclarationString() { final List paramTypes = parameterTypes(); - final StringBuilder returnType = returnType(); + final String returnType = returnType(); final StringBuilder declaration = new StringBuilder(); comment( declaration ); modifiers( paramTypes, declaration ); @@ -123,7 +123,7 @@ public class QueryMethod extends AbstractQueryMethod { declaration.append(")\n"); } - private void castResult(StringBuilder declaration, StringBuilder returnType) { + private void castResult(StringBuilder declaration, String returnType) { if ( isNative && returnTypeName != null && containerType == null && isUsingEntityManager() ) { // EntityManager.createNativeQuery() does not return TypedQuery, @@ -192,7 +192,7 @@ public class QueryMethod extends AbstractQueryMethod { .append(")\n"); } - private StringBuilder returnType() { + private String returnType() { final StringBuilder type = new StringBuilder(); if ( "[]".equals(containerType) ) { if ( returnTypeName == null ) { @@ -219,7 +219,7 @@ public class QueryMethod extends AbstractQueryMethod { type.append('>'); } } - return type; + return type.toString(); } private void comment(StringBuilder declaration) { diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/util/Constants.java b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/util/Constants.java index db9fe54963..309607f9be 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/util/Constants.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/util/Constants.java @@ -76,6 +76,9 @@ public final class Constants { public static final String JD_PAGE_REQUEST = "jakarta.data.page.PageRequest"; public static final String JD_PAGE = "jakarta.data.page.Page"; public static final String JD_CURSORED_PAGE = "jakarta.data.page.CursoredPage"; + public static final String BASIC_REPOSITORY = "jakarta.data.repository.BasicRepository"; + public static final String CRUD_REPOSITORY = "jakarta.data.repository.CrudRepository"; + public static final String DATA_REPOSITORY = "jakarta.data.repository.DataRepository"; public static final String HIB_ORDER = "org.hibernate.query.Order"; public static final String HIB_PAGE = "org.hibernate.query.Page";