[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