sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1556837 - in /sis/branches/JDK7/core: sis-metadata/src/main/java/org/apache/sis/metadata/ sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/ sis-referencing/src/main/java/org/apache/sis/referencing/ sis-referencing/src...
Date Thu, 09 Jan 2014 15:31:02 GMT
Author: desruisseaux
Date: Thu Jan  9 15:31:01 2014
New Revision: 1556837

URL: http://svn.apache.org/r1556837
Log:
AbstractIdentifier.getNames() collection should be live, because JAXB implementation
writes directly in that collection at unmarshalling time.

Modified:
    sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/ModifiableMetadata.java
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/Code.java
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/NamedIdentifier.java
    sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/AbstractIdentifiedObjectTest.java

Modified: sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/ModifiableMetadata.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/ModifiableMetadata.java?rev=1556837&r1=1556836&r2=1556837&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/ModifiableMetadata.java
[UTF-8] (original)
+++ sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/ModifiableMetadata.java
[UTF-8] Thu Jan  9 15:31:01 2014
@@ -282,7 +282,7 @@ public abstract class ModifiableMetadata
             List<E> target, final Class<E> elementType)
             throws UnmodifiableMetadataException
     {
-        // See the comments in writeCollection(...) for implementation notes.
+        // See the comments in writeCollection(…) for implementation notes.
         if (source != target) {
             if (unmodifiable == FREEZING) {
                 return (List<E>) source;
@@ -330,7 +330,7 @@ public abstract class ModifiableMetadata
             Set<E> target, final Class<E> elementType)
             throws UnmodifiableMetadataException
     {
-        // See the comments in writeCollection(...) for implementation notes.
+        // See the comments in writeCollection(…) for implementation notes.
         if (source != target) {
             if (unmodifiable == FREEZING) {
                 return (Set<E>) source;
@@ -387,7 +387,8 @@ public abstract class ModifiableMetadata
         /*
          * It is not worth to copy the content if the current and the new instance are the
          * same. This is safe only using the != operator, not the !equals(Object) method.
-         * This optimization is required for efficient working of PropertyAccessor.set(...).
+         * This optimization is required for efficient working of PropertyAccessor.set(…)
+         * and JAXB unmarshalling.
          */
         if (source != target) {
             if (unmodifiable == FREEZING) {

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/Code.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/Code.java?rev=1556837&r1=1556836&r2=1556837&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/Code.java
[UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/Code.java
[UTF-8] Thu Jan  9 15:31:01 2014
@@ -22,7 +22,7 @@ import javax.xml.bind.annotation.XmlAttr
 import org.opengis.metadata.citation.Citation;
 import org.opengis.referencing.ReferenceIdentifier;
 import org.apache.sis.internal.util.DefinitionURI;
-import org.apache.sis.metadata.iso.ImmutableIdentifier;
+import org.apache.sis.referencing.NamedIdentifier;
 import org.apache.sis.metadata.iso.citation.Citations;
 
 import static org.apache.sis.internal.referencing.ReferencingUtilities.toURNType;
@@ -114,7 +114,7 @@ public final class Code {
             }
             authority = Citations.fromName(cs);
         }
-        return new ImmutableIdentifier(authority, cs, c, version, null);
+        return new NamedIdentifier(authority, cs, c, version, null);
     }
 
     /**

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java?rev=1556837&r1=1556836&r2=1556837&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java
[UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java
[UTF-8] Thu Jan  9 15:31:01 2014
@@ -21,6 +21,7 @@ import java.util.Set;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.AbstractCollection;
 import java.util.Iterator;
 import java.util.Locale;
 import java.io.Serializable;
@@ -137,7 +138,7 @@ public class AbstractIdentifiedObject ex
      * The name for this object or code. Shall never be {@code null}.
      *
      * <p><b>Consider this field as final!</b>
-     * This field is modified only at unmarshalling time by {@link #setNames(Collection)}</p>
+     * This field is modified only at unmarshalling time by {@link Names#add(ReferenceIdentifier)}.</p>
      *
      * @see #getName()
      * @see #getNames()
@@ -150,7 +151,7 @@ public class AbstractIdentifiedObject ex
      * we may get both on unmarshalling.
      *
      * <p><b>Consider this field as final!</b>
-     * This field is modified only at unmarshalling time by {@link #setNames(Collection)}</p>
+     * This field is modified only at unmarshalling time by {@link Names#add(ReferenceIdentifier)}.</p>
      */
     private Collection<GenericName> alias;
 
@@ -455,41 +456,99 @@ public class AbstractIdentifiedObject ex
     }
 
     /**
+     * A writable view over the {@linkplain AbstractIdentifiedObject#getName() name} of the
enclosing object followed by
+     * all {@linkplain AbstractIdentifiedObject#getAlias() aliases} which are instance of
{@link ReferenceIdentifier}.
+     * Used by JAXB only at (un)marshalling time because GML merges the name and aliases
in a single {@code <gml:name>}
+     * property.
+     */
+    private final class Names extends AbstractCollection<ReferenceIdentifier> {
+        /**
+         * Invoked by JAXB before to write in the collection at unmarshalling time.
+         * Do nothing since our object is already empty.
+         */
+        @Override
+        public void clear() {
+        }
+
+        /**
+         * Returns the number of name and aliases that are instance of {@link ReferenceIdentifier}.
+         */
+        @Override
+        public int size() {
+            return NameIterator.count(AbstractIdentifiedObject.this);
+        }
+
+        /**
+         * Returns an iterator over the name and aliases that are instance of {@link ReferenceIdentifier}.
+         */
+        @Override
+        public Iterator<ReferenceIdentifier> iterator() {
+            return new NameIterator(AbstractIdentifiedObject.this);
+        }
+
+        /**
+         * Invoked by JAXB at unmarshalling time for each identifier. The first identifier
will be taken
+         * as the name and all other identifiers (if any) as aliases.
+         *
+         * <p>Some JAXB implementations never invoke {@link AbstractIdentifiedObject#setNames(Collection)}.
+         * Instead they invoke {@link AbstractIdentifiedObject#getNames()} and add directly
the identifiers
+         * in the returned collection. Consequently this method must writes directly in the
enclosing object.
+         * See <a href="https://java.net/jira/browse/JAXB-488">JAXB-488</a> for
more information.</p>
+         */
+        @Override
+        public boolean add(final ReferenceIdentifier id) {
+            if (name == null) {
+                name = id;
+                return true;
+            }
+            if (alias == null) {
+                alias = new ArrayList<>(4);
+            }
+            /*
+             * Our Code and RS_Identifier implementations should always create NamedIdentifier
instance,
+             * so the 'instanceof' check should not be necessary. But do a paranoiac check
anyway.
+             */
+            return alias.add(id instanceof GenericName ? (GenericName) id : new NamedIdentifier(id));
+        }
+    }
+
+    /**
      * Returns the {@link #name} and all aliases which are also instance of {@lik ReferenceIdentifier}.
      * The later happen often in SIS implementation since many aliases are instance of {@link
NamedIdentifier}.
      */
     @XmlElement(name = "name", required = true)
     final Collection<ReferenceIdentifier> getNames() {
-        // Unconditionally creates a modifiable list because some JAXB implementations modify
it.
-        final Collection<ReferenceIdentifier> names = new ArrayList<>(nonNull(alias).size()
+ 1);
-        names.add(name);
-        if (alias != null) {
-            for (final GenericName c : alias) {
-                if (c != name && (c instanceof ReferenceIdentifier)) {
-                    names.add((ReferenceIdentifier) c);
-                }
-            }
-        }
-        return names;
+        return new Names();
     }
 
     /**
      * Sets the first element as the {@link #name} and all remaining elements as {@link #alias}.
-     * This method is invoked by JAXB at unmarshalling time. It should not be invoked anymore
-     * after the object has been made available to the user.
+     * This method is invoked by some implementations of JAXB (not all of them) at unmarshalling
time.
+     * It should not be invoked anymore after the object has been made available to the user.
+     *
+     * <p>Some JAXB implementations never invoke this setter method. Instead they invoke
{@link #getNames()}
+     * and add directly the identifiers in the returned collection. Whether JAXB will perform
a final call to
+     * {@code setNames(…)} is JAXB-implementation dependent (JDK7 does but JDK6 and JDK8
early access do not).
+     * Consequently we can not rely on this method to be invoked. It is better if this method
is invoked, but
+     * we will not lost data if it is not.</p>
+     *
+     * @see <a href="https://java.net/jira/browse/JAXB-488">JAXB-488</a>
      */
     private void setNames(final Collection<ReferenceIdentifier> names) {
-        if (names != null && canSetProperty("name", name != null)) {
-            final Iterator<ReferenceIdentifier> it = names.iterator();
-            if (it.hasNext()) {
-                name = it.next();
-                if (it.hasNext() && canSetProperty("alias", alias != null)) {
-                    alias = new ArrayList<>(4); // There is generally few aliases.
-                    do {
-                        alias.add(new NamedIdentifier(it.next()));
-                    } while (it.hasNext());
-                }
-            }
+        /*
+         * If the collection is an instance of Names, then assume that the collection is
the instance obtained
+         * by getNames(), in which case this IdentifiedObject already contains the content
of that collection.
+         * This behavior is necessary for working around the JAXB-488 issue.
+         */
+        if (!(names instanceof Names)) {
+            getNames().addAll(names);
+        }
+        /*
+         * Froze aliases in an unmodifiable set. In JAXB implementations that do not invoke
the setter method,
+         * the aliases list is left modifiable. This is a hole in our object immutability.
+         */
+        if (alias != null) {
+            alias = immutableSet(true, alias.toArray(new GenericName[alias.size()]));
         }
     }
 

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/NamedIdentifier.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/NamedIdentifier.java?rev=1556837&r1=1556836&r2=1556837&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/NamedIdentifier.java
[UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/NamedIdentifier.java
[UTF-8] Thu Jan  9 15:31:01 2014
@@ -137,8 +137,6 @@ public class NamedIdentifier extends Imm
     /**
      * Constructs an identifier from an authority and localizable code.
      * This is a convenience constructor for commonly-used parameters.
-     * If more control are wanted (for example adding remarks), use the
-     * {@linkplain #NamedIdentifier(Map) constructor with a properties map}.
      *
      * @param authority The authority (e.g. {@link Citations#OGC} or {@link Citations#EPSG}),
      *                  or {@code null} if not available.
@@ -155,30 +153,38 @@ public class NamedIdentifier extends Imm
     /**
      * Constructs an identifier from an authority and code.
      * This is a convenience constructor for commonly-used parameters.
-     * If more control are wanted (for example adding remarks), use the
-     * {@linkplain #NamedIdentifier(Map) constructor with a properties map}.
      *
      * @param authority The authority (e.g. {@link Citations#OGC} or {@link Citations#EPSG}),
      *                  or {@code null} if not available.
      * @param code      The code. This parameter is mandatory.
      */
     public NamedIdentifier(final Citation authority, final String code) {
-        this(authority, code, null);
+        super(authority, Citations.getIdentifier(authority), code);
     }
 
     /**
-     * Constructs an identifier from an authority, code and version.
-     * This is a convenience constructor for commonly-used parameters.
-     * If more control are wanted (for example adding remarks), use the
-     * {@linkplain #NamedIdentifier(Map) constructor with a properties map}.
+     * Creates an identifier from the specified code and authority,
+     * with an optional version number and remarks.
      *
-     * @param authority The authority (e.g. {@link Citations#OGC} or {@link Citations#EPSG}),
-     *                  or {@code null} if not available.
-     * @param code      The code. This parameter is mandatory.
-     * @param version   The version, or {@code null} if none.
-     */
-    public NamedIdentifier(final Citation authority, final String code, final String version)
{
-        super(authority, Citations.getIdentifier(authority), code, version, null);
+     * @param authority
+     *          Organization or party responsible for definition and maintenance of the code
+     *          space or code, or {@code null} if not available.
+     * @param codeSpace
+     *          Name or identifier of the person or organization responsible for namespace,
or
+     *          {@code null} if not available. This is often an abbreviation of the authority
name.
+     * @param code
+     *          Identifier code or name, optionally from a controlled list or pattern defined
by
+     *          a code space. The code can not be null.
+     * @param version
+     *          The version of the associated code space or code as specified by the code
authority,
+     *          or {@code null} if none.
+     * @param remarks
+     *          Comments on or information about this identifier, or {@code null} if none.
+     */
+    public NamedIdentifier(final Citation authority, final String codeSpace,
+            final String code, final String version, final InternationalString remarks)
+    {
+        super(authority, codeSpace, code, version, remarks);
     }
 
     /**

Modified: sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/AbstractIdentifiedObjectTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/AbstractIdentifiedObjectTest.java?rev=1556837&r1=1556836&r2=1556837&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/AbstractIdentifiedObjectTest.java
[UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/AbstractIdentifiedObjectTest.java
[UTF-8] Thu Jan  9 15:31:01 2014
@@ -85,7 +85,7 @@ public final strictfp class AbstractIden
         assertEquals("codespace",   "EPSG",                          name.getCodeSpace());
         assertEquals("version",     "8.3",                           name.getVersion());
         assertEquals("aliases",     "International 1979",            getSingleton(object.getAlias()).toString());
-        assertEquals("names",       Collections.singletonList(name), object.getNames());
+        assertEquals("names",       name,                            getSingleton(object.getNames()));
         assertEquals("identifiers", identifiers,                     object.getIdentifiers());
         assertEquals("ID",          gmlID,                           object.getID());
         assertEquals("remarks",     "Adopted by IUGG 1979 Canberra", object.getRemarks().toString(Locale.ENGLISH));



Mime
View raw message