HHH-17772 allow lifecycle methods accepting arrays/iterables

as required by Jakarta Data
This commit is contained in:
Gavin King 2024-02-25 21:09:17 +01:00
parent f73d7aac9f
commit be448afdab
4 changed files with 72 additions and 22 deletions

View File

@ -47,6 +47,7 @@ import javax.lang.model.type.ExecutableType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.WildcardType;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import javax.tools.Diagnostic;
import java.util.ArrayList;
@ -70,6 +71,7 @@ import static org.hibernate.jpamodelgen.util.Constants.FIND;
import static org.hibernate.jpamodelgen.util.Constants.HIB_SESSION;
import static org.hibernate.jpamodelgen.util.Constants.HIB_STATELESS_SESSION;
import static org.hibernate.jpamodelgen.util.Constants.HQL;
import static org.hibernate.jpamodelgen.util.Constants.ITERABLE;
import static org.hibernate.jpamodelgen.util.Constants.JD_DELETE;
import static org.hibernate.jpamodelgen.util.Constants.JD_FIND;
import static org.hibernate.jpamodelgen.util.Constants.JD_INSERT;
@ -680,34 +682,57 @@ public class AnnotationMetaEntity extends AnnotationMeta {
final String operation = lifecycleOperation( method );
final VariableElement parameter = method.getParameters().get(0);
final TypeMirror parameterType = parameter.asType();
if ( parameterType.getKind() != TypeKind.DECLARED ) {
final DeclaredType declaredType = entityType( parameterType );
if ( declaredType == null ) {
context.message( parameter,
"incorrect parameter type '" + parameterType + "' is not an entity type",
Diagnostic.Kind.ERROR );
}
else if ( !containsAnnotation( declaredType.asElement(), Constants.ENTITY ) ) {
context.message( parameter,
"incorrect parameter type '" + parameterType + "' is not annotated '@Entity'",
Diagnostic.Kind.ERROR );
}
else {
putMember(
method.getSimpleName().toString()
+ '.' + operation,
new LifecycleMethod(
this,
parameterType.toString(),
method.getSimpleName().toString(),
parameter.getSimpleName().toString(),
getSessionVariableName(),
operation,
context.addNonnullAnnotation(),
declaredType != parameterType
)
);
}
}
}
private @Nullable DeclaredType entityType(TypeMirror parameterType) {
switch ( parameterType.getKind() ) {
case DECLARED:
final DeclaredType declaredType = (DeclaredType) parameterType;
if ( !containsAnnotation( declaredType.asElement(), Constants.ENTITY ) ) {
context.message( parameter,
"incorrect parameter type '" + parameterType + "' is not annotated '@Entity'",
Diagnostic.Kind.ERROR );
final Types types = context.getTypeUtils();
final Elements elements = context.getElementUtils();
if ( types.isAssignable( declaredType,
types.erasure( elements.getTypeElement(ITERABLE).asType() ) )
&& !declaredType.getTypeArguments().isEmpty() ) {
final TypeMirror elementType = declaredType.getTypeArguments().get(0);
return elementType.getKind() == TypeKind.DECLARED ? (DeclaredType) elementType : null;
}
else {
putMember(
method.getSimpleName().toString()
+ '.' + operation,
new LifecycleMethod(
this,
parameterType.toString(),
method.getSimpleName().toString(),
parameter.getSimpleName().toString(),
getSessionVariableName(),
operation,
context.addNonnullAnnotation()
)
);
return declaredType;
}
}
case ARRAY:
final ArrayType arrayType = (ArrayType) parameterType;
final TypeMirror componentType = arrayType.getComponentType();
return componentType.getKind() == TypeKind.DECLARED ? (DeclaredType) componentType : null;
default:
return null;
}
}

View File

@ -17,6 +17,7 @@ public class LifecycleMethod implements MetaAttribute {
private final String sessionName;
private final String operationName;
private final boolean addNonnullAnnotation;
private final boolean iterateParameter;
public LifecycleMethod(
AnnotationMetaEntity annotationMetaEntity,
@ -25,7 +26,8 @@ public class LifecycleMethod implements MetaAttribute {
String parameterName,
String sessionName,
String operationName,
boolean addNonnullAnnotation) {
boolean addNonnullAnnotation,
boolean iterateParameter) {
this.annotationMetaEntity = annotationMetaEntity;
this.entity = entity;
this.methodName = methodName;
@ -33,6 +35,7 @@ public class LifecycleMethod implements MetaAttribute {
this.sessionName = sessionName;
this.operationName = operationName;
this.addNonnullAnnotation = addNonnullAnnotation;
this.iterateParameter = iterateParameter;
}
@Override
@ -70,15 +73,26 @@ public class LifecycleMethod implements MetaAttribute {
}
private void delegateCall(StringBuilder declaration) {
if ( iterateParameter ) {
declaration
.append("\t\tfor (var entity : ")
.append(parameterName)
.append(") {\n\t");
}
declaration
.append("\t\t")
.append(sessionName)
.append('.')
.append(operationName)
.append('(')
.append(parameterName)
.append(iterateParameter ? "entity" : parameterName)
.append(')')
.append(";\n")
.append(";\n");
if ( iterateParameter ) {
declaration
.append("\t\t}\n");
}
declaration
.append("\t}\n");
}

View File

@ -96,6 +96,7 @@ public final class Constants {
public static final String MAP_ATTRIBUTE = "jakarta.persistence.metamodel.MapAttribute";
public static final String JAVA_OBJECT = Object.class.getName();
public static final String ITERABLE = java.lang.Iterable.class.getName();
public static final String COLLECTION = java.util.Collection.class.getName();
public static final String LIST = java.util.List.class.getName();
public static final String MAP = java.util.Map.class.getName();

View File

@ -18,6 +18,7 @@ import org.hibernate.StatelessSession;
import java.time.LocalDate;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Stream;
@Repository(dataStore = "myds")
@ -25,6 +26,15 @@ public interface BookAuthorRepository {
StatelessSession session();
@Insert
void insertBooks0(Book[] books);
@Insert
void insertBooks1(Iterable<Book> books);
@Insert
void insertBooks2(Set<Book> books);
@Find
Book book(String isbn);