21
21
package org .influxdb .impl ;
22
22
23
23
import java .lang .reflect .Field ;
24
+ import java .lang .reflect .InvocationTargetException ;
25
+ import java .lang .reflect .Method ;
24
26
import java .time .Instant ;
25
27
import java .time .format .DateTimeFormatter ;
26
28
import java .time .format .DateTimeFormatterBuilder ;
@@ -51,6 +53,8 @@ public class InfluxDBResultMapper {
51
53
private static final
52
54
ConcurrentMap <String , ConcurrentMap <String , Field >> CLASS_FIELD_CACHE = new ConcurrentHashMap <>();
53
55
56
+ private static final ConcurrentMap <String , ConcurrentMap <String , Method >> CLASS_SETTERS_CACHE = new ConcurrentHashMap <>();
57
+
54
58
private static final int FRACTION_MIN_WIDTH = 0 ;
55
59
private static final int FRACTION_MAX_WIDTH = 9 ;
56
60
private static final boolean ADD_DECIMAL_POINT = true ;
@@ -217,11 +221,25 @@ void cacheMeasurementClass(final Class<?>... classVarAgrs) {
217
221
influxColumnAndFieldMap = initialMap ;
218
222
}
219
223
224
+ ConcurrentMap <String , Method > classFieldSetters = new ConcurrentHashMap <>();
225
+ ConcurrentMap <String , Method > fieldSetters = CLASS_SETTERS_CACHE .putIfAbsent (clazz .getName (), classFieldSetters );
226
+ if (fieldSetters == null ) {
227
+ fieldSetters = classFieldSetters ;
228
+ }
229
+
220
230
Class <?> c = clazz ;
221
231
while (c != null ) {
222
232
for (Field field : c .getDeclaredFields ()) {
223
233
Column colAnnotation = field .getAnnotation (Column .class );
224
234
if (colAnnotation != null ) {
235
+ String fieldName = field .getName ();
236
+ String setterName = "set" .concat (fieldName .substring (0 ,1 ).toUpperCase ().concat (fieldName .substring (1 )));
237
+ try {
238
+ Method setter = c .getDeclaredMethod (setterName , field .getType ());
239
+ fieldSetters .put (colAnnotation .name (), setter );
240
+ } catch (NoSuchMethodException e ) {
241
+ //sj_todo ignore? maybe print a warning that no setter found?
242
+ }
225
243
influxColumnAndFieldMap .put (colAnnotation .name (), field );
226
244
}
227
245
}
@@ -254,16 +272,18 @@ <T> List<T> parseSeriesAs(final QueryResult.Series series, final Class<T> clazz,
254
272
final TimeUnit precision ) {
255
273
int columnSize = series .getColumns ().size ();
256
274
ConcurrentMap <String , Field > colNameAndFieldMap = CLASS_FIELD_CACHE .get (clazz .getName ());
275
+ ConcurrentMap <String , Method > fieldSettersMap = CLASS_SETTERS_CACHE .get (clazz .getName ());
257
276
try {
258
277
T object = null ;
259
278
for (List <Object > row : series .getValues ()) {
260
279
for (int i = 0 ; i < columnSize ; i ++) {
280
+ Method fieldSetter = fieldSettersMap .get (series .getColumns ().get (i ));
261
281
Field correspondingField = colNameAndFieldMap .get (series .getColumns ().get (i )/*InfluxDB columnName*/ );
262
- if (correspondingField != null ) {
282
+ if (correspondingField != null || fieldSetter != null ) {
263
283
if (object == null ) {
264
284
object = clazz .newInstance ();
265
285
}
266
- setFieldValue (object , correspondingField , row .get (i ), precision );
286
+ setFieldValue (object , correspondingField , fieldSetter , row .get (i ), precision );
267
287
}
268
288
}
269
289
// When the "GROUP BY" clause is used, "tags" are returned as Map<String,String> and
@@ -273,9 +293,10 @@ <T> List<T> parseSeriesAs(final QueryResult.Series series, final Class<T> clazz,
273
293
if (series .getTags () != null && !series .getTags ().isEmpty ()) {
274
294
for (Entry <String , String > entry : series .getTags ().entrySet ()) {
275
295
Field correspondingField = colNameAndFieldMap .get (entry .getKey ()/*InfluxDB columnName*/ );
276
- if (correspondingField != null ) {
296
+ Method fieldSetter = fieldSettersMap .get (entry .getKey ());
297
+ if (correspondingField != null || fieldSetter != null ) {
277
298
// I don't think it is possible to reach here without a valid "object"
278
- setFieldValue (object , correspondingField , entry .getValue (), precision );
299
+ setFieldValue (object , correspondingField , fieldSetter , entry .getValue (), precision );
279
300
}
280
301
}
281
302
}
@@ -284,7 +305,7 @@ <T> List<T> parseSeriesAs(final QueryResult.Series series, final Class<T> clazz,
284
305
object = null ;
285
306
}
286
307
}
287
- } catch (InstantiationException | IllegalAccessException e ) {
308
+ } catch (InstantiationException | IllegalAccessException | InvocationTargetException e ) {
288
309
throw new InfluxDBMapperException (e );
289
310
}
290
311
return result ;
@@ -302,8 +323,8 @@ <T> List<T> parseSeriesAs(final QueryResult.Series series, final Class<T> clazz,
302
323
* @throws IllegalArgumentException
303
324
* @throws IllegalAccessException
304
325
*/
305
- <T > void setFieldValue (final T object , final Field field , final Object value , final TimeUnit precision )
306
- throws IllegalArgumentException , IllegalAccessException {
326
+ <T > void setFieldValue (final T object , final Field field , final Method fieldSetter , final Object value , final TimeUnit precision )
327
+ throws IllegalArgumentException , IllegalAccessException , InvocationTargetException {
307
328
if (value == null ) {
308
329
return ;
309
330
}
@@ -312,9 +333,15 @@ <T> void setFieldValue(final T object, final Field field, final Object value, fi
312
333
if (!field .isAccessible ()) {
313
334
field .setAccessible (true );
314
335
}
315
- if (fieldValueModified (fieldType , field , object , value , precision )
316
- || fieldValueForPrimitivesModified (fieldType , field , object , value )
317
- || fieldValueForPrimitiveWrappersModified (fieldType , field , object , value )) {
336
+ if (!fieldSetter .isAccessible ()) {
337
+ fieldSetter .setAccessible (true );
338
+ }
339
+ if (assignInstant (fieldType , field , fieldSetter , object , value , precision )
340
+ || assignString (fieldType , field , fieldSetter , object , value )
341
+ || assignDouble (fieldType , field , fieldSetter , object , value )
342
+ || assignInteger (fieldType , field , fieldSetter , object , value )
343
+ || assignLong (fieldType , field , fieldSetter , object , value )
344
+ || assignBoolean (fieldType , field , fieldSetter , object , value )) {
318
345
return ;
319
346
}
320
347
String msg = "Class '%s' field '%s' is from an unsupported type '%s'." ;
@@ -328,14 +355,9 @@ <T> void setFieldValue(final T object, final Field field, final Object value, fi
328
355
}
329
356
}
330
357
331
- <T > boolean fieldValueModified (final Class <?> fieldType , final Field field , final T object , final Object value ,
332
- final TimeUnit precision )
333
- throws IllegalArgumentException , IllegalAccessException {
334
- if (String .class .isAssignableFrom (fieldType )) {
335
- field .set (object , String .valueOf (value ));
336
- return true ;
337
- }
338
- if (Instant .class .isAssignableFrom (fieldType )) {
358
+ <T > boolean assignInstant (final Class <?> fieldType , final Field field , final Method fieldSetter , final T object , final Object value , final TimeUnit precision ) throws InvocationTargetException , IllegalAccessException {
359
+ boolean isInstantAssigned = false ;
360
+ if (Instant .class .isAssignableFrom (fieldType )) {
339
361
Instant instant ;
340
362
if (value instanceof String ) {
341
363
instant = Instant .from (RFC3339_FORMATTER .parse (String .valueOf (value )));
@@ -348,52 +370,102 @@ <T> boolean fieldValueModified(final Class<?> fieldType, final Field field, fina
348
370
} else {
349
371
throw new InfluxDBMapperException ("Unsupported type " + field .getClass () + " for field " + field .getName ());
350
372
}
351
- field .set (object , instant );
352
- return true ;
373
+ if (fieldSetter != null && fieldSetter .isAccessible ()) {
374
+ fieldSetter .invoke (object , instant );
375
+ isInstantAssigned = true ;
376
+ } else {
377
+ field .set (object , instant );
378
+ isInstantAssigned = true ;
379
+ }
353
380
}
354
- return false ;
381
+ return isInstantAssigned ;
355
382
}
356
383
357
- <T > boolean fieldValueForPrimitivesModified (final Class <?> fieldType , final Field field , final T object ,
358
- final Object value ) throws IllegalArgumentException , IllegalAccessException {
359
- if (double .class .isAssignableFrom (fieldType )) {
360
- field .setDouble (object , ((Double ) value ).doubleValue ());
361
- return true ;
362
- }
363
- if (long .class .isAssignableFrom (fieldType )) {
364
- field .setLong (object , ((Double ) value ).longValue ());
365
- return true ;
366
- }
367
- if (int .class .isAssignableFrom (fieldType )) {
368
- field .setInt (object , ((Double ) value ).intValue ());
369
- return true ;
370
- }
371
- if (boolean .class .isAssignableFrom (fieldType )) {
372
- field .setBoolean (object , Boolean .valueOf (String .valueOf (value )).booleanValue ());
373
- return true ;
384
+ <T > boolean assignString (final Class <?> fieldType , final Field field , final Method fieldSetter , final T object , final Object value ) throws InvocationTargetException , IllegalAccessException {
385
+ boolean isStringAssigned = false ;
386
+ if (String .class .isAssignableFrom (fieldType )) {
387
+ final String stringValue = String .valueOf (value );
388
+ if (fieldSetter != null && fieldSetter .isAccessible ()) {
389
+ fieldSetter .invoke (object , stringValue );
390
+ isStringAssigned = true ;
391
+ } else {
392
+ field .set (object , stringValue );
393
+ isStringAssigned = true ;
394
+ }
374
395
}
375
- return false ;
396
+ return isStringAssigned ;
376
397
}
377
398
378
- <T > boolean fieldValueForPrimitiveWrappersModified (final Class <?> fieldType , final Field field , final T object ,
379
- final Object value ) throws IllegalArgumentException , IllegalAccessException {
380
- if (Double .class .isAssignableFrom (fieldType )) {
381
- field .set (object , value );
382
- return true ;
399
+ <T > boolean assignDouble (final Class <?> fieldType , final Field field , final Method fieldSetter , final T object , final Object value ) throws InvocationTargetException , IllegalAccessException {
400
+ boolean isDoubleAssigned = false ;
401
+ if (double .class .isAssignableFrom (fieldType ) || Double .class .isAssignableFrom (fieldType )) {
402
+ if (fieldSetter != null && fieldSetter .isAccessible ()) {
403
+ fieldSetter .invoke (object , value );
404
+ isDoubleAssigned = true ;
405
+ } else if (double .class .isAssignableFrom (fieldType )) {
406
+ final double doubleValue = (Double ) value ;
407
+ field .setDouble (object , doubleValue );
408
+ isDoubleAssigned = true ;
409
+ } else if (Double .class .isAssignableFrom (fieldType )) {
410
+ field .set (object , value );
411
+ isDoubleAssigned = true ;
412
+ }
383
413
}
384
- if (Long .class .isAssignableFrom (fieldType )) {
385
- field .set (object , Long .valueOf (((Double ) value ).longValue ()));
386
- return true ;
414
+ return isDoubleAssigned ;
415
+ }
416
+
417
+ <T > boolean assignLong (final Class <?> fieldType , final Field field , final Method fieldSetter , final T object , final Object value ) throws InvocationTargetException , IllegalAccessException {
418
+ boolean isLongAssigned = false ;
419
+ if (long .class .isAssignableFrom (fieldType ) || Long .class .isAssignableFrom (fieldType )) {
420
+ final long longValue = ((Double ) value ).longValue ();
421
+ if (fieldSetter != null && fieldSetter .isAccessible ()) {
422
+ fieldSetter .invoke (object , longValue );
423
+ isLongAssigned = true ;
424
+ } else if (long .class .isAssignableFrom (fieldType )) {
425
+ field .setLong (object , longValue );
426
+ isLongAssigned = true ;
427
+ } else if (Long .class .isAssignableFrom (fieldType )) {
428
+ field .set (object , longValue );
429
+ isLongAssigned = true ;
430
+ }
387
431
}
388
- if (Integer .class .isAssignableFrom (fieldType )) {
389
- field .set (object , Integer .valueOf (((Double ) value ).intValue ()));
390
- return true ;
432
+ return isLongAssigned ;
433
+ }
434
+
435
+ <T > boolean assignInteger (final Class <?> fieldType , final Field field , final Method fieldSetter , final T object , final Object value ) throws InvocationTargetException , IllegalAccessException {
436
+ boolean isIntegerAssigned = false ;
437
+ if (int .class .isAssignableFrom (fieldType ) || Integer .class .isAssignableFrom (fieldType )) {
438
+ final int intValue = ((Double ) value ).intValue ();
439
+ if (fieldSetter != null && fieldSetter .isAccessible ()) {
440
+ fieldSetter .invoke (object , intValue );
441
+ isIntegerAssigned = true ;
442
+ } else if (int .class .isAssignableFrom (fieldType )) {
443
+ field .setInt (object , intValue );
444
+ isIntegerAssigned = true ;
445
+ } else if (Integer .class .isAssignableFrom (fieldType )) {
446
+ field .set (object , intValue );
447
+ isIntegerAssigned = true ;
448
+ }
391
449
}
392
- if (Boolean .class .isAssignableFrom (fieldType )) {
393
- field .set (object , Boolean .valueOf (String .valueOf (value )));
394
- return true ;
450
+ return isIntegerAssigned ;
451
+ }
452
+
453
+ <T > boolean assignBoolean (final Class <?> fieldType , final Field field , final Method fieldSetter , final T object , final Object value ) throws InvocationTargetException , IllegalAccessException {
454
+ boolean isBooleanAssigned = false ;
455
+ if (boolean .class .isAssignableFrom (fieldType ) || Boolean .class .isAssignableFrom (fieldType )) {
456
+ final boolean boolValue = Boolean .parseBoolean (String .valueOf (value ));
457
+ if (fieldSetter != null && fieldSetter .isAccessible ()) {
458
+ fieldSetter .invoke (object , boolValue );
459
+ isBooleanAssigned = true ;
460
+ } else if (boolean .class .isAssignableFrom (fieldType )) {
461
+ field .setBoolean (object , boolValue );
462
+ isBooleanAssigned = true ;
463
+ } else if (Boolean .class .isAssignableFrom (fieldType )) {
464
+ field .set (object , boolValue );
465
+ isBooleanAssigned = true ;
466
+ }
395
467
}
396
- return false ;
468
+ return isBooleanAssigned ;
397
469
}
398
470
399
471
private Long toMillis (final long value , final TimeUnit precision ) {
0 commit comments