[jackson-annotations] 16/207: Further improvements to Object Id annotations, types

Timo Aaltonen tjaalton at moszumanska.debian.org
Sat Sep 6 13:55:34 UTC 2014


This is an automated email from the git hooks/post-receive script.

tjaalton pushed a commit to branch master
in repository jackson-annotations.

commit 17eb41feaf482e9a5df174459cfeeecd10f6aa82
Author: Tatu Saloranta <tsaloranta at gmail.com>
Date:   Tue Feb 7 09:10:53 2012 -0800

    Further improvements to Object Id annotations, types
---
 .../jackson/annotation/JsonIdentityInfo.java       |  66 +++++++++
 .../fasterxml/jackson/annotation/JsonObjectId.java |  26 ----
 .../jackson/annotation/ObjectIdGenerator.java      |  61 +++++++++
 .../jackson/annotation/ObjectIdGenerators.java     | 150 +++++++++++++++++++++
 4 files changed, 277 insertions(+), 26 deletions(-)

diff --git a/src/main/java/com/fasterxml/jackson/annotation/JsonIdentityInfo.java b/src/main/java/com/fasterxml/jackson/annotation/JsonIdentityInfo.java
new file mode 100644
index 0000000..28c0724
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/annotation/JsonIdentityInfo.java
@@ -0,0 +1,66 @@
+package com.fasterxml.jackson.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation used for indicating that values of annotated type
+ * or property should be serializing so that instances either
+ * contain additional object identifier (in addition actual object
+ * properties), or as a reference that consists of an object id
+ * that refers to a full serialization. In practice this is done
+ * by serializing the first instance as full object and object
+ * identity, and other references to the object as reference values.
+ *<p>
+ * There are two main approaches to generating object identifier:
+ * either using a generator (either one of standard ones, or a custom
+ * generator), or using a value of a property. The latter case is
+ * indicated by using a placeholder generator marker
+ * {@link ObjectIdGenerators#ObjectIdGenerator}; former by using explicit generator.
+ * Object id has to be serialized as a property in case of POJOs;
+ * object identity is currently NOT support for JSON Array types
+ * (Java arrays or Lists) or Java Map types.
+ * 
+ * @since 2.0
+ */
+ at Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE,
+    ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
+ at Retention(RetentionPolicy.RUNTIME)
+ at JacksonAnnotation
+public @interface JsonIdentityInfo
+{
+    /**
+     * Name of JSON property in which Object Id will reside: also,
+     * if "from property" marker generator is used, identifies
+     * property that will be accessed to get type id.
+     * If a property is used, name must match its external
+     * name (one defined by annotation, or derived from accessor
+     * name as per Java Bean Introspection rules).
+     *<p>
+     * Default value is <code>@id</code>.
+     */
+    public String property() default "@id";
+
+    /**
+     * Generator to use for producing Object Identifier for objects:
+     * either one of pre-defined generators from
+     * {@link IdGenerator}, or a custom generator.
+     * Defined as class to instantiate.
+     */
+    public Class<? extends ObjectIdGenerator<?>> generator();
+
+    /**
+     * Scope is a concept used by {@link ObjectIdGenerator} created based
+     * on {@link #property}, iff {@link ObjectIdGenerator#usesGlobalScope()}
+     * returns false. If so, separate generator instances are created for
+     * each distinct scope. If not defined (i.e. left at default value of
+     * {@link JsonIdentityInfo}), will just use type of the annotated
+     * class or property as scope.
+     *<p>
+     * If {@link ObjectIdGenerator#usesGlobalScope()} returns true,
+     * value of this property is ignored.
+     */
+    public Class<?> scope() default JsonIdentityInfo.class;
+}
diff --git a/src/main/java/com/fasterxml/jackson/annotation/JsonObjectId.java b/src/main/java/com/fasterxml/jackson/annotation/JsonObjectId.java
deleted file mode 100644
index 194eba2..0000000
--- a/src/main/java/com/fasterxml/jackson/annotation/JsonObjectId.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.fasterxml.jackson.annotation;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Marker annotation that can be used on a property value accessor
- * (field, getter) to indicate that
- * the property will be used to find id value that indicates identity
- * of the object, for purposes of handling object references (needed
- * to handled cyclic dependencies, or avoid value duplications).
- * Any objects should only have at most one accessor defined as
- * id property; using it for multiple may result in an exception
- * (behavior is unspecified).
- * 
- * @since 2.0
- */
- at Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD, ElementType.METHOD})
- at Retention(RetentionPolicy.RUNTIME)
- at JacksonAnnotation
-public @interface JsonObjectId
-{
-
-}
diff --git a/src/main/java/com/fasterxml/jackson/annotation/ObjectIdGenerator.java b/src/main/java/com/fasterxml/jackson/annotation/ObjectIdGenerator.java
new file mode 100644
index 0000000..83d176c
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/annotation/ObjectIdGenerator.java
@@ -0,0 +1,61 @@
+package com.fasterxml.jackson.annotation;
+
+/**
+ * Definition of API used for constructing Object Identifiers
+ * (as annotated using {@link JsonIdentityInfo}).
+ * Also defines factory methods used for creating instances
+ * for serialization, deserialization.
+ *
+ * @param <T> Type of Object Identifiers produced.
+ */
+public abstract class ObjectIdGenerator<T>
+{
+    /**
+     * Factory method called to create a new instance to use for
+     * serialization. This includes initializing storage for keeping
+     * track of serialized instances, along with id used.
+     * Caller has to make sure to create proper number of instances
+     * to ensure scoping (as implied by {@link #usesGlobalScope()}).
+     */
+    public abstract ObjectIdGenerator<T> newForSerialization(Class<?> scope);
+
+    /**
+     * Factory method called to create a new instance to use for
+     * serialization. This includes initializing storage for keeping
+     * track of deserialized instances, along with id used.
+     * Caller has to make sure to create proper number of instances
+     * to ensure scoping (as implied by {@link #usesGlobalScope()}).
+     */
+    public abstract ObjectIdGenerator<T> newForDeserialization(Class<?> scope);
+    
+    /**
+     * Accessor called to determine whether scope of Object Identifiers
+     * is global (within context of a single serialization) or not;
+     * if not, scope is assumed to be per-type (using statically declared
+     * type). Definition of scope is that all identifiers produced must
+     * be unique within a scope: thus global scope would guarantee
+     * that all produced identifiers are unique for full serialization
+     * process, whereas local scopes only guarantee it for the supported
+     * type (within single serialization).
+     *<p>
+     * One generator instance is needed per scope, and for deserialization,
+     * separate Maps are kept on per-scope basis.
+     *<p>
+     * Standard generators (UUID, sequence-number) support global scope;
+     * custom generators may support
+     * 
+     * @return True if global (one per serialization) scope is needed by
+     *   generator; false if per-type scope is needed.
+     */
+    public abstract boolean usesGlobalScope();
+    
+    /**
+     * Method used for generating an Object Identifier to serialize
+     * for given POJO.
+     * 
+     * @param forPojo POJO for which identifier is needed
+     * 
+     * @return Object Identifier to use.
+     */
+    public abstract T generateId(Object forPojo);
+}
diff --git a/src/main/java/com/fasterxml/jackson/annotation/ObjectIdGenerators.java b/src/main/java/com/fasterxml/jackson/annotation/ObjectIdGenerators.java
new file mode 100644
index 0000000..2fc08f8
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/annotation/ObjectIdGenerators.java
@@ -0,0 +1,150 @@
+package com.fasterxml.jackson.annotation;
+
+import java.util.IdentityHashMap;
+import java.util.UUID;
+
+/**
+ * Container class for standard {@link ObjectIdGenerator} implementations.
+ */
+public class ObjectIdGenerators
+{
+    /*
+    /**********************************************************
+    /* Implementation classes
+    /**********************************************************
+     */
+
+    /**
+     * Helper class that implements scoped storage for Object
+     * references.
+     */
+    private abstract static class Base<T> extends ObjectIdGenerator<T>
+    {
+        /**
+         * Lazily constructed mapping of "ids-to-Objects" used by deserialization.
+         */
+        protected IdentityHashMap<Object, T> _ids;
+
+        protected IdentityHashMap<T, Object> _items;
+        
+        protected T findId(Object item) {
+            if (_ids == null) {
+                return null;
+            }
+            return _ids.get(item);
+        }
+
+        protected Object findItem(T id) {
+            if (_items == null) {
+                return null;
+            }
+            return _items.get(id);
+        }
+
+        /**
+         * Method called during serialization to keep track of ids we have
+         * used.
+         */
+        protected void addId(Object item, T id) {
+            if (_ids == null) {
+                _ids = new IdentityHashMap<Object, T>(16);
+            }
+            _ids.put(item, id);
+        }
+
+        /**
+         * Method called during deserialization to keep track of items we have
+         * deserialized, along with ids they had.
+         */
+        protected void addItem(Object item, T id) {
+            if (_items == null) {
+                _items = new IdentityHashMap<T, Object>(16);
+            }
+            _ids.put(item, id);
+        }
+    }
+    
+    /**
+     * Abstract place-holder class which is used to denote case
+     * where Object Identifier to use comes from a POJO property
+     * (getter method or field). If so, value is written directly
+     * during serialization, and used as-is during deserialization.
+     *<p>
+     * Actual implementation class is part of <code>databind</code>
+     * package.
+     */
+    public abstract class PropertyGenerator<T> extends Base<T> { }
+    
+    /**
+     * Simple sequence-number based generator, which uses basic Java
+     * <code>int</code>s (starting with value 1) as Object Identifiers.
+     */
+    public static class IntSequenceGenerator extends Base<Integer>
+    {
+        protected int _nextValue;
+
+        public IntSequenceGenerator() { this(1); }
+        public IntSequenceGenerator(int fv) {
+            super();
+            _nextValue = fv;
+        }
+
+        @Override
+        public ObjectIdGenerator<Integer> newForSerialization(Class<?> scope) {
+            return new IntSequenceGenerator(_nextValue);
+        }
+
+        // we don't really need value for deserialization but...
+        @Override
+        public ObjectIdGenerator<Integer> newForDeserialization(Class<?> scope) {
+            return new IntSequenceGenerator(_nextValue);
+        }
+        
+        /**
+         * We can easily support global scope with simple sequences, so return true
+         */
+        @Override
+        public boolean usesGlobalScope() {
+            return true;
+        }
+
+        @Override
+        public Integer generateId(Object forPojo) {
+            int id = _nextValue;
+            ++_nextValue;
+            return id;
+        }
+    }
+
+    /**
+     * Implementation that just uses {@link java.util.UUID}s as reliably
+     * unique identifiers: downside is that resulting String is
+     * 36 characters long.
+     */
+    public static class UUIDGenerator extends Base<UUID>
+    {
+        @Override
+        public ObjectIdGenerator<UUID> newForSerialization(Class<?> scope) {
+            return new UUIDGenerator();
+        }
+
+        @Override
+        public ObjectIdGenerator<UUID> newForDeserialization(Class<?> scope) {
+            return new UUIDGenerator();
+        }
+        
+        /**
+         * UUIDs are globally unique, so yes we can support global scope
+         */
+        @Override
+        public boolean usesGlobalScope() {
+            return true;
+        }
+
+        @Override
+        public UUID generateId(Object forPojo) {
+            return UUID.randomUUID();
+        }
+    }
+    
+}

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/jackson-annotations.git



More information about the pkg-java-commits mailing list