sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1609161 - in /sis/branches/JDK8/core/sis-utility/src: main/java/org/apache/sis/util/iso/ test/java/org/apache/sis/util/iso/
Date Wed, 09 Jul 2014 14:06:20 GMT
Author: desruisseaux
Date: Wed Jul  9 14:06:19 2014
New Revision: 1609161

URL: http://svn.apache.org/r1609161
Log:
DefaultRecord uses array of primitive type when possible.

Modified:
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultRecord.java
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/iso/RecordDefinition.java
    sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/util/iso/DefaultRecordTest.java
    sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/util/iso/DefaultRecordTypeTest.java
    sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/util/iso/SerializableRecordSchema.java

Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultRecord.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultRecord.java?rev=1609161&r1=1609160&r2=1609161&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultRecord.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultRecord.java
[UTF-8] Wed Jul  9 14:06:19 2014
@@ -22,18 +22,26 @@ import java.util.AbstractMap;
 import java.util.AbstractSet;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
-import java.util.Arrays;
 import java.io.Serializable;
+import java.lang.reflect.Array;
 import org.opengis.util.MemberName;
 import org.opengis.util.Record;
 import org.opengis.util.RecordType;
 import org.apache.sis.util.Debug;
+import org.apache.sis.util.Utilities;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.resources.Errors;
 
+// Branch-dependent imports
+import java.util.Objects;
+
 
 /**
  * A list of logically related elements as (<var>name</var>, <var>value</var>)
pairs in a dictionary.
+ * By definition, all record members have a [1 … 1] cardinality
+ * (for a more flexible construct, see {@linkplain org.apache.sis.feature features}).
+ * Since all members are expected to be assigned a value, the initial values on {@code DefaultRecord}
+ * instantiation are undetermined. Some may be null, or some may be zero.
  *
  * {@section Limitations}
  * <ul>
@@ -65,12 +73,15 @@ public class DefaultRecord implements Re
     final RecordDefinition definition;
 
     /**
-     * The record values.
+     * The record values in an array. May be an array of primitive type for compactness,
+     * which is why the type is not {@code Object[]}.
      */
-    private final Object[] values;
+    private final Object values;
 
     /**
      * Creates a new record for the given record type.
+     * The initial values are undetermined - they may be null or zero.
+     * Callers can assign values by a call to {@link #setAll(Object[])}.
      *
      * @param type The type definition of the new record.
      */
@@ -81,7 +92,7 @@ public class DefaultRecord implements Re
         } else {
             definition = new RecordDefinition.Adapter(type);
         }
-        values = new Object[definition.size()];
+        values = Array.newInstance(definition.baseValueClass(), definition.size());
     }
 
     /**
@@ -222,7 +233,7 @@ public class DefaultRecord implements Re
     @Override
     public Object locate(final MemberName name) {
         final Integer index = definition.indexOf(name);
-        return (index != null) ? values[index] : null;
+        return (index != null) ? Array.get(values, index) : null;
     }
 
     /**
@@ -247,7 +258,7 @@ public class DefaultRecord implements Re
                         name, value.getClass()));
             }
         }
-        values[index] = value;
+        Array.set(values, index, value);
     }
 
     /**
@@ -257,11 +268,12 @@ public class DefaultRecord implements Re
      * @throws IllegalArgumentException if the given number of values does not match the
expected number.
      * @throws ClassCastException if a value is not an instance of the expected type for
this record.
      */
-    public void setValues(final Object... newValues) {
+    public void setAll(final Object... newValues) {
         ArgumentChecks.ensureNonNull("values", newValues);
-        if (newValues.length != values.length) {
+        final int length = Array.getLength(values);
+        if (newValues.length != length) {
             throw new IllegalArgumentException(Errors.format(
-                    Errors.Keys.UnexpectedArrayLength_2, values.length, newValues.length));
+                    Errors.Keys.UnexpectedArrayLength_2, length, newValues.length));
         }
         for (int i=0; i<newValues.length; i++) {
             final Object value = newValues[i];
@@ -272,7 +284,7 @@ public class DefaultRecord implements Re
                             definition.getName(i), value.getClass()));
                 }
             }
-            values[i] = value;
+            Array.set(values, i, value);
         }
     }
 
@@ -290,7 +302,7 @@ public class DefaultRecord implements Re
         if (object != null && object.getClass() == getClass()) {
             final DefaultRecord that = (DefaultRecord) object;
             return definition.getRecordType().equals(that.definition.getRecordType()) &&
-                   Arrays.equals(values, that.values);
+                   Objects.deepEquals(values, that.values);
         }
         return false;
     }
@@ -302,7 +314,7 @@ public class DefaultRecord implements Re
      */
     @Override
     public int hashCode() {
-        return Arrays.hashCode(values) ^ definition.getRecordType().hashCode();
+        return Utilities.deepHashCode(values) ^ definition.getRecordType().hashCode();
     }
 
     /**

Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/iso/RecordDefinition.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/iso/RecordDefinition.java?rev=1609161&r1=1609160&r2=1609161&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/iso/RecordDefinition.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/iso/RecordDefinition.java
[UTF-8] Wed Jul  9 14:06:19 2014
@@ -21,12 +21,15 @@ import java.util.LinkedHashMap;
 import java.io.Serializable;
 import java.io.IOException;
 import java.io.ObjectInputStream;
+import java.lang.reflect.Array;
 import javax.xml.bind.annotation.XmlTransient;
 import org.opengis.util.Type;
 import org.opengis.util.RecordType;
 import org.opengis.util.MemberName;
 import org.opengis.feature.AttributeType;
 import org.apache.sis.util.Debug;
+import org.apache.sis.util.Classes;
+import org.apache.sis.util.Numbers;
 import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.collection.Containers;
 import org.apache.sis.internal.util.CollectionsExt;
@@ -116,6 +119,11 @@ abstract class RecordDefinition { // Int
     private transient Class<?>[] valueClasses;
 
     /**
+     * The common parent of all value classes. May be a primitive type.
+     */
+    private transient Class<?> baseValueClass;
+
+    /**
      * Creates a new instance. Subclasses shall invoke {@link #computeTransientFields(Map)}
in their constructor.
      */
     RecordDefinition() {
@@ -148,6 +156,7 @@ abstract class RecordDefinition { // Int
                         valueClasses = new Class<?>[size];
                     }
                     valueClasses[i] = c;
+                    baseValueClass = Classes.findCommonClass(baseValueClass, c);
                 }
             }
             final MemberName name = entry.getKey();
@@ -157,10 +166,18 @@ abstract class RecordDefinition { // Int
             i++;
         }
         memberIndices = CollectionsExt.unmodifiableOrCopy(memberIndices);
+        baseValueClass = (baseValueClass != null) ? Numbers.wrapperToPrimitive(baseValueClass)
: Object.class;
         return types;
     }
 
     /**
+     * Returns the common parent of all value classes. May be a primitive type.
+     */
+    final Class<?> baseValueClass() {
+        return baseValueClass;
+    }
+
+    /**
      * Read-only access to the map of member indices.
      */
     final Map<MemberName,Integer> memberIndices() {
@@ -211,10 +228,10 @@ abstract class RecordDefinition { // Int
      * Returns a string representation of a {@code Record} or {@code RecordType}.
      *
      * @param  head   Either {@code "Record"} or {@code "RecordType"}.
-     * @param  values The values, or {@code null} for writing the types instead.
+     * @param  values The values as an array, or {@code null} for writing the types instead.
      * @return The string representation.
      */
-    final String toString(final String head, final Object[] values) {
+    final String toString(final String head, final Object values) {
         final StringBuilder buffer = new StringBuilder(250);
         final String lineSeparator = System.lineSeparator();
         final String[] names = new String[members.length];
@@ -226,7 +243,7 @@ abstract class RecordDefinition { // Int
         for (int i=0; i<names.length; i++) {
             final String name = names[i];
             buffer.append("    ").append(name);
-            final Object value = (values != null) ? values[i] : members[i].getAttributeType();
+            final Object value = (values != null) ? Array.get(values, i) : members[i].getAttributeType();
             if (value != null) {
                 buffer.append(CharSequences.spaces(width - name.length())).append(" : ").append(value);
             }

Modified: sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/util/iso/DefaultRecordTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/util/iso/DefaultRecordTest.java?rev=1609161&r1=1609160&r2=1609161&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/util/iso/DefaultRecordTest.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/util/iso/DefaultRecordTest.java
[UTF-8] Wed Jul  9 14:06:19 2014
@@ -16,9 +16,8 @@
  */
 package org.apache.sis.util.iso;
 
-
-import java.util.LinkedHashMap;
 import java.util.Map;
+import java.util.LinkedHashMap;
 import org.opengis.util.MemberName;
 import org.opengis.util.RecordType;
 
@@ -73,28 +72,35 @@ public final strictfp class DefaultRecor
     }
 
     /**
-     * Tests {@link DefaultRecord#setValues(Object[])}.
+     * Sets all values in the given record using the {@link DefaultRecord#setAll(Object[])}
method,
+     * then checks that the values were correctly stored.
+     */
+    private static void setAllAndCompare(final DefaultRecord record, final Object... values)
{
+        record.setAll(values);
+        assertArrayEquals("attributes.values", values, record.getAttributes().values().toArray());
+    }
+
+    /**
+     * Tests {@link DefaultRecord#setAll(Object[])}.
      */
     @Test
-    public void testSetValues() {
+    public void testSetAll() {
         final DefaultRecord record = new DefaultRecord(recordType);
         try {
-            record.setValues("Machu Picchu", -13.1639, -72.5468);
+            record.setAll("Machu Picchu", -13.1639, -72.5468);
             fail("Shall not accept array of illegal length.");
         } catch (IllegalArgumentException e) {
             assertNotNull(e.getMessage());
         }
         try {
-            record.setValues("Machu Picchu", -13.1639, -72.5468, "Unknown");
+            record.setAll("Machu Picchu", -13.1639, -72.5468, "Unknown");
             fail("Shall not accept 'population' value of class String.");
         } catch (ClassCastException e) {
             final String message = e.getMessage();
             assertTrue(message, message.contains("population"));
             assertTrue(message, message.contains("String"));
         }
-        final Object[] values = {"Machu Picchu", -13.1639, -72.5468, null};
-        record.setValues(values);
-        assertArrayEquals(values, record.getAttributes().values().toArray());
+        setAllAndCompare(record, "Machu Picchu", -13.1639, -72.5468, null);
     }
 
     /**
@@ -128,10 +134,10 @@ public final strictfp class DefaultRecor
      * Tests {@link DefaultRecord#toString()}.
      */
     @Test
-    @DependsOnMethod("testSetValues")
+    @DependsOnMethod("testSetAll")
     public void testToString() {
         final DefaultRecord record = new DefaultRecord(recordType);
-        record.setValues("Machu Picchu", -13.1639, -72.5468, null);
+        record.setAll("Machu Picchu", -13.1639, -72.5468, null);
         assertMultilinesEquals(
                 "Record[“MyRecordType”] {\n" +
                 "    city       : Machu Picchu\n" +
@@ -158,10 +164,43 @@ public final strictfp class DefaultRecor
      * Tests serialization of a {@link DefaultRecord}.
      */
     @Test
-    @DependsOnMethod("testSetValues")
+    @DependsOnMethod("testSetAll")
     public void testSerialization() {
         final DefaultRecord record = new DefaultRecord(recordType);
-        record.setValues("Machu Picchu", -13.1639, -72.5468, null);
+        record.setAll("Machu Picchu", -13.1639, -72.5468, null);
+        assertNotSame(record, assertSerializedEquals(record));
+    }
+
+    /**
+     * Tests a record where all members are the same primitive type. This method performs
tests
+     * similar to {@link #testSetAll()}, {@link #testToString()} and {@link #testSerialization()}.
+     */
+    @Test
+    @DependsOnMethod({"testSetAll", "testToString", "testSerialization"})
+    public void testPrimitiveType() {
+        final Map<CharSequence,Class<?>> members = new LinkedHashMap<>(8);
+        assertNull(members.put("latitude",  Double.class));
+        assertNull(members.put("longitude", Double.class));
+        final DefaultRecord record = new DefaultRecord(
+                SerializableRecordSchema.INSTANCE.createRecordType("MyRecordType", members));
+        /*
+         * As a side effect of the fact that DefaultRecord uses an array of primitive type,
+         * initial values should be zero instead than null. We use this trick as a way to
+         * detect that we really got an array of primitive type.
+         */
+        assertEquals("baseValueClass", Double.TYPE, record.definition.baseValueClass());
+        assertArrayEquals("attributes.values", new Double[] {0.0, 0.0},
+                record.getAttributes().values().toArray());
+        /*
+         * Combines tests similar to 3 other test methods in this class.
+         */
+        setAllAndCompare(record, -13.1639, -72.5468);
+        assertMultilinesEquals(
+                "Record[“MyRecordType”] {\n" +
+                "    latitude  : -13.1639\n" +
+                "    longitude : -72.5468\n" +
+                "}\n",
+                record.toString());
         assertNotSame(record, assertSerializedEquals(record));
     }
 }

Modified: sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/util/iso/DefaultRecordTypeTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/util/iso/DefaultRecordTypeTest.java?rev=1609161&r1=1609160&r2=1609161&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/util/iso/DefaultRecordTypeTest.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/util/iso/DefaultRecordTypeTest.java
[UTF-8] Wed Jul  9 14:06:19 2014
@@ -18,10 +18,8 @@ package org.apache.sis.util.iso;
 
 import java.util.Collections;
 import org.opengis.util.Type;
-import org.opengis.util.TypeName;
 import org.opengis.util.MemberName;
 import org.opengis.util.NameSpace;
-import org.opengis.util.RecordSchema;
 import org.apache.sis.internal.simple.SimpleAttributeType;
 
 // Test imports
@@ -44,10 +42,10 @@ import static org.apache.sis.test.TestUt
  */
 @DependsOn(AbstractNameTest.class)
 public final strictfp class DefaultRecordTypeTest extends TestCase {
-    /** Value of {@link DefaultRecordType#getContainer()}.   */ private RecordSchema container;
-    /** Value of {@link DefaultRecordType#getTypeName()}.    */ private TypeName     recordTypeName;
-    /** Value of {@link DefaultRecordType#getMembers()}.     */ private MemberName   memberName;
-    /** Value of {@link DefaultRecordType#getMemberTypes()}. */ private TypeName     memberTypeName;
+    /** Value of {@link DefaultRecordType#getContainer()}.   */ private DefaultRecordSchema
container;
+    /** Value of {@link DefaultRecordType#getTypeName()}.    */ private DefaultTypeName 
   recordTypeName;
+    /** Value of {@link DefaultRecordType#getMembers()}.     */ private DefaultMemberName
  memberName;
+    /** Value of {@link DefaultRecordType#getMemberTypes()}. */ private DefaultTypeName 
   memberTypeName;
 
     /**
      * Initializes the private fields.
@@ -82,6 +80,10 @@ public final strictfp class DefaultRecor
     public void testConstructor() {
         init();
         final DefaultRecordType type = create();
+        assertEquals("size", 1, type.size());
+        assertEquals("baseValueClass", Integer.TYPE, type.baseValueClass());
+
+        // Public properties
         assertSame("container",   container,      type.getContainer());
         assertSame("typeName",    recordTypeName, type.getTypeName());
         assertSame("members",     memberName,     getSingleton(type.getMembers()));
@@ -99,7 +101,7 @@ public final strictfp class DefaultRecor
     @DependsOnMethod("testConstructor")
     public void testArgumentChecks() {
         init();
-        final TypeName         correctRecordName      = recordTypeName;
+        final DefaultTypeName  correctRecordName      = recordTypeName;
         final NameSpace        correctMemberNamespace = memberName.scope();
         final DefaultNameSpace wrongNamespace         = new DefaultNameSpace(null, "WrongNameSpace",
":", ":");
         /*

Modified: sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/util/iso/SerializableRecordSchema.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/util/iso/SerializableRecordSchema.java?rev=1609161&r1=1609160&r2=1609161&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/util/iso/SerializableRecordSchema.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/util/iso/SerializableRecordSchema.java
[UTF-8] Wed Jul  9 14:06:19 2014
@@ -18,7 +18,6 @@ package org.apache.sis.util.iso;
 
 import java.io.Serializable;
 import java.io.ObjectStreamException;
-import org.opengis.util.RecordSchema;
 
 
 /**
@@ -35,7 +34,7 @@ final class SerializableRecordSchema ext
     /**
      * The unique instance for the shema.
      */
-    static RecordSchema INSTANCE;
+    static DefaultRecordSchema INSTANCE;
 
     /**
      * Construct a new record schema.



Mime
View raw message