sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1624414 - in /sis/branches/JDK8/core/sis-utility/src: main/java/org/apache/sis/util/ main/java/org/apache/sis/util/iso/ test/java/org/apache/sis/util/
Date Thu, 11 Sep 2014 22:41:40 GMT
Author: desruisseaux
Date: Thu Sep 11 22:41:39 2014
New Revision: 1624414

URL: http://svn.apache.org/r1624414
Log:
Consolidation of parameter work: we will move the Class <-> TypeName mapping in a dedicated
class
outside of DefaultRecordSchema, so we can use it for ISO 19115 <-> ISO 19111 parameters
as well.
This work is still in progress.

Modified:
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/Classes.java
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultNameFactory.java
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultTypeName.java
    sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/util/ClassesTest.java

Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/Classes.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/Classes.java?rev=1624414&r1=1624413&r2=1624414&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/Classes.java [UTF-8]
(original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/Classes.java [UTF-8]
Thu Sep 11 22:41:39 2014
@@ -213,7 +213,7 @@ public final class Classes extends Stati
                  */
                 if (type instanceof ParameterizedType) {
                     // Example: replace ParameterDescriptor<?> by ParameterDescriptor
-                    // before we test for instance of Class.
+                    // before we test if (type instanceof Class<?>).
                     type = ((ParameterizedType) type).getRawType();
                 }
                 int dimension = 0;

Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultNameFactory.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultNameFactory.java?rev=1624414&r1=1624413&r2=1624414&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultNameFactory.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultNameFactory.java
[UTF-8] Thu Sep 11 22:41:39 2014
@@ -31,7 +31,6 @@ import org.opengis.util.GenericName;
 import org.opengis.util.NameFactory;
 import org.opengis.util.InternationalString;
 import org.apache.sis.util.resources.Errors;
-import org.apache.sis.util.NullArgumentException;
 import org.apache.sis.util.collection.WeakHashSet;
 
 import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
@@ -61,6 +60,7 @@ import static org.apache.sis.util.iso.De
  * <ul>
  *   <li>{@link #parseGenericName(NameSpace, CharSequence)}</li>
  *   <li>{@link #toGenericNames(Object)}</li>
+ *   <li>{@link #toTypeName(Class)}</li>
  * </ul>
  *
  * {@section Thread safety}
@@ -82,11 +82,26 @@ import static org.apache.sis.util.iso.De
  */
 public class DefaultNameFactory extends AbstractFactory implements NameFactory {
     /**
+     * The key for name separator.
+     */
+    static final String SEPARATOR_KEY = "separator";
+
+    /**
+     * The key or the separator after the first name.
+     */
+    static final String HEAD_SEPARATOR_KEY = "separator.head";
+
+    /**
      * Weak references to the name created by this factory.
      */
     private final WeakHashSet<GenericName> pool;
 
     /**
+     * Helper class for mapping {@link Class} to {@link TypeName}, created when first needed.
+     */
+    private transient volatile TypeNames typeNames;
+
+    /**
      * Creates a new factory.
      */
     public DefaultNameFactory() {
@@ -167,18 +182,18 @@ public class DefaultNameFactory extends 
     @Override
     public NameSpace createNameSpace(final GenericName name, final Map<String,?> properties)
{
         ensureNonNull("name", name);
-        String separator = getString(properties, "separator");
+        String separator = getString(properties, SEPARATOR_KEY);
         if (separator == null) {
             separator = DefaultNameSpace.DEFAULT_SEPARATOR_STRING;
         }
-        String headSeparator = getString(properties, "separator.head");
+        String headSeparator = getString(properties, HEAD_SEPARATOR_KEY);
         if (headSeparator == null) {
             headSeparator = separator;
         }
         final boolean isEmpty = separator.isEmpty();
         if (isEmpty || headSeparator.isEmpty()) {
             throw new IllegalArgumentException(Errors.format(
-                    Errors.Keys.EmptyProperty_1, isEmpty ? "separator" : "separator.head"));
+                    Errors.Keys.EmptyProperty_1, isEmpty ? SEPARATOR_KEY : HEAD_SEPARATOR_KEY));
         }
         return DefaultNameSpace.forName(name.toFullyQualifiedName(), headSeparator, separator);
     }
@@ -191,7 +206,9 @@ public class DefaultNameFactory extends 
      *         name to be created, or {@code null} for a global namespace.
      * @param  name The type name as a string or an international string.
      * @return The type name for the given character sequence.
-     * @throws NullArgumentException If the {@code name} argument is null.
+     *
+     * @see #toTypeName(Class)
+     * @see Names#createTypeName(CharSequence, String, CharSequence)
      */
     @Override
     public TypeName createTypeName(final NameSpace scope, final CharSequence name) {
@@ -200,15 +217,13 @@ public class DefaultNameFactory extends 
 
     /**
      * Creates a member name from the given character sequence and attribute type.
-     * The default implementation returns a new or an existing {@link DefaultMemberName}
-     * instance.
+     * The default implementation returns a new or an existing {@link DefaultMemberName}
instance.
      *
      * @param  scope The {@linkplain AbstractName#scope() scope} of the member
      *         name to be created, or {@code null} for a global namespace.
      * @param  name The member name as a string or an international string.
      * @param  attributeType The type of the data associated with the record member.
      * @return The member name for the given character sequence.
-     * @throws NullArgumentException If the {@code name} or {@code attributeType} argument
is null.
      */
     @Override
     public MemberName createMemberName(final NameSpace scope, final CharSequence name, final
TypeName attributeType) {
@@ -223,7 +238,6 @@ public class DefaultNameFactory extends 
      *         name to be created, or {@code null} for a global namespace.
      * @param  name The local name as a string or an international string.
      * @return The local name for the given character sequence.
-     * @throws NullArgumentException If the {@code name} argument is null.
      *
      * @see Names#createLocalName(CharSequence, String, CharSequence)
      */
@@ -251,7 +265,8 @@ public class DefaultNameFactory extends 
      * @param  parsedNames The local names as an array of {@link String} or {@link InternationalString}
instances.
      *         This array shall contain at least one element.
      * @return The generic name for the given parsed names.
-     * @throws NullArgumentException If the given array is empty.
+     *
+     * @see #parseGenericName(NameSpace, CharSequence)
      */
     @Override
     public GenericName createGenericName(final NameSpace scope, final CharSequence... parsedNames)
{
@@ -273,6 +288,8 @@ public class DefaultNameFactory extends 
      * @param  name The qualified name, as a sequence of names separated by a scope-dependent
      *         separator.
      * @return A name parsed from the given string.
+     *
+     * @see Names#parseGenericName(CharSequence, String, CharSequence)
      */
     @Override
     public GenericName parseGenericName(final NameSpace scope, final CharSequence name) {
@@ -371,8 +388,8 @@ public class DefaultNameFactory extends 
 
     /**
      * Creates a generic name from the given value. The value may be an instance of
-     * {@link GenericName}, {@link Identifier} or {@link CharSequence}. If the given
-     * object is not recognized, then this method returns {@code null}.
+     * {@link GenericName}, {@link Identifier}, {@link CharSequence} or {@link Class}.
+     * If the given object is not recognized, then this method returns {@code null}.
      *
      * @param  value The object to convert.
      * @return The converted object, or {@code null} if {@code value} is not convertible.
@@ -387,6 +404,34 @@ public class DefaultNameFactory extends 
         if (value instanceof CharSequence) {
             return parseGenericName(null, (CharSequence) value);
         }
+        if (value instanceof Class<?>) {
+            return toTypeName((Class<?>) value);
+        }
         return null;
     }
+
+    /**
+     * Suggests a type name for the given class. Apache SIS provides a mapping between {@code
Class}
+     * and {@code TypeName} objects as documented in the {@link DefaultTypeName} javadoc.
+     *
+     * <p>In order to protect against potential changes in the {@code Class} ↔ {@code
TypeName} mapping, users are
+     * encouraged to retrieve the {@code valueClass} by invoking the {@link DefaultTypeName#getValueClass()}
method
+     * instead than parsing the name.</p>
+     *
+     * @param  valueClass The Java class for which to get a type name, or {@code null}.
+     * @return A suggested type name, or {@code null} if the given class was null.
+     *
+     * @since 0.5
+     */
+    public TypeName toTypeName(final Class<?> valueClass) {
+        if (valueClass == null) {
+            return null;
+        }
+        TypeNames t = typeNames;
+        if (t == null) synchronized (this) {
+            // Double-check strategy is ok if 'typeNames' is volatile.
+            typeNames = t = new TypeNames(this);
+        }
+        return t.toTypeName(this, valueClass);
+    }
 }

Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultTypeName.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultTypeName.java?rev=1624414&r1=1624413&r2=1624414&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultTypeName.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultTypeName.java
[UTF-8] Thu Sep 11 22:41:39 2014
@@ -20,6 +20,7 @@ import javax.xml.bind.annotation.XmlType
 import javax.xml.bind.annotation.XmlRootElement;
 import org.opengis.util.TypeName;
 import org.opengis.util.NameSpace;
+import org.apache.sis.util.resources.Errors;
 
 
 /**
@@ -28,8 +29,38 @@ import org.opengis.util.NameSpace;
  *
  * <ul>
  *   <li>{@link DefaultNameFactory#createTypeName(NameSpace, CharSequence)}</li>
+ *   <li>{@link DefaultNameFactory#toTypeName(Class)}</li>
  * </ul>
  *
+ * {@section Mapping Java classes to type names}
+ * It is sometime useful to establish a mapping between {@link Class} and {@code TypeName}.
+ * When an UML identifier from an OGC standard exists for a given {@code Class}, Apache SIS
+ * uses that identifier prefixed by the {@code "OGC"} namespace.
+ * Note that this is <strong>not</strong> a standard practice.
+ * A more standard practice would be to use the <cite>definition identifiers in OGC
namespace</cite>
+ * (last column in the table below), but the set of data type identifiers defined by OGC
is currently
+ * small and is sometime not an exact match.
+ *
+ * <table class="sis">
+ *   <caption>Mapping from Java classes to type names (non exhaustive list)</caption>
+ *   <tr><th>Java class</th>                                   <th>Type
name (unofficial)</th>      <th>Definition identifier in OGC namespace</th></tr>
+ *   <tr><td>{@link org.opengis.util.InternationalString}</td> <td>{@code
OGC:FreeText}</td>        <td></td></tr>
+ *   <tr><td>{@link java.lang.String}</td>                     <td>{@code
OGC:CharacterString}</td> <td>urn:ogc:def:dataType:OGC::string</td></tr>
+ *   <tr><td>{@link java.net.URI}</td>                         <td>{@code
OGC:URI}</td>             <td>urn:ogc:def:dataType:OGC::anyURI</td></tr>
+ *   <tr><td>{@link java.lang.Boolean}</td>                    <td>{@code
OGC:Boolean}</td>         <td>urn:ogc:def:dataType:OGC::boolean</td></tr>
+ *   <tr><td>{@link java.lang.Integer}</td>                    <td>{@code
OGC:Integer}</td>         <td>urn:ogc:def:dataType:OGC::nonNegativeInteger</td></tr>
+ *   <tr><td>{@link java.lang.Double}</td>                     <td>{@code
OGC:Real}</td>            <td></td></tr>
+ *   <tr><td>{@link java.util.Date}</td>                       <td>{@code
OGC:DateTime}</td>        <td></td></tr>
+ *   <tr><td>{@link java.util.Locale}</td>                     <td>{@code
OGC:PT_Locale}</td>       <td></td></tr>
+ *   <tr><td>{@link org.opengis.metadata.Metadata}</td>        <td>{@code
OGC:MD_Metadata}</td>     <td></td></tr>
+ *   <tr><td>Unknown Java class</td>                           <td>{@code
class:}&lt;the class name&gt;</td><td></td></tr>
+ * </table>
+ *
+ * The mapping defined by Apache SIS may change in any future version depending on standardization
progress.
+ * To protect against such changes, users are encouraged to rely on methods or constructors
like
+ * {@link DefaultNameFactory#toTypeName(Class)} or {@link #getValueClass()} instead than
parsing the name.
+ *
+ *
  * {@section Immutability and thread safety}
  * This class is immutable and thus inherently thread-safe if the {@link NameSpace} and {@link
CharSequence}
  * arguments given to the constructor are also immutable. Subclasses shall make sure that
any overridden methods
@@ -37,6 +68,7 @@ import org.opengis.util.NameSpace;
  *
  * @author  Guilhem Legal (Geomatys)
  * @author  Cédric Briançon (Geomatys)
+ * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3 (derived from geotk-3.00)
  * @version 0.5
  * @module
@@ -53,6 +85,13 @@ public class DefaultTypeName extends Def
     private static final long serialVersionUID = 7182126541436753582L;
 
     /**
+     * The value class to be returned by {@link #getValueClass()}, or {@code null} if not
yet computed.
+     * This field is serialized because it may be specified at construction time.
+     * {@link Void#TYPE} is used as a sentinel value meaning explicit {@code null}.
+     */
+    private Class<?> valueClass;
+
+    /**
      * Empty constructor to be used by JAXB only. Despite its "final" declaration,
      * the {@link #name} field will be set by JAXB during unmarshalling.
      */
@@ -72,6 +111,28 @@ public class DefaultTypeName extends Def
     }
 
     /**
+     * Constructs a type name from the given character sequence and value class.
+     * The given value class is stored for retrieval by {@link #getValueClass()}.
+     *
+     * @param scope      The scope of this name, or {@code null} for a global scope.
+     * @param name       The local name (never {@code null}).
+     * @param valueClass The Java class associated to this {@code TypeName}, or {@code null}.
+     *
+     * @see DefaultNameFactory#toTypeName(Class)
+     *
+     * @since 0.5
+     */
+    protected DefaultTypeName(final NameSpace scope, final CharSequence name, Class<?>
valueClass) {
+        super(scope, name);
+        if (valueClass == null) {
+            valueClass = Void.TYPE;
+        } else if (valueClass == Void.TYPE) {
+            throw new IllegalArgumentException(Errors.format(Errors.Keys.IllegalArgumentValue_2,
"valueClass", "void"));
+        }
+        this.valueClass = valueClass;
+    }
+
+    /**
      * Returns a SIS type name implementation with the values of the given arbitrary implementation.
      * This method performs the first applicable action in the following choices:
      *
@@ -95,4 +156,25 @@ public class DefaultTypeName extends Def
         }
         return new DefaultTypeName(object.scope(), object.toInternationalString());
     }
+
+    /**
+     * Returns the Java class associated to this type name. If a Java class has been explicitely
specified to the
+     * {@linkplain #DefaultTypeName(NameSpace, CharSequence, Class) constructor}, then that
class is returned
+     * (note that it may be explicitely {@code null}). Otherwise if this {@code TypeName}
is as documented in
+     * the <cite>Mapping Java classes to type names</cite> section of class javadoc,
then the corresponding
+     * Java class is returned. Otherwise this method returns {@code null}.
+     *
+     * @return The Java class associated to this {@code TypeName}, or {@code null} if none.
+     *
+     * @since 0.5
+     */
+    public Class<?> getValueClass() {
+        if (valueClass == Void.TYPE) {
+            return null;
+        }
+        if (valueClass == null) {
+            // TODO: infer here.
+        }
+        return valueClass;
+    }
 }

Modified: sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/util/ClassesTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/util/ClassesTest.java?rev=1624414&r1=1624413&r2=1624414&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/util/ClassesTest.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/util/ClassesTest.java
[UTF-8] Thu Sep 11 22:41:39 2014
@@ -57,7 +57,7 @@ import org.opengis.referencing.operation
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3 (derived from geotk-2.5)
- * @version 0.3
+ * @version 0.5
  * @module
  */
 public final strictfp class ClassesTest extends TestCase {
@@ -106,13 +106,13 @@ public final strictfp class ClassesTest 
         assertArrayEquals("TreeSet class", new Class<?>[] {NavigableSet.class},
                 getLeafInterfaces(TreeSet.class, Collection.class));
 
-        assertArrayEquals("Convolved class", new Class<?>[] {GeographicCRS.class},
+        assertArrayEquals("GeographicCRS", new Class<?>[] {GeographicCRS.class},
                 getLeafInterfaces(T1.class, IdentifiedObject.class));
 
-        assertArrayEquals("Convolved class", new Class<?>[] {GeographicCRS.class, CoordinateOperation.class},
+        assertArrayEquals("Mixed types",   new Class<?>[] {GeographicCRS.class, CoordinateOperation.class},
                 getLeafInterfaces(T2.class, IdentifiedObject.class));
 
-        assertArrayEquals("Convolved class", new Class<?>[] {Transformation.class,
GeographicCRS.class},
+        assertArrayEquals("Mixed types",   new Class<?>[] {Transformation.class, GeographicCRS.class},
                 getLeafInterfaces(T3.class, IdentifiedObject.class));
     }
 
@@ -198,28 +198,30 @@ public final strictfp class ClassesTest 
         final Class<Parameterized> c = Parameterized.class;
         assertNull(                 boundOfParameterizedProperty(c.getMethod("getter0", g)));
         assertNull(                 boundOfParameterizedProperty(c.getMethod("setter0", s)));
-        assertEquals(Long   .class, boundOfParameterizedProperty(c.getField ("attrib2"  
)));
-        assertEquals(Integer.class, boundOfParameterizedProperty(c.getMethod("getter1", g)));
-        assertEquals(Byte   .class, boundOfParameterizedProperty(c.getMethod("getter2", g)));
-        assertEquals(Object .class, boundOfParameterizedProperty(c.getMethod("getter3", g)));
-        assertEquals(short[].class, boundOfParameterizedProperty(c.getMethod("getter4", g)));
-        assertEquals(String .class, boundOfParameterizedProperty(c.getMethod("setter1", s)));
-        assertEquals(Short  .class, boundOfParameterizedProperty(c.getMethod("setter2", s)));
-        assertEquals(Object .class, boundOfParameterizedProperty(c.getMethod("setter3", s)));
+        assertEquals(Long      .class, boundOfParameterizedProperty(c.getField ("attrib2"
  )));
+        assertEquals(Integer   .class, boundOfParameterizedProperty(c.getMethod("getter1",
g)));
+        assertEquals(Byte      .class, boundOfParameterizedProperty(c.getMethod("getter2",
g)));
+        assertEquals(Object    .class, boundOfParameterizedProperty(c.getMethod("getter3",
g)));
+        assertEquals(short[]   .class, boundOfParameterizedProperty(c.getMethod("getter4",
g)));
+        assertEquals(Comparable.class, boundOfParameterizedProperty(c.getMethod("getter5",
g)));
+        assertEquals(String    .class, boundOfParameterizedProperty(c.getMethod("setter1",
s)));
+        assertEquals(Short     .class, boundOfParameterizedProperty(c.getMethod("setter2",
s)));
+        assertEquals(Object    .class, boundOfParameterizedProperty(c.getMethod("setter3",
s)));
     }
 
     /**
      * Dummy class for {@link #testBoundOfParameterizedProperty()} usage only.
      */
+    @SuppressWarnings("rawtypes")
     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 Set<Comparable<?>>  getter5() {return null;}
+
         public void setter0(Set                  dummy) {}  // Intentionnaly unparameterized.
         public void setter1(Set<         String> dummy) {}
         public void setter2(Set<? extends Short> dummy) {}



Mime
View raw message