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 */ value()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 */ ignoreUnknown()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 */ allowGetters()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 */ allowSetters()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 Value(Set<String> ignored, boolean ignoreUnknown, boolean allowGetters, boolean allowSetters, boolean merge)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 from(JsonIgnoreProperties src)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 */ construct(Set<String> ignored, boolean ignoreUnknown, boolean allowGetters, boolean allowSetters, boolean merge)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 */ empty()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 */ merge(Value base, Value overrides)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 */ mergeAll(Value... values)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 forIgnoredProperties(Set<String> propNames)224 public static Value forIgnoredProperties(Set<String> propNames) { 225 return EMPTY.withIgnored(propNames); 226 } 227 forIgnoredProperties(String... propNames)228 public static Value forIgnoredProperties(String... propNames) { 229 if (propNames.length == 0) { 230 return EMPTY; 231 } 232 return EMPTY.withIgnored(_asSet(propNames)); 233 } 234 forIgnoreUnknown(boolean state)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 */ withOverrides(Value overrides)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 withIgnored(Set<String> ignored)269 public Value withIgnored(Set<String> ignored) { 270 return construct(ignored, _ignoreUnknown, _allowGetters, _allowSetters, _merge); 271 } 272 withIgnored(String... ignored)273 public Value withIgnored(String... ignored) { 274 return construct(_asSet(ignored), _ignoreUnknown, _allowGetters, _allowSetters, _merge); 275 } 276 withoutIgnored()277 public Value withoutIgnored() { 278 return construct(null, _ignoreUnknown, _allowGetters, _allowSetters, _merge); 279 } 280 withIgnoreUnknown()281 public Value withIgnoreUnknown() { 282 return _ignoreUnknown ? this : 283 construct(_ignored, true, _allowGetters, _allowSetters, _merge); 284 } withoutIgnoreUnknown()285 public Value withoutIgnoreUnknown() { 286 return !_ignoreUnknown ? this : 287 construct(_ignored, false, _allowGetters, _allowSetters, _merge); 288 } 289 withAllowGetters()290 public Value withAllowGetters() { 291 return _allowGetters ? this : 292 construct(_ignored, _ignoreUnknown, true, _allowSetters, _merge); 293 } withoutAllowGetters()294 public Value withoutAllowGetters() { 295 return !_allowGetters ? this : 296 construct(_ignored, _ignoreUnknown, false, _allowSetters, _merge); 297 } 298 withAllowSetters()299 public Value withAllowSetters() { 300 return _allowSetters ? this : 301 construct(_ignored, _ignoreUnknown, _allowGetters, true, _merge); 302 } withoutAllowSetters()303 public Value withoutAllowSetters() { 304 return !_allowSetters ? this : 305 construct(_ignored, _ignoreUnknown, _allowGetters, false, _merge); 306 } 307 withMerge()308 public Value withMerge() { 309 return _merge ? this : 310 construct(_ignored, _ignoreUnknown, _allowGetters, _allowSetters, true); 311 } 312 withoutMerge()313 public Value withoutMerge() { 314 return !_merge ? this : 315 construct(_ignored, _ignoreUnknown, _allowGetters, _allowSetters, false); 316 } 317 318 @Override valueFor()319 public Class<JsonIgnoreProperties> valueFor() { 320 return JsonIgnoreProperties.class; 321 } 322 323 // for JDK serialization readResolve()324 protected Object readResolve() { 325 if (_empty(_ignored, _ignoreUnknown, _allowGetters, _allowSetters, _merge)) { 326 return EMPTY; 327 } 328 return this; 329 } 330 getIgnored()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 */ findIgnoredForSerialization()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 */ findIgnoredForDeserialization()356 public Set<String> findIgnoredForDeserialization() { 357 if (_allowSetters) { 358 return Collections.emptySet(); 359 } 360 return _ignored; 361 } 362 getIgnoreUnknown()363 public boolean getIgnoreUnknown() { 364 return _ignoreUnknown; 365 } 366 getAllowGetters()367 public boolean getAllowGetters() { 368 return _allowGetters; 369 } 370 getAllowSetters()371 public boolean getAllowSetters() { 372 return _allowSetters; 373 } 374 getMerge()375 public boolean getMerge() { 376 return _merge; 377 } 378 379 @Override toString()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 hashCode()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 equals(Object o)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 _equals(Value a, Value b)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 _asSet(String[] v)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 _merge(Set<String> s1, Set<String> s2)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 _empty(Set<String> ignored, boolean ignoreUnknown, boolean allowGetters, boolean allowSetters, boolean merge)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