sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1455514 - in /sis/branches/JDK7/sis-utility/src: main/java/org/apache/sis/internal/converter/ main/java/org/apache/sis/util/ test/java/org/apache/sis/internal/converter/ test/java/org/apache/sis/test/suite/
Date Tue, 12 Mar 2013 12:54:32 GMT
Author: desruisseaux
Date: Tue Mar 12 12:54:31 2013
New Revision: 1455514

URL: http://svn.apache.org/r1455514
Log:
Reduces the size of NumberConverter, since this is not Apache SIS job to provide a framework for converters
(there is other Apache projects for that). Begin the port of ServiceRegistry, to be completed later.

Added:
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/converter/ConverterRegistry.java   (with props)
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/converter/SystemConverter.java   (with props)
    sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/internal/converter/NumberConverterTest.java   (with props)
Modified:
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/converter/ClassPair.java
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/converter/NumberConverter.java
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/Numbers.java
    sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/internal/converter/StringConverterTest.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/internal/converter/ClassPair.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/converter/ClassPair.java?rev=1455514&r1=1455513&r2=1455514&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/converter/ClassPair.java [UTF-8] (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/converter/ClassPair.java [UTF-8] Tue Mar 12 12:54:31 2013
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.internal.converter;
 
+import java.io.Serializable;
 import net.jcip.annotations.Immutable;
 import org.apache.sis.util.ObjectConverter;
 
@@ -35,7 +36,12 @@ import org.apache.sis.util.ObjectConvert
  * @module
  */
 @Immutable
-class ClassPair<S,T> {
+class ClassPair<S,T> implements Serializable {
+    /**
+     * For cross-version compatibility.
+     */
+    private static final long serialVersionUID = -9157788501686115L;
+
     /**
      * The source class.
      */

Added: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/converter/ConverterRegistry.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/converter/ConverterRegistry.java?rev=1455514&view=auto
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/converter/ConverterRegistry.java (added)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/converter/ConverterRegistry.java [UTF-8] Tue Mar 12 12:54:31 2013
@@ -0,0 +1,155 @@
+/*
+ * 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.internal.converter;
+
+import java.util.Map;
+import java.util.LinkedHashMap;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import net.jcip.annotations.ThreadSafe;
+import org.apache.sis.internal.util.SystemListener;
+import org.apache.sis.util.ObjectConverter;
+
+
+/**
+ * A collection of {@link ObjectConverter} instances.
+ * A converter from the given <var>source type</var> to the given <var>target type</var> can be
+ * obtained by a call to {@link #converter(Class, Class)}. If no converter exists for the given
+ * source and target types, then this registry searches for a suitable converter accepting a
+ * parent class of the given source type, or returning a sub-class of the given target type.
+ *
+ * <p>New instances of {@code ConverterRegistry} are initially empty. Custom converters must be
+ * explicitly {@linkplain #register registered}. However a system-wide registry initialized
+ * with default converters is provided by the {@link #SYSTEM} constant.</p>
+ *
+ * {@section Note about conversions from interfaces}
+ * {@code ConverterRegistry} is primarily designed for handling converters from classes to
+ * other classes. Handling of interfaces are not prohibited (and actually sometime supported),
+ * but their behavior may be more ambiguous than in the case of classes because of
+ * multi-inheritance in interface hierarchy.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.3 (derived from geotk-3.20)
+ * @version 0.3
+ * @module
+ */
+@ThreadSafe
+public class ConverterRegistry {
+    /**
+     * The default system-wide instance. This register is initialized with conversions between
+     * some basic Java and SIS objects, like conversions between {@link java.util.Date} and
+     * {@link java.lang.Long}. Those conversions are defined for the lifetime of the JVM.
+     *
+     * <p>If a temporary set of converters is desired, a new instance of {@code ConverterRegistry}
+     * should be created explicitly instead.</p>
+     *
+     * {@section Adding system-wide converters}
+     * Applications can add system-wide custom providers either by explicit call to the
+     * {@link #register(ObjectConverter)} method on the system converter, or by listing
+     * the fully qualified classnames of their {@link ObjectConverter} instances in the
+     * following file (see {@link ServiceLoader} for more info about services loading):
+     *
+     * {@preformat text
+     *     META-INF/services/org.apache.sis.util.converter.ObjectConverter
+     * }
+     */
+    public static final ConverterRegistry SYSTEM = new ConverterRegistry();
+    static {
+        SystemListener.add(new SystemListener() {
+            @Override protected void classpathChanged() {
+                SYSTEM.clear();
+            }
+        });
+    }
+
+    /**
+     * The map of converters of any kind. We use a single read/write lock for the whole map
+     * because write operations will be rare (so {@code ConcurrentHashMap} may be an overkill).
+     */
+    private final Map<ClassPair<?,?>, SystemConverter<?,?>> converters;
+
+    /**
+     * The locks for the {@link #converters} map.
+     */
+    private final ReadWriteLock locks;
+
+    /**
+     * Creates an initially empty set of object converters.
+     */
+    public ConverterRegistry() {
+        converters = new LinkedHashMap<>();
+        locks = new ReentrantReadWriteLock();
+    }
+
+    /**
+     * Removes all converters from this registry.
+     */
+    public void clear() {
+        final Lock lock = locks.writeLock();
+        lock.lock();
+        try {
+            converters.clear();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns an unique instance of the given converter. If a converter already exists for the
+     * same source an target classes, then that converter is returned. Otherwise that converter
+     * is cached if {@code cache} is {@code true} and returned.
+     *
+     * @param  converter The converter to look for a unique instance.
+     * @param  cache Whether to cache the given converter if there is no existing instance.
+     * @return A previously existing instance if one exists, or the given converter otherwise.
+     */
+    @SuppressWarnings("unchecked")
+    final <S,T> ObjectConverter<S,T> unique(final SystemConverter<S,T> converter, final boolean cache) {
+        SystemConverter<S,T> existing;
+        Lock lock = locks.readLock();
+        lock.lock();
+        try {
+            existing = (SystemConverter<S,T>) converters.get(converter);
+        } finally {
+            lock.unlock();
+        }
+        /*
+         * If no instance existed before for the source and target classes, stores this
+         * instance in the pool. However we will need to check again during the write
+         * operation in case an other thread had the time to add an instance in the pool.
+         */
+        if (existing == null) {
+            if (!cache) {
+                return converter;
+            }
+            lock = locks.writeLock();
+            lock.lock();
+            try {
+                existing = (SystemConverter<S,T>) converters.put(converter, converter);
+                if (existing != null) {
+                    converters.put(existing, existing);
+                } else {
+                    existing = converter;
+                }
+            } finally {
+                lock.unlock();
+            }
+        }
+        return existing;
+    }
+}

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/converter/ConverterRegistry.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/converter/ConverterRegistry.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/converter/NumberConverter.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/converter/NumberConverter.java?rev=1455514&r1=1455513&r2=1455514&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/converter/NumberConverter.java [UTF-8] (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/converter/NumberConverter.java [UTF-8] Tue Mar 12 12:54:31 2013
@@ -16,20 +16,31 @@
  */
 package org.apache.sis.internal.converter;
 
-import java.io.Serializable;
-import java.io.ObjectStreamException;
+import java.util.Set;
+import java.util.EnumSet;
 import net.jcip.annotations.Immutable;
 import org.apache.sis.util.Numbers;
 import org.apache.sis.util.ObjectConverter;
-import org.apache.sis.util.resources.Errors;
+import org.apache.sis.math.FunctionProperty;
 
 
 /**
- * Handles conversions from {@link java.lang.Number} to various objects.
+ * Handles conversions from {@link java.lang.Number} to other numbers.
+ * This class supports only the type supported by {@link Numbers}.
  *
- * @param <S> The source type. All shared instances will declare {@link Number},
- *            but some more specific types will occasionally need to be declared
- *            for inverse converters.
+ * {@section Performance note}
+ * We provide a single class for all supported kinds of {@code Number} and delegate the actual
+ * work to the {@code Numbers} static methods. This is not a very efficient way to do the work.
+ * For example it may be more efficient to provide specialized subclasses for each target class,
+ * so we don't have to execute the {@code switch} inside the {@code Numbers} class every time a
+ * value is converted. However performance is not the primary concern here, since those converters
+ * will typically be used by code doing more costly work (e.g. the {@code sis-metadata} module
+ * providing {@code Map} views using Java reflection). So we rather try to be more compact.
+ * If nevertheless performance appear to be a problem, consider reverting to revision 1455255,
+ * which was using one subclass per target type as described above.
+ *
+ * @param <S> The source number type.
+ * @param <T> The target number type.
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3 (derived from geotk-2.4)
@@ -37,470 +48,90 @@ import org.apache.sis.util.resources.Err
  * @module
  */
 @Immutable
-abstract class NumberConverter<S extends Number, T> extends InjectiveConverter<S,T> implements Serializable {
+final class NumberConverter<S extends Number, T extends Number> extends SystemConverter<S,T> {
     /**
      * For cross-version compatibility.
      */
     private static final long serialVersionUID = -8715054480508622025L;
 
     /**
-     * The source class.
-     */
-    private final Class<S> sourceClass;
-
-    /**
-     * For inner classes only.
+     * Creates a new converter for the given source and target classes.
+     * This constructor does not verify the validity of parameter values.
+     * It is caller's responsibility to ensure that the given class are
+     * supported by the {@link Numbers} methods.
      */
-    NumberConverter(final Class<S> sourceClass) {
-        this.sourceClass = sourceClass;
+    NumberConverter(final Class<S> sourceClass, final Class<T> targetClass) {
+        super(sourceClass, targetClass);
     }
 
     /**
-     * Returns the source class given at construction time.
+     * Declares this converter as a injective or surjective function,
+     * depending on whether conversions loose information or not.
      */
     @Override
-    public final Class<S> getSourceClass() {
-        return sourceClass;
+    public Set<FunctionProperty> properties() {
+        return EnumSet.of(Numbers.widestClass(sourceClass, targetClass) == targetClass
+                              ? FunctionProperty.INJECTIVE : FunctionProperty.SURJECTIVE,
+                          FunctionProperty.ORDER_PRESERVING, FunctionProperty.INVERTIBLE);
     }
 
     /**
-     * Default implementation suitable only for subclasses having a target class assignable
-     * to {@link java.lang.Number}. In particular, the {@code Comparable} and {@code String}
-     * subclasses <strong>must</strong> override this method.
+     * Converts the given number to the target type if that type is different.
      */
     @Override
-    @SuppressWarnings("unchecked")
-    public ObjectConverter<T,S> inverse() {
-        assert Number.class.isAssignableFrom(getTargetClass()) : this;
-        return (ObjectConverter<T,S>) create((Class<? extends Number>) getTargetClass(), sourceClass);
+    public T convert(final S source) {
+        return Numbers.cast(source, targetClass);
     }
 
     /**
-     * Creates a converter between numbers of the given classes.
+     * Returns the inverse of this converter.
      */
-    @SuppressWarnings("unchecked") // Only for the last line.
-    private static <S extends Number, T extends Number> ObjectConverter<S,T>
-            create(final Class<S> sourceClass, final Class<T> targetClass)
-    {
-        final ObjectConverter<S,?> c;
-        switch (Numbers.getEnumConstant(targetClass)) {
-            case Numbers.DOUBLE:      c = new Double<>    (sourceClass); break;
-            case Numbers.FLOAT:       c = new Float<>     (sourceClass); break;
-            case Numbers.LONG:        c = new Long<>      (sourceClass); break;
-            case Numbers.INTEGER:     c = new Integer<>   (sourceClass); break;
-            case Numbers.SHORT:       c = new Short<>     (sourceClass); break;
-            case Numbers.BYTE:        c = new Byte<>      (sourceClass); break;
-            case Numbers.BIG_INTEGER: c = new BigInteger<>(sourceClass); break;
-            case Numbers.BIG_DECIMAL: c = new BigDecimal<>(sourceClass); break;
-            default: throw new AssertionError(targetClass);
-        }
-        return (ObjectConverter<S,T>) c;
-    }
-
-    /**
-     * Returns the singleton instance on deserialization if the type is {@link Number}.
-     */
-    final Object readResolve() throws ObjectStreamException {
-        return (sourceClass == Number.class) ? singleton() : this;
+    @Override
+    public ObjectConverter<T,S> inverse() {
+        return new NumberConverter<>(targetClass, sourceClass).unique();
     }
 
     /**
-     * Returns the singleton instance of this converter.
-     */
-    abstract NumberConverter<Number,T> singleton();
-
-    /**
      * Converter from numbers to comparables. This special case exists because {@link Number}
      * does not implement {@link java.lang.Comparable} directly, but all known subclasses do.
      */
     @Immutable
-    static final class Comparable<S extends Number> extends NumberConverter<S, java.lang.Comparable<?>> {
+    static final class Comparable<S extends Number> extends SystemConverter<S, java.lang.Comparable<?>> {
         /**
          * For cross-version compatibility.
          */
         private static final long serialVersionUID = 3716134638218072176L;
 
         /**
-         * The usually shared instance. {@link ConverterRegistry} needs only the {@link Number}
-         * type. Other types are created only by {@code StringConverter.Foo.inverse()} methods.
-         */
-        static final Comparable<Number> INSTANCE = new Comparable<>(Number.class);
-
-        /**
          * Creates a new converter from the given type of numbers to {@code Comparable} instances.
          */
+        @SuppressWarnings({"rawtypes","unchecked"})
         Comparable(final Class<S> sourceClass) {
-            super(sourceClass);
-        }
-
-        /** Returns the destination type (same for all instances of this class). */
-        @Override @SuppressWarnings({"rawtypes","unchecked"})
-        public Class<java.lang.Comparable<?>> getTargetClass() {
-            return (Class) java.lang.Comparable.class;
-        }
-
-        /** Converts the given number to a {@code Comparable} if its type is different. */
-        @Override public java.lang.Comparable<?> convert(final Number source) {
-            if (source == null || source instanceof java.lang.Comparable<?>) {
-                return (java.lang.Comparable<?>) source;
-            }
-            return (java.lang.Comparable<?>) Numbers.narrowestNumber(source);
-        }
-
-        /** Non-invertible converter (for now). */
-        @Override public ObjectConverter<java.lang.Comparable<?>, S> inverse() {
-            throw new UnsupportedOperationException(Errors.format(
-                    Errors.Keys.UnsupportedOperation_1, "inverse"));
-        }
-
-        /** Returns the singleton instance on deserialization. */
-        @Override NumberConverter<Number, java.lang.Comparable<?>> singleton() {
-            return INSTANCE;
-        }
-    }
-
-    /**
-     * Converter from numbers to doubles.
-     */
-    @Immutable
-    static final class Double<S extends Number> extends NumberConverter<S, java.lang.Double> {
-        /**
-         * For cross-version compatibility.
-         */
-        private static final long serialVersionUID = 1643009985070268985L;
-
-        /**
-         * The usually shared instance. {@link ConverterRegistry} needs only the {@link Number}
-         * type. Other types are created only by {@code StringConverter.Foo.inverse()} methods.
-         */
-        static final Double<Number> INSTANCE = new Double<>(Number.class);
-
-        /**
-         * Creates a new converter from the given type of numbers to {@code Double} instances.
-         */
-        Double(final Class<S> sourceClass) {
-            super(sourceClass);
-        }
-
-        /** Returns the destination type (same for all instances of this class). */
-        @Override public Class<java.lang.Double> getTargetClass() {
-            return java.lang.Double.class;
-        }
-
-        /** Converts the given number to a {@code Double} if its type is different. */
-        @Override public java.lang.Double convert(final S source) {
-            if (source == null || source instanceof java.lang.Double) {
-                return (java.lang.Double) source;
-            }
-            return java.lang.Double.valueOf(source.doubleValue());
-        }
-
-        /** Returns the singleton instance on deserialization. */
-        @Override NumberConverter<Number, java.lang.Double> singleton() {
-            return INSTANCE;
-        }
-    }
-
-    /**
-     * Converter from numbers to floats.
-     */
-    @Immutable
-    static final class Float<S extends Number> extends NumberConverter<S, java.lang.Float> {
-        /**
-         * For cross-version compatibility.
-         */
-        private static final long serialVersionUID = -5900985555014433974L;
-
-        /**
-         * The usually shared instance. {@link ConverterRegistry} needs only the {@link Number}
-         * type. Other types are created only by {@code StringConverter.Foo.inverse()} methods.
-         */
-        static final Float<Number> INSTANCE = new Float<>(Number.class);
-
-        /**
-         * Creates a new converter from the given type of numbers to {@code Float} instances.
-         */
-        Float(final Class<S> sourceClass) {
-            super(sourceClass);
-        }
-
-        /** Returns the destination type (same for all instances of this class). */
-        @Override public Class<java.lang.Float> getTargetClass() {
-            return java.lang.Float.class;
-        }
-
-        /** Converts the given number to a {@code Float} if its type is different. */
-        @Override public java.lang.Float convert(final S source) {
-            if (source == null || source instanceof java.lang.Float) {
-                return (java.lang.Float) source;
-            }
-            return java.lang.Float.valueOf(source.floatValue());
-        }
-
-        /** Returns the singleton instance on deserialization. */
-        @Override NumberConverter<Number, java.lang.Float> singleton() {
-            return INSTANCE;
-        }
-    }
-
-    /**
-     * Converter from numbers to longs.
-     */
-    @Immutable
-    static final class Long<S extends Number> extends NumberConverter<S, java.lang.Long> {
-        /**
-         * For cross-version compatibility.
-         */
-        private static final long serialVersionUID = -5320144566275003574L;
-
-        /**
-         * The usually shared instance. {@link ConverterRegistry} needs only the {@link Number}
-         * type. Other types are created only by {@code StringConverter.Foo.inverse()} methods.
-         */
-        static final Long<Number> INSTANCE = new Long<>(Number.class);
-
-        /**
-         * Creates a new converter from the given type of numbers to {@code Long} instances.
-         */
-        Long(final Class<S> sourceClass) {
-            super(sourceClass);
-        }
-
-        /** Returns the destination type (same for all instances of this class). */
-        @Override public Class<java.lang.Long> getTargetClass() {
-            return java.lang.Long.class;
-        }
-
-        /** Converts the given number to a {@code Long} if its type is different. */
-        @Override public java.lang.Long convert(final S source) {
-            if (source == null || source instanceof java.lang.Long) {
-                return (java.lang.Long) source;
-            }
-            return java.lang.Long.valueOf(source.longValue());
-        }
-
-        /** Returns the singleton instance on deserialization. */
-        @Override NumberConverter<Number, java.lang.Long> singleton() {
-            return INSTANCE;
-        }
-    }
-
-    /**
-     * Converter from numbers to integers.
-     */
-    @Immutable
-    static final class Integer<S extends Number> extends NumberConverter<S, java.lang.Integer> {
-        /**
-         * For cross-version compatibility.
-         */
-        private static final long serialVersionUID = 2661178278691398269L;
-
-        /**
-         * The usually shared instance. {@link ConverterRegistry} needs only the {@link Number}
-         * type. Other types are created only by {@code StringConverter.Foo.inverse()} methods.
-         */
-        static final Integer<Number> INSTANCE = new Integer<>(Number.class);
-
-        /**
-         * Creates a new converter from the given type of numbers to {@code Integer} instances.
-         */
-        Integer(final Class<S> sourceClass) {
-            super(sourceClass);
-        }
-
-        /** Returns the destination type (same for all instances of this class). */
-        @Override public Class<java.lang.Integer> getTargetClass() {
-            return java.lang.Integer.class;
-        }
-
-        /** Converts the given number to an {@code Integer} if its type is different. */
-        @Override public java.lang.Integer convert(final S source) {
-            if (source == null || source instanceof java.lang.Integer) {
-                return (java.lang.Integer) source;
-            }
-            return java.lang.Integer.valueOf(source.intValue());
+            super(sourceClass, (Class) java.lang.Comparable.class);
         }
 
-        /** Returns the singleton instance on deserialization. */
-        @Override NumberConverter<Number, java.lang.Integer> singleton() {
-            return INSTANCE;
-        }
-    }
-
-    /**
-     * Converter from numbers to shorts.
-     */
-    @Immutable
-    static final class Short<S extends Number> extends NumberConverter<S, java.lang.Short> {
-        /**
-         * For cross-version compatibility.
-         */
-        private static final long serialVersionUID = -5943559376400249179L;
-
         /**
-         * The usually shared instance. {@link ConverterRegistry} needs only the {@link Number}
-         * type. Other types are created only by {@code StringConverter.Foo.inverse()} methods.
+         * If the source class implements {@code Comparable}, then this converter is bijective.
+         * Otherwise there is no known property for this converter.
          */
-        static final Short<Number> INSTANCE = new Short<>(Number.class);
-
-        /**
-         * Creates a new converter from the given type of numbers to {@code Short} instances.
-         */
-        Short(final Class<S> sourceClass) {
-            super(sourceClass);
-        }
-
-        /** Returns the destination type (same for all instances of this class). */
-        @Override public Class<java.lang.Short> getTargetClass() {
-            return java.lang.Short.class;
-        }
-
-        /** Converts the given number to a {@code Short} if its type is different. */
-        @Override public java.lang.Short convert(final S source) {
-            if (source == null || source instanceof java.lang.Short) {
-                return (java.lang.Short) source;
+        @Override
+        public Set<FunctionProperty> properties() {
+            if (Comparable.class.isAssignableFrom(sourceClass)) {
+                return EnumSet.of(FunctionProperty.INJECTIVE, FunctionProperty.SURJECTIVE,
+                            FunctionProperty.ORDER_PRESERVING);
             }
-            return java.lang.Short.valueOf(source.shortValue());
+            return EnumSet.noneOf(FunctionProperty.class);
         }
 
-        /** Returns the singleton instance on deserialization. */
-        @Override NumberConverter<Number, java.lang.Short> singleton() {
-            return INSTANCE;
-        }
-    }
-
-    /**
-     * Converter from numbers to shorts.
-     */
-    @Immutable
-    static final class Byte<S extends Number> extends NumberConverter<S, java.lang.Byte> {
         /**
-         * For cross-version compatibility.
+         * Converts the given number to a {@code Comparable} if its type is different.
          */
-        private static final long serialVersionUID = 1381038535870541045L;
-
-        /**
-         * The usually shared instance. {@link ConverterRegistry} needs only the {@link Number}
-         * type. Other types are created only by {@code StringConverter.Foo.inverse()} methods.
-         */
-        static final Byte<Number> INSTANCE = new Byte<>(Number.class);
-
-        /**
-         * Creates a new converter from the given type of numbers to {@code Byte} instances.
-         */
-        Byte(final Class<S> sourceClass) {
-            super(sourceClass);
-        }
-
-        /** Returns the destination type (same for all instances of this class). */
-        @Override public Class<java.lang.Byte> getTargetClass() {
-            return java.lang.Byte.class;
-        }
-
-        /** Converts the given number to a {@code Byte} if its type is different. */
-        @Override public java.lang.Byte convert(final S source) {
-            if (source == null || source instanceof java.lang.Byte) {
-                return (java.lang.Byte) source;
-            }
-            return java.lang.Byte.valueOf(source.byteValue());
-        }
-
-        /** Returns the singleton instance on deserialization. */
-        @Override NumberConverter<Number, java.lang.Byte> singleton() {
-            return INSTANCE;
-        }
-    }
-
-    /**
-     * Converter from numbers to {@link java.math.BigDecimal}.
-     */
-    @Immutable
-    static final class BigDecimal<S extends Number> extends NumberConverter<S, java.math.BigDecimal> {
-        /**
-         * For cross-version compatibility.
-         */
-        private static final long serialVersionUID = -6318144992861058878L;
-
-        /**
-         * The usually shared instance. {@link ConverterRegistry} needs only the {@link Number}
-         * type. Other types are created only by {@code StringConverter.Foo.inverse()} methods.
-         */
-        static final BigDecimal<Number> INSTANCE = new BigDecimal<>(Number.class);
-
-        /**
-         * Creates a new converter from the given type of numbers to {@code BigDecimal} instances.
-         */
-        BigDecimal(final Class<S> sourceClass) {
-            super(sourceClass);
-        }
-
-        /** Returns the destination type (same for all instances of this class). */
-        @Override public Class<java.math.BigDecimal> getTargetClass() {
-            return java.math.BigDecimal.class;
-        }
-
-        /** Converts the given number to a {@code BigDecimal} if its type is different. */
-        @Override public java.math.BigDecimal convert(final S source) {
-            if (source == null || source instanceof java.math.BigDecimal) {
-                return (java.math.BigDecimal) source;
-            }
-            if (source instanceof java.math.BigInteger) {
-                return new java.math.BigDecimal((java.math.BigInteger) source);
-            }
-            if (Numbers.isInteger(source.getClass())) {
-                return java.math.BigDecimal.valueOf(source.longValue());
-            }
-            return java.math.BigDecimal.valueOf(source.doubleValue());
-        }
-
-        /** Returns the singleton instance on deserialization. */
-        @Override NumberConverter<Number, java.math.BigDecimal> singleton() {
-            return INSTANCE;
-        }
-    }
-
-    /**
-     * Converter from numbers to {@link java.math.BigInteger}.
-     */
-    @Immutable
-    static final class BigInteger<S extends Number> extends NumberConverter<S, java.math.BigInteger> {
-        /**
-         * For cross-version compatibility.
-         */
-        private static final long serialVersionUID = 5940724099300523246L;
-
-        /**
-         * The usually shared instance. {@link ConverterRegistry} needs only the {@link Number}
-         * type. Other types are created only by {@code StringConverter.Foo.inverse()} methods.
-         */
-        static final BigInteger<Number> INSTANCE = new BigInteger<>(Number.class);
-
-        /**
-         * Creates a new converter from the given type of numbers to {@code BigInteger} instances.
-         */
-        BigInteger(final Class<S> sourceClass) {
-            super(sourceClass);
-        }
-
-        /** Returns the destination type (same for all instances of this class). */
-        @Override public Class<java.math.BigInteger> getTargetClass() {
-            return java.math.BigInteger.class;
-        }
-
-        /** Converts the given number to a {@code BigInteger} if its type is different. */
-        @Override public java.math.BigInteger convert(final S source) {
-            if (source == null || source instanceof java.math.BigInteger) {
-                return (java.math.BigInteger) source;
-            }
-            if (source instanceof java.math.BigDecimal) {
-                return ((java.math.BigDecimal) source).toBigInteger();
+        @Override
+        public java.lang.Comparable<?> convert(final Number source) {
+            if (source == null || source instanceof java.lang.Comparable<?>) {
+                return (java.lang.Comparable<?>) source;
             }
-            return java.math.BigInteger.valueOf(source.longValue());
-        }
-
-        /** Returns the singleton instance on deserialization. */
-        @Override NumberConverter<Number, java.math.BigInteger> singleton() {
-            return INSTANCE;
+            return (java.lang.Comparable<?>) Numbers.narrowestNumber(source);
         }
     }
 }

Added: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/converter/SystemConverter.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/converter/SystemConverter.java?rev=1455514&view=auto
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/converter/SystemConverter.java (added)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/converter/SystemConverter.java [UTF-8] Tue Mar 12 12:54:31 2013
@@ -0,0 +1,94 @@
+/*
+ * 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.internal.converter;
+
+import java.io.ObjectStreamException;
+import org.apache.sis.util.ObjectConverter;
+import org.apache.sis.util.resources.Errors;
+
+
+/**
+ * Base class of all converters defined in the {@code org.apache.sis.internal} package.
+ * Those converters are returned by system-wide {@link ConverterRegitry}, and cached for
+ * reuse.
+ *
+ * @param <S> The base type of source objects.
+ * @param <T> The base type of converted objects.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.3
+ * @version 0.3
+ * @module
+ */
+abstract class SystemConverter<S,T> extends ClassPair<S,T> implements ObjectConverter<S,T> {
+    /**
+     * For cross-version compatibility.
+     */
+    private static final long serialVersionUID = 885663610056067478L;
+
+    /**
+     * Creates a new converter for the given source and target classes.
+     *
+     * @param sourceClass The {@linkplain ObjectConverter#getSourceClass() source class}.
+     * @param targetClass The {@linkplain ObjectConverter#getTargetClass() target class}.
+     */
+    SystemConverter(final Class<S> sourceClass, final Class<T> targetClass) {
+        super(sourceClass, targetClass);
+    }
+
+    /**
+     * Returns the source class given at construction time.
+     */
+    @Override
+    public final Class<S> getSourceClass() {
+        return sourceClass;
+    }
+
+    /**
+     * Returns the target class given at construction time.
+     */
+    @Override
+    public final Class<T> getTargetClass() {
+        return targetClass;
+    }
+
+    /**
+     * Unsupported by default. To be overridden by subclasses that support this operation.
+     */
+    @Override
+    public ObjectConverter<T, S> inverse() throws UnsupportedOperationException {
+        throw new UnsupportedOperationException(Errors.format(
+                Errors.Keys.UnsupportedOperation_1, "inverse"));
+    }
+
+    /**
+     * Returns an unique instance of this converter. If a converter already exists for the same
+     * source an target classes, then this converter is returned. Otherwise this converter is
+     * cached and returned.
+     */
+    final ObjectConverter<S,T> unique() {
+        return ConverterRegistry.SYSTEM.unique(this, true);
+    }
+
+    /**
+     * Returns the singleton instance on deserialization, if any. If no instance already exist
+     * in the virtual machine, we do not cache the instance (for now) for security reasons.
+     */
+    protected final Object readResolve() throws ObjectStreamException {
+        return ConverterRegistry.SYSTEM.unique(this, false);
+    }
+}

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/converter/SystemConverter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/converter/SystemConverter.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/Numbers.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/Numbers.java?rev=1455514&r1=1455513&r2=1455514&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/Numbers.java [UTF-8] (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/Numbers.java [UTF-8] Tue Mar 12 12:54:31 2013
@@ -419,8 +419,8 @@ public final class Numbers extends Stati
     }
 
     /**
-     * Returns the number of the smallest class capable to hold the specified value. If the
-     * given value is {@code null}, then this method returns {@code null}. Otherwise this
+     * Returns the given number wrapped in the smallest class capable to hold the specified value.
+     * If the given value is {@code null}, then this method returns {@code null}. Otherwise this
      * method delegates to {@link #narrowestNumber(double)} or {@link #narrowestNumber(long)}
      * depending on the value type.
      *
@@ -517,7 +517,8 @@ public final class Numbers extends Stati
 
     /**
      * Casts a number to the specified class. The class must by one of {@link Byte},
-     * {@link Short}, {@link Integer}, {@link Long}, {@link Float} or {@link Double}.
+     * {@link Short}, {@link Integer}, {@link Long}, {@link Float}, {@link Double},
+     * {@link BigInteger} or {@link BigDecimal}.
      * This method makes the following choice:
      *
      * <ul>
@@ -528,10 +529,6 @@ public final class Numbers extends Stati
      *   <li>And likewise for all remaining known types.</li>
      * </ul>
      *
-     * {@note This method is intentionally restricted to primitive types. Other types
-     *        like <code>BigDecimal</code> are not the purpose of this method.
-     *        See <code>ObjectConverter</code> for more generic methods.}
-     *
      * This method does not verify if the given type is wide enough for the given value,
      * because the type has typically been calculated by {@link #widestClass(Class, Class)}
      * or {@link #narrowestClass(Number)}. If nevertheless the given type is not wide enough,
@@ -552,20 +549,47 @@ public final class Numbers extends Stati
         if (number == null || number.getClass() == type) {
             return (N) number;
         }
-        if (type == Double .class) return (N) Double .valueOf(number.doubleValue());
-        if (type == Float  .class) return (N) Float  .valueOf(number. floatValue());
-        if (type == Long   .class) return (N) Long   .valueOf(number.  longValue());
-        if (type == Integer.class) return (N) Integer.valueOf(number.   intValue());
-        if (type == Short  .class) return (N) Short  .valueOf(number. shortValue());
-        if (type == Byte   .class) return (N) Byte   .valueOf(number.  byteValue());
-        throw unknownType(type);
+        switch (getEnumConstant(type)) {
+            case BYTE:    return (N) Byte   .valueOf(number.  byteValue());
+            case SHORT:   return (N) Short  .valueOf(number. shortValue());
+            case INTEGER: return (N) Integer.valueOf(number.   intValue());
+            case LONG:    return (N) Long   .valueOf(number.  longValue());
+            case FLOAT:   return (N) Float  .valueOf(number. floatValue());
+            case DOUBLE:  return (N) Double .valueOf(number.doubleValue());
+            case BIG_INTEGER: {
+                final BigInteger c;
+                if (number instanceof BigDecimal) {
+                    c = ((BigDecimal) number).toBigInteger();
+                } else {
+                    c = BigInteger.valueOf(number.longValue());
+                }
+                return (N) c;
+            }
+            case BIG_DECIMAL: {
+                final BigDecimal c;
+                if (number instanceof BigInteger) {
+                    c =new BigDecimal((BigInteger) number);
+                } else if (isInteger(number.getClass())) {
+                    c = BigDecimal.valueOf(number.longValue());
+                } else {
+                    c = BigDecimal.valueOf(number.doubleValue());
+                }
+                return (N) c;
+            }
+            default: {
+                if (type.isInstance(number)) {
+                    return (N) number;
+                }
+                throw unknownType(type);
+            }
+        }
     }
 
     /**
      * Wraps the given value in a {@code Number} of the specified class.
-     * The given type shall be one of {@link Byte}, {@link Short}, {@link Integer},
-     * {@link Long}, {@link Float} or {@link Double} classes. Furthermore, the given
-     * value shall be convertible to the given class without precision lost,
+     * The given type shall be one of {@link Byte}, {@link Short}, {@link Integer}, {@link Long},
+     * {@link Float}, {@link Double}, {@link BigInteger} and {@link BigDecimal} classes.
+     * Furthermore, the given value shall be convertible to the given class without precision lost,
      * otherwise an {@link IllegalArgumentException} will be thrown.
      *
      * @param  <N> The wrapper class.
@@ -581,13 +605,17 @@ public final class Numbers extends Stati
             throws IllegalArgumentException
     {
         final N number;
-             if (type == Double .class) return   (N) Double .valueOf(value); // No need to verify.
-        else if (type == Float  .class) number = (N) Float  .valueOf((float) value);
-        else if (type == Long   .class) number = (N) Long   .valueOf((long)  value);
-        else if (type == Integer.class) number = (N) Integer.valueOf((int)   value);
-        else if (type == Short  .class) number = (N) Short  .valueOf((short) value);
-        else if (type == Byte   .class) number = (N) Byte   .valueOf((byte)  value);
-        else throw unknownType(type);
+        switch (getEnumConstant(type)) {
+            case BYTE:        number = (N) Byte      .valueOf((byte)  value); break;
+            case SHORT:       number = (N) Short     .valueOf((short) value); break;
+            case INTEGER:     number = (N) Integer   .valueOf((int)   value); break;
+            case LONG:        number = (N) Long      .valueOf((long)  value); break;
+            case FLOAT:       number = (N) Float     .valueOf((float) value); break;
+            case DOUBLE:      return   (N) Double    .valueOf(value); // No need to verify.
+            case BIG_INTEGER: number = (N) BigInteger.valueOf((long) value); break;
+            case BIG_DECIMAL: return   (N) BigDecimal.valueOf(value); // No need to verify.
+            default: throw unknownType(type);
+        }
         if (Double.doubleToLongBits(number.doubleValue()) != Double.doubleToLongBits(value)) {
             throw new IllegalArgumentException(Errors.format(Errors.Keys.CanNotConvertValue_2, value, type));
         }
@@ -596,6 +624,7 @@ public final class Numbers extends Stati
 
     /**
      * Converts the specified string into a value object. The value object can be an instance of
+     * {@link BigDecimal}, {@link BigInteger},
      * {@link Double}, {@link Float}, {@link Long}, {@link Integer}, {@link Short}, {@link Byte},
      * {@link Boolean}, {@link Character} or {@link String} according the specified type. This
      * method makes the following choice:
@@ -608,11 +637,6 @@ public final class Numbers extends Stati
      *   <li>And likewise for all remaining known types.</li>
      * </ul>
      *
-     * {@note This method is intentionally restricted to primitive types, with the addition of
-     *        <code>String</code> which can be though as an identity operation. Other types
-     *        like <code>BigDecimal</code> are not the purpose of this method. See the
-     *        <code>ConverterRegistry</code> class for a more generic method.}
-     *
      * @param  <T> The requested type.
      * @param  value the value to parse.
      * @param  type The requested type.
@@ -628,26 +652,30 @@ public final class Numbers extends Stati
         if (value == null || type == String.class) {
             return (T) value;
         }
-        if (type == Character.class) {
-            /*
-             * If the string is empty, returns 0 which means "end of string" in C/C++
-             * and NULL in Unicode standard. If non-empty, take only the first char.
-             * This is somewhat consistent with Boolean.valueOf(...) which is quite
-             * lenient about the parsing as well, and throwing a NumberFormatException
-             * for those would not be appropriate.
-             */
-            return (T) Character.valueOf(value.isEmpty() ? 0 : value.charAt(0));
+        switch (getEnumConstant(type)) {
+            case CHARACTER: {
+                /*
+                 * If the string is empty, returns 0 which means "end of string" in C/C++
+                 * and NULL in Unicode standard. If non-empty, take only the first char.
+                 * This is somewhat consistent with Boolean.valueOf(...) which is quite
+                 * lenient about the parsing as well, and throwing a NumberFormatException
+                 * for those would not be appropriate.
+                 */
+                return (T) Character.valueOf(value.isEmpty() ? 0 : value.charAt(0));
+            }
+            // Do not trim whitespaces. It is up to the caller to do that if he wants.
+            // For such low level function, we are better to avoid hidden initiative.
+            case BOOLEAN:     return (T) Boolean.valueOf(value);
+            case BYTE:        return (T) Byte   .valueOf(value);
+            case SHORT:       return (T) Short  .valueOf(value);
+            case INTEGER:     return (T) Integer.valueOf(value);
+            case LONG:        return (T) Long   .valueOf(value);
+            case FLOAT:       return (T) Float  .valueOf(value);
+            case DOUBLE:      return (T) Double .valueOf(value);
+            case BIG_INTEGER: return (T) new BigInteger(value);
+            case BIG_DECIMAL: return (T) new BigDecimal(value);
+            default: throw unknownType(type);
         }
-        // Do not trim whitespaces. It is up to the caller to do that if he wants.
-        // For such low level function, we are better to avoid hidden initiative.
-        if (type == Double .class) return (T) Double .valueOf(value);
-        if (type == Float  .class) return (T) Float  .valueOf(value);
-        if (type == Long   .class) return (T) Long   .valueOf(value);
-        if (type == Integer.class) return (T) Integer.valueOf(value);
-        if (type == Short  .class) return (T) Short  .valueOf(value);
-        if (type == Byte   .class) return (T) Byte   .valueOf(value);
-        if (type == Boolean.class) return (T) Boolean.valueOf(value);
-        throw unknownType(type);
     }
 
     /**

Added: sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/internal/converter/NumberConverterTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/internal/converter/NumberConverterTest.java?rev=1455514&view=auto
==============================================================================
--- sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/internal/converter/NumberConverterTest.java (added)
+++ sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/internal/converter/NumberConverterTest.java [UTF-8] Tue Mar 12 12:54:31 2013
@@ -0,0 +1,154 @@
+/*
+ * 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.internal.converter;
+
+import java.math.BigInteger;
+import java.math.BigDecimal;
+import org.apache.sis.math.FunctionProperty;
+import org.apache.sis.util.ObjectConverter;
+import org.apache.sis.util.UnconvertibleObjectException;
+import org.apache.sis.test.TestCase;
+import org.junit.Test;
+
+import static org.apache.sis.test.Assert.*;
+
+
+/**
+ * Tests the various {@link NumberConverter} implementations.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.3 (derived from geotk-2.4)
+ * @version 0.3
+ * @module
+ */
+public final strictfp class NumberConverterTest extends TestCase {
+    /**
+     * Asserts that conversion of the given {@code source} value produces
+     * the given {@code target} value, and tests the inverse conversion.
+     */
+    private static <S extends Number, T extends Number> void runInvertibleConversion(
+            final ObjectConverter<S,T> c, final S source, final T target)
+            throws UnconvertibleObjectException
+    {
+        assertEquals("Forward conversion.", target, c.convert(source));
+        assertEquals("Inverse conversion.", source, c.inverse().convert(target));
+        assertSame("Inconsistent inverse.", c, c.inverse().inverse());
+        assertTrue("Invertible converters shall declare this capability.",
+                c.properties().contains(FunctionProperty.INVERTIBLE));
+    }
+
+    /**
+     * Tests conversions to {@link Byte} values.
+     */
+    @Test
+    public void testByte() {
+        final ObjectConverter<Integer, Byte> c =
+                new NumberConverter<>(Integer.class, Byte.class).unique();
+        runInvertibleConversion(c, Integer.valueOf(-8), Byte.valueOf((byte) -8));
+        assertSame("Deserialization shall resolves to the singleton instance.", c, assertSerializedEquals(c));
+    }
+
+    /**
+     * Tests conversions to {@link Short} values.
+     */
+    @Test
+    public void testShort() {
+        final ObjectConverter<Integer, Short> c =
+                new NumberConverter<>(Integer.class, Short.class).unique();
+        runInvertibleConversion(c, Integer.valueOf(-8), Short.valueOf((short) -8));
+        assertSame("Deserialization shall resolves to the singleton instance.", c, assertSerializedEquals(c));
+    }
+
+    /**
+     * Tests conversions to {@link Integer} values.
+     */
+    @Test
+    public void testInteger() {
+        final ObjectConverter<Float, Integer> c =
+                new NumberConverter<>(Float.class, Integer.class).unique();
+        runInvertibleConversion(c, Float.valueOf(-8), Integer.valueOf(-8));
+        assertSame("Deserialization shall resolves to the singleton instance.", c, assertSerializedEquals(c));
+    }
+
+    /**
+     * Tests conversions to {@link Long} values.
+     */
+    @Test
+    public void testLong() {
+        final ObjectConverter<Float, Long> c =
+                new NumberConverter<>(Float.class, Long.class).unique();
+        runInvertibleConversion(c, Float.valueOf(-8), Long.valueOf(-8));
+        assertSame("Deserialization shall resolves to the singleton instance.", c, assertSerializedEquals(c));
+    }
+
+    /**
+     * Tests conversions to {@link Float} values.
+     */
+    @Test
+    public void testFloat() {
+        final ObjectConverter<Double, Float> c =
+                new NumberConverter<>(Double.class, Float.class).unique();
+        runInvertibleConversion(c, Double.valueOf(2.5), Float.valueOf(2.5f));
+        assertSame("Deserialization shall resolves to the singleton instance.", c, assertSerializedEquals(c));
+    }
+
+    /**
+     * Tests conversions to {@link Double} values.
+     */
+    @Test
+    public void testDouble() {
+        final ObjectConverter<BigDecimal, Double> c =
+                new NumberConverter<>(BigDecimal.class, Double.class).unique();
+        runInvertibleConversion(c, BigDecimal.valueOf(2.5), Double.valueOf(2.5));
+        assertSame("Deserialization shall resolves to the singleton instance.", c, assertSerializedEquals(c));
+    }
+
+    /**
+     * Tests conversions to {@link BigInteger} values.
+     */
+    @Test
+    public void testBigInteger() {
+        final ObjectConverter<Double, BigInteger> c =
+                new NumberConverter<>(Double.class, BigInteger.class).unique();
+        runInvertibleConversion(c, Double.valueOf(1000), BigInteger.valueOf(1000));
+        assertSame("Deserialization shall resolves to the singleton instance.", c, assertSerializedEquals(c));
+    }
+
+    /**
+     * Tests conversions to {@link BigDecimal} values.
+     */
+    @Test
+    public void testBigDecimal() {
+        final ObjectConverter<Double, BigDecimal> c =
+                new NumberConverter<>(Double.class, BigDecimal.class).unique();
+        runInvertibleConversion(c, Double.valueOf(2.5), BigDecimal.valueOf(2.5));
+        assertSame("Deserialization shall resolves to the singleton instance.", c, assertSerializedEquals(c));
+    }
+
+    /**
+     * Tests conversions to comparable objects. Should returns the object unchanged
+     * since all {@link Number} subclasses are comparable.
+     */
+    @Test
+    public void testComparable() {
+        final ObjectConverter<Number,Comparable<?>> c =
+                new NumberConverter.Comparable<>(Number.class).unique();
+        final Integer value = 8;
+        assertSame(value, c.convert(value));
+        assertSame("Deserialization shall resolves to the singleton instance.", c, assertSerializedEquals(c));
+    }
+}

Propchange: sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/internal/converter/NumberConverterTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/internal/converter/NumberConverterTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Modified: sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/internal/converter/StringConverterTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/internal/converter/StringConverterTest.java?rev=1455514&r1=1455513&r2=1455514&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/internal/converter/StringConverterTest.java [UTF-8] (original)
+++ sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/internal/converter/StringConverterTest.java [UTF-8] Tue Mar 12 12:54:31 2013
@@ -31,6 +31,7 @@ import org.apache.sis.math.FunctionPrope
 import org.apache.sis.util.ObjectConverter;
 import org.apache.sis.util.UnconvertibleObjectException;
 import org.apache.sis.util.iso.SimpleInternationalString;
+import org.apache.sis.test.TestCase;
 import org.junit.Test;
 
 import static org.apache.sis.test.Assert.*;
@@ -44,7 +45,7 @@ import static org.apache.sis.test.Assert
  * @version 0.3
  * @module
  */
-public final strictfp class StringConverterTest {
+public final strictfp class StringConverterTest extends TestCase {
     /**
      * Asserts that conversion of the given {@code source} value produces
      * the given {@code target} value, and tests the inverse conversion.

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=1455514&r1=1455513&r2=1455514&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java [UTF-8] (original)
+++ sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java [UTF-8] Tue Mar 12 12:54:31 2013
@@ -95,6 +95,7 @@ import org.junit.runners.Suite;
     org.apache.sis.internal.converter.URLConverterTest.class,
     org.apache.sis.internal.converter.FileConverterTest.class,
     org.apache.sis.internal.converter.StringConverterTest.class,
+    org.apache.sis.internal.converter.NumberConverterTest.class,
     org.apache.sis.internal.converter.FallbackConverterTest.class,
 
     // XML most basic types.



Mime
View raw message