• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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      */
value()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      */
nulls()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      */
contentNulls()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 
Value(Nulls nulls, Nulls contentNulls)77         protected Value(Nulls nulls, Nulls contentNulls) {
78             _nulls = nulls;
79             _contentNulls = contentNulls;
80         }
81 
82         @Override
valueFor()83         public Class<JsonSetter> valueFor() {
84             return JsonSetter.class;
85         }
86 
87         // for JDK serialization
readResolve()88         protected Object readResolve() {
89             if (_empty(_nulls, _contentNulls)) {
90                 return EMPTY;
91             }
92             return this;
93         }
94 
from(JsonSetter src)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          */
construct(Nulls nulls, Nulls contentNulls)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          */
empty()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          */
merge(Value base, Value overrides)142         public static Value merge(Value base, Value overrides)
143         {
144             return (base == null) ? overrides
145                     : base.withOverrides(overrides);
146         }
147 
forValueNulls(Nulls nulls)148         public static Value forValueNulls(Nulls nulls) {
149             return construct(nulls, Nulls.DEFAULT);
150         }
151 
forValueNulls(Nulls nulls, Nulls contentNulls)152         public static Value forValueNulls(Nulls nulls, Nulls contentNulls) {
153             return construct(nulls, contentNulls);
154         }
155 
forContentNulls(Nulls nulls)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          */
withOverrides(Value overrides)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 
withValueNulls(Nulls nulls)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 
withValueNulls(Nulls valueNulls, Nulls contentNulls)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 
withContentNulls(Nulls nulls)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 
getValueNulls()219         public Nulls getValueNulls() { return _nulls; }
getContentNulls()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          */
nonDefaultValueNulls()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          */
nonDefaultContentNulls()234         public Nulls nonDefaultContentNulls() {
235             return (_contentNulls == Nulls.DEFAULT) ? null : _contentNulls;
236         }
237 
238         /*
239         /**********************************************************
240         /* Std method overrides
241         /**********************************************************
242          */
243 
244         @Override
toString()245         public String toString() {
246             return String.format("JsonSetter.Value(valueNulls=%s,contentNulls=%s)",
247                     _nulls, _contentNulls);
248         }
249 
250         @Override
hashCode()251         public int hashCode() {
252             return _nulls.ordinal() + (_contentNulls.ordinal() << 2);
253         }
254 
255         @Override
equals(Object o)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 
_empty(Nulls nulls, Nulls contentNulls)273         private static boolean _empty(Nulls nulls, Nulls contentNulls) {
274             return (nulls == Nulls.DEFAULT)
275                     && (contentNulls == Nulls.DEFAULT);
276         }
277     }
278 }
279