HHH-17860 query-based @Delete
This commit is contained in:
parent
003c0d0960
commit
c3e210e923
|
@ -30,6 +30,12 @@ public interface BookAuthorRepository {
|
|||
|
||||
StatelessSession session();
|
||||
|
||||
@Delete
|
||||
int deleteByIdIn(String[] isbn);
|
||||
|
||||
@Delete
|
||||
void deleteById(String isbn);
|
||||
|
||||
@Insert
|
||||
void insertBooks0(Book[] books);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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<Book> books(@By("isbn") List<String> isbns);
|
||||
|
||||
@Find
|
||||
Book books(String title, LocalDate publicationDate);
|
||||
Book book(String title, LocalDate publicationDate);
|
||||
|
||||
@Find
|
||||
List<Book> publications(Type type, Sort<Book> sort);
|
||||
|
||||
@Find
|
||||
@OrderBy("title")
|
||||
List<Book> booksByPublisher(String publisher_name);
|
||||
|
||||
@Query("where title like :titlePattern")
|
||||
@OrderBy("title")
|
||||
List<Book> 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<BookWithAuthor> 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<Book> allBooks(PageRequest<Book> pageRequest);
|
||||
|
||||
@Find
|
||||
@OrderBy("name")
|
||||
@OrderBy("address.city") //not working currently
|
||||
List<Author> authors();
|
||||
@OrderBy("address.city")
|
||||
List<Author> allAuthors(Order<Author> order, Limit limit);
|
||||
|
||||
@Find
|
||||
List<Author> authorsByCity(@By("address.city") String city);
|
||||
|
|
|
@ -29,8 +29,8 @@ public interface SuperRepo<T,K> {
|
|||
@Find
|
||||
Page<T> findAll(PageRequest<T> pageRequest);
|
||||
|
||||
@Delete
|
||||
void deleteById(@By("#id") K id);
|
||||
// @Delete
|
||||
// void deleteById(@By("#id") K id);
|
||||
|
||||
@Delete
|
||||
void delete(T entity);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -97,7 +97,7 @@ public abstract class AbstractQueryMethod implements MetaAttribute {
|
|||
return type.endsWith("...") ? stripped + "..." : stripped;
|
||||
}
|
||||
|
||||
void preamble(StringBuilder declaration, StringBuilder returnType, List<String> paramTypes) {
|
||||
void preamble(StringBuilder declaration, String returnType, List<String> paramTypes) {
|
||||
declaration
|
||||
.append(returnType)
|
||||
.append(" ")
|
||||
|
|
|
@ -149,6 +149,11 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
|
||||
private final Map<String,String> 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<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) {
|
||||
//TODO just use Elements.getAllMembers(element) here!
|
||||
for ( TypeMirror typeMirror : element.getInterfaces() ) {
|
||||
|
@ -870,11 +922,22 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
private void addLifecycleMethods(List<ExecutableElement> queryMethods) {
|
||||
for ( ExecutableElement method : queryMethods) {
|
||||
if ( method.getModifiers().contains(Modifier.ABSTRACT) ) {
|
||||
if ( hasAnnotation( method, JD_INSERT, JD_UPDATE, JD_DELETE, JD_SAVE ) ) {
|
||||
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) {
|
||||
|
@ -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<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) {
|
||||
context.message(parameter,
|
||||
(pageRequest
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
}
|
|
@ -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<Boolean> paramNullability;
|
||||
private final List<Boolean> multivalued;
|
||||
private final List<Boolean> 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<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) {
|
||||
void executeQuery(StringBuilder declaration, List<String> 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<String> 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<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");
|
||||
}
|
||||
|
||||
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() {
|
||||
@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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@ public class QueryMethod extends AbstractQueryMethod {
|
|||
@Override
|
||||
public String getAttributeDeclarationString() {
|
||||
final List<String> 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) {
|
||||
|
|
|
@ -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";
|
||||
|
|
Loading…
Reference in New Issue