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.TypeKind;
import javax.lang.model.type.TypeMirror; import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.WildcardType; import javax.lang.model.type.WildcardType;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types; import javax.lang.model.util.Types;
import javax.tools.Diagnostic; import javax.tools.Diagnostic;
import java.util.ArrayList; 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_SESSION;
import static org.hibernate.jpamodelgen.util.Constants.HIB_STATELESS_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.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_DELETE;
import static org.hibernate.jpamodelgen.util.Constants.JD_FIND; import static org.hibernate.jpamodelgen.util.Constants.JD_FIND;
import static org.hibernate.jpamodelgen.util.Constants.JD_INSERT; import static org.hibernate.jpamodelgen.util.Constants.JD_INSERT;
@ -680,34 +682,57 @@ public class AnnotationMetaEntity extends AnnotationMeta {
final String operation = lifecycleOperation( method ); final String operation = lifecycleOperation( method );
final VariableElement parameter = method.getParameters().get(0); final VariableElement parameter = method.getParameters().get(0);
final TypeMirror parameterType = parameter.asType(); final TypeMirror parameterType = parameter.asType();
if ( parameterType.getKind() != TypeKind.DECLARED ) { final DeclaredType declaredType = entityType( parameterType );
if ( declaredType == null ) {
context.message( parameter, context.message( parameter,
"incorrect parameter type '" + parameterType + "' is not an entity type", "incorrect parameter type '" + parameterType + "' is not an entity type",
Diagnostic.Kind.ERROR ); 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 { 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; final DeclaredType declaredType = (DeclaredType) parameterType;
if ( !containsAnnotation( declaredType.asElement(), Constants.ENTITY ) ) { final Types types = context.getTypeUtils();
context.message( parameter, final Elements elements = context.getElementUtils();
"incorrect parameter type '" + parameterType + "' is not annotated '@Entity'", if ( types.isAssignable( declaredType,
Diagnostic.Kind.ERROR ); 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 { else {
putMember( return declaredType;
method.getSimpleName().toString()
+ '.' + operation,
new LifecycleMethod(
this,
parameterType.toString(),
method.getSimpleName().toString(),
parameter.getSimpleName().toString(),
getSessionVariableName(),
operation,
context.addNonnullAnnotation()
)
);
} }
} 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 sessionName;
private final String operationName; private final String operationName;
private final boolean addNonnullAnnotation; private final boolean addNonnullAnnotation;
private final boolean iterateParameter;
public LifecycleMethod( public LifecycleMethod(
AnnotationMetaEntity annotationMetaEntity, AnnotationMetaEntity annotationMetaEntity,
@ -25,7 +26,8 @@ public class LifecycleMethod implements MetaAttribute {
String parameterName, String parameterName,
String sessionName, String sessionName,
String operationName, String operationName,
boolean addNonnullAnnotation) { boolean addNonnullAnnotation,
boolean iterateParameter) {
this.annotationMetaEntity = annotationMetaEntity; this.annotationMetaEntity = annotationMetaEntity;
this.entity = entity; this.entity = entity;
this.methodName = methodName; this.methodName = methodName;
@ -33,6 +35,7 @@ public class LifecycleMethod implements MetaAttribute {
this.sessionName = sessionName; this.sessionName = sessionName;
this.operationName = operationName; this.operationName = operationName;
this.addNonnullAnnotation = addNonnullAnnotation; this.addNonnullAnnotation = addNonnullAnnotation;
this.iterateParameter = iterateParameter;
} }
@Override @Override
@ -70,15 +73,26 @@ public class LifecycleMethod implements MetaAttribute {
} }
private void delegateCall(StringBuilder declaration) { private void delegateCall(StringBuilder declaration) {
if ( iterateParameter ) {
declaration
.append("\t\tfor (var entity : ")
.append(parameterName)
.append(") {\n\t");
}
declaration declaration
.append("\t\t") .append("\t\t")
.append(sessionName) .append(sessionName)
.append('.') .append('.')
.append(operationName) .append(operationName)
.append('(') .append('(')
.append(parameterName) .append(iterateParameter ? "entity" : parameterName)
.append(')') .append(')')
.append(";\n") .append(";\n");
if ( iterateParameter ) {
declaration
.append("\t\t}\n");
}
declaration
.append("\t}\n"); .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 MAP_ATTRIBUTE = "jakarta.persistence.metamodel.MapAttribute";
public static final String JAVA_OBJECT = Object.class.getName(); 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 COLLECTION = java.util.Collection.class.getName();
public static final String LIST = java.util.List.class.getName(); public static final String LIST = java.util.List.class.getName();
public static final String MAP = java.util.Map.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.time.LocalDate;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.Set;
import java.util.stream.Stream; import java.util.stream.Stream;
@Repository(dataStore = "myds") @Repository(dataStore = "myds")
@ -25,6 +26,15 @@ public interface BookAuthorRepository {
StatelessSession session(); StatelessSession session();
@Insert
void insertBooks0(Book[] books);
@Insert
void insertBooks1(Iterable<Book> books);
@Insert
void insertBooks2(Set<Book> books);
@Find @Find
Book book(String isbn); Book book(String isbn);