1717
1818import jakarta .persistence .Tuple ;
1919
20+ import java .lang .reflect .Array ;
2021import java .lang .reflect .Method ;
22+ import java .util .ArrayList ;
2123import java .util .Collection ;
24+ import java .util .Optional ;
25+ import java .util .function .UnaryOperator ;
2226import java .util .stream .Stream ;
2327
2428import org .jspecify .annotations .Nullable ;
2529
2630import org .springframework .core .CollectionFactory ;
31+ import org .springframework .core .convert .ConversionService ;
32+ import org .springframework .core .convert .support .ConfigurableConversionService ;
33+ import org .springframework .core .convert .support .DefaultConversionService ;
2734import org .springframework .data .domain .Slice ;
2835import org .springframework .data .domain .Sort ;
2936import org .springframework .data .expression .ValueEvaluationContextProvider ;
3037import org .springframework .data .expression .ValueExpression ;
3138import org .springframework .data .jpa .repository .query .DeclaredQuery ;
3239import org .springframework .data .jpa .repository .query .JpaParameters ;
40+ import org .springframework .data .jpa .repository .query .JpaResultConverters ;
3341import org .springframework .data .jpa .repository .query .QueryEnhancer ;
3442import org .springframework .data .jpa .repository .query .QueryEnhancerSelector ;
3543import org .springframework .data .jpa .util .TupleBackedMap ;
5058 */
5159public class AotRepositoryFragmentSupport {
5260
61+ private static final ConversionService CONVERSION_SERVICE ;
62+
63+ static {
64+
65+ ConfigurableConversionService conversionService = new DefaultConversionService ();
66+
67+ conversionService .addConverter (JpaResultConverters .BlobToByteArrayConverter .INSTANCE );
68+ conversionService .removeConvertible (Collection .class , Object .class );
69+ conversionService .removeConvertible (Object .class , Optional .class );
70+
71+ CONVERSION_SERVICE = conversionService ;
72+ }
73+
5374 private final RepositoryMetadata repositoryMetadata ;
5475
5576 private final ValueExpressionDelegate valueExpressions ;
@@ -111,6 +132,41 @@ protected String rewriteQuery(DeclaredQuery query, Sort sort, Class<?> returnedT
111132 return expression .evaluate (contextProvider .getEvaluationContext (args , expression .getExpressionDependencies ()));
112133 }
113134
135+ protected @ Nullable Object mapIgnoreCase (@ Nullable Object source , UnaryOperator <String > mapper ) {
136+
137+ if (source == null ) {
138+ return null ;
139+ }
140+
141+ if (source .getClass ().isArray ()) {
142+ int length = Array .getLength (source );
143+ Collection <Object > result = new ArrayList <>(length );
144+
145+ for (int i = 0 ; i < length ; i ++) {
146+ result .add (Array .get (source , i ));
147+ }
148+ source = result ;
149+ }
150+
151+ if (source instanceof Collection <?> c ) {
152+
153+ Collection <@ Nullable Object > result = new ArrayList <>(c .size ());
154+
155+ for (Object o : c ) {
156+
157+ if (o instanceof String s ) {
158+ result .add (mapper .apply (s ));
159+ } else {
160+ result .add (o != null ? mapper .apply (o .toString ()) : null );
161+ }
162+ }
163+
164+ return result ;
165+ }
166+
167+ return source ;
168+ }
169+
114170 protected <T > @ Nullable T convertOne (@ Nullable Object result , boolean nativeQuery , Class <T > projection ) {
115171
116172 if (result == null ) {
@@ -121,6 +177,10 @@ protected String rewriteQuery(DeclaredQuery query, Sort sort, Class<?> returnedT
121177 return projection .cast (result );
122178 }
123179
180+ if (CONVERSION_SERVICE .canConvert (result .getClass (), projection )) {
181+ return CONVERSION_SERVICE .convert (result , projection );
182+ }
183+
124184 return projectionFactory .createProjection (projection ,
125185 result instanceof Tuple t ? new TupleBackedMap (nativeQuery ? TupleBackedMap .underscoreAware (t ) : t ) : result );
126186 }
0 commit comments