26
26
import java .util .Arrays ;
27
27
import java .util .Collection ;
28
28
import java .util .HashMap ;
29
+ import java .util .HashSet ;
29
30
import java .util .List ;
30
31
import java .util .Map ;
31
32
import java .util .Set ;
47
48
import org .springframework .data .repository .query .ResultProcessor ;
48
49
import org .springframework .data .repository .query .ReturnedType ;
49
50
import org .springframework .data .util .Lazy ;
51
+ import org .springframework .jdbc .support .JdbcUtils ;
50
52
import org .springframework .lang .Nullable ;
51
53
import org .springframework .util .Assert ;
52
54
62
64
* @author Сергей Цыпанов
63
65
* @author Wonchul Heo
64
66
* @author Julia Lee
67
+ * @author Yanming Zhou
65
68
*/
66
69
public abstract class AbstractJpaQuery implements RepositoryQuery {
67
70
@@ -149,7 +152,7 @@ private Object doExecute(JpaQueryExecution execution, Object[] values) {
149
152
Object result = execution .execute (this , accessor );
150
153
151
154
ResultProcessor withDynamicProjection = method .getResultProcessor ().withDynamicProjection (accessor );
152
- return withDynamicProjection .processResult (result , new TupleConverter (withDynamicProjection .getReturnedType ()));
155
+ return withDynamicProjection .processResult (result , new TupleConverter (withDynamicProjection .getReturnedType (), method . isNativeQuery () ));
153
156
}
154
157
155
158
private JpaParametersParameterAccessor obtainParameterAccessor (Object [] values ) {
@@ -304,16 +307,30 @@ static class TupleConverter implements Converter<Object, Object> {
304
307
305
308
private final ReturnedType type ;
306
309
310
+ private final boolean nativeQuery ;
311
+
307
312
/**
308
313
* Creates a new {@link TupleConverter} for the given {@link ReturnedType}.
309
314
*
310
315
* @param type must not be {@literal null}.
311
316
*/
312
317
public TupleConverter (ReturnedType type ) {
313
318
319
+ this (type , false );
320
+ }
321
+
322
+ /**
323
+ * Creates a new {@link TupleConverter} for the given {@link ReturnedType}.
324
+ *
325
+ * @param type must not be {@literal null}.
326
+ * @param nativeQuery is this converter for native query?
327
+ */
328
+ public TupleConverter (ReturnedType type , boolean nativeQuery ) {
329
+
314
330
Assert .notNull (type , "Returned type must not be null" );
315
331
316
332
this .type = type ;
333
+ this .nativeQuery = nativeQuery ;
317
334
}
318
335
319
336
@ Override
@@ -334,7 +351,7 @@ public Object convert(Object source) {
334
351
}
335
352
}
336
353
337
- return new TupleBackedMap (tuple );
354
+ return new TupleBackedMap (tuple , nativeQuery );
338
355
}
339
356
340
357
/**
@@ -350,12 +367,20 @@ private static class TupleBackedMap implements Map<String, Object> {
350
367
351
368
private final Tuple tuple ;
352
369
353
- TupleBackedMap (Tuple tuple ) {
370
+ private final boolean nativeQuery ;
371
+
372
+ TupleBackedMap (Tuple tuple , boolean nativeQuery ) {
354
373
this .tuple = tuple ;
374
+ this .nativeQuery = nativeQuery ;
355
375
}
356
376
357
377
@ Override
358
378
public int size () {
379
+
380
+ if (nativeQuery ) {
381
+ return keySet ().size ();
382
+ }
383
+
359
384
return tuple .getElements ().size ();
360
385
}
361
386
@@ -378,6 +403,14 @@ public boolean containsKey(Object key) {
378
403
tuple .get ((String ) key );
379
404
return true ;
380
405
} catch (IllegalArgumentException e ) {
406
+ if (nativeQuery ) {
407
+ try {
408
+ tuple .get (JdbcUtils .convertPropertyNameToUnderscoreName ((String ) key ));
409
+ return true ;
410
+ } catch (IllegalArgumentException ignored ) {
411
+ return false ;
412
+ }
413
+ }
381
414
return false ;
382
415
}
383
416
}
@@ -405,6 +438,13 @@ public Object get(Object key) {
405
438
try {
406
439
return tuple .get ((String ) key );
407
440
} catch (IllegalArgumentException e ) {
441
+ if (nativeQuery ) {
442
+ try {
443
+ return tuple .get (JdbcUtils .convertPropertyNameToUnderscoreName ((String ) key ));
444
+ } catch (IllegalArgumentException ignored ) {
445
+ return null ;
446
+ }
447
+ }
408
448
return null ;
409
449
}
410
450
}
@@ -432,19 +472,40 @@ public void clear() {
432
472
@ Override
433
473
public Set <String > keySet () {
434
474
435
- return tuple .getElements ().stream () //
475
+ Set < String > keys = tuple .getElements ().stream () //
436
476
.map (TupleElement ::getAlias ) //
437
477
.collect (Collectors .toSet ());
478
+
479
+ if (nativeQuery ) {
480
+ Set <String > camelCasedKeys = keys .stream () //
481
+ .map (JdbcUtils ::convertUnderscoreNameToPropertyName ) //
482
+ .collect (Collectors .toSet ());
483
+ keys = new HashSet <>(keys );
484
+ keys .addAll (camelCasedKeys );
485
+ }
486
+
487
+ return keys ;
438
488
}
439
489
440
490
@ Override
441
491
public Collection <Object > values () {
492
+
493
+ if (nativeQuery ) {
494
+ return keySet ().stream ().map (this ::get ).collect (Collectors .toList ());
495
+ }
496
+
442
497
return Arrays .asList (tuple .toArray ());
443
498
}
444
499
445
500
@ Override
446
501
public Set <Entry <String , Object >> entrySet () {
447
502
503
+ if (nativeQuery ) {
504
+ return keySet ().stream () //
505
+ .map (e -> new HashMap .SimpleEntry <>(e , get (e ))) //
506
+ .collect (Collectors .toSet ());
507
+ }
508
+
448
509
return tuple .getElements ().stream () //
449
510
.map (e -> new HashMap .SimpleEntry <String , Object >(e .getAlias (), tuple .get (e ))) //
450
511
.collect (Collectors .toSet ());
0 commit comments