1 package com.fasterxml.jackson.annotation;
2
3 import java.lang.annotation.*;
4
5 /**
6 * Annotation that can be used to define a non-static,
7 * single-argument method to be used as a "setter" for a logical property
8 * as an alternative to recommended
9 * {@link JsonProperty} annotation;
10 * or (as of 2.9 and later), specify additional aspects of the
11 * assigning property a value during serialization.
12 */
13 @Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
14 // ^^^ allowed on Fields, (constructor) parameters since 2.9
15 @Retention(RetentionPolicy.RUNTIME)
16 @JacksonAnnotation
17 public @interface JsonSetter
18 {
19 /**
20 * Optional default argument that defines logical property this
21 * method is used to modify ("set"); this is the property
22 * name used in JSON content.
23 */
24 String value() default "";
25
26 /**
27 * Specifies action to take when input contains explicit `null` value
28 * (if format has one).
29 * Default action, in absence of any explicit configuration,
30 * is usually {@link Nulls#SET}, meaning that the `null` is set as
31 * value using setter.
32 *<p>
33 * NOTE: is not usually used in case property value is missing, unless
34 * data format specifies that there is defaulting which would result
35 * in an explicit null assignment.
36 */
37 Nulls nulls() default Nulls.DEFAULT;
38
39 /**
40 * Specifies action to take when input to match into content value
41 * (of a {@link java.util.Collection}, {@link java.util.Map}, array,
42 * or referential value) contains explicit `null` value
43 * (if format has one) to bind.
44 * Default action, in absence of any explicit configuration,
45 * is usually {@link Nulls#SET}, meaning that the `null` is included as usual.
46 */
47 Nulls contentNulls() default Nulls.DEFAULT;
48
49 /*
50 /**********************************************************
51 /* Value class used to enclose information, allow for
52 /* merging of layered configuration settings.
53 /**********************************************************
54 */
55
56 /**
57 * Helper class used to contain information from a single {@link JsonSetter}
58 * annotation, as well as to provide possible overrides from non-annotation sources.
59 *
60 * @since 2.9
61 */
62 public static class Value
63 implements JacksonAnnotationValue<JsonSetter>,
64 java.io.Serializable
65 {
66 private static final long serialVersionUID = 1L;
67
68 private final Nulls _nulls;
69
70 private final Nulls _contentNulls;
71
72 /**
73 * Default instance used in place of "default settings".
74 */
75 protected final static Value EMPTY = new Value(Nulls.DEFAULT, Nulls.DEFAULT);
76
77 protected Value(Nulls nulls, Nulls contentNulls) {
78 _nulls = nulls;
79 _contentNulls = contentNulls;
80 }
81
82 @Override
83 public Class<JsonSetter> valueFor() {
84 return JsonSetter.class;
85 }
86
87 // for JDK serialization
88 protected Object readResolve() {
89 if (_empty(_nulls, _contentNulls)) {
90 return EMPTY;
91 }
92 return this;
93 }
94
95 public static Value from(JsonSetter src) {
96 if (src == null) {
97 return EMPTY;
98 }
99 return construct(src.nulls(), src.contentNulls());
100 }
101
102 /**
103 * Factory method that may be used (although is NOT the recommended way)
104 * to construct an instance from a full set of properties. Most users would
105 * be better of starting by {@link #empty()} instance and using `withXxx`/`withoutXxx`
106 * methods, as this factory method may need to be changed if new properties
107 * are added in {@link JsonIgnoreProperties} annotation.
108 */
109 public static Value construct(Nulls nulls, Nulls contentNulls) {
110 if (nulls == null) {
111 nulls = Nulls.DEFAULT;
112 }
113 if (contentNulls == null) {
114 contentNulls = Nulls.DEFAULT;
115 }
116 if (_empty(nulls, contentNulls)) {
117 return EMPTY;
118 }
119 return new Value(nulls, contentNulls);
120 }
121
122 /**
123 * Accessor for default instances which has "empty" settings; that is:
124 *<ul>
125 * <li>Null handling using global defaults, {@link Nulls#DEFAULT}.
126 * </li>
127 * </ul>
128 */
129 public static Value empty() {
130 return EMPTY;
131 }
132
133 /**
134 * Helper method that will try to combine values from two {@link Value}
135 * instances, using one as base settings, and the other as overrides
136 * to use instead of base values when defined; base values are only
137 * use if override does not specify a value (matching value is null
138 * or logically missing).
139 * Note that one or both of value instances may be `null`, directly;
140 * if both are `null`, result will also be `null`; otherwise never null.
141 */
142 public static Value merge(Value base, Value overrides)
143 {
144 return (base == null) ? overrides
145 : base.withOverrides(overrides);
146 }
147
148 public static Value forValueNulls(Nulls nulls) {
149 return construct(nulls, Nulls.DEFAULT);
150 }
151
152 public static Value forValueNulls(Nulls nulls, Nulls contentNulls) {
153 return construct(nulls, contentNulls);
154 }
155
156 public static Value forContentNulls(Nulls nulls) {
157 return construct(Nulls.DEFAULT, nulls);
158 }
159
160 /**
161 * Mutant factory method that merges values of this value with given override
162 * values, so that any explicitly defined inclusion in overrides has precedence over
163 * settings of this value instance. If no overrides exist will return <code>this</code>
164 * instance; otherwise new {@link Value} with changed inclusion values.
165 */
166 public Value withOverrides(Value overrides) {
167 if ((overrides == null) || (overrides == EMPTY)) {
168 return this;
169 }
170 Nulls nulls = overrides._nulls;
171 Nulls contentNulls = overrides._contentNulls;
172
173 if (nulls == Nulls.DEFAULT) {
174 nulls = _nulls;
175 }
176 if (contentNulls == Nulls.DEFAULT) {
177 contentNulls = _contentNulls;
178 }
179
180 if ((nulls == _nulls) && (contentNulls == _contentNulls)) {
181 return this;
182 }
183 return construct(nulls, contentNulls);
184 }
185
186 public Value withValueNulls(Nulls nulls) {
187 if (nulls == null) {
188 nulls = Nulls.DEFAULT;
189 }
190 if (nulls == _nulls) {
191 return this;
192 }
193 return construct(nulls, _contentNulls);
194 }
195
196 public Value withValueNulls(Nulls valueNulls, Nulls contentNulls) {
197 if (valueNulls == null) {
198 valueNulls = Nulls.DEFAULT;
199 }
200 if (contentNulls == null) {
201 contentNulls = Nulls.DEFAULT;
202 }
203 if ((valueNulls == _nulls) && (contentNulls == _contentNulls)) {
204 return this;
205 }
206 return construct(valueNulls, contentNulls);
207 }
208
209 public Value withContentNulls(Nulls nulls) {
210 if (nulls == null) {
211 nulls = Nulls.DEFAULT;
212 }
213 if (nulls == _contentNulls) {
214 return this;
215 }
216 return construct(_nulls, nulls);
217 }
218
219 public Nulls getValueNulls() { return _nulls; }
220 public Nulls getContentNulls() { return _contentNulls; }
221
222 /**
223 * Returns same as {@link #getValueNulls()} unless value would be
224 * {@link Nulls#DEFAULT} in which case `null` is returned.
225 */
226 public Nulls nonDefaultValueNulls() {
227 return (_nulls == Nulls.DEFAULT) ? null : _nulls;
228 }
229
230 /**
231 * Returns same as {@link #getContentNulls()} unless value would be
232 * {@link Nulls#DEFAULT} in which case `null` is returned.
233 */
234 public Nulls nonDefaultContentNulls() {
235 return (_contentNulls == Nulls.DEFAULT) ? null : _contentNulls;
236 }
237
238 /*
239 /**********************************************************
240 /* Std method overrides
241 /**********************************************************
242 */
243
244 @Override
245 public String toString() {
246 return String.format("JsonSetter.Value(valueNulls=%s,contentNulls=%s)",
247 _nulls, _contentNulls);
248 }
249
250 @Override
251 public int hashCode() {
252 return _nulls.ordinal() + (_contentNulls.ordinal() << 2);
253 }
254
255 @Override
256 public boolean equals(Object o) {
257 if (o == this) return true;
258 if (o == null) return false;
259 if (o.getClass() == getClass()) {
260 Value other = (Value) o;
261 return (other._nulls == _nulls)
262 && (other._contentNulls == _contentNulls);
263 }
264 return false;
265 }
266
267 /*
268 /**********************************************************
269 /* Internal methods
270 /**********************************************************
271 */
272
273 private static boolean _empty(Nulls nulls, Nulls contentNulls) {
274 return (nulls == Nulls.DEFAULT)
275 && (contentNulls == Nulls.DEFAULT);
276 }
277 }
278 }
279