sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1419525 - in /sis/branches/JDK7/sis-utility/src: main/java/org/apache/sis/util/Classes.java test/java/org/apache/sis/test/suite/UtilityTestSuite.java test/java/org/apache/sis/util/ClassesTest.java
Date Mon, 10 Dec 2012 15:34:29 GMT
Author: desruisseaux
Date: Mon Dec 10 15:34:27 2012
New Revision: 1419525

URL: http://svn.apache.org/viewvc?rev=1419525&view=rev
Log:
Ported recent bug fixes from Geotk, and added a test case.

Added:
    sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/util/ClassesTest.java   (with
props)
Modified:
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/Classes.java
    sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/Classes.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/Classes.java?rev=1419525&r1=1419524&r2=1419525&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/Classes.java (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/Classes.java Mon Dec 10
15:34:27 2012
@@ -19,6 +19,7 @@ package org.apache.sis.util;
 import java.util.Set;
 import java.util.Iterator;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.LinkedHashSet;
 import java.lang.reflect.Type;
 import java.lang.reflect.Field;
@@ -30,6 +31,7 @@ import java.lang.reflect.ParameterizedTy
 import static java.util.Arrays.copyOf;
 import static org.apache.sis.util.Arrays.resize;
 import static org.apache.sis.util.Arrays.contains;
+import static org.apache.sis.util.collection.Collections.hashMapCapacity;
 
 
 /**
@@ -56,6 +58,11 @@ import static org.apache.sis.util.Arrays
  */
 public final class Classes extends Static {
     /**
+     * An empty array of classes.
+     */
+    private static final Class<?>[] EMPTY_ARRAY = new Class<?>[0];
+
+    /**
      * Methods to be rejected by {@link #isGetter(Method)}. They are mostly methods inherited
      * from {@link Object}. Only no-argument methods having a non-void return value need
to be
      * declared in this list.
@@ -109,7 +116,7 @@ public final class Classes extends Stati
                 do element = element.getComponentType();
                 while (element!=null && ++dimension != 0);
             } else if (element != Void.TYPE) {
-                final StringBuilder buffer = new StringBuilder(16);
+                final StringBuilder buffer = new StringBuilder();
                 do buffer.insert(0, '[');
                 while (--dimension != 0);
                 if (element.isPrimitive()) {
@@ -297,28 +304,39 @@ public final class Classes extends Stati
      *         interface), or an empty set if none. Callers can freely modify the returned
set.
      */
     public static Set<Class<?>> getAllInterfaces(Class<?> type) {
-        final Set<Class<?>> interfaces = new LinkedHashSet<>();
+        Set<Class<?>> interfaces = null;
         while (type != null) {
-            getAllInterfaces(type, interfaces);
+            interfaces = getAllInterfaces(type, interfaces);
             type = type.getSuperclass();
         }
-        return interfaces;
+        return (interfaces != null) ? interfaces : Collections.<Class<?>>emptySet();
     }
 
     /**
-     * Adds to the given collection every interfaces implemented by the given class or interface.
+     * Adds to the given set every interfaces implemented by the given class or interface.
+     *
+     * @param  type  The type for which to add the interfaces in the given set.
+     * @param  addTo The set where to add interfaces, or {@code null} if not yet created.
+     * @return The given set (may be {@code null}), or a new set if the given set was null
+     *         and at least one interface has been found.
      */
-    private static void getAllInterfaces(final Class<?> type, final Set<Class<?>>
interfaces) {
-        for (final Class<?> i : type.getInterfaces()) {
-            if (interfaces.add(i)) {
-                getAllInterfaces(i, interfaces);
+    private static Set<Class<?>> getAllInterfaces(final Class<?> type,
Set<Class<?>> addTo) {
+        final Class<?>[] interfaces = type.getInterfaces();
+        for (int i=0; i<interfaces.length; i++) {
+            final Class<?> candidate = interfaces[i];
+            if (addTo == null) {
+                addTo = new LinkedHashSet<>(hashMapCapacity(interfaces.length - i));
+            }
+            if (addTo.add(candidate)) {
+                getAllInterfaces(candidate, addTo);
             }
         }
+        return addTo;
     }
 
     /**
      * Returns the interfaces implemented by the given class and assignable to the given
base
-     * interface, or {@code null} if none. If more than one interface extends the given base,
+     * interface, or an empty array if none. If more than one interface extends the given
base,
      * then the most specialized interfaces are returned. For example if the given class
      * implements both the {@link Set} and {@link Collection} interfaces, then the returned
      * array contains only the {@code Set} interface.
@@ -328,15 +346,14 @@ public final class Classes extends Stati
      * containing {@code List.class}.
      *
      * @param  <T>  The type of the {@code baseInterface} class argument.
-     * @param  type A class for which the implemented interface is desired.
-     * @param  baseInterface The base type of the interface to search.
-     * @return The leaf interfaces matching the given criterion, or {@code null} if none.
-     *         If non-null, than the array is guaranteed to contain at least one element.
+     * @param  type A class for which the implemented interfaces are desired.
+     * @param  baseInterface The base type of the interfaces to search.
+     * @return The leaf interfaces matching the given criterion, or an empty array if none.
      */
     @SuppressWarnings("unchecked")
     public static <T> Class<? extends T>[] getLeafInterfaces(Class<?> type,
final Class<T> baseInterface) {
         int count = 0;
-        Class<?>[] types = null;
+        Class<?>[] types = EMPTY_ARRAY;
         while (type != null) {
             final Class<?>[] candidates = type.getInterfaces();
 next:       for (final Class<?> candidate : candidates) {
@@ -356,7 +373,7 @@ next:       for (final Class<?> candidat
                             continue next;
                         }
                     }
-                    if (types == null) {
+                    if (types == EMPTY_ARRAY) {
                         types = candidates;
                     }
                     if (count >= types.length) {
@@ -484,7 +501,7 @@ next:       for (final Class<?> candidat
         interfaces.retainAll(buffer);
         for (Iterator<Class<?>> it=interfaces.iterator(); it.hasNext();) {
             final Class<?> candidate = it.next();
-            buffer.clear();
+            buffer.clear(); // Safe because the buffer can not be Collections.EMPTY_SET at
this point.
             getAllInterfaces(candidate, buffer);
             if (interfaces.removeAll(buffer)) {
                 it = interfaces.iterator();
@@ -494,11 +511,13 @@ next:       for (final Class<?> candidat
     }
 
     /**
-     * Returns {@code true} if the two specified objects implements exactly the same set
of
-     * interfaces. Only interfaces assignable to {@code base} are compared. Declaration order
-     * doesn't matter. For example in ISO 19111, different interfaces exist for different
coordinate
-     * system geometries ({@code CartesianCS}, {@code PolarCS}, etc.). We can check if two
-     * CS implementations has the same geometry with the following code:
+     * Returns {@code true} if the two specified objects implements exactly the same set
+     * of interfaces. Only interfaces assignable to {@code baseInterface} are compared.
+     * Declaration order doesn't matter.
+     *
+     * For example in ISO 19111, different interfaces exist for different coordinate system
(CS)
+     * geometries ({@code CartesianCS}, {@code PolarCS}, etc.). One can check if two implementations
+     * have the same geometry with the following code:
      *
      * {@preformat java
      *     if (implementSameInterfaces(cs1, cs2, CoordinateSystem.class)) {
@@ -508,39 +527,27 @@ next:       for (final Class<?> candidat
      *
      * @param object1 The first object to check for interfaces.
      * @param object2 The second object to check for interfaces.
-     * @param base    The parent of all interfaces to check.
-     * @return        {@code true} if both objects implement the same set of interfaces,
-     *                considering only sub-interfaces of {@code base}.
+     * @param baseInterface The parent of all interfaces to check.
+     * @return {@code true} if both objects implement the same set of interfaces,
+     *         considering only sub-interfaces of {@code baseInterface}.
      */
-    public static boolean implementSameInterfaces(final Class<?> object1, final Class<?>
object2, final Class<?> base) {
+    public static boolean implementSameInterfaces(final Class<?> object1, final Class<?>
object2, final Class<?> baseInterface) {
         if (object1 == object2) {
             return true;
         }
         if (object1 == null || object2 == null) {
             return false;
         }
-        final Class<?>[] c1 = object1.getInterfaces();
-        final Class<?>[] c2 = object2.getInterfaces();
-        /*
-         * Trim all interfaces that are not assignable to 'base' in the 'c2' array.
-         * Doing this once will avoid to redo the same test many time in the inner
-         * loops j=[0..n].
-         */
-        int n = 0;
-        for (int i=0; i<c2.length; i++) {
-            final Class<?> c = c2[i];
-            if (base.isAssignableFrom(c)) {
-                c2[n++] = c;
-            }
-        }
+        final Class<?>[] c1 = getLeafInterfaces(object1, baseInterface);
+        final Class<?>[] c2 = getLeafInterfaces(object2, baseInterface);
         /*
-         * For each interface assignable to 'base' in the 'c1' array, check if
-         * this interface exists also in the 'c2' array. Order doesn't matter.
+         * For each interface in the 'c1' array, check if
+         * this interface exists also in the 'c2' array.
          */
-compare:for (int i=0; i<c1.length; i++) {
-            final Class<?> c = c1[i];
-            if (base.isAssignableFrom(c)) {
-                for (int j=0; j<n; j++) {
+        int n = (c2 != null) ? c2.length : 0;
+        if (c1 != null) {
+compare:    for (final Class<?> c : c1) {
+                for (int j=n; --j>=0;) {
                     if (c == c2[j]) {
                         System.arraycopy(c2, j+1, c2, j, --n-j);
                         continue compare;

Modified: sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java?rev=1419525&r1=1419524&r2=1419525&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java
(original)
+++ sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java
Mon Dec 10 15:34:27 2012
@@ -39,6 +39,7 @@ import org.junit.runners.Suite;
   org.apache.sis.util.CharSequencesTest.class,
   org.apache.sis.util.StringBuildersTest.class,
   org.apache.sis.util.UtilitiesTest.class,
+  org.apache.sis.util.ClassesTest.class,
   org.apache.sis.util.VersionTest.class,
   org.apache.sis.util.LocalesTest.class,
   org.apache.sis.util.resources.IndexedResourceBundleTest.class,

Added: sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/util/ClassesTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/util/ClassesTest.java?rev=1419525&view=auto
==============================================================================
--- sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/util/ClassesTest.java (added)
+++ sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/util/ClassesTest.java Mon Dec
10 15:34:27 2012
@@ -0,0 +1,226 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.util;
+
+import org.junit.Test;
+import org.apache.sis.test.TestCase;
+
+import static org.junit.Assert.*;
+import static org.apache.sis.util.Classes.*;
+
+/*
+ * Following imports are not used for actual code.
+ * The are used only as various Class<?> arguments
+ * given to the methods to test.
+ */
+import java.util.Set;
+import java.util.List;
+import java.util.HashSet;
+import java.util.TreeSet;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.NavigableSet;
+import java.util.RandomAccess;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.ObjectStreamException;
+import java.io.InvalidObjectException;
+import java.io.NotSerializableException;
+import java.io.Serializable;
+import org.opengis.referencing.IdentifiedObject;
+import org.opengis.referencing.crs.SingleCRS;
+import org.opengis.referencing.crs.GeographicCRS;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.operation.Transformation;
+import org.opengis.referencing.operation.CoordinateOperation;
+
+
+/**
+ * Tests the {@link Classes} static methods.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.3 (derived from geotk-2.5)
+ * @version 0.3
+ * @module
+ */
+public final strictfp class ClassesTest extends TestCase {
+    /**
+     * Tests {@link Classes#changeArrayDimension(Class, int)}.
+     */
+    @Test
+    public void testChangeArrayDimension() {
+        assertEquals(float    .class, changeArrayDimension(float    .class,  0));
+        assertEquals(Float    .class, changeArrayDimension(Float    .class,  0));
+        assertEquals(float[]  .class, changeArrayDimension(float    .class,  1));
+        assertEquals(Float[]  .class, changeArrayDimension(Float    .class,  1));
+        assertEquals(float[][].class, changeArrayDimension(float    .class,  2));
+        assertEquals(Float[][].class, changeArrayDimension(Float    .class,  2));
+        assertEquals(float[][].class, changeArrayDimension(float[]  .class,  1));
+        assertEquals(Float[][].class, changeArrayDimension(Float[]  .class,  1));
+        assertEquals(float[]  .class, changeArrayDimension(float[][].class, -1));
+        assertEquals(Float[]  .class, changeArrayDimension(Float[][].class, -1));
+        assertEquals(float    .class, changeArrayDimension(float[][].class, -2));
+        assertEquals(Float    .class, changeArrayDimension(Float[][].class, -2));
+        assertNull  (                 changeArrayDimension(float[][].class, -3));
+        assertNull  (                 changeArrayDimension(Float[][].class, -3));
+        assertNull  (                 changeArrayDimension(Void.TYPE,       -1));
+        assertEquals(Void.TYPE,       changeArrayDimension(Void.TYPE,        1));
+    }
+
+    /**
+     * Tests {@link Classes#getAllInterfaces(Class)}.
+     */
+    @Test
+    public void testGetAllInterfaces() {
+        final Set<Class<?>> interfaces = getAllInterfaces(ArrayList.class);
+        assertTrue(interfaces.contains(List        .class));
+        assertTrue(interfaces.contains(Collection  .class));
+        assertTrue(interfaces.contains(Iterable    .class));
+        assertTrue(interfaces.contains(RandomAccess.class));
+        assertTrue(interfaces.contains(Serializable.class));
+        assertTrue(interfaces.contains(Cloneable   .class));
+    }
+
+    /**
+     * Tests {@link Classes#getLeafInterfaces(Class, Class)}.
+     */
+    @Test
+    public void testGetLeafInterfaces() {
+        assertArrayEquals("TreeSet class", new Class<?>[] {NavigableSet.class},
+                getLeafInterfaces(TreeSet.class, Collection.class));
+
+        assertArrayEquals("Convolved class", new Class<?>[] {GeographicCRS.class},
+                getLeafInterfaces(T1.class, IdentifiedObject.class));
+
+        assertArrayEquals("Convolved class", new Class<?>[] {GeographicCRS.class, CoordinateOperation.class},
+                getLeafInterfaces(T2.class, IdentifiedObject.class));
+
+        assertArrayEquals("Convolved class", new Class<?>[] {Transformation.class,
GeographicCRS.class},
+                getLeafInterfaces(T3.class, IdentifiedObject.class));
+    }
+
+    /**
+     * Dummy class for {@link #testGetLeafInterfaces()}.
+     */
+    private static abstract class T1 implements GeographicCRS {}
+    private static abstract class T2 extends T1 implements SingleCRS, CoordinateOperation
{}
+    private static abstract class T3 extends T2 implements Transformation {}
+
+    /**
+     * Tests {@link Classes#findCommonClass(Collection)}
+     * and {@link Classes#findSpecializedClass(Collection)}.
+     */
+    @Test
+    public void testFindCommonParent() {
+        final Set<Object> types = new HashSet<>();
+
+        assertTrue(types.add(new NotSerializableException()));
+        assertEquals(NotSerializableException.class, findCommonClass     (types));
+        assertEquals(NotSerializableException.class, findSpecializedClass(types));
+
+        assertTrue(types.add(new InvalidObjectException(null)));
+        assertEquals(ObjectStreamException.class, findCommonClass     (types));
+        assertEquals(ObjectStreamException.class, findSpecializedClass(types));
+
+        assertTrue(types.add(new FileNotFoundException()));
+        assertEquals(IOException.class, findCommonClass     (types));
+        assertEquals(IOException.class, findSpecializedClass(types));
+
+        assertTrue(types.add(new IOException()));
+        assertEquals(IOException.class, findCommonClass     (types));
+        assertEquals(IOException.class, findSpecializedClass(types));
+
+        assertTrue(types.add(new Exception()));
+        assertEquals(  Exception.class, findCommonClass     (types));
+        assertEquals(IOException.class, findSpecializedClass(types));
+    }
+
+    /**
+     * Tests {@link Classes#findCommonInterfaces(Class, Class)}.
+     */
+    @Test
+    public void testFindCommonInterfaces() {
+        final Set<Class<?>> interfaces = findCommonInterfaces(ArrayList.class,
HashSet.class);
+        assertFalse(interfaces.contains(Set         .class));
+        assertFalse(interfaces.contains(List        .class));
+        assertTrue (interfaces.contains(Collection  .class));
+        assertFalse(interfaces.contains(Iterable    .class));
+        assertFalse(interfaces.contains(RandomAccess.class));
+        assertTrue (interfaces.contains(Serializable.class));
+        assertTrue (interfaces.contains(Cloneable   .class));
+    }
+
+    /**
+     * Tests {@link Classes#implementSameInterfaces(Class, Class, Class)}.
+     */
+    @Test
+    public void testImplementSameInterfaces() {
+        assertTrue (implementSameInterfaces(StringBuilder.class, String.class, CharSequence.class));
+        assertTrue (implementSameInterfaces(StringBuilder.class, String.class, Serializable.class));
+        assertFalse(implementSameInterfaces(         File.class, String.class, CharSequence.class));
+        assertTrue (implementSameInterfaces(         File.class, String.class, Serializable.class));
+
+        // Tests more convolved cases
+        assertTrue (implementSameInterfaces(T1.class, T3.class, CoordinateReferenceSystem.class));
+        assertTrue (implementSameInterfaces(T3.class, T1.class, CoordinateReferenceSystem.class));
+        assertFalse(implementSameInterfaces(T2.class, T3.class, CoordinateOperation.class));
+        assertFalse(implementSameInterfaces(T3.class, T2.class, CoordinateOperation.class));
+        assertFalse(implementSameInterfaces(T3.class, T1.class, CoordinateOperation.class));
+    }
+
+    /**
+     * Tests the {@link #boundOfParameterizedAttribute} method.
+     *
+     * @throws NoSuchFieldException  Should never occur.
+     * @throws NoSuchMethodException Should never occur.
+     */
+    @Test
+    public void testBoundOfParameterizedAttribute() throws NoSuchFieldException, NoSuchMethodException
{
+        final Class<?>[] g = null;
+        final Class<?>[] s = new Class<?>[] {Set.class};
+        final Class<Parameterized> c = Parameterized.class;
+        assertNull(                 boundOfParameterizedAttribute(c.getMethod("getter0",
g)));
+        assertNull(                 boundOfParameterizedAttribute(c.getMethod("setter0",
s)));
+        assertEquals(Long   .class, boundOfParameterizedAttribute(c.getField ("attrib2" 
 )));
+        assertEquals(Integer.class, boundOfParameterizedAttribute(c.getMethod("getter1",
g)));
+        assertEquals(Byte   .class, boundOfParameterizedAttribute(c.getMethod("getter2",
g)));
+        assertEquals(Object .class, boundOfParameterizedAttribute(c.getMethod("getter3",
g)));
+        assertEquals(short[].class, boundOfParameterizedAttribute(c.getMethod("getter4",
g)));
+        assertEquals(String .class, boundOfParameterizedAttribute(c.getMethod("setter1",
s)));
+        assertEquals(Short  .class, boundOfParameterizedAttribute(c.getMethod("setter2",
s)));
+        assertEquals(Object .class, boundOfParameterizedAttribute(c.getMethod("setter3",
s)));
+    }
+
+    /**
+     * Dummy class for {@link #testBoundOfParameterizedAttribute()} usage only.
+     */
+    private static final class Parameterized {
+        public Set<? extends Long> attrib2 = null;
+        @SuppressWarnings("rawtypes")
+        public Set                 getter0() {return null;} // Intentionnaly unparameterized.
+        public Set<       Integer> getter1() {return null;}
+        public Set<? extends Byte> getter2() {return null;}
+        public Set<? super  Float> getter3() {return null;}
+        public Set<       short[]> getter4() {return null;}
+        @SuppressWarnings("rawtypes")
+        public void setter0(Set                  dummy) {}  // Intentionnaly unparameterized.
+        public void setter1(Set<         String> dummy) {}
+        public void setter2(Set<? extends Short> dummy) {}
+        public void setter3(Set<? super  Double> dummy) {}
+    }
+}

Propchange: sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/util/ClassesTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/util/ClassesTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain



Mime
View raw message