You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2015/05/15 00:45:18 UTC
svn commit: r1679471 - in /sis/branches/JDK8/core:
sis-feature/src/main/java/org/apache/sis/feature/
sis-referencing/src/main/java/org/apache/sis/referencing/
sis-referencing/src/main/java/org/apache/sis/referencing/crs/
sis-utility/src/main/java/org/a...
Author: desruisseaux
Date: Thu May 14 22:45:18 2015
New Revision: 1679471
URL: http://svn.apache.org/r1679471
Log:
Referencing: GeodeticObjectFactory applies default properties for all object constructions.
Modified:
sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicTypeMap.java
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/GeodeticObjectFactory.java
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultDerivedCRS.java
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/AbstractMap.java
sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/internal/util/AbstractMapTest.java
Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicTypeMap.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicTypeMap.java?rev=1679471&r1=1679470&r2=1679471&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicTypeMap.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicTypeMap.java [UTF-8] Thu May 14 22:45:18 2015
@@ -124,6 +124,14 @@ final class CharacteristicTypeMap extend
}
/**
+ * Returns {@code true} if there is no attribute characteristics.
+ */
+ @Override
+ public boolean isEmpty() {
+ return characterizedBy.length == 0;
+ }
+
+ /**
* Returns the number of attribute characteristics.
*/
@Override
Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/GeodeticObjectFactory.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/GeodeticObjectFactory.java?rev=1679471&r1=1679470&r2=1679471&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/GeodeticObjectFactory.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/GeodeticObjectFactory.java [UTF-8] Thu May 14 22:45:18 2015
@@ -20,6 +20,7 @@ import java.util.Date;
import java.util.Locale;
import java.util.Map;
import java.util.HashMap;
+import java.util.Collections;
import javax.measure.unit.Unit;
import javax.measure.quantity.Angle;
import javax.measure.quantity.Length;
@@ -38,6 +39,7 @@ import org.apache.sis.referencing.crs.*;
import org.apache.sis.referencing.datum.*;
import org.apache.sis.internal.referencing.OperationMethods;
import org.apache.sis.internal.system.DefaultFactories;
+import org.apache.sis.internal.util.AbstractMap;
import org.apache.sis.internal.util.CollectionsExt;
import org.apache.sis.util.collection.WeakHashSet;
import org.apache.sis.util.iso.AbstractFactory;
@@ -55,7 +57,7 @@ import org.apache.sis.util.ArgumentCheck
* without explicit dependency to Apache SIS (when using the GeoAPI interfaces implemented by this class).</li>
* <li><b>For providers</b>, allows <cite>inversion of control</cite> by overriding methods in this class,
* then specifying the customized instance to other services that consume {@code CRSFactory} (for example
- * authority factories or WKT parsers).</li>
+ * authority factories or {@linkplain org.apache.sis.io.wkt.WKTFormat WKT parsers}).</li>
* </ul>
*
* This {@code GeodeticObjectFactory} class is not easy to use directly.
@@ -68,7 +70,7 @@ import org.apache.sis.util.ArgumentCheck
* Unless otherwise noticed, information provided in the {@code properties} map are considered ignorable metadata
* while information provided in explicit arguments have an impact on coordinate transformation results.
*
- * <p>The following table lists the keys recognized by {@code GeodeticObjectFactory} default implementation,
+ * <p>The following table lists the keys recognized by the {@code GeodeticObjectFactory} default implementation,
* together with the type of values associated to those keys.
* A value for the {@code "name"} key is mandatory for all objects, while all other properties are optional.
* {@code GeodeticObjectFactory} methods ignore all unknown properties.</p>
@@ -123,12 +125,12 @@ import org.apache.sis.util.ArgumentCheck
* <tr>
* <td>{@value org.opengis.referencing.ReferenceSystem#DOMAIN_OF_VALIDITY_KEY}</td>
* <td>{@link Extent}</td>
- * <td>{@link AbstractReferenceSystem#getDomainOfValidity()} or {@link AbstractDatum#getDomainOfValidity()}</td>
+ * <td>{@link AbstractReferenceSystem#getDomainOfValidity()}</td>
* </tr>
* <tr>
* <td>{@value org.opengis.referencing.ReferenceSystem#SCOPE_KEY}</td>
* <td>{@link String} or {@link InternationalString}</td>
- * <td>{@link AbstractReferenceSystem#getScope()} or {@link AbstractDatum#getScope()}</td>
+ * <td>{@link AbstractReferenceSystem#getScope()}</td>
* </tr>
* <tr>
* <td>{@value org.opengis.referencing.datum.Datum#ANCHOR_POINT_KEY}</td>
@@ -146,12 +148,12 @@ import org.apache.sis.util.ArgumentCheck
* <td>{@link AbstractIdentifiedObject#getRemarks()}</td>
* </tr>
* <tr>
- * <td>{@value #DEPRECATED_KEY}</td>
+ * <td>{@value org.apache.sis.referencing.AbstractIdentifiedObject#DEPRECATED_KEY}</td>
* <td>{@link Boolean}</td>
* <td>{@link AbstractIdentifiedObject#isDeprecated()}</td>
* </tr>
* <tr>
- * <td>{@value #LOCALE_KEY}</td>
+ * <td>{@value org.apache.sis.referencing.AbstractIdentifiedObject#LOCALE_KEY}</td>
* <td>{@link Locale}</td>
* <td>(none)</td>
* </tr>
@@ -174,12 +176,13 @@ import org.apache.sis.util.ArgumentCheck
*/
public class GeodeticObjectFactory extends AbstractFactory implements CRSFactory, CSFactory, DatumFactory {
/**
- * The default properties, or {@code null} if none.
+ * The default properties, or an empty map if none.
*/
private final Map<String,?> defaultProperties;
/**
* The math transform factory. Will be created only when first needed.
+ * This is normally not needed by this factory, except when constructing derived and projected CRS.
*/
private volatile MathTransformFactory mtFactory;
@@ -199,23 +202,79 @@ public class GeodeticObjectFactory exten
/**
* Constructs a factory with the given default properties.
* {@code GeodeticObjectFactory} will fallback on the map given to this constructor for any property
- * not present in the map provided to a {@code createFoo(Map<String,?> properties, …)} method.
+ * not present in the map provided to a {@code createFoo(Map<String,?>, …)} method.
*
* @param properties The default properties, or {@code null} if none.
*/
public GeodeticObjectFactory(Map<String,?> properties) {
- if (properties != null) {
- if (properties.isEmpty()) {
- properties = null;
- } else {
- properties = CollectionsExt.compact(new HashMap<String,Object>(properties));
- }
+ if (properties == null || properties.isEmpty()) {
+ properties = Collections.emptyMap();
+ } else {
+ properties = CollectionsExt.compact(new HashMap<String,Object>(properties));
}
defaultProperties = properties;
pool = new WeakHashSet<>(IdentifiedObject.class);
}
/**
+ * Returns the union of the given {@code properties} map with the default properties given at
+ * {@linkplain #GeodeticObjectFactory(Map) construction time}. Entries in the given properties
+ * map have precedence, even if their {@linkplain java.util.Map.Entry#getValue() value} is {@code null}
+ * (i.e. a null value "erase" the default property value).
+ * Entries with null value after the union will be omitted.
+ *
+ * <p>This method is invoked by all {@code createFoo(Map<String,?>, …)} methods.</p>
+ *
+ * @param properties The user-supplied properties.
+ * @return The union of the given properties with the default properties.
+ */
+ protected Map<String,?> complete(final Map<String,?> properties) {
+ ArgumentChecks.ensureNonNull("properties", properties);
+ return new AbstractMap<String,Object>() {
+ /**
+ * A map containing the merge of user and default properties, or {@code null} if not yet created.
+ * This map is normally never needed. It may be created only if the user create his own subclass
+ * of {@link GeodeticObjectFactory} and iterate on this map or ask for its size.
+ */
+ private Map<String,Object> merge;
+
+ /**
+ * Returns an iterator over the user-supplied properties together with
+ * the default properties which were not specified in the user's ones.
+ */
+ @Override
+ protected EntryIterator<String,Object> entryIterator() {
+ if (merge == null) {
+ merge = new HashMap<>(defaultProperties);
+ merge.putAll(properties);
+ merge.remove(null);
+ }
+ return new IteratorAdapter<>(merge); // That iterator will skip null values.
+ }
+
+ /**
+ * Returns the value for the given key by first looking in the user-supplied map,
+ * then by looking in the default properties if no value were specified in the user map.
+ * We handle the "mtFactory" key in a special way since this is normally not needed for
+ * {@link GeodeticObjectFactory}, except when creating the SIS implementation of derived
+ * or projected CRS (because of the way we implemented derived CRS, but this is somewhat
+ * specific to SIS).
+ */
+ @Override
+ public Object get(final Object key) {
+ Object value = properties.get(key);
+ if (value == null && !properties.containsKey(key)) {
+ value = defaultProperties.get(key);
+ if (value == null && OperationMethods.MT_FACTORY.equals(key)) {
+ value = getMathTransformFactory();
+ }
+ }
+ return value;
+ }
+ };
+ }
+
+ /**
* Returns the math transform factory for internal usage only.
*/
final MathTransformFactory getMathTransformFactory() {
@@ -243,7 +302,7 @@ public class GeodeticObjectFactory exten
{
final GeocentricCRS crs;
try {
- crs = new DefaultGeocentricCRS(properties, datum, cs);
+ crs = new DefaultGeocentricCRS(complete(properties), datum, cs);
} catch (IllegalArgumentException exception) {
throw new FactoryException(exception);
}
@@ -270,7 +329,7 @@ public class GeodeticObjectFactory exten
{
final CartesianCS cs;
try {
- cs = new DefaultCartesianCS(properties, axis0, axis1, axis2);
+ cs = new DefaultCartesianCS(complete(properties), axis0, axis1, axis2);
} catch (IllegalArgumentException exception) {
throw new FactoryException(exception);
}
@@ -294,7 +353,7 @@ public class GeodeticObjectFactory exten
{
final GeocentricCRS crs;
try {
- crs = new DefaultGeocentricCRS(properties, datum, cs);
+ crs = new DefaultGeocentricCRS(complete(properties), datum, cs);
} catch (IllegalArgumentException exception) {
throw new FactoryException(exception);
}
@@ -321,7 +380,7 @@ public class GeodeticObjectFactory exten
{
final SphericalCS cs;
try {
- cs = new DefaultSphericalCS(properties, axis0, axis1, axis2);
+ cs = new DefaultSphericalCS(complete(properties), axis0, axis1, axis2);
} catch (IllegalArgumentException exception) {
throw new FactoryException(exception);
}
@@ -346,7 +405,7 @@ public class GeodeticObjectFactory exten
{
final GeographicCRS crs;
try {
- crs = new DefaultGeographicCRS(properties, datum, cs);
+ crs = new DefaultGeographicCRS(complete(properties), datum, cs);
} catch (IllegalArgumentException exception) {
throw new FactoryException(exception);
}
@@ -370,7 +429,7 @@ public class GeodeticObjectFactory exten
{
final GeodeticDatum datum;
try {
- datum = new DefaultGeodeticDatum(properties, ellipsoid, primeMeridian);
+ datum = new DefaultGeodeticDatum(complete(properties), ellipsoid, primeMeridian);
} catch (IllegalArgumentException exception) {
throw new FactoryException(exception);
}
@@ -394,7 +453,7 @@ public class GeodeticObjectFactory exten
{
final PrimeMeridian meridian;
try {
- meridian = new DefaultPrimeMeridian(properties, longitude, angularUnit);
+ meridian = new DefaultPrimeMeridian(complete(properties), longitude, angularUnit);
} catch (IllegalArgumentException exception) {
throw new FactoryException(exception);
}
@@ -419,7 +478,7 @@ public class GeodeticObjectFactory exten
{
final EllipsoidalCS cs;
try {
- cs = new DefaultEllipsoidalCS(properties, axis0, axis1);
+ cs = new DefaultEllipsoidalCS(complete(properties), axis0, axis1);
} catch (IllegalArgumentException exception) {
throw new FactoryException(exception);
}
@@ -446,7 +505,7 @@ public class GeodeticObjectFactory exten
{
final EllipsoidalCS cs;
try {
- cs = new DefaultEllipsoidalCS(properties, axis0, axis1, axis2);
+ cs = new DefaultEllipsoidalCS(complete(properties), axis0, axis1, axis2);
} catch (IllegalArgumentException exception) {
throw new FactoryException(exception);
}
@@ -472,7 +531,7 @@ public class GeodeticObjectFactory exten
{
final Ellipsoid ellipsoid;
try {
- ellipsoid = DefaultEllipsoid.createEllipsoid(properties, semiMajorAxis, semiMinorAxis, unit);
+ ellipsoid = DefaultEllipsoid.createEllipsoid(complete(properties), semiMajorAxis, semiMinorAxis, unit);
} catch (IllegalArgumentException exception) {
throw new FactoryException(exception);
}
@@ -498,7 +557,7 @@ public class GeodeticObjectFactory exten
{
final Ellipsoid ellipsoid;
try {
- ellipsoid = DefaultEllipsoid.createFlattenedSphere(properties, semiMajorAxis, inverseFlattening, unit);
+ ellipsoid = DefaultEllipsoid.createFlattenedSphere(complete(properties), semiMajorAxis, inverseFlattening, unit);
} catch (IllegalArgumentException exception) {
throw new FactoryException(exception);
}
@@ -522,18 +581,13 @@ public class GeodeticObjectFactory exten
* @see DefaultProjectedCRS
*/
@Override
- public ProjectedCRS createProjectedCRS(Map<String,?> properties,
+ public ProjectedCRS createProjectedCRS(final Map<String,?> properties,
final GeographicCRS baseCRS, Conversion conversion,
final CartesianCS derivedCS) throws FactoryException
{
- if (!properties.containsKey(OperationMethods.MT_FACTORY)) {
- final Map<String,Object> copy = new HashMap<>(properties);
- copy.put(OperationMethods.MT_FACTORY, getMathTransformFactory());
- properties = copy;
- }
final ProjectedCRS crs;
try {
- crs = new DefaultProjectedCRS(properties, baseCRS, conversion, derivedCS);
+ crs = new DefaultProjectedCRS(complete(properties), baseCRS, conversion, derivedCS);
} catch (IllegalArgumentException exception) {
throw new FactoryException(exception);
}
@@ -558,7 +612,7 @@ public class GeodeticObjectFactory exten
{
final CartesianCS cs;
try {
- cs = new DefaultCartesianCS(properties, axis0, axis1);
+ cs = new DefaultCartesianCS(complete(properties), axis0, axis1);
} catch (IllegalArgumentException exception) {
throw new FactoryException(exception);
}
@@ -586,7 +640,7 @@ public class GeodeticObjectFactory exten
ArgumentChecks.ensureCanCast("baseCRS", SingleCRS.class, baseCRS);
final DerivedCRS crs;
try {
- crs = new DefaultDerivedCRS(properties, (SingleCRS) baseCRS, conversion, derivedCS);
+ crs = DefaultDerivedCRS.create(complete(properties), (SingleCRS) baseCRS, conversion, derivedCS);
} catch (IllegalArgumentException exception) {
throw new FactoryException(exception);
}
@@ -610,7 +664,7 @@ public class GeodeticObjectFactory exten
{
final VerticalCRS crs;
try {
- crs = new DefaultVerticalCRS(properties, datum, cs);
+ crs = new DefaultVerticalCRS(complete(properties), datum, cs);
} catch (IllegalArgumentException exception) {
throw new FactoryException(exception);
}
@@ -633,7 +687,7 @@ public class GeodeticObjectFactory exten
{
final VerticalDatum datum;
try {
- datum = new DefaultVerticalDatum(properties, type);
+ datum = new DefaultVerticalDatum(complete(properties), type);
} catch (IllegalArgumentException exception) {
throw new FactoryException(exception);
}
@@ -656,7 +710,7 @@ public class GeodeticObjectFactory exten
{
final VerticalCS cs;
try {
- cs = new DefaultVerticalCS(properties, axis);
+ cs = new DefaultVerticalCS(complete(properties), axis);
} catch (IllegalArgumentException exception) {
throw new FactoryException(exception);
}
@@ -680,7 +734,7 @@ public class GeodeticObjectFactory exten
{
final TemporalCRS crs;
try {
- crs = new DefaultTemporalCRS(properties, datum, cs);
+ crs = new DefaultTemporalCRS(complete(properties), datum, cs);
} catch (IllegalArgumentException exception) {
throw new FactoryException(exception);
}
@@ -703,7 +757,7 @@ public class GeodeticObjectFactory exten
{
final TemporalDatum datum;
try {
- datum = new DefaultTemporalDatum(properties, origin);
+ datum = new DefaultTemporalDatum(complete(properties), origin);
} catch (IllegalArgumentException exception) {
throw new FactoryException(exception);
}
@@ -726,7 +780,7 @@ public class GeodeticObjectFactory exten
{
final TimeCS cs;
try {
- cs = new DefaultTimeCS(properties, axis);
+ cs = new DefaultTimeCS(complete(properties), axis);
} catch (IllegalArgumentException exception) {
throw new FactoryException(exception);
}
@@ -749,7 +803,7 @@ public class GeodeticObjectFactory exten
{
final CompoundCRS crs;
try {
- crs = new DefaultCompoundCRS(properties, elements);
+ crs = new DefaultCompoundCRS(complete(properties), elements);
} catch (IllegalArgumentException exception) {
throw new FactoryException(exception);
}
@@ -773,7 +827,7 @@ public class GeodeticObjectFactory exten
{
final ImageCRS crs;
try {
- crs = new DefaultImageCRS(properties, datum, cs);
+ crs = new DefaultImageCRS(complete(properties), datum, cs);
} catch (IllegalArgumentException exception) {
throw new FactoryException(exception);
}
@@ -796,7 +850,7 @@ public class GeodeticObjectFactory exten
{
final ImageDatum datum;
try {
- datum = new DefaultImageDatum(properties, pixelInCell);
+ datum = new DefaultImageDatum(complete(properties), pixelInCell);
} catch (IllegalArgumentException exception) {
throw new FactoryException(exception);
}
@@ -821,7 +875,7 @@ public class GeodeticObjectFactory exten
{
final AffineCS cs;
try {
- cs = new DefaultAffineCS(properties, axis0, axis1);
+ cs = new DefaultAffineCS(complete(properties), axis0, axis1);
} catch (IllegalArgumentException exception) {
throw new FactoryException(exception);
}
@@ -845,7 +899,7 @@ public class GeodeticObjectFactory exten
{
final EngineeringCRS crs;
try {
- crs = new DefaultEngineeringCRS(properties, datum, cs);
+ crs = new DefaultEngineeringCRS(complete(properties), datum, cs);
} catch (IllegalArgumentException exception) {
throw new FactoryException(exception);
}
@@ -867,7 +921,7 @@ public class GeodeticObjectFactory exten
{
final EngineeringDatum datum;
try {
- datum = new DefaultEngineeringDatum(properties);
+ datum = new DefaultEngineeringDatum(complete(properties));
} catch (IllegalArgumentException exception) {
throw new FactoryException(exception);
}
@@ -894,7 +948,7 @@ public class GeodeticObjectFactory exten
{
final AffineCS cs;
try {
- cs = new DefaultAffineCS(properties, axis0, axis1, axis2);
+ cs = new DefaultAffineCS(complete(properties), axis0, axis1, axis2);
} catch (IllegalArgumentException exception) {
throw new FactoryException(exception);
}
@@ -921,7 +975,7 @@ public class GeodeticObjectFactory exten
{
final CylindricalCS cs;
try {
- cs = new DefaultCylindricalCS(properties, axis0, axis1, axis2);
+ cs = new DefaultCylindricalCS(complete(properties), axis0, axis1, axis2);
} catch (IllegalArgumentException exception) {
throw new FactoryException(exception);
}
@@ -946,7 +1000,7 @@ public class GeodeticObjectFactory exten
{
final PolarCS cs;
try {
- cs = new DefaultPolarCS(properties, axis0, axis1);
+ cs = new DefaultPolarCS(complete(properties), axis0, axis1);
} catch (IllegalArgumentException exception) {
throw new FactoryException(exception);
}
@@ -969,7 +1023,7 @@ public class GeodeticObjectFactory exten
{
final LinearCS cs;
try {
- cs = new DefaultLinearCS(properties, axis);
+ cs = new DefaultLinearCS(complete(properties), axis);
} catch (IllegalArgumentException exception) {
throw new FactoryException(exception);
}
@@ -994,7 +1048,7 @@ public class GeodeticObjectFactory exten
{
final UserDefinedCS cs;
try {
- cs = new DefaultUserDefinedCS(properties, axis0, axis1);
+ cs = new DefaultUserDefinedCS(complete(properties), axis0, axis1);
} catch (IllegalArgumentException exception) {
throw new FactoryException(exception);
}
@@ -1021,7 +1075,7 @@ public class GeodeticObjectFactory exten
{
final UserDefinedCS cs;
try {
- cs = new DefaultUserDefinedCS(properties, axis0, axis1, axis2);
+ cs = new DefaultUserDefinedCS(complete(properties), axis0, axis1, axis2);
} catch (IllegalArgumentException exception) {
throw new FactoryException(exception);
}
@@ -1047,7 +1101,7 @@ public class GeodeticObjectFactory exten
{
final CoordinateSystemAxis axis;
try {
- axis = new DefaultCoordinateSystemAxis(properties, abbreviation, direction, unit);
+ axis = new DefaultCoordinateSystemAxis(complete(properties), abbreviation, direction, unit);
} catch (IllegalArgumentException exception) {
throw new FactoryException(exception);
}
Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultDerivedCRS.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultDerivedCRS.java?rev=1679471&r1=1679470&r2=1679471&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultDerivedCRS.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultDerivedCRS.java [UTF-8] Thu May 14 22:45:18 2015
@@ -154,10 +154,10 @@ public class DefaultDerivedCRS extends A
*
* @see #create(Map, SingleCRS, Conversion, CoordinateSystem)
*/
- public DefaultDerivedCRS(final Map<String,?> properties,
- final SingleCRS baseCRS,
- final Conversion conversionFromBase,
- final CoordinateSystem derivedCS)
+ protected DefaultDerivedCRS(final Map<String,?> properties,
+ final SingleCRS baseCRS,
+ final Conversion conversionFromBase,
+ final CoordinateSystem derivedCS)
throws MismatchedDimensionException
{
super(properties, baseCRS, conversionFromBase, derivedCS);
Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/AbstractMap.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/AbstractMap.java?rev=1679471&r1=1679470&r2=1679471&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/AbstractMap.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/AbstractMap.java [UTF-8] Thu May 14 22:45:18 2015
@@ -50,7 +50,7 @@ import java.util.Objects;
*
* <p>Read-only subclasses need to implement the following methods:</p>
* <ul>
- * <li>{@link #size()}</li>
+ * <li>{@link #size()} (not mandatory but recommended)</li>
* <li>{@link #get(Object)}</li>
* <li>{@link #entryIterator()} (non-standard method)</li>
* </ul>
@@ -69,7 +69,7 @@ import java.util.Objects;
*
* @author Martin Desruisseaux (Geomatys)
* @since 0.5
- * @version 0.5
+ * @version 0.6
* @module
*/
public abstract class AbstractMap<K,V> implements Map<K,V> {
@@ -133,19 +133,114 @@ public abstract class AbstractMap<K,V> i
}
/**
+ * An implementation of {@link EntryIterator} which delegates its work to a standard iterator.
+ * Subclasses can modify the {@link #value} or other properties during iteration.
+ *
+ * <p>This method does not implement the {@link #remove()} method, thus assuming an unmodifiable map
+ * (which is consistent with the default implementation of {@link AbstractMap} methods).
+ * Modifiable maps should override {@code remove()} themselves.</p>
+ *
+ * @param <K> The type of keys maintained by the map.
+ * @param <V> The type of mapped values.
+ *
+ * @see AbstractMap#entryIterator()
+ */
+ protected static class IteratorAdapter<K,V> extends EntryIterator<K,V> {
+ /**
+ * The standard iterator on which to delegate the work.
+ * It is safe to change this value before to invoke {@link #next()}.
+ */
+ protected Iterator<Entry<K,V>> it;
+
+ /**
+ * The entry found by the last call to {@link #next()}.
+ */
+ protected Entry<K,V> entry;
+
+ /**
+ * The value of <code>{@linkplain #entry}.getValue()}</code>.
+ * It is safe to change this value after {@link #next()} invocation.
+ */
+ protected V value;
+
+ /**
+ * Creates a new adapter initialized to the entry iterator of the given map.
+ *
+ * @param map The map from which to return entries.
+ */
+ public IteratorAdapter(final Map<K,V> map) {
+ it = map.entrySet().iterator();
+ }
+
+ /**
+ * Moves to the next entry having a non-null value. If this method returns {@code true}, then the
+ * {@link #entry} and {@link #value} fields are set to the properties of the new current entry.
+ * Otherwise (if this method returns {@code false}) the {@link #entry} and {@link #value} fields
+ * are undetermined.
+ *
+ * @return {@inheritDoc}
+ */
+ @Override
+ protected boolean next() {
+ do {
+ if (!it.hasNext()) {
+ return false;
+ }
+ entry = it.next();
+ value = entry.getValue();
+ } while (value == null);
+ return true;
+ }
+
+ /**
+ * Returns <code>{@linkplain #entry}.getKey()}</code>.
+ *
+ * @return {@inheritDoc}
+ */
+ @Override
+ protected K getKey() {
+ return entry.getKey();
+ }
+
+ /**
+ * Returns {@link #value}, which was itself initialized to <code>{@linkplain #entry}.getValue()}</code>.
+ *
+ * @return {@inheritDoc}
+ */
+ @Override
+ protected V getValue() {
+ return value;
+ }
+ }
+
+ /**
* For subclass constructors.
*/
protected AbstractMap() {
}
/**
+ * Returns the number of key-value mappings in this map.
+ * The default implementation count the number of values returned by {@link #entryIterator()}.
+ * Subclasses should implement a more efficient method.
+ */
+ @Override
+ public int size() {
+ int count = 0;
+ for (final EntryIterator<K,V> it = entryIterator(); it.next();) {
+ if (++count == Integer.MAX_VALUE) break;
+ }
+ return count;
+ }
+
+ /**
* Returns {@code true} if this map contains no element.
*
* @return {@code true} if this map contains no element.
*/
@Override
public boolean isEmpty() {
- return size() == 0;
+ return !entryIterator().next();
}
/**
Modified: sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/internal/util/AbstractMapTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/internal/util/AbstractMapTest.java?rev=1679471&r1=1679470&r2=1679471&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/internal/util/AbstractMapTest.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/internal/util/AbstractMapTest.java [UTF-8] Thu May 14 22:45:18 2015
@@ -50,7 +50,6 @@ public final strictfp class AbstractMapT
private final List<String> values = new ArrayList<>(Arrays.asList("one", "two", "three"));
@Override public void clear () { values.clear();}
- @Override public int size () {return values.size();}
@Override public String get (Object k) {return values.get(((Integer) k) - 1);}
@Override public String put (Integer k, String v) {return values.set(k - 1, v);}
@Override protected boolean addKey (Integer k) {return values.add(k == 4 ? "four" : "other");}
@@ -58,7 +57,7 @@ public final strictfp class AbstractMapT
@Override protected EntryIterator<Integer,String> entryIterator() {
return new EntryIterator<Integer,String>() {
private int key;
- @Override protected boolean next() {return ++key <= size();}
+ @Override protected boolean next() {return ++key <= values.size();}
@Override protected Integer getKey() {return key;}
@Override protected String getValue() {return get(key);}
};
@@ -68,15 +67,16 @@ public final strictfp class AbstractMapT
/**
* Tests {@link AbstractMap#keySet()}, {@link AbstractMap#values()} and {@link AbstractMap#entrySet()}.
* This method will also opportunistically tests basic methods like {@link AbstractMap#isEmpty()} and
- * {@link AbstractMap#containsValue(Object)}. This test does not write in the map.
+ * {@link AbstractMap#containsValue(Object)}. This test does not add new values in the map.
*/
@Test
public void testReadOnly() {
final Count map = new Count();
- assertFalse("isEmpty", map.isEmpty());
- assertTrue ("containsKey", map.containsKey(3));
- assertTrue ("containsValue", map.containsValue("three"));
- assertFalse("containsValue", map.containsValue("six"));
+ assertEquals("size", 3, map.size());
+ assertFalse ("isEmpty", map.isEmpty());
+ assertTrue ("containsKey", map.containsKey(3));
+ assertTrue ("containsValue", map.containsValue("three"));
+ assertFalse ("containsValue", map.containsValue("six"));
final Collection<Integer> keys = map.keySet();
assertTrue("contains", keys.contains(3));
@@ -97,11 +97,15 @@ public final strictfp class AbstractMapT
}, entries.toArray());
map.clear();
- assertFalse("containsValue", map.containsValue("three"));
- assertTrue ("isEmpty", map.isEmpty());
- assertTrue ("isEmpty", keys.isEmpty());
- assertTrue ("isEmpty", values.isEmpty());
- assertTrue ("isEmpty", entries.isEmpty());
+ assertFalse ("containsValue", map.containsValue("three"));
+ assertTrue ("isEmpty", map .isEmpty());
+ assertTrue ("isEmpty", keys .isEmpty());
+ assertTrue ("isEmpty", values .isEmpty());
+ assertTrue ("isEmpty", entries.isEmpty());
+ assertEquals("size", 0, map .size());
+ assertEquals("size", 0, keys .size());
+ assertEquals("size", 0, values .size());
+ assertEquals("size", 0, entries.size());
}
/**
@@ -112,7 +116,9 @@ public final strictfp class AbstractMapT
@DependsOnMethod("testReadOnly")
public void testAddKey() {
final Count map = new Count();
+ assertEquals("size", 3, map.size());
assertTrue(map.keySet().add(4));
+ assertEquals("size", 4, map.size());
assertArrayEquals("entrySet", new SimpleEntry<?,?>[] {
new SimpleEntry<>(1, "one"),
new SimpleEntry<>(2, "two"),
@@ -129,7 +135,9 @@ public final strictfp class AbstractMapT
@DependsOnMethod("testReadOnly")
public void testAddValue() {
final Count map = new Count();
+ assertEquals("size", 3, map.size());
assertTrue(map.values().add("quatre"));
+ assertEquals("size", 4, map.size());
assertArrayEquals("entrySet", new SimpleEntry<?,?>[] {
new SimpleEntry<>(1, "one"),
new SimpleEntry<>(2, "two"),