HHH-17860 query-based @Delete
This commit is contained in:
parent
003c0d0960
commit
c3e210e923
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
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(" ")
|
||||||
|
|
|
@ -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,13 +922,24 @@ 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) {
|
||||||
for ( ExecutableElement method : queryMethods) {
|
for ( ExecutableElement method : queryMethods) {
|
||||||
final Set<Modifier> modifiers = method.getModifiers();
|
final Set<Modifier> modifiers = method.getModifiers();
|
||||||
|
@ -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
|
||||||
|
|
|
@ -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 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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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";
|
||||||
|
|
Loading…
Reference in New Issue