diff --git a/src/main/java/org/influxdb/impl/InfluxDBResultMapper.java b/src/main/java/org/influxdb/impl/InfluxDBResultMapper.java index c94d848bf..2c3e05ff0 100644 --- a/src/main/java/org/influxdb/impl/InfluxDBResultMapper.java +++ b/src/main/java/org/influxdb/impl/InfluxDBResultMapper.java @@ -21,6 +21,8 @@ package org.influxdb.impl; import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.time.Instant; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; @@ -51,6 +53,9 @@ public class InfluxDBResultMapper { private static final ConcurrentMap> CLASS_FIELD_CACHE = new ConcurrentHashMap<>(); + private static final + ConcurrentMap> CLASS_SETTERS_CACHE = new ConcurrentHashMap<>(); + private static final int FRACTION_MIN_WIDTH = 0; private static final int FRACTION_MAX_WIDTH = 9; private static final boolean ADD_DECIMAL_POINT = true; @@ -217,11 +222,25 @@ void cacheMeasurementClass(final Class... classVarAgrs) { influxColumnAndFieldMap = initialMap; } + ConcurrentMap classFieldSetters = new ConcurrentHashMap<>(); + ConcurrentMap fieldSetters = CLASS_SETTERS_CACHE.putIfAbsent(clazz.getName(), classFieldSetters); + if (fieldSetters == null) { + fieldSetters = classFieldSetters; + } + Class c = clazz; while (c != null) { for (Field field : c.getDeclaredFields()) { Column colAnnotation = field.getAnnotation(Column.class); if (colAnnotation != null) { + String fieldName = field.getName(); + String setterName = "set".concat(fieldName.substring(0, 1).toUpperCase().concat(fieldName.substring(1))); + try { + Method setter = c.getDeclaredMethod(setterName, field.getType()); + fieldSetters.put(colAnnotation.name(), setter); + } catch (NoSuchMethodException e) { + //sj_todo ignore? maybe print a warning that no setter found? + } influxColumnAndFieldMap.put(colAnnotation.name(), field); } } @@ -254,16 +273,18 @@ List parseSeriesAs(final QueryResult.Series series, final Class clazz, final TimeUnit precision) { int columnSize = series.getColumns().size(); ConcurrentMap colNameAndFieldMap = CLASS_FIELD_CACHE.get(clazz.getName()); + ConcurrentMap fieldSettersMap = CLASS_SETTERS_CACHE.get(clazz.getName()); try { T object = null; for (List row : series.getValues()) { for (int i = 0; i < columnSize; i++) { + Method fieldSetter = fieldSettersMap.get(series.getColumns().get(i)); Field correspondingField = colNameAndFieldMap.get(series.getColumns().get(i)/*InfluxDB columnName*/); - if (correspondingField != null) { + if (correspondingField != null || fieldSetter != null) { if (object == null) { object = clazz.newInstance(); } - setFieldValue(object, correspondingField, row.get(i), precision); + setFieldValue(object, correspondingField, fieldSetter, row.get(i), precision); } } // When the "GROUP BY" clause is used, "tags" are returned as Map and @@ -273,9 +294,10 @@ List parseSeriesAs(final QueryResult.Series series, final Class clazz, if (series.getTags() != null && !series.getTags().isEmpty()) { for (Entry entry : series.getTags().entrySet()) { Field correspondingField = colNameAndFieldMap.get(entry.getKey()/*InfluxDB columnName*/); - if (correspondingField != null) { + Method fieldSetter = fieldSettersMap.get(entry.getKey()); + if (correspondingField != null || fieldSetter != null) { // I don't think it is possible to reach here without a valid "object" - setFieldValue(object, correspondingField, entry.getValue(), precision); + setFieldValue(object, correspondingField, fieldSetter, entry.getValue(), precision); } } } @@ -284,7 +306,7 @@ List parseSeriesAs(final QueryResult.Series series, final Class clazz, object = null; } } - } catch (InstantiationException | IllegalAccessException e) { + } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { throw new InfluxDBMapperException(e); } return result; @@ -302,8 +324,9 @@ List parseSeriesAs(final QueryResult.Series series, final Class clazz, * @throws IllegalArgumentException * @throws IllegalAccessException */ - void setFieldValue(final T object, final Field field, final Object value, final TimeUnit precision) - throws IllegalArgumentException, IllegalAccessException { + void setFieldValue(final T object, final Field field, final Method fieldSetter, final Object value, + final TimeUnit precision) + throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { if (value == null) { return; } @@ -312,9 +335,12 @@ void setFieldValue(final T object, final Field field, final Object value, fi if (!field.isAccessible()) { field.setAccessible(true); } - if (fieldValueModified(fieldType, field, object, value, precision) - || fieldValueForPrimitivesModified(fieldType, field, object, value) - || fieldValueForPrimitiveWrappersModified(fieldType, field, object, value)) { + if (assignInstant(fieldType, field, fieldSetter, object, value, precision) + || assignString(fieldType, field, fieldSetter, object, value) + || assignDouble(fieldType, field, fieldSetter, object, value) + || assignInteger(fieldType, field, fieldSetter, object, value) + || assignLong(fieldType, field, fieldSetter, object, value) + || assignBoolean(fieldType, field, fieldSetter, object, value)) { return; } String msg = "Class '%s' field '%s' is from an unsupported type '%s'."; @@ -328,13 +354,10 @@ void setFieldValue(final T object, final Field field, final Object value, fi } } - boolean fieldValueModified(final Class fieldType, final Field field, final T object, final Object value, - final TimeUnit precision) - throws IllegalArgumentException, IllegalAccessException { - if (String.class.isAssignableFrom(fieldType)) { - field.set(object, String.valueOf(value)); - return true; - } + boolean assignInstant(final Class fieldType, final Field field, final Method fieldSetter, final T object, + final Object value, final TimeUnit precision) throws InvocationTargetException, + IllegalAccessException { + boolean isInstantAssigned = false; if (Instant.class.isAssignableFrom(fieldType)) { Instant instant; if (value instanceof String) { @@ -348,52 +371,107 @@ boolean fieldValueModified(final Class fieldType, final Field field, fina } else { throw new InfluxDBMapperException("Unsupported type " + field.getClass() + " for field " + field.getName()); } - field.set(object, instant); - return true; + if (fieldSetter != null) { + fieldSetter.invoke(object, instant); + isInstantAssigned = true; + } else { + field.set(object, instant); + isInstantAssigned = true; + } } - return false; + return isInstantAssigned; } - boolean fieldValueForPrimitivesModified(final Class fieldType, final Field field, final T object, - final Object value) throws IllegalArgumentException, IllegalAccessException { - if (double.class.isAssignableFrom(fieldType)) { - field.setDouble(object, ((Double) value).doubleValue()); - return true; - } - if (long.class.isAssignableFrom(fieldType)) { - field.setLong(object, ((Double) value).longValue()); - return true; - } - if (int.class.isAssignableFrom(fieldType)) { - field.setInt(object, ((Double) value).intValue()); - return true; - } - if (boolean.class.isAssignableFrom(fieldType)) { - field.setBoolean(object, Boolean.valueOf(String.valueOf(value)).booleanValue()); - return true; + boolean assignString(final Class fieldType, final Field field, final Method fieldSetter, final T object, + final Object value) throws InvocationTargetException, IllegalAccessException { + boolean isStringAssigned = false; + if (String.class.isAssignableFrom(fieldType)) { + final String stringValue = String.valueOf(value); + if (fieldSetter != null) { + fieldSetter.invoke(object, stringValue); + isStringAssigned = true; + } else { + field.set(object, stringValue); + isStringAssigned = true; + } } - return false; + return isStringAssigned; } - boolean fieldValueForPrimitiveWrappersModified(final Class fieldType, final Field field, final T object, - final Object value) throws IllegalArgumentException, IllegalAccessException { - if (Double.class.isAssignableFrom(fieldType)) { - field.set(object, value); - return true; + boolean assignDouble(final Class fieldType, final Field field, final Method fieldSetter, final T object, + final Object value) throws InvocationTargetException, IllegalAccessException { + boolean isDoubleAssigned = false; + if (double.class.isAssignableFrom(fieldType) || Double.class.isAssignableFrom(fieldType)) { + if (fieldSetter != null) { + fieldSetter.invoke(object, value); + isDoubleAssigned = true; + } else if (double.class.isAssignableFrom(fieldType)) { + final double doubleValue = (Double) value; + field.setDouble(object, doubleValue); + isDoubleAssigned = true; + } else if (Double.class.isAssignableFrom(fieldType)) { + field.set(object, value); + isDoubleAssigned = true; + } } - if (Long.class.isAssignableFrom(fieldType)) { - field.set(object, Long.valueOf(((Double) value).longValue())); - return true; + return isDoubleAssigned; + } + + boolean assignLong(final Class fieldType, final Field field, final Method fieldSetter, final T object, + final Object value) throws InvocationTargetException, IllegalAccessException { + boolean isLongAssigned = false; + if (long.class.isAssignableFrom(fieldType) || Long.class.isAssignableFrom(fieldType)) { + final long longValue = ((Double) value).longValue(); + if (fieldSetter != null) { + fieldSetter.invoke(object, longValue); + isLongAssigned = true; + } else if (long.class.isAssignableFrom(fieldType)) { + field.setLong(object, longValue); + isLongAssigned = true; + } else if (Long.class.isAssignableFrom(fieldType)) { + field.set(object, longValue); + isLongAssigned = true; + } } - if (Integer.class.isAssignableFrom(fieldType)) { - field.set(object, Integer.valueOf(((Double) value).intValue())); - return true; + return isLongAssigned; + } + + boolean assignInteger(final Class fieldType, final Field field, final Method fieldSetter, final T object, + final Object value) throws InvocationTargetException, IllegalAccessException { + boolean isIntegerAssigned = false; + if (int.class.isAssignableFrom(fieldType) || Integer.class.isAssignableFrom(fieldType)) { + final int intValue = ((Double) value).intValue(); + if (fieldSetter != null) { + fieldSetter.invoke(object, intValue); + isIntegerAssigned = true; + } else if (int.class.isAssignableFrom(fieldType)) { + field.setInt(object, intValue); + isIntegerAssigned = true; + } else if (Integer.class.isAssignableFrom(fieldType)) { + field.set(object, intValue); + isIntegerAssigned = true; + } } - if (Boolean.class.isAssignableFrom(fieldType)) { - field.set(object, Boolean.valueOf(String.valueOf(value))); - return true; + return isIntegerAssigned; + } + + boolean assignBoolean(final Class fieldType, final Field field, final Method fieldSetter, final T object, + final Object value) throws InvocationTargetException, IllegalAccessException { + boolean isBooleanAssigned = false; + if (boolean.class.isAssignableFrom(fieldType) || Boolean.class.isAssignableFrom(fieldType)) { + final boolean boolValue = Boolean.parseBoolean(String.valueOf(value)); + if (fieldSetter != null) { + fieldSetter.invoke(object, boolValue); + isBooleanAssigned = true; + } else if (boolean.class.isAssignableFrom(fieldType)) { + field.setBoolean(object, boolValue); + isBooleanAssigned = true; + } else if (Boolean.class.isAssignableFrom(fieldType)) { + field.set(object, boolValue); + isBooleanAssigned = true; + } } - return false; + return isBooleanAssigned; } private Long toMillis(final long value, final TimeUnit precision) {