17
17
18
18
import jakarta .persistence .Tuple ;
19
19
20
+ import java .lang .reflect .Array ;
20
21
import java .lang .reflect .Method ;
22
+ import java .util .ArrayList ;
21
23
import java .util .Collection ;
24
+ import java .util .Optional ;
25
+ import java .util .function .UnaryOperator ;
22
26
import java .util .stream .Stream ;
23
27
24
28
import org .jspecify .annotations .Nullable ;
25
29
26
30
import 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 ;
27
34
import org .springframework .data .domain .Slice ;
28
35
import org .springframework .data .domain .Sort ;
29
36
import org .springframework .data .expression .ValueEvaluationContextProvider ;
30
37
import org .springframework .data .expression .ValueExpression ;
31
38
import org .springframework .data .jpa .repository .query .DeclaredQuery ;
32
39
import org .springframework .data .jpa .repository .query .JpaParameters ;
40
+ import org .springframework .data .jpa .repository .query .JpaResultConverters ;
33
41
import org .springframework .data .jpa .repository .query .QueryEnhancer ;
34
42
import org .springframework .data .jpa .repository .query .QueryEnhancerSelector ;
35
43
import org .springframework .data .jpa .util .TupleBackedMap ;
50
58
*/
51
59
public class AotRepositoryFragmentSupport {
52
60
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
+
53
74
private final RepositoryMetadata repositoryMetadata ;
54
75
55
76
private final ValueExpressionDelegate valueExpressions ;
@@ -111,6 +132,41 @@ protected String rewriteQuery(DeclaredQuery query, Sort sort, Class<?> returnedT
111
132
return expression .evaluate (contextProvider .getEvaluationContext (args , expression .getExpressionDependencies ()));
112
133
}
113
134
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
+
114
170
protected <T > @ Nullable T convertOne (@ Nullable Object result , boolean nativeQuery , Class <T > projection ) {
115
171
116
172
if (result == null ) {
@@ -121,6 +177,10 @@ protected String rewriteQuery(DeclaredQuery query, Sort sort, Class<?> returnedT
121
177
return projection .cast (result );
122
178
}
123
179
180
+ if (CONVERSION_SERVICE .canConvert (result .getClass (), projection )) {
181
+ return CONVERSION_SERVICE .convert (result , projection );
182
+ }
183
+
124
184
return projectionFactory .createProjection (projection ,
125
185
result instanceof Tuple t ? new TupleBackedMap (nativeQuery ? TupleBackedMap .underscoreAware (t ) : t ) : result );
126
186
}
0 commit comments