44 */
55package org .hibernate .processor .annotation ;
66
7-
87import javax .lang .model .element .ExecutableElement ;
9-
8+ import javax .lang .model .element .TypeElement ;
9+ import javax .lang .model .element .TypeParameterElement ;
10+ import javax .lang .model .element .VariableElement ;
11+ import javax .lang .model .type .ArrayType ;
12+ import javax .lang .model .type .DeclaredType ;
13+ import javax .lang .model .type .IntersectionType ;
14+ import javax .lang .model .type .TypeKind ;
15+ import javax .lang .model .type .TypeMirror ;
16+ import javax .lang .model .type .TypeVariable ;
17+ import javax .lang .model .type .WildcardType ;
18+ import java .util .Collection ;
1019import java .util .Set ;
1120
1221import static java .lang .Character .toUpperCase ;
22+ import static java .util .stream .Collectors .joining ;
23+ import static java .util .stream .Collectors .toSet ;
24+ import static javax .lang .model .type .TypeKind .VOID ;
1325import static org .hibernate .processor .util .Constants .EVENT ;
1426import static org .hibernate .processor .util .Constants .INJECT ;
1527import static org .hibernate .processor .util .Constants .JD_LIFECYCLE_EVENT ;
1628import static org .hibernate .processor .util .Constants .LIST ;
1729import static org .hibernate .processor .util .Constants .NONNULL ;
1830import static org .hibernate .processor .util .Constants .TYPE_LITERAL ;
1931import static org .hibernate .processor .util .Constants .UNI ;
32+ import static org .hibernate .processor .util .TypeUtils .resolveTypeName ;
2033
2134public class LifecycleMethod extends AbstractAnnotatedMethod {
2235 private final String entity ;
@@ -28,6 +41,8 @@ public class LifecycleMethod extends AbstractAnnotatedMethod {
2841 private final ParameterKind parameterKind ;
2942 private final boolean returnArgument ;
3043 private final boolean hasGeneratedId ;
44+ private final Collection <String > methodTypeParameters ;
45+ private final TypeElement element ;
3146
3247 public enum ParameterKind {
3348 NORMAL ,
@@ -48,7 +63,8 @@ public LifecycleMethod(
4863 boolean addNonnullAnnotation ,
4964 ParameterKind parameterKind ,
5065 boolean returnArgument ,
51- boolean hasGeneratedId ) {
66+ boolean hasGeneratedId ,
67+ TypeElement element ) {
5268 super (annotationMetaEntity , method , sessionName , sessionType );
5369 this .entity = entity ;
5470 this .actualEntity = actualEntity ;
@@ -59,6 +75,11 @@ public LifecycleMethod(
5975 this .parameterKind = parameterKind ;
6076 this .returnArgument = returnArgument ;
6177 this .hasGeneratedId = hasGeneratedId ;
78+ this .methodTypeParameters = method .getTypeParameters ().stream ()
79+ .map ( TypeParameterElement ::asType )
80+ .map ( TypeMirror ::toString )
81+ .collect ( toSet () );
82+ this .element = element ;
6283 }
6384
6485 @ Override
@@ -334,27 +355,86 @@ private boolean isGeneratedIdUpsert() {
334355 private void preamble (StringBuilder declaration ) {
335356 declaration
336357 .append ("\n @Override\n public " )
358+ .append (parameterTypeBopunds ())
337359 .append (returnType ())
338360 .append (' ' )
339361 .append (methodName )
340362 .append ('(' );
341363 notNull (declaration );
364+ final var parameters = method .getParameters ();
365+ assert parameters .size () == 1 ;
366+ final VariableElement element = parameters .get (0 );
342367 declaration
343- .append (annotationMetaEntity . importType ( entity ))
368+ .append (resolveAsString ( element . asType () ))
344369 .append (' ' )
345- .append (parameterName )
370+ .append (element . getSimpleName () )
346371 .append (')' )
347372 .append (" {\n " );
348373 }
349374
375+ private String parameterTypeBopunds () {
376+ if ( method .getTypeParameters ().isEmpty () ) {
377+ return "" ;
378+ }
379+ return method .getTypeParameters ().stream ()
380+ .map ( this ::resolveTypeParameter )
381+ .collect ( joining ( ", " , " <" , "> " ) );
382+ }
383+
384+ private String resolveAsString (TypeMirror type ) {
385+ if ( type .getKind ().isPrimitive () || type .getKind () == VOID ) {
386+ return type .toString ();
387+ }
388+ else if ( type instanceof DeclaredType declaredType ) {
389+ final var element = annotationMetaEntity .importType (
390+ ((TypeElement ) declaredType .asElement ()).getQualifiedName ().toString ()
391+ );
392+ if ( declaredType .getTypeArguments ().isEmpty () ) {
393+ return element ;
394+ }
395+ return element + declaredType .getTypeArguments ().stream ().map ( this ::resolveAsString )
396+ .collect ( joining ( "," , "<" , ">" ) );
397+ }
398+ else if ( type instanceof TypeVariable typeVariable ) {
399+ final var value = typeVariable .toString ();
400+ if ( methodTypeParameters .contains ( value ) ) {
401+ return value ;
402+ }
403+ return annotationMetaEntity .importType ( resolveTypeName ( element , method .getEnclosingElement (), value ) );
404+ }
405+ else if ( type instanceof WildcardType wildcardType ) {
406+ return "?"
407+ + (wildcardType .getExtendsBound () == null ? ""
408+ : " extends " + resolveAsString ( wildcardType .getExtendsBound () ))
409+ + (wildcardType .getSuperBound () == null ? ""
410+ : " super " + resolveAsString ( wildcardType .getExtendsBound () ));
411+ }
412+ else if ( type instanceof ArrayType arrayType ) {
413+ return resolveAsString ( arrayType .getComponentType () ) + "[]" ;
414+ }
415+ else if ( type instanceof IntersectionType intersectionType ) {
416+ return intersectionType .getBounds ().stream ().map ( this ::resolveAsString ).collect ( joining ( "&" ) );
417+ }
418+ else {
419+ return type .toString ();
420+ }
421+ }
422+
423+ private String resolveTypeParameter (TypeParameterElement p ) {
424+ final var type = (TypeVariable ) p .asType ();
425+ return type .toString ()
426+ + (type .getUpperBound ().getKind () == TypeKind .NULL ? ""
427+ : " extends " + resolveAsString ( type .getUpperBound () ))
428+ + (type .getLowerBound ().getKind () == TypeKind .NULL ? ""
429+ : " super " + resolveAsString ( type .getLowerBound () ));
430+ }
431+
350432 private String returnType () {
351- final String entityType = annotationMetaEntity .importType (entity );
352- if ( isReactive () ) {
353- return annotationMetaEntity .importType (UNI )
354- + '<' + (returnArgument ? entityType : "Void" ) + '>' ;
433+ if ( returnArgument ) {
434+ return resolveAsString (method .getReturnType ());
355435 }
356436 else {
357- return returnArgument ? entityType : "void" ;
437+ return isReactive () ? annotationMetaEntity . importType ( UNI ) + "<Void>" : "void" ;
358438 }
359439 }
360440
0 commit comments