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