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 <[email protected]> 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 + */ +@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE, + ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER}) +@Retention(RetentionPolicy.RUNTIME) +@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 - */ -@Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD, ElementType.METHOD}) -@Retention(RetentionPolicy.RUNTIME) -@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 _______________________________________________ pkg-java-commits mailing list [email protected] http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-java-commits

