17
17
18
18
import java .nio .ByteBuffer ;
19
19
import java .util .Map ;
20
- import java .util .Optional ;
21
20
22
21
import org .jspecify .annotations .NullUnmarked ;
23
22
import org .jspecify .annotations .Nullable ;
39
38
import org .springframework .data .convert .CustomConversions ;
40
39
import org .springframework .data .domain .Limit ;
41
40
import org .springframework .data .domain .Sort ;
41
+ import org .springframework .data .javapoet .LordOfTheStrings ;
42
+ import org .springframework .data .javapoet .TypeNames ;
42
43
import org .springframework .data .repository .aot .generate .AotQueryMethodGenerationContext ;
44
+ import org .springframework .data .repository .aot .generate .MethodReturn ;
43
45
import org .springframework .javapoet .CodeBlock ;
44
46
import org .springframework .javapoet .CodeBlock .Builder ;
45
47
import org .springframework .javapoet .TypeName ;
@@ -88,7 +90,6 @@ static class QueryBlockBuilder {
88
90
89
91
private final AotQueryMethodGenerationContext context ;
90
92
private final CassandraQueryMethod queryMethod ;
91
- private final String parameterNames ;
92
93
93
94
private @ Nullable AotQuery query ;
94
95
private String queryVariableName ;
@@ -98,14 +99,6 @@ static class QueryBlockBuilder {
98
99
99
100
this .context = context ;
100
101
this .queryMethod = queryMethod ;
101
-
102
- String parameterNames = StringUtils .collectionToDelimitedString (context .getAllParameterNames (), ", " );
103
-
104
- if (StringUtils .hasText (parameterNames )) {
105
- this .parameterNames = ", " + parameterNames ;
106
- } else {
107
- this .parameterNames = "" ;
108
- }
109
102
}
110
103
111
104
QueryBlockBuilder query (AotQuery query ) {
@@ -178,8 +171,7 @@ private CodeBlock buildQuery(StringAotQuery query) {
178
171
for (ParameterBinding binding : query .getParameterBindings ()) {
179
172
180
173
// TODO:Conversion, Data type
181
- builder .addStatement ("$1L[$2L] = $3L" , context .localVariable ("args" ), index ++,
182
- getParameter (binding .getOrigin ()));
174
+ builder .addStatement ("$1L[$2L] = $3L" , context .localVariable ("args" ), index ++, getParameter (binding ));
183
175
}
184
176
185
177
builder .addStatement ("$1T $2L = $1T.newInstance($3S, $4L)" , SimpleStatement .class , queryVariableName ,
@@ -259,28 +251,22 @@ private CodeBlock buildQuery(org.springframework.data.cassandra.core.query.Query
259
251
return queryBuilder .build ();
260
252
}
261
253
262
- boolean first = true ;
263
- queryBuilder .add ("$[" );
264
- queryBuilder .add ("$1T $2L = $1T.query(" , org .springframework .data .cassandra .core .query .Query .class ,
265
- queryVariableName );
254
+ LordOfTheStrings .CodeBlockBuilder CodeBlockBuilder = LordOfTheStrings .builder (queryBuilder );
255
+ CodeBlockBuilder .addStatement (it -> {
256
+ it .add ("$1T $2L = $1T.query(" , org .springframework .data .cassandra .core .query .Query .class , queryVariableName );
266
257
267
- for ( CriteriaDefinition criteriaDefinition : query ) {
258
+ it . addAll ( query , ".and(" , ( criteria ) -> {
268
259
269
- if (first ) {
270
- first = false ;
271
- } else {
272
- queryBuilder .add (".and(" );
273
- }
260
+ LordOfTheStrings .CodeBlockBuilder builder = LordOfTheStrings .builder ("$1T.where($2S)" , Criteria .class ,
261
+ criteria .getColumnName ().toCql ());
262
+ appendPredicate (criteria , builder );
263
+ builder .add (")" );
274
264
275
- queryBuilder .add ("$1T.where($2S)" , Criteria .class , criteriaDefinition .getColumnName ().toCql ());
276
- appendPredicate (criteriaDefinition , queryBuilder );
277
-
278
- queryBuilder .add (")" );
279
- }
265
+ return builder .build ();
266
+ });
267
+ });
280
268
281
- queryBuilder .add (";\n $]" );
282
-
283
- return queryBuilder .build ();
269
+ return CodeBlockBuilder .build ();
284
270
}
285
271
286
272
private CodeBlock buildColumns (Columns columns ) {
@@ -368,27 +354,21 @@ private CodeBlock buildSortScrollLimit(DerivedAotQuery derived,
368
354
369
355
private static CodeBlock buildSort (Sort sort ) {
370
356
371
- Builder sortBuilder = CodeBlock .builder ();
372
- sortBuilder .add ("$T.by(" , Sort .class );
357
+ LordOfTheStrings .InvocationBuilder invocation = LordOfTheStrings .invoke ("$T.by($L)" , Sort .class );
373
358
374
- boolean first = true ;
375
- for (Sort .Order order : sort ) {
359
+ invocation .arguments (sort , order -> {
376
360
377
- sortBuilder .add ("$T.$L($S)" , Sort .Order .class , order .isAscending () ? "asc" : "desc" , order .getProperty ());
378
- if (order .isIgnoreCase ()) {
379
- sortBuilder .add (".ignoreCase()" );
380
- }
361
+ LordOfTheStrings .CodeBlockBuilder builder = LordOfTheStrings .builder ("$T.$L($S)" , Sort .Order .class ,
362
+ order .isAscending () ? "asc" : "desc" , order .getProperty ());
381
363
382
- if (first ) {
383
- first = false ;
384
- } else {
385
- sortBuilder .add (", " );
364
+ if (order .isIgnoreCase ()) {
365
+ builder .add (".ignoreCase()" );
386
366
}
387
- }
388
367
389
- sortBuilder .add (")" );
368
+ return builder .build ();
369
+ });
390
370
391
- return sortBuilder .build ();
371
+ return invocation .build ();
392
372
}
393
373
394
374
private CodeBlock buildQueryOptions (DerivedAotQuery derived ) {
@@ -456,7 +436,8 @@ private void applyOptions(Limit limit, Builder builder) {
456
436
}
457
437
}
458
438
459
- private void appendPredicate (CriteriaDefinition criteriaDefinition , Builder criteriaBuilder ) {
439
+ private void appendPredicate (CriteriaDefinition criteriaDefinition ,
440
+ LordOfTheStrings .CodeBlockBuilder criteriaBuilder ) {
460
441
461
442
CriteriaDefinition .Predicate predicate = criteriaDefinition .getPredicate ();
462
443
@@ -524,42 +505,26 @@ String getParameterName(ParameterBinding binding) {
524
505
throw new UnsupportedOperationException ("Unsupported origin: " + binding .getOrigin ());
525
506
}
526
507
527
- private CodeBlock getParameter (ParameterBinding . ParameterOrigin origin ) {
508
+ private CodeBlock getParameter (ParameterBinding binding ) {
528
509
510
+ ParameterBinding .ParameterOrigin origin = binding .getOrigin ();
529
511
if (origin .isMethodArgument () && origin instanceof ParameterBinding .MethodInvocationArgument mia ) {
530
-
531
- CodeBlock .Builder builder = CodeBlock .builder ();
532
-
533
- builder .add ("potentiallyConvertBindingValue(" );
534
-
535
- if (mia .identifier ().hasPosition ()) {
536
- builder .add ("$L" , context .getRequiredBindableParameterName (mia .identifier ().getPosition ()));
537
- } else if (mia .identifier ().hasName ()) {
538
- builder .add ("$L" , context .getMethodParameter (mia .identifier ().getName ()).getParameterName ());
539
- }
540
- else {
541
- throw new IllegalStateException (
542
- "MethodInvocationArgument '%s' does not define a name or a position" .formatted (mia ));
543
- }
544
- builder .add (")" );
545
-
546
- return builder .build ();
512
+ return CodeBlock .of ("potentiallyConvertBindingValue($L)" , getParameterName (binding ));
547
513
}
548
514
549
515
if (origin .isExpression () && origin instanceof ParameterBinding .Expression expr ) {
550
516
551
- Builder builder = CodeBlock .builder ();
552
-
553
517
String expressionString = expr .expression ().getExpressionString ();
554
518
// re-wrap expression
555
519
if (!expressionString .startsWith ("$" )) {
556
520
expressionString = "#{" + expressionString + "}" ;
557
521
}
558
522
559
- builder .add ("evaluateExpression($L, $S$L)" , context .getExpressionMarker ().enclosingMethod (), expressionString ,
560
- parameterNames );
561
-
562
- return builder .build ();
523
+ return LordOfTheStrings .invoke ("evaluateExpression($L)" )
524
+ .argument (context .getExpressionMarker ().enclosingMethod ()) //
525
+ .argument ("$S" , expressionString ) //
526
+ .arguments (context .getAllParameterNames ()) //
527
+ .build ();
563
528
}
564
529
565
530
throw new UnsupportedOperationException ("Not supported yet for: " + origin );
@@ -598,43 +563,49 @@ QueryExecutionBlockBuilder usingQueryVariableName(String queryVariableName) {
598
563
CodeBlock build () {
599
564
600
565
Builder builder = CodeBlock .builder ();
566
+ MethodReturn methodReturn = context .getMethodReturn ();
601
567
602
568
boolean isProjecting = !query .isCount () && !query .isExists ()
603
- && (context .getReturnedType ().isProjecting ()
604
- && !customConversions .isSimpleType (context .getReturnedType ().getReturnedType ()))
569
+ && (context .getMethodReturn ().isProjecting ()
570
+ && !customConversions .isSimpleType (context .getMethodReturn ().toClass ()))
605
571
|| StringUtils .hasText (context .getDynamicProjectionParameterName ());
606
572
Class <?> domainType = context .getRepositoryInformation ().getDomainType ();
607
573
608
574
builder .add ("\n " );
609
575
610
576
if (query .isDelete ()) {
611
577
578
+ LordOfTheStrings .InvocationBuilder method ;
612
579
if (query instanceof StringAotQuery ) {
613
580
614
- builder . addStatement ( "boolean $1L = $2L .getCqlOperations().execute($3L)" , context . localVariable ( "result" ) ,
581
+ method = LordOfTheStrings . invoke ( "$L .getCqlOperations().execute($L)" ,
615
582
context .fieldNameOf (CassandraOperations .class ), queryVariableName );
616
583
} else {
617
- builder . addStatement ( "boolean $1L = $2L .delete($3L , $4T .class)" , context .localVariable ( "result" ),
618
- context . fieldNameOf ( CassandraOperations . class ), queryVariableName , domainType );
584
+ method = LordOfTheStrings . invoke ( "$L .delete($L , $T .class)" , context .fieldNameOf ( CassandraOperations . class ),
585
+ queryVariableName , domainType );
619
586
}
620
587
621
- if (context .getReturnType ().isAssignableFrom (Boolean .class )
622
- || context .getReturnType ().isAssignableFrom (Boolean .TYPE )) {
623
- builder .addStatement ("return $1L" , context .localVariable ("result" ));
588
+ if (methodReturn .isVoid ()) {
589
+ builder .addStatement (method .build ());
590
+ } else {
591
+ builder .addStatement (method .assignTo ("boolean $L" , context .localVariable ("result" )));
624
592
}
625
593
594
+ builder .addStatement (LordOfTheStrings .returning (methodReturn .toClass ()) //
595
+ .whenBoolean ("$L" , context .localVariable ("result" )) //
596
+ .build ());
597
+
626
598
return builder .build ();
627
599
}
628
600
629
- boolean isInterfaceProjection = context . getActualReturnType (). toClass (). isInterface ();
601
+ boolean isInterfaceProjection = methodReturn . isInterfaceProjection ();
630
602
boolean requiresConversion = false ;
631
603
632
- boolean isMapProjection = Map . class . isAssignableFrom ( context . getActualReturnType (). toClass () );
633
- boolean rawProjection = isMapProjection || ResultSet . class . isAssignableFrom ( context . getReturnType (). toClass () );
604
+ boolean isMapProjection = methodReturn . getActualReturnClass (). equals ( Map . class );
605
+ boolean rawProjection = isMapProjection || methodReturn . toClass (). equals ( ResultSet . class );
634
606
635
- TypeName actualReturnType = isMapProjection
636
- ? TypeName .get (Map .class )
637
- : context .getActualReturnTypeName ();
607
+ TypeName actualReturnType = isMapProjection ? methodReturn .getActualClassName ()
608
+ : TypeNames .typeNameOrWrapper (methodReturn .getActualType ());
638
609
Object asDynamicTypeNameOrProjectionTypeParameter = actualReturnType ;
639
610
640
611
if (StringUtils .hasText (context .getDynamicProjectionParameterName ())) {
@@ -703,54 +674,52 @@ CodeBlock build() {
703
674
} else if (query .isLimited ()) {
704
675
terminatingMethod = "firstValue()" ;
705
676
} else {
706
- terminatingMethod = Optional . class . isAssignableFrom ( context . getReturnType (). toClass ()) ? "one()" : "oneValue()" ;
677
+ terminatingMethod = "oneValue()" ;
707
678
}
708
679
709
680
Builder execution = CodeBlock .builder ();
710
681
711
682
if (queryMethod .isScrollQuery ()) {
712
683
execution .add ("$T.of($L.$L)" , WindowUtil .class , context .localVariable ("select" ), terminatingMethod );
713
- } else if (context . getReturnType () .isArray ()) {
684
+ } else if (methodReturn .isArray ()) {
714
685
execution .add ("$L.$L.toArray(new $T[0])" , context .localVariable ("select" ), terminatingMethod ,
715
- context . getActualReturnTypeName ());
686
+ methodReturn . getActualClassName ());
716
687
} else {
717
688
718
689
if (rawProjection && isMapProjection ) {
719
- execution .add ("($T) $L.$L" , context . getReturnType (). toClass (), context .localVariable ("select" ),
690
+ execution .add ("($T) $L.$L" , methodReturn . getClassName (), context .localVariable ("select" ),
720
691
terminatingMethod );
721
692
} else {
722
693
execution .add ("$L.$L" , context .localVariable ("select" ), terminatingMethod );
723
694
}
724
695
}
725
696
697
+ LordOfTheStrings .TypedReturnBuilder returnBuilder = LordOfTheStrings .returning (methodReturn .toClass ());
726
698
if (requiresConversion ) {
727
699
728
- if (Optional .class .isAssignableFrom (context .getReturnType ().toClass ())) {
729
- builder .addStatement ("return ($T) $T.ofNullable(convertOne($L, $T.class))" , context .getReturnTypeName (),
730
- Optional .class , execution .build (), actualReturnType );
731
- } else {
732
-
733
- String conversionMethod ;
734
-
735
- if (queryMethod .isCollectionQuery () || queryMethod .isPageQuery () || queryMethod .isSliceQuery ()
736
- || queryMethod .isStreamQuery ()) {
737
- conversionMethod = "convertMany" ;
738
- } else {
739
- conversionMethod = "convertOne" ;
740
- }
700
+ String conversionMethod ;
741
701
742
- builder .addStatement ("return ($T) $L($L, $T.class)" , context .getReturnTypeName (), conversionMethod ,
743
- execution .build (), actualReturnType );
702
+ if (queryMethod .isCollectionQuery () || queryMethod .isPageQuery () || queryMethod .isSliceQuery ()
703
+ || queryMethod .isStreamQuery ()) {
704
+ conversionMethod = "convertMany" ;
705
+ } else {
706
+ conversionMethod = "convertOne" ;
744
707
}
745
708
709
+ builder .addStatement (returnBuilder //
710
+ .optional ("($T) $L($L, $T.class)" , methodReturn .getTypeName (), conversionMethod , execution .build (),
711
+ actualReturnType ) //
712
+ .build ());
746
713
} else {
747
714
748
- if (query .isCount () && (context .getReturnType ().isAssignableFrom (Integer .class )
749
- || context .getReturnType ().isAssignableFrom (int .class ))) {
750
- builder .addStatement ("return (int) $L" , execution .build ());
751
- } else {
752
- builder .addStatement ("return $L" , execution .build ());
715
+ CodeBlock executionBlock = execution .build ();
716
+
717
+ if (query .isCount ()) {
718
+ returnBuilder .whenPrimitiveOrBoxed (Integer .class , "(int) $L" , executionBlock );
753
719
}
720
+
721
+ builder .addStatement (returnBuilder .optional (executionBlock ) //
722
+ .build ());
754
723
}
755
724
756
725
return builder .build ();
0 commit comments