2323import org .jspecify .annotations .Nullable ;
2424
2525import org .springframework .core .annotation .MergedAnnotation ;
26+ import org .springframework .core .convert .TypeDescriptor ;
27+ import org .springframework .core .convert .support .DefaultConversionService ;
2628import org .springframework .data .cassandra .core .CassandraOperations ;
2729import org .springframework .data .cassandra .core .ExecutableSelectOperation ;
2830import org .springframework .data .cassandra .core .cql .QueryOptions ;
@@ -718,13 +720,29 @@ CodeBlock build() {
718720
719721 if (streamableResult && Collection .class .isAssignableFrom (methodReturn .toClass ())) {
720722 result = CodeBlock .of ("$L.getContent()" , result );
721- } else if (!streamableResult && methodReturn . toClass (). equals ( Streamable . class )) {
723+ } else if (!streamableResult && ( isStreamable ( methodReturn ) || isStreamableWrapper ( methodReturn ) )) {
722724 result = CodeBlock .of ("$T.of(($T) $L)" , Streamable .class , Iterable .class , result );
723725 }
724726
725- builder .addStatement (returnBuilder //
727+ if (isStreamableWrapper (methodReturn ) && canConvert (Streamable .class , methodReturn )) {
728+
729+ Builder wrapperBuilder = CodeBlock .builder ();
730+
731+ builder .addStatement ("$1T<$2T> $3L = $4L" , Streamable .class , actualReturnType ,
732+ context .localVariable ("streamable" ), result );
733+
734+ builder .addStatement (
735+ "return ($1T) $2T.getSharedInstance().convert($3L, $4T.valueOf($5T.class), $4T.valueOf($6T.class))" ,
736+ methodReturn .getTypeName (), DefaultConversionService .class , context .localVariable ("streamable" ),
737+ TypeDescriptor .class , Streamable .class , methodReturn .toClass ());
738+
739+ builder .add (wrapperBuilder .build ());
740+ } else {
741+
742+ builder .addStatement (returnBuilder //
726743 .optional ("($T) $L" , methodReturn .getTypeName (), result ) //
727744 .build ());
745+ }
728746 } else {
729747
730748 CodeBlock executionBlock = execution .build ();
@@ -733,16 +751,40 @@ CodeBlock build() {
733751 returnBuilder .whenPrimitiveOrBoxed (Integer .class , "(int) $L" , executionBlock );
734752 } else if (streamableResult && Collection .class .isAssignableFrom (methodReturn .toClass ())) {
735753 executionBlock = CodeBlock .of ("$L.getContent()" , executionBlock );
736- } else if (!streamableResult && methodReturn . toClass (). equals ( Streamable . class )) {
754+ } else if (!streamableResult && ( isStreamable ( methodReturn ) || isStreamableWrapper ( methodReturn ) )) {
737755 executionBlock = CodeBlock .of ("$T.of($L)" , Streamable .class , executionBlock );
738756 }
739757
740- builder .addStatement (returnBuilder .optional (executionBlock ) //
758+ if (isStreamableWrapper (methodReturn ) && canConvert (Streamable .class , methodReturn )) {
759+
760+ builder .addStatement ("$1T<$2T> $3L = $4L" , Streamable .class , actualReturnType ,
761+ context .localVariable ("streamable" ), executionBlock );
762+
763+ builder .addStatement (
764+ "return ($1T) $2T.getSharedInstance().convert($3L, $4T.valueOf($5T.class), $4T.valueOf($6T.class))" ,
765+ methodReturn .getTypeName (), DefaultConversionService .class , context .localVariable ("streamable" ),
766+ TypeDescriptor .class , Streamable .class , methodReturn .toClass ());
767+ } else {
768+
769+ builder .addStatement (returnBuilder .optional (executionBlock ) //
741770 .build ());
771+ }
742772 }
743773
744774 return builder .build ();
745775 }
776+
777+ private boolean canConvert (Class <?> from , MethodReturn methodReturn ) {
778+ return DefaultConversionService .getSharedInstance ().canConvert (from , methodReturn .toClass ());
779+ }
780+
781+ private static boolean isStreamable (MethodReturn methodReturn ) {
782+ return methodReturn .toClass ().equals (Streamable .class );
783+ }
784+
785+ private static boolean isStreamableWrapper (MethodReturn methodReturn ) {
786+ return !isStreamable (methodReturn ) && Streamable .class .isAssignableFrom (methodReturn .toClass ());
787+ }
746788 }
747789
748790}
0 commit comments