Repository: influxdata/influxdb-java (java)

Issue:
Default column name to pojo field name, and add `allFields` mode to `Measurement` annotation
It would be nice if `@Column` could be used without a name, in which case the field name would be used as the column name.

In addition, when a pojo has many fields, it would be nice to be able to annotate it with `@Measurement(name = "...", allFields = true)` instead of annotating every field with `@Column`.
Finally, an `@Exclude` annotation on fields would be helpful, for opting a field out in this mode.

I have implemented such support. Should I submit a PR?


Pull request description:
Default column name to pojo field name, and add `allFields` mode to `Measurement` annotation
if `@Column` is used without a name, the annotated field's name is used as the column name.

In addition, when a pojo is annotated with `@Measurement(name = "...", allFields = true)`, then all its fields are loaded or saved.
Finally, an `@Exclude` annotation can be used for opting a field out in this mode.

Fixes #971.


Patch:
diff --git a/MANUAL.md b/MANUAL.md
index 62d45d6..18040ae 100644
--- a/MANUAL.md
+++ b/MANUAL.md
@@ -323,21 +323,40 @@ public class Cpu {
 }
 ```
 
-2. Add @Measurement,@TimeColumn and @Column annotations:
+2. Add @Measurement,@TimeColumn and @Column annotations (column names default to field names unless otherwise specified):
 
 ```Java
 @Measurement(name = "cpu")
 public class Cpu {
     @TimeColumn
-    @Column(name = "time")
+    @Column
     private Instant time;
     @Column(name = "host", tag = true)
     private String hostname;
-    @Column(name = "region", tag = true)
+    @Column(tag = true)
+    private String region;
+    @Column
+    private Double idle;
+    @Column
+    private Boolean happydevop;
+    @Column(name = "uptimesecs")
+    private Long uptimeSecs;
+    // getters (and setters if you need)
+}
+```
+
+Alternatively, you can use:
+
+```Java
+@Measurement(name = "cpu", allFields = true)
+public class Cpu {
+    @TimeColumn
+    private Instant time;
+    @Column(name = "host", tag = true)
+    private String hostname;
+    @Column(tag = true)
     private String region;
-    @Column(name = "idle")
     private Double idle;
-    @Column(name = "happydevop")
     private Boolean happydevop;
     @Column(name = "uptimesecs")
     private Long uptimeSecs;
diff --git a/src/main/java/org/influxdb/annotation/Column.java b/src/main/java/org/influxdb/annotation/Column.java
index cde2fbe..6edb256 100644
--- a/src/main/java/org/influxdb/annotation/Column.java
+++ b/src/main/java/org/influxdb/annotation/Column.java
@@ -32,7 +32,10 @@ import java.lang.annotation.Target;
 @Target(ElementType.FIELD)
 public @interface Column {
 
-  String name();
+  /**
+   * If unset, the annotated field's name will be used as the column name.
+   */
+  String name() default "";
 
   boolean tag() default false;
 }
diff --git a/src/main/java/org/influxdb/annotation/Exclude.java b/src/main/java/org/influxdb/annotation/Exclude.java
new file mode 100644
index 0000000..01e6f52
--- /dev/null
+++ b/src/main/java/org/influxdb/annotation/Exclude.java
@@ -0,0 +1,38 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 azeti Networks AG (<info@azeti.net>)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+ * associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+ * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+package org.influxdb.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * When a POJO annotated with {@code @Measurement(allFields = true)} is loaded or saved,
+ * this annotation can be used to exclude some of its fields.
+ * @see Measurement#allFields()
+ *
+ * @author Eran Leshem
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface Exclude {
+}
diff --git a/src/main/java/org/influxdb/annotation/Measurement.java b/src/main/java/org/influxdb/annotation/Measurement.java
index a834bfb..fa9d19f 100644
--- a/src/main/java/org/influxdb/annotation/Measurement.java
+++ b/src/main/java/org/influxdb/annotation/Measurement.java
@@ -40,4 +40,11 @@ public @interface Measurement {
   String retentionPolicy() default "autogen";
 
   TimeUnit timeUnit() default TimeUnit.MILLISECONDS;
+
+  /**
+   * If {@code true}, then all non-static fields of this measurement will be loaded or saved,
+   * regardless of any {@code @Column} annotations.
+   * @see Exclude
+   */
+  boolean allFields() default false;
 }
diff --git a/src/main/java/org/influxdb/dto/Point.java b/src/main/java/org/influxdb/dto/Point.java
index 9606902..b8cc9e2 100755
--- a/src/main/java/org/influxdb/dto/Point.java
+++ b/src/main/java/org/influxdb/dto/Point.java
@@ -1,7 +1,15 @@
 package org.influxdb.dto;
 
+import org.influxdb.BuilderException;
+import org.influxdb.annotation.Column;
+import org.influxdb.annotation.Exclude;
+import org.influxdb.annotation.Measurement;
+import org.influxdb.annotation.TimeColumn;
+import org.influxdb.impl.Preconditions;
+
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.math.RoundingMode;
@@ -11,14 +19,9 @@ import java.util.Locale;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Objects;
-import java.util.TreeMap;
 import java.util.Optional;
+import java.util.TreeMap;
 import java.util.concurrent.TimeUnit;
-import org.influxdb.BuilderException;
-import org.influxdb.annotation.Column;
-import org.influxdb.annotation.Measurement;
-import org.influxdb.annotation.TimeColumn;
-import org.influxdb.impl.Preconditions;
 
 /**
  * Representation of a InfluxDB database Point.
@@ -276,23 +279,34 @@ public class Point {
      */
     public Builder addFieldsFromPOJO(final Object pojo) {
 
-      Class<? extends Object> clazz = pojo.getClass();
+      Class<?> clazz = pojo.getClass();
+      Measurement measurement = clazz.getAnnotation(Measurement.class);
+      boolean allFields = measurement != null && measurement.allFields();
+
       while (clazz != null) {
 
         for (Field field : clazz.getDeclaredFields()) {
 
           Column column = field.getAnnotation(Column.class);
 
-          if (column == null) {
+          if (column == null && !(allFields
+                  && !field.isAnnotationPresent(Exclude.class) && !Modifier.isStatic(field.getModifiers()))) {
             continue;
           }
 
           field.setAccessible(true);
-          String fieldName = column.name();
-          addFieldByAttribute(pojo, field, column, fieldName);
+
+          String fieldName;
+          if (column != null && !column.name().isEmpty()) {
+            fieldName = column.name();
+          } else {
+            fieldName = field.getName();
+          }
+
+          addFieldByAttribute(pojo, field, column != null && column.tag(), fieldName);
         }
-      clazz = clazz.getSuperclass();
-    }
+        clazz = clazz.getSuperclass();
+      }
 
       if (this.fields.isEmpty()) {
         throw new BuilderException("Class " + pojo.getClass().getName()
@@ -302,8 +316,8 @@ public class Point {
       return this;
     }
 
-    private void addFieldByAttribute(final Object pojo, final Field field, final Column column,
-        final String fieldName) {
+    private void addFieldByAttribute(final Object pojo, final Field field, final boolean tag,
+                                     final String fieldName) {
       try {
         Object fieldValue = field.get(pojo);
 
@@ -325,7 +339,7 @@ public class Point {
           return;
         }
 
-        if (column.tag()) {
+        if (tag) {
           if (fieldValue != null) {
             this.tags.put(fieldName, (String) fieldValue);
           }
diff --git a/src/main/java/org/influxdb/impl/InfluxDBResultMapper.java b/src/main/java/org/influxdb/impl/InfluxDBResultMapper.java
index d6edef1..15d4c28 100644
--- a/src/main/java/org/influxdb/impl/InfluxDBResultMapper.java
+++ b/src/main/java/org/influxdb/impl/InfluxDBResultMapper.java
@@ -20,7 +20,14 @@
  */
 package org.influxdb.impl;
 
+import org.influxdb.InfluxDBMapperException;
+import org.influxdb.annotation.Column;
+import org.influxdb.annotation.Exclude;
+import org.influxdb.annotation.Measurement;
+import org.influxdb.dto.QueryResult;
+
 import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
 import java.time.Instant;
 import java.time.format.DateTimeFormatter;
 import java.time.format.DateTimeFormatterBuilder;
@@ -33,11 +40,6 @@ import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.TimeUnit;
 
-import org.influxdb.InfluxDBMapperException;
-import org.influxdb.annotation.Column;
-import org.influxdb.annotation.Measurement;
-import org.influxdb.dto.QueryResult;
-
 /**
  * Main class responsible for mapping a QueryResult to a POJO.
  *
@@ -213,13 +215,19 @@ public class InfluxDBResultMapper {
       }
       ConcurrentMap<String, Field> influxColumnAndFieldMap = new ConcurrentHashMap<>();
 
+      Measurement measurement = clazz.getAnnotation(Measurement.class);
+      boolean allFields = measurement != null && measurement.allFields();
+
       Class<?> c = clazz;
       while (c != null) {
         for (Field field : c.getDeclaredFields()) {
           Column colAnnotation = field.getAnnotation(Column.class);
-          if (colAnnotation != null) {
-            influxColumnAndFieldMap.put(colAnnotation.name(), field);
+          if (colAnnotation == null && !(allFields
+                  && !field.isAnnotationPresent(Exclude.class) && !Modifier.isStatic(field.getModifiers()))) {
+            continue;
           }
+
+          influxColumnAndFieldMap.put(getFieldName(field, colAnnotation), field);
         }
         c = c.getSuperclass();
       }
@@ -227,6 +235,14 @@ public class InfluxDBResultMapper {
     }
   }
 
+  private static String getFieldName(final Field field, final Column colAnnotation) {
+    if (colAnnotation != null && !colAnnotation.name().isEmpty()) {
+      return colAnnotation.name();
+    }
+
+    return field.getName();
+  }
+
   String getMeasurementName(final Class<?> clazz) {
     return ((Measurement) clazz.getAnnotation(Measurement.class)).name();
   }
@@ -289,17 +305,11 @@ public class InfluxDBResultMapper {
 
   /**
    * InfluxDB client returns any number as Double.
-   * See https://github.com/influxdata/influxdb-java/issues/153#issuecomment-259681987
+   * See <a href="https://github.com/influxdata/influxdb-java/issues/153#issuecomment-259681987">...</a>
    * for more information.
    *
-   * @param object
-   * @param field
-   * @param value
-   * @param precision
-   * @throws IllegalArgumentException
-   * @throws IllegalAccessException
    */
-  <T> void setFieldValue(final T object, final Field field, final Object value, final TimeUnit precision)
+  private static <T> void setFieldValue(final T object, final Field field, final Object value, final TimeUnit precision)
     throws IllegalArgumentException, IllegalAccessException {
     if (value == null) {
       return;
@@ -325,8 +335,8 @@ public class InfluxDBResultMapper {
     }
   }
 
-  <T> boolean fieldValueModified(final Class<?> fieldType, final Field field, final T object, final Object value,
-                                 final TimeUnit precision)
+  static <T> 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));
@@ -351,8 +361,9 @@ public class InfluxDBResultMapper {
     return false;
   }
 
-  <T> boolean fieldValueForPrimitivesModified(final Class<?> fieldType, final Field field, final T object,
-    final Object value) throws IllegalArgumentException, IllegalAccessException {
+  static <T> 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;
@@ -372,8 +383,9 @@ public class InfluxDBResultMapper {
     return false;
   }
 
-  <T> boolean fieldValueForPrimitiveWrappersModified(final Class<?> fieldType, final Field field, final T object,
-    final Object value) throws IllegalArgumentException, IllegalAccessException {
+  static <T> 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;
@@ -393,7 +405,7 @@ public class InfluxDBResultMapper {
     return false;
   }
 
-  private Long toMillis(final long value, final TimeUnit precision) {
+  private static Long toMillis(final long value, final TimeUnit precision) {
 
     return TimeUnit.MILLISECONDS.convert(value, precision);
   }


Test patch:
diff --git a/src/test/java/org/influxdb/dto/PointTest.java b/src/test/java/org/influxdb/dto/PointTest.java
index a494541..c315aad 100755
--- a/src/test/java/org/influxdb/dto/PointTest.java
+++ b/src/test/java/org/influxdb/dto/PointTest.java
@@ -1,7 +1,17 @@
 package org.influxdb.dto;
 
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
+import org.influxdb.BuilderException;
+import org.influxdb.InfluxDB;
+import org.influxdb.annotation.Column;
+import org.influxdb.annotation.Measurement;
+import org.influxdb.annotation.TimeColumn;
+import org.influxdb.impl.InfluxDBImpl;
+import org.junit.Assert;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.junit.platform.runner.JUnitPlatform;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
 
 import java.lang.reflect.Field;
 import java.math.BigDecimal;
@@ -16,18 +26,8 @@ import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicLong;
 
-import org.influxdb.BuilderException;
-import org.influxdb.InfluxDB;
-import org.influxdb.annotation.Column;
-import org.influxdb.annotation.Measurement;
-import org.influxdb.annotation.TimeColumn;
-import org.influxdb.impl.InfluxDBImpl;
-import org.junit.Assert;
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.Test;
-import org.junit.platform.runner.JUnitPlatform;
-import org.junit.runner.RunWith;
-import org.mockito.Mockito;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
 
 /**
  * Test for the Point DTO.
@@ -794,6 +794,63 @@ public class PointTest {
         Assertions.assertEquals(pojo.uuid, p.getTags().get("uuid"));
     }
 
+    @Test
+    public void testAddFieldsFromPojoWithAllFieldsAnnotation() {
+
+        PojoWithAllFieldsAnnotation pojo = new PojoWithAllFieldsAnnotation();
+        pojo.booleanObject = true;
+        pojo.booleanPrimitive = false;
+        pojo.doubleObject = 2.0;
+        pojo.doublePrimitive = 3.1;
+        pojo.integerObject = 32;
+        pojo.integerPrimitive = 64;
+        pojo.longObject = 1L;
+        pojo.longPrimitive = 2L;
+        pojo.time = Instant.now();
+        pojo.uuid = "TEST";
+
+        Point p = Point.measurementByPOJO(PojoWithAllFieldsAnnotation.class).addFieldsFromPOJO(pojo).build();
+
+        assertThat(p.lineProtocol()).startsWith("mymeasurement");
+        assertThat(p.getFields()).doesNotContainKey("staticField");
+        Assertions.assertEquals(pojo.booleanObject, p.getFields().get("booleanObject"));
+        Assertions.assertEquals(pojo.booleanPrimitive, p.getFields().get("booleanPrimitive"));
+        Assertions.assertEquals(pojo.doubleObject, p.getFields().get("doubleObject"));
+        Assertions.assertEquals(pojo.doublePrimitive, p.getFields().get("doublePrimitive"));
+        Assertions.assertEquals(pojo.integerObject, p.getFields().get("integerObject"));
+        Assertions.assertEquals(pojo.integerPrimitive, p.getFields().get("integerPrimitive"));
+        Assertions.assertEquals(pojo.longObject, p.getFields().get("longObject"));
+        Assertions.assertEquals(pojo.longPrimitive, p.getFields().get("longPrimitive"));
+        Assertions.assertEquals(pojo.uuid, p.getTags().get("uuid"));
+    }
+
+    @Test
+    public void testAddFieldsFromPojoWithBlankColumnAnnotations() {
+        PojoWithBlankColumnAnnotations pojo = new PojoWithBlankColumnAnnotations();
+        pojo.booleanObject = true;
+        pojo.booleanPrimitive = false;
+        pojo.doubleObject = 2.0;
+        pojo.doublePrimitive = 3.1;
+        pojo.integerObject = 32;
+        pojo.integerPrimitive = 64;
+        pojo.longObject = 1L;
+        pojo.longPrimitive = 2L;
+        pojo.time = Instant.now();
+        pojo.uuid = "TEST";
+
+        Point p = Point.measurementByPOJO(PojoWithBlankColumnAnnotations.class).addFieldsFromPOJO(pojo).build();
+
+        Assertions.assertEquals(pojo.booleanObject, p.getFields().get("booleanObject"));
+        Assertions.assertEquals(pojo.booleanPrimitive, p.getFields().get("booleanPrimitive"));
+        Assertions.assertEquals(pojo.doubleObject, p.getFields().get("doubleObject"));
+        Assertions.assertEquals(pojo.doublePrimitive, p.getFields().get("doublePrimitive"));
+        Assertions.assertEquals(pojo.integerObject, p.getFields().get("integerObject"));
+        Assertions.assertEquals(pojo.integerPrimitive, p.getFields().get("integerPrimitive"));
+        Assertions.assertEquals(pojo.longObject, p.getFields().get("longObject"));
+        Assertions.assertEquals(pojo.longPrimitive, p.getFields().get("longPrimitive"));
+        Assertions.assertEquals(pojo.uuid, p.getTags().get("uuid"));
+    }
+
     @Test
     public void testInheritMeasurement() {
         Point expected = Point.measurementByPOJO(SubClassMeasurement.class)
@@ -1007,6 +1064,62 @@ public class PointTest {
         public Boolean booleanObject;
     }
 
+    @Measurement(name = "mymeasurement", allFields = true)
+    static class PojoWithAllFieldsAnnotation {
+        public static final String staticField = "static";
+
+        public boolean booleanPrimitive;
+
+        @TimeColumn
+        public Instant time;
+
+        @Column(tag = true)
+        public String uuid;
+
+        public Double doubleObject;
+        public Long longObject;
+        public Integer integerObject;
+        public double doublePrimitive;
+        public long longPrimitive;
+        public int integerPrimitive;
+        public Boolean booleanObject;
+    }
+
+    @Measurement(name = "mymeasurement")
+    static class PojoWithBlankColumnAnnotations {
+
+        @Column
+        public boolean booleanPrimitive;
+
+        @Column
+        @TimeColumn
+        public Instant time;
+
+        @Column(tag = true)
+        public String uuid;
+
+        @Column
+        public Double doubleObject;
+
+        @Column
+        public Long longObject;
+
+        @Column
+        public Integer integerObject;
+
+        @Column
+        public double doublePrimitive;
+
+        @Column
+        public long longPrimitive;
+
+        @Column
+        public int integerPrimitive;
+
+        @Column
+        public Boolean booleanObject;
+    }
+
     @Measurement(name = "SuperMeasuremet")
     static class SuperMeasurement {
         @Column(name = "superClassField")
diff --git a/src/test/java/org/influxdb/impl/InfluxDBResultMapperTest.java b/src/test/java/org/influxdb/impl/InfluxDBResultMapperTest.java
index f4eee0b..d93c4d3 100644
--- a/src/test/java/org/influxdb/impl/InfluxDBResultMapperTest.java
+++ b/src/test/java/org/influxdb/impl/InfluxDBResultMapperTest.java
@@ -20,6 +20,17 @@
  */
 package org.influxdb.impl;
 
+import org.influxdb.InfluxDBMapperException;
+import org.influxdb.annotation.Column;
+import org.influxdb.annotation.Exclude;
+import org.influxdb.annotation.Measurement;
+import org.influxdb.annotation.TimeColumn;
+import org.influxdb.dto.QueryResult;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.junit.platform.runner.JUnitPlatform;
+import org.junit.runner.RunWith;
+
 import java.time.Instant;
 import java.util.Arrays;
 import java.util.Date;
@@ -31,16 +42,6 @@ import java.util.Random;
 import java.util.UUID;
 import java.util.concurrent.TimeUnit;
 
-import org.influxdb.InfluxDBMapperException;
-import org.influxdb.annotation.Column;
-import org.influxdb.annotation.Measurement;
-import org.influxdb.annotation.TimeColumn;
-import org.influxdb.dto.QueryResult;
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.Test;
-import org.junit.platform.runner.JUnitPlatform;
-import org.junit.runner.RunWith;
-
 /**
  * @author fmachado
  */
@@ -71,6 +72,12 @@ public class InfluxDBResultMapperTest {
 
     // Then...
     Assertions.assertEquals(1, myList.size(), "there must be one entry in the result list");
+
+		//When...
+  	List<MyAllFieldsCustomMeasurement> myList1 = mapper.toPOJO(queryResult, MyAllFieldsCustomMeasurement.class);
+
+  	// Then...
+  	Assertions.assertEquals(1, myList1.size(), "there must be one entry in the result list");
   }
 
 	@Test
@@ -578,6 +585,35 @@ public class InfluxDBResultMapperTest {
 		}
 	}
 
+	@Measurement(name = "CustomMeasurement", allFields = true)
+	static class MyAllFieldsCustomMeasurement {
+		private Instant time;
+		private String uuid;
+		private Double doubleObject;
+		private Long longObject;
+		private Integer integerObject;
+		private double doublePrimitive;
+		private long longPrimitive;
+		private int integerPrimitive;
+		private Boolean booleanObject;
+		private boolean booleanPrimitive;
+
+		@SuppressWarnings("unused")
+		@Exclude
+		private String nonColumn1;
+
+		@SuppressWarnings("unused")
+		@Exclude
+		private Random rnd;
+
+		@Override
+		public String toString() {
+			return "MyCustomMeasurement [time=" + time + ", uuid=" + uuid + ", doubleObject=" + doubleObject + ", longObject=" + longObject
+				+ ", integerObject=" + integerObject + ", doublePrimitive=" + doublePrimitive + ", longPrimitive=" + longPrimitive
+				+ ", integerPrimitive=" + integerPrimitive + ", booleanObject=" + booleanObject + ", booleanPrimitive=" + booleanPrimitive + "]";
+		}
+	}
+
   @Measurement(name = "SuperMeasurement")
   static class MySuperMeasurement {