1 package com.fasterxml.jackson.annotation;
2
3 import java.lang.annotation.ElementType;
4 import java.lang.annotation.Retention;
5 import java.lang.annotation.RetentionPolicy;
6 import java.lang.annotation.Target;
7 import java.util.*;
8
9 /**
10 * Annotation that can be used to either suppress serialization of
11 * properties (during serialization), or ignore processing of
12 * JSON properties read (during deserialization).
13 *<p>
14 * Example:
15 *<pre>
16 * // to prevent specified fields from being serialized or deserialized
17 * // (i.e. not include in JSON output; or being set even if they were included)
18 * @JsonIgnoreProperties({ "internalId", "secretKey" })
19 * // To ignore any unknown properties in JSON input without exception:
20 * @JsonIgnoreProperties(ignoreUnknown=true)
21 *</pre>
22 *<p>
23 * Annotation can be applied both to classes and
24 * to properties. If used for both, actual set will be union of all
25 * ignorals: that is, you can only add properties to ignore, not remove
26 * or override. So you can not remove properties to ignore using
27 * per-property annotation.
28 */
29 @Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE,
30 ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD})
31 @Retention(RetentionPolicy.RUNTIME)
32 @JacksonAnnotation
33 public @interface JsonIgnoreProperties
34 {
35 /**
36 * Names of properties to ignore.
37 */
38 public String[] value() default { };
39
40 /**
41 * Property that defines whether it is ok to just ignore any
42 * unrecognized properties during deserialization.
43 * If true, all properties that are unrecognized -- that is,
44 * there are no setters or creators that accept them -- are
45 * ignored without warnings (although handlers for unknown
46 * properties, if any, will still be called) without
47 * exception.
48 *<p>
49 * Does not have any effect on serialization.
50 *
51 * @return True if any and all unknown properties are to be ignored without
52 * exceptions (or other special handling); false otherwise.
53 */
54 public boolean ignoreUnknown() default false;
55
56 /**
57 * Property that can be enabled to allow "getters" to be used (that is,
58 * prevent ignoral of getters for properties listed in {@link #value()}).
59 * This is commonly set to support defining "read-only" properties; ones
60 * for which there is a getter, but no matching setter: in this case,
61 * properties should be ignored for deserialization but NOT serialization.
62 * Another way to think about this setting is that setting it to `true`
63 * will "disable" ignoring of getters.
64 *<p>
65 * Default value is `false`, which means that getters with matching names
66 * will be ignored.
67 *
68 * @return True if getters should be allowed (i.e. NOT ignored); false if getters
69 * are to be ignored
70 *
71 * @since 2.6
72 */
73 public boolean allowGetters() default false;
74
75 /**
76 * Property that can be enabled to allow "setters" to be used (that is,
77 * prevent ignoral of setters for properties listed in {@link #value()}).
78 * This could be used to specify "write-only" properties; ones
79 * that should not be serialized out, but that may be provided in for
80 * deserialization.
81 * Another way to think about this setting is that setting it to `true`
82 * will "disable" ignoring of setters.
83 *<p>
84 * Default value is `false`, which means that setters with matching names
85 * will be ignored.
86 *
87 *
88 * @return True if setters should be allowed (i.e. NOT ignored); false if setters
89 * are to be ignored
90 * @since 2.6
91 */
92 public boolean allowSetters() default false;
93
94 /*
95 /**********************************************************
96 /* Value class used to enclose information, allow for
97 /* merging of layered configuration settings.
98 /**********************************************************
99 */
100
101 /**
102 * Helper class used to contain information from a single {@link JsonIgnoreProperties}
103 * annotation, as well as to provide possible overrides from non-annotation sources.
104 *
105 * @since 2.8
106 */
107 public static class Value
108 implements JacksonAnnotationValue<JsonIgnoreProperties>,
109 java.io.Serializable
110 {
111 private static final long serialVersionUID = 1L;
112
113 /**
114 * Default instance has no explicitly ignored fields, does not ignore unknowns,
115 * does not explicitly allow getters/setters (that is, ignorals apply to both),
116 * but does use merging for combining overrides with base settings
117 */
118 protected final static Value EMPTY = new Value(Collections.<String>emptySet(),
119 false, false, false, true);
120
121 /**
122 * Names of properties to ignore.
123 */
124 protected final Set<String> _ignored;
125
126 protected final boolean _ignoreUnknown;
127 protected final boolean _allowGetters;
128 protected final boolean _allowSetters;
129
130 protected final boolean _merge;
131
132 protected Value(Set<String> ignored, boolean ignoreUnknown,
133 boolean allowGetters, boolean allowSetters,
134 boolean merge)
135 {
136 if (ignored == null) {
137 _ignored = Collections.emptySet();
138 } else {
139 _ignored = ignored;
140 }
141 _ignoreUnknown = ignoreUnknown;
142 _allowGetters = allowGetters;
143 _allowSetters = allowSetters;
144 _merge = merge;
145 }
146
147 public static Value from(JsonIgnoreProperties src) {
148 if (src == null) {
149 return EMPTY; // since 2.9
150 }
151 return construct(_asSet(src.value()),
152 src.ignoreUnknown(), src.allowGetters(), src.allowSetters(),
153 // 27-Apr-2016, tatu: No matching property in annotation because
154 // we don't know how to merge (so no point in pretending it's there)
155 // so choice is arbitrary. Probably will default to `false` fwtw:
156 false);
157 }
158
159 /**
160 * Factory method that may be used (although is NOT the recommended way)
161 * to construct an instance from a full set of properties. Most users would
162 * be better of starting by {@link #empty()} instance and using `withXxx()`/`withoutXxx()`
163 * methods, as this factory method may need to be changed if new properties
164 * are added in {@link JsonIgnoreProperties} annotation.
165 */
166 public static Value construct(Set<String> ignored, boolean ignoreUnknown,
167 boolean allowGetters, boolean allowSetters,
168 boolean merge) {
169 if (_empty(ignored, ignoreUnknown, allowGetters, allowSetters, merge)) {
170 return EMPTY;
171 }
172 return new Value(ignored, ignoreUnknown, allowGetters, allowSetters, merge);
173 }
174
175 /**
176 * Accessor for default instances which has "empty" settings; that is:
177 *<ul>
178 * <li>No explicitly defined fields to ignore
179 * </li>
180 * <li>Does not ignore unknown fields
181 * </li>
182 * <li>Does not "allow" getters if property ignored (that is, ignorals apply to both setter and getter)
183 * </li>
184 * <li>Does not "allow" setters if property ignored (that is, ignorals apply to both setter and getter)
185 * </li>
186 * <li>Does use merge when combining overrides to base settings, such that `true` settings
187 * for any of the properties results in `true`, and names of fields are combined (union)
188 * </li>
189 * </ul>
190 */
191 public static Value empty() {
192 return EMPTY;
193 }
194
195 /**
196 * Helper method that will try to combine values from two {@link Value}
197 * instances, using one as base settings, and the other as overrides
198 * to use instead of base values when defined; base values are only
199 * use if override does not specify a value (matching value is null
200 * or logically missing).
201 * Note that one or both of value instances may be `null`, directly;
202 * if both are `null`, result will also be `null`; otherwise never null.
203 */
204 public static Value merge(Value base, Value overrides)
205 {
206 return (base == null) ? overrides
207 : base.withOverrides(overrides);
208 }
209
210 /**
211 * @since 2.8
212 */
213 public static Value mergeAll(Value... values)
214 {
215 Value result = null;
216 for (Value curr : values) {
217 if (curr != null) {
218 result = (result == null) ? curr : result.withOverrides(curr);
219 }
220 }
221 return result;
222 }
223
224 public static Value forIgnoredProperties(Set<String> propNames) {
225 return EMPTY.withIgnored(propNames);
226 }
227
228 public static Value forIgnoredProperties(String... propNames) {
229 if (propNames.length == 0) {
230 return EMPTY;
231 }
232 return EMPTY.withIgnored(_asSet(propNames));
233 }
234
235 public static Value forIgnoreUnknown(boolean state) {
236 return state ? EMPTY.withIgnoreUnknown()
237 : EMPTY.withoutIgnoreUnknown();
238 }
239
240 /**
241 * Mutant factory method that merges values of this value with given override
242 * values, so that any explicitly defined inclusion in overrides has precedence over
243 * settings of this value instance. If no overrides exist will return <code>this</code>
244 * instance; otherwise new {@link Value} with changed inclusion values.
245 */
246 public Value withOverrides(Value overrides) {
247 if ((overrides == null) || (overrides == EMPTY)) {
248 return this;
249 }
250 // if non merging, we'll actually end up with just the overrides don't we?
251 // (given there's no "use default" value for anything
252 if (!overrides._merge) {
253 return overrides;
254 }
255 if (_equals(this, overrides)) {
256 return this;
257 }
258
259 // Here's where mergeability needs to be checked
260 Set<String> ignored = _merge(_ignored, overrides._ignored);
261 boolean ignoreUnknown = _ignoreUnknown || overrides._ignoreUnknown;
262 boolean allowGetters = _allowGetters || overrides._allowGetters;
263 boolean allowSetters = _allowSetters || overrides._allowSetters;
264
265 // must have 'merge=true' to get this far
266 return construct(ignored, ignoreUnknown, allowGetters, allowSetters, true);
267 }
268
269 public Value withIgnored(Set<String> ignored) {
270 return construct(ignored, _ignoreUnknown, _allowGetters, _allowSetters, _merge);
271 }
272
273 public Value withIgnored(String... ignored) {
274 return construct(_asSet(ignored), _ignoreUnknown, _allowGetters, _allowSetters, _merge);
275 }
276
277 public Value withoutIgnored() {
278 return construct(null, _ignoreUnknown, _allowGetters, _allowSetters, _merge);
279 }
280
281 public Value withIgnoreUnknown() {
282 return _ignoreUnknown ? this :
283 construct(_ignored, true, _allowGetters, _allowSetters, _merge);
284 }
285 public Value withoutIgnoreUnknown() {
286 return !_ignoreUnknown ? this :
287 construct(_ignored, false, _allowGetters, _allowSetters, _merge);
288 }
289
290 public Value withAllowGetters() {
291 return _allowGetters ? this :
292 construct(_ignored, _ignoreUnknown, true, _allowSetters, _merge);
293 }
294 public Value withoutAllowGetters() {
295 return !_allowGetters ? this :
296 construct(_ignored, _ignoreUnknown, false, _allowSetters, _merge);
297 }
298
299 public Value withAllowSetters() {
300 return _allowSetters ? this :
301 construct(_ignored, _ignoreUnknown, _allowGetters, true, _merge);
302 }
303 public Value withoutAllowSetters() {
304 return !_allowSetters ? this :
305 construct(_ignored, _ignoreUnknown, _allowGetters, false, _merge);
306 }
307
308 public Value withMerge() {
309 return _merge ? this :
310 construct(_ignored, _ignoreUnknown, _allowGetters, _allowSetters, true);
311 }
312
313 public Value withoutMerge() {
314 return !_merge ? this :
315 construct(_ignored, _ignoreUnknown, _allowGetters, _allowSetters, false);
316 }
317
318 @Override
319 public Class<JsonIgnoreProperties> valueFor() {
320 return JsonIgnoreProperties.class;
321 }
322
323 // for JDK serialization
324 protected Object readResolve() {
325 if (_empty(_ignored, _ignoreUnknown, _allowGetters, _allowSetters, _merge)) {
326 return EMPTY;
327 }
328 return this;
329 }
330
331 public Set<String> getIgnored() {
332 return _ignored;
333 }
334
335 /**
336 * Method called to find names of properties to ignore when used for
337 * serialization: functionally
338 * same as {@link #getIgnored} if {@link #getAllowGetters()} is false
339 * (that is, there is "allowGetters=false" or equivalent),
340 * otherwise returns empty {@link java.util.Set}.
341 */
342 public Set<String> findIgnoredForSerialization() {
343 if (_allowGetters) {
344 return Collections.emptySet();
345 }
346 return _ignored;
347 }
348
349 /**
350 * Method called to find names of properties to ignore when used for
351 * serialization: functionally
352 * same as {@link #getIgnored} if {@link #getAllowSetters()} is false
353 * (that is, there is "allowSetters=false" or equivalent),
354 * otherwise returns empty {@link java.util.Set}.
355 */
356 public Set<String> findIgnoredForDeserialization() {
357 if (_allowSetters) {
358 return Collections.emptySet();
359 }
360 return _ignored;
361 }
362
363 public boolean getIgnoreUnknown() {
364 return _ignoreUnknown;
365 }
366
367 public boolean getAllowGetters() {
368 return _allowGetters;
369 }
370
371 public boolean getAllowSetters() {
372 return _allowSetters;
373 }
374
375 public boolean getMerge() {
376 return _merge;
377 }
378
379 @Override
380 public String toString() {
381 return String.format("JsonIgnoreProperties.Value(ignored=%s,ignoreUnknown=%s,allowGetters=%s,allowSetters=%s,merge=%s)",
382 _ignored, _ignoreUnknown, _allowGetters, _allowSetters, _merge);
383 }
384
385 @Override
386 public int hashCode() {
387 return (_ignored.size())
388 + (_ignoreUnknown ? 1 : -3)
389 + (_allowGetters ? 3 : -7)
390 + (_allowSetters ? 7 : -11)
391 + (_merge ? 11 : -13)
392 ;
393 }
394
395 @Override
396 public boolean equals(Object o) {
397 if (o == this) return true;
398 if (o == null) return false;
399 return (o.getClass() == getClass())
400 && _equals(this, (Value) o);
401 }
402
403 private static boolean _equals(Value a, Value b)
404 {
405 return (a._ignoreUnknown == b._ignoreUnknown)
406 && (a._merge == b._merge)
407 && (a._allowGetters == b._allowGetters)
408 && (a._allowSetters == b._allowSetters)
409 // this last just because it can be expensive
410 && a._ignored.equals(b._ignored)
411 ;
412 }
413
414 private static Set<String> _asSet(String[] v) {
415 if (v == null || v.length == 0) {
416 return Collections.emptySet();
417 }
418 Set<String> s = new HashSet<String>(v.length);
419 for (String str : v) {
420 s.add(str);
421 }
422 return s;
423 }
424
425 private static Set<String> _merge(Set<String> s1, Set<String> s2)
426 {
427 if (s1.isEmpty()) {
428 return s2;
429 } else if (s2.isEmpty()) {
430 return s1;
431 }
432 HashSet<String> result = new HashSet<String>(s1.size() + s2.size());
433 result.addAll(s1);
434 result.addAll(s2);
435 return result;
436 }
437
438 private static boolean _empty(Set<String> ignored, boolean ignoreUnknown,
439 boolean allowGetters, boolean allowSetters, boolean merge)
440 {
441 if ((ignoreUnknown == EMPTY._ignoreUnknown)
442 && (allowGetters == EMPTY._allowGetters)
443 && (allowSetters == EMPTY._allowSetters)
444 && (merge == EMPTY._merge)) {
445 return (ignored == null || ignored.size() == 0);
446 }
447 return false;
448 }
449 }
450 }
451