HHH-17860 query-based @Delete

This commit is contained in:
Gavin King 2024-03-22 17:08:50 +01:00
parent 003c0d0960
commit c3e210e923
11 changed files with 453 additions and 172 deletions

View File

@ -30,6 +30,12 @@ public interface BookAuthorRepository {
StatelessSession session(); StatelessSession session();
@Delete
int deleteByIdIn(String[] isbn);
@Delete
void deleteById(String isbn);
@Insert @Insert
void insertBooks0(Book[] books); void insertBooks0(Book[] books);

View File

@ -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<Book,String> {
@Find
List<Book> byPublisher(String publisher_name);
}

View File

@ -1,5 +1,8 @@
package org.hibernate.processor.test.data.eg; 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.CursoredPage;
import jakarta.data.page.PageRequest; import jakarta.data.page.PageRequest;
import jakarta.data.repository.By; import jakarta.data.repository.By;
@ -25,18 +28,22 @@ public interface Library {
List<Book> books(@By("isbn") List<String> isbns); List<Book> books(@By("isbn") List<String> isbns);
@Find @Find
Book books(String title, LocalDate publicationDate); Book book(String title, LocalDate publicationDate);
@Find
List<Book> publications(Type type, Sort<Book> sort);
@Find @Find
@OrderBy("title") @OrderBy("title")
List<Book> booksByPublisher(String publisher_name); List<Book> booksByPublisher(String publisher_name);
@Query("where title like :titlePattern") @Query("where title like :titlePattern")
@OrderBy("title")
List<Book> booksByTitle(String titlePattern); List<Book> booksByTitle(String titlePattern);
// not required by Jakarta Data // not required by Jakarta Data
record BookWithAuthor(Book book, Author author) {} 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<BookWithAuthor> booksWithAuthors(); List<BookWithAuthor> booksWithAuthors();
@Insert @Insert
@ -69,14 +76,20 @@ public interface Library {
@Update @Update
void update(Author author); void update(Author author);
@Save
void save(Publisher publisher);
@Delete
void delete(Publisher publisher);
@Find @Find
@OrderBy("isbn") @OrderBy("isbn")
CursoredPage<Book> allBooks(PageRequest<Book> pageRequest); CursoredPage<Book> allBooks(PageRequest<Book> pageRequest);
@Find @Find
@OrderBy("name") @OrderBy("name")
@OrderBy("address.city") //not working currently @OrderBy("address.city")
List<Author> authors(); List<Author> allAuthors(Order<Author> order, Limit limit);
@Find @Find
List<Author> authorsByCity(@By("address.city") String city); List<Author> authorsByCity(@By("address.city") String city);

View File

@ -29,8 +29,8 @@ public interface SuperRepo<T,K> {
@Find @Find
Page<T> findAll(PageRequest<T> pageRequest); Page<T> findAll(PageRequest<T> pageRequest);
@Delete // @Delete
void deleteById(@By("#id") K id); // void deleteById(@By("#id") K id);
@Delete @Delete
void delete(T entity); void delete(T entity);

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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<Boolean> multivalued;
private final List<Boolean> paramPatterns;
public AbstractCriteriaMethod(
AnnotationMetaEntity annotationMetaEntity,
String methodName, String entity,
boolean belongsToDao,
String sessionType, String sessionName,
List<String> fetchProfiles,
List<String> paramNames,
List<String> paramTypes,
List<OrderBy> orderBys,
boolean addNonnullAnnotation,
boolean convertToDataExceptions,
List<Boolean> multivalued,
List<Boolean> 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<String> 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<String> 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<String> 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<String> 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);
}
}
}

View File

@ -97,7 +97,7 @@ public abstract class AbstractQueryMethod implements MetaAttribute {
return type.endsWith("...") ? stripped + "..." : stripped; return type.endsWith("...") ? stripped + "..." : stripped;
} }
void preamble(StringBuilder declaration, StringBuilder returnType, List<String> paramTypes) { void preamble(StringBuilder declaration, String returnType, List<String> paramTypes) {
declaration declaration
.append(returnType) .append(returnType)
.append(" ") .append(" ")

View File

@ -149,6 +149,11 @@ public class AnnotationMetaEntity extends AnnotationMeta {
private final Map<String,String> memberTypes = new HashMap<>(); private final Map<String,String> memberTypes = new HashMap<>();
/**
* The primary entity type for a repository
*/
private @Nullable TypeElement primaryEntity;
public AnnotationMetaEntity( public AnnotationMetaEntity(
TypeElement element, Context context, boolean managed, TypeElement element, Context context, boolean managed,
boolean jakartaDataStaticMetamodel) { boolean jakartaDataStaticMetamodel) {
@ -349,10 +354,20 @@ public class AnnotationMetaEntity extends AnnotationMeta {
if ( containsAnnotation( method, HQL, SQL, JD_QUERY, FIND, JD_FIND ) ) { if ( containsAnnotation( method, HQL, SQL, JD_QUERY, FIND, JD_FIND ) ) {
queryMethods.add( method ); 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 ); lifecycleMethods.add( method );
} }
else if ( hasAnnotation( method, JD_DELETE) ) {
if ( isDeleteLifecycle(method) ) {
lifecycleMethods.add( method );
} }
else {
queryMethods.add( method );
}
}
}
primaryEntity = primaryEntity( lifecycleMethods );
} }
else { else {
determineAccessTypeForHierarchy( element, context ); determineAccessTypeForHierarchy( element, context );
@ -393,6 +408,43 @@ public class AnnotationMetaEntity extends AnnotationMeta {
initialized = true; initialized = true;
} }
private @Nullable TypeElement primaryEntity(List<ExecutableElement> 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<ExecutableElement> methodsOfClass) { private void addMethods(TypeElement element, List<ExecutableElement> methodsOfClass) {
//TODO just use Elements.getAllMembers(element) here! //TODO just use Elements.getAllMembers(element) here!
for ( TypeMirror typeMirror : element.getInterfaces() ) { for ( TypeMirror typeMirror : element.getInterfaces() ) {
@ -870,11 +922,22 @@ public class AnnotationMetaEntity extends AnnotationMeta {
private void addLifecycleMethods(List<ExecutableElement> queryMethods) { private void addLifecycleMethods(List<ExecutableElement> queryMethods) {
for ( ExecutableElement method : queryMethods) { for ( ExecutableElement method : queryMethods) {
if ( method.getModifiers().contains(Modifier.ABSTRACT) ) { 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<ExecutableElement> queryMethods) { private void addQueryMethods(List<ExecutableElement> queryMethods) {
@ -1018,6 +1081,9 @@ public class AnnotationMetaEntity extends AnnotationMeta {
if ( hasAnnotation( method, FIND, JD_FIND ) ) { if ( hasAnnotation( method, FIND, JD_FIND ) ) {
addFinderMethod( method, returnType, containerType ); addFinderMethod( method, returnType, containerType );
} }
else if ( hasAnnotation( method, JD_DELETE ) ) {
createCriteriaDelete( method, returnType );
}
} }
private void addLifecycleMethod(ExecutableElement method) { 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<String> paramNames = parameterNames( method, entity );
final List<String> paramTypes = parameterTypes( method );
final List<Boolean> paramPatterns = parameterPatterns( method );
final String[] sessionType = sessionTypeFromParameters( paramNames, paramTypes );
final String methodKey = methodName + paramTypes;
final List<Boolean> 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) { private void wrongTypeArgError(String entity, VariableElement parameter, boolean pageRequest) {
context.message(parameter, context.message(parameter,
(pageRequest (pageRequest

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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<Boolean> paramNullability;
private final String returnType;
CriteriaDeleteMethod(
AnnotationMetaEntity annotationMetaEntity,
String methodName, String entity, String returnType,
List<String> paramNames,
List<String> paramTypes,
List<Boolean> paramNullability,
List<Boolean> multivalued,
List<Boolean> 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<String> 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");
}
}

View File

@ -11,22 +11,16 @@ import org.hibernate.AssertionFailure;
import org.hibernate.processor.util.Constants; import org.hibernate.processor.util.Constants;
import java.util.List; 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.Constants.LIST;
import static org.hibernate.processor.util.TypeUtils.isPrimitive;
/** /**
* @author Gavin King * @author Gavin King
*/ */
public class CriteriaFinderMethod extends AbstractFinderMethod { public class CriteriaFinderMethod extends AbstractCriteriaMethod {
private final @Nullable String containerType; private final @Nullable String containerType;
private final List<Boolean> paramNullability; private final List<Boolean> paramNullability;
private final List<Boolean> multivalued;
private final List<Boolean> paramPatterns;
CriteriaFinderMethod( CriteriaFinderMethod(
AnnotationMetaEntity annotationMetaEntity, AnnotationMetaEntity annotationMetaEntity,
@ -44,11 +38,9 @@ public class CriteriaFinderMethod extends AbstractFinderMethod {
boolean addNonnullAnnotation, boolean addNonnullAnnotation,
boolean dataRepository) { boolean dataRepository) {
super( annotationMetaEntity, methodName, entity, belongsToDao, sessionType, sessionName, fetchProfiles, super( annotationMetaEntity, methodName, entity, belongsToDao, sessionType, sessionName, fetchProfiles,
paramNames, paramTypes, orderBys, addNonnullAnnotation, dataRepository ); paramNames, paramTypes, orderBys, addNonnullAnnotation, dataRepository, multivalued, paramPatterns );
this.containerType = containerType; this.containerType = containerType;
this.paramNullability = paramNullability; this.paramNullability = paramNullability;
this.multivalued = multivalued;
this.paramPatterns = paramPatterns;
} }
@Override @Override
@ -62,25 +54,7 @@ public class CriteriaFinderMethod extends AbstractFinderMethod {
} }
@Override @Override
public String getAttributeDeclarationString() { void executeQuery(StringBuilder declaration, List<String> paramTypes) {
final List<String> 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<String> paramTypes) {
declaration declaration
.append('\n'); .append('\n');
collectOrdering( declaration, paramTypes ); collectOrdering( declaration, paramTypes );
@ -110,27 +84,15 @@ public class CriteriaFinderMethod extends AbstractFinderMethod {
return unwrapped; return unwrapped;
} }
@Override
void createQuery(StringBuilder declaration) {
declaration
.append(localSessionName())
.append(".createQuery(_query)\n");
}
private void execute(StringBuilder declaration, List<String> paramTypes, boolean unwrapped) { private void execute(StringBuilder declaration, List<String> paramTypes, boolean unwrapped) {
final boolean mustUnwrap = final boolean mustUnwrap =
containerType != null && containerType.startsWith("org.hibernate"); containerType != null && containerType.startsWith("org.hibernate");
executeSelect( declaration, paramTypes, containerType, unwrapped, mustUnwrap ); executeSelect( declaration, paramTypes, containerType, unwrapped, mustUnwrap );
} }
private void createCriteriaQuery(StringBuilder declaration) { @Override
void createCriteriaQuery(StringBuilder declaration) {
declaration declaration
.append("\tvar _builder = ")
.append(localSessionName())
.append(isUsingEntityManager()
? ".getEntityManagerFactory()"
: ".getFactory()")
.append(".getCriteriaBuilder();\n")
.append("\tvar _query = _builder.createQuery(") .append("\tvar _query = _builder.createQuery(")
.append(annotationMetaEntity.importType(entity)) .append(annotationMetaEntity.importType(entity))
.append(".class);\n") .append(".class);\n")
@ -139,119 +101,8 @@ public class CriteriaFinderMethod extends AbstractFinderMethod {
.append(".class);\n"); .append(".class);\n");
} }
private void nullChecks(List<String> paramTypes, StringBuilder declaration) { @Override
for ( int i = 0; i< paramNames.size(); i++ ) { String returnType() {
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<String> 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() {
final StringBuilder type = new StringBuilder(); final StringBuilder type = new StringBuilder();
if ( "[]".equals(containerType) ) { if ( "[]".equals(containerType) ) {
if ( returnTypeName == null ) { if ( returnTypeName == null ) {
@ -276,6 +127,6 @@ public class CriteriaFinderMethod extends AbstractFinderMethod {
type.append('>'); type.append('>');
} }
} }
return type; return type.toString();
} }
} }

View File

@ -80,7 +80,7 @@ public class QueryMethod extends AbstractQueryMethod {
@Override @Override
public String getAttributeDeclarationString() { public String getAttributeDeclarationString() {
final List<String> paramTypes = parameterTypes(); final List<String> paramTypes = parameterTypes();
final StringBuilder returnType = returnType(); final String returnType = returnType();
final StringBuilder declaration = new StringBuilder(); final StringBuilder declaration = new StringBuilder();
comment( declaration ); comment( declaration );
modifiers( paramTypes, declaration ); modifiers( paramTypes, declaration );
@ -123,7 +123,7 @@ public class QueryMethod extends AbstractQueryMethod {
declaration.append(")\n"); declaration.append(")\n");
} }
private void castResult(StringBuilder declaration, StringBuilder returnType) { private void castResult(StringBuilder declaration, String returnType) {
if ( isNative && returnTypeName != null && containerType == null if ( isNative && returnTypeName != null && containerType == null
&& isUsingEntityManager() ) { && isUsingEntityManager() ) {
// EntityManager.createNativeQuery() does not return TypedQuery, // EntityManager.createNativeQuery() does not return TypedQuery,
@ -192,7 +192,7 @@ public class QueryMethod extends AbstractQueryMethod {
.append(")\n"); .append(")\n");
} }
private StringBuilder returnType() { private String returnType() {
final StringBuilder type = new StringBuilder(); final StringBuilder type = new StringBuilder();
if ( "[]".equals(containerType) ) { if ( "[]".equals(containerType) ) {
if ( returnTypeName == null ) { if ( returnTypeName == null ) {
@ -219,7 +219,7 @@ public class QueryMethod extends AbstractQueryMethod {
type.append('>'); type.append('>');
} }
} }
return type; return type.toString();
} }
private void comment(StringBuilder declaration) { private void comment(StringBuilder declaration) {

View File

@ -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_REQUEST = "jakarta.data.page.PageRequest";
public static final String JD_PAGE = "jakarta.data.page.Page"; 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 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_ORDER = "org.hibernate.query.Order";
public static final String HIB_PAGE = "org.hibernate.query.Page"; public static final String HIB_PAGE = "org.hibernate.query.Page";