1 package com.fasterxml.jackson.annotation; 2 3 /** 4 * Definition of API used for constructing Object Identifiers 5 * (as annotated using {@link JsonIdentityInfo}). 6 * Also defines factory methods used for creating instances 7 * for serialization, deserialization. 8 * 9 * @param <T> Type of Object Identifiers produced. 10 */ 11 @SuppressWarnings("serial") 12 public abstract class ObjectIdGenerator<T> 13 implements java.io.Serializable 14 { 15 /* 16 /********************************************************** 17 /* Accessors 18 /********************************************************** 19 */ 20 getScope()21 public abstract Class<?> getScope(); 22 23 /** 24 * Method called to check whether this generator instance can 25 * be used for Object Ids of specific generator type and 26 * scope; determination is based by passing a configured 27 * "blueprint" (prototype) instance; from which the actual 28 * instances are created (using {@link #newForSerialization}). 29 * 30 * @return True if this instance can be used as-is; false if not 31 */ canUseFor(ObjectIdGenerator<?> gen)32 public abstract boolean canUseFor(ObjectIdGenerator<?> gen); 33 34 /** 35 * Accessor that needs to be overridden to return <code>true</code> 36 * if the Object Id may be serialized as JSON Object; used by, for example, 37 * JSOG handling. 38 * The reason accessor is needed is because handling such Object Ids is 39 * more complex and may incur additional buffering or performance overhead, 40 * avoiding of which makes sense for common case of scalar object ids 41 * (or native object ids some formats support). 42 *<p> 43 * Default implementation returns <code>false</code>, so needs to be overridden 44 * by Object-producing generators. 45 * 46 * @since 2.5 47 */ maySerializeAsObject()48 public boolean maySerializeAsObject() { 49 return false; 50 } 51 52 /** 53 * Accessor that may be called (after verifying (via {@link #maySerializeAsObject()}) 54 * whether given name 55 * 56 * @param name Name of property to check 57 * @param parser Parser that points to property name, in case generator needs 58 * further verification (note: untyped, because <code>JsonParser</code> is defined 59 * in `jackson-core`, and this package does not depend on it). 60 * 61 * @since 2.5 62 */ isValidReferencePropertyName(String name, Object parser)63 public boolean isValidReferencePropertyName(String name, Object parser) { 64 return false; 65 } 66 67 /* 68 /********************************************************** 69 /* Factory methods 70 /********************************************************** 71 */ 72 73 /** 74 * Factory method to create a blueprint instance for specified 75 * scope. Generators that do not use scope may return 'this'. 76 */ forScope(Class<?> scope)77 public abstract ObjectIdGenerator<T> forScope(Class<?> scope); 78 79 /** 80 * Factory method called to create a new instance to use for 81 * serialization: needed since generators may have state 82 * (next id to produce). 83 *<p> 84 * Note that actual type of 'context' is 85 * <code>com.fasterxml.jackson.databind.SerializerProvider</code>, 86 * but can not be declared here as type itself (as well as call 87 * to this object) comes from databind package. 88 * 89 * @param context Serialization context object used (of type 90 * <code>com.fasterxml.jackson.databind.SerializerProvider</code>; 91 * may be needed by more complex generators to access contextual 92 * information such as configuration. 93 */ newForSerialization(Object context)94 public abstract ObjectIdGenerator<T> newForSerialization(Object context); 95 96 /** 97 * Method for constructing key to use for ObjectId-to-POJO maps. 98 */ key(Object key)99 public abstract IdKey key(Object key); 100 101 /* 102 /********************************************************** 103 /* Methods for serialization 104 /********************************************************** 105 */ 106 107 /** 108 * Method used for generating a new Object Identifier to serialize 109 * for given POJO. 110 * 111 * @param forPojo POJO for which identifier is needed 112 * 113 * @return Object Identifier to use. 114 */ generateId(Object forPojo)115 public abstract T generateId(Object forPojo); 116 117 /* 118 /********************************************************** 119 /* Helper classes 120 /********************************************************** 121 */ 122 123 /** 124 * Simple key class that can be used as a key for 125 * ObjectId-to-POJO mappings, when multiple ObjectId types 126 * and scopes are used. 127 */ 128 public final static class IdKey 129 implements java.io.Serializable 130 { 131 private static final long serialVersionUID = 1L; 132 133 /** 134 * Type of {@link ObjectIdGenerator} used for generating Object Id 135 */ 136 public final Class<?> type; 137 138 /** 139 * Scope of the Object Id (may be null, to denote global) 140 */ 141 public final Class<?> scope; 142 143 /** 144 * Object for which Object Id was generated: can NOT be null. 145 */ 146 public final Object key; 147 148 private final int hashCode; 149 IdKey(Class<?> type, Class<?> scope, Object key)150 public IdKey(Class<?> type, Class<?> scope, Object key) { 151 if (key == null) { 152 throw new IllegalArgumentException("Can not construct IdKey for null key"); 153 } 154 this.type = type; 155 this.scope = scope; 156 this.key = key; 157 158 int h = key.hashCode() + type.getName().hashCode(); 159 if (scope != null) { 160 h ^= scope.getName().hashCode(); 161 } 162 hashCode = h; 163 } 164 165 @Override hashCode()166 public int hashCode() { return hashCode; } 167 168 @Override equals(Object o)169 public boolean equals(Object o) 170 { 171 if (o == this) return true; 172 if (o == null) return false; 173 if (o.getClass() != getClass()) return false; 174 IdKey other = (IdKey) o; 175 return (other.key.equals(key)) && (other.type == type) && (other.scope == scope); 176 } 177 178 @Override toString()179 public String toString() { 180 return String.format("[ObjectId: key=%s, type=%s, scope=%s]", key, 181 (type == null) ? "NONE" : type.getName(), 182 (scope == null) ? "NONE" : scope.getName()); 183 } 184 } 185 } 186