package com.fasterxml.jackson.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.util.*; /** * Annotation that can be used to either suppress serialization of * properties (during serialization), or ignore processing of * JSON properties read (during deserialization). *

* Example: *

 * // to prevent specified fields from being serialized or deserialized
 * // (i.e. not include in JSON output; or being set even if they were included)
 * @JsonIgnoreProperties({ "internalId", "secretKey" })
 * // To ignore any unknown properties in JSON input without exception:
 * @JsonIgnoreProperties(ignoreUnknown=true)
 *
*

* Annotation can be applied both to classes and * to properties. If used for both, actual set will be union of all * ignorals: that is, you can only add properties to ignore, not remove * or override. So you can not remove properties to ignore using * per-property annotation. */ @Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @JacksonAnnotation public @interface JsonIgnoreProperties { /** * Names of properties to ignore. */ public String[] value() default { }; /** * Property that defines whether it is ok to just ignore any * unrecognized properties during deserialization. * If true, all properties that are unrecognized -- that is, * there are no setters or creators that accept them -- are * ignored without warnings (although handlers for unknown * properties, if any, will still be called) without * exception. *

* Does not have any effect on serialization. * * @return True if any and all unknown properties are to be ignored without * exceptions (or other special handling); false otherwise. */ public boolean ignoreUnknown() default false; /** * Property that can be enabled to allow "getters" to be used (that is, * prevent ignoral of getters for properties listed in {@link #value()}). * This is commonly set to support defining "read-only" properties; ones * for which there is a getter, but no matching setter: in this case, * properties should be ignored for deserialization but NOT serialization. * Another way to think about this setting is that setting it to `true` * will "disable" ignoring of getters. *

* Default value is `false`, which means that getters with matching names * will be ignored. * * @return True if getters should be allowed (i.e. NOT ignored); false if getters * are to be ignored * * @since 2.6 */ public boolean allowGetters() default false; /** * Property that can be enabled to allow "setters" to be used (that is, * prevent ignoral of setters for properties listed in {@link #value()}). * This could be used to specify "write-only" properties; ones * that should not be serialized out, but that may be provided in for * deserialization. * Another way to think about this setting is that setting it to `true` * will "disable" ignoring of setters. *

* Default value is `false`, which means that setters with matching names * will be ignored. * * * @return True if setters should be allowed (i.e. NOT ignored); false if setters * are to be ignored * @since 2.6 */ public boolean allowSetters() default false; /* /********************************************************** /* Value class used to enclose information, allow for /* merging of layered configuration settings. /********************************************************** */ /** * Helper class used to contain information from a single {@link JsonIgnoreProperties} * annotation, as well as to provide possible overrides from non-annotation sources. * * @since 2.8 */ public static class Value implements JacksonAnnotationValue, java.io.Serializable { private static final long serialVersionUID = 1L; /** * Default instance has no explicitly ignored fields, does not ignore unknowns, * does not explicitly allow getters/setters (that is, ignorals apply to both), * but does use merging for combining overrides with base settings */ protected final static Value EMPTY = new Value(Collections.emptySet(), false, false, false, true); /** * Names of properties to ignore. */ protected final Set _ignored; protected final boolean _ignoreUnknown; protected final boolean _allowGetters; protected final boolean _allowSetters; protected final boolean _merge; protected Value(Set ignored, boolean ignoreUnknown, boolean allowGetters, boolean allowSetters, boolean merge) { if (ignored == null) { _ignored = Collections.emptySet(); } else { _ignored = ignored; } _ignoreUnknown = ignoreUnknown; _allowGetters = allowGetters; _allowSetters = allowSetters; _merge = merge; } public static Value from(JsonIgnoreProperties src) { if (src == null) { return EMPTY; // since 2.9 } return construct(_asSet(src.value()), src.ignoreUnknown(), src.allowGetters(), src.allowSetters(), // 27-Apr-2016, tatu: No matching property in annotation because // we don't know how to merge (so no point in pretending it's there) // so choice is arbitrary. Probably will default to `false` fwtw: false); } /** * Factory method that may be used (although is NOT the recommended way) * to construct an instance from a full set of properties. Most users would * be better of starting by {@link #empty()} instance and using `withXxx()`/`withoutXxx()` * methods, as this factory method may need to be changed if new properties * are added in {@link JsonIgnoreProperties} annotation. */ public static Value construct(Set ignored, boolean ignoreUnknown, boolean allowGetters, boolean allowSetters, boolean merge) { if (_empty(ignored, ignoreUnknown, allowGetters, allowSetters, merge)) { return EMPTY; } return new Value(ignored, ignoreUnknown, allowGetters, allowSetters, merge); } /** * Accessor for default instances which has "empty" settings; that is: *

*/ public static Value empty() { return EMPTY; } /** * Helper method that will try to combine values from two {@link Value} * instances, using one as base settings, and the other as overrides * to use instead of base values when defined; base values are only * use if override does not specify a value (matching value is null * or logically missing). * Note that one or both of value instances may be `null`, directly; * if both are `null`, result will also be `null`; otherwise never null. */ public static Value merge(Value base, Value overrides) { return (base == null) ? overrides : base.withOverrides(overrides); } /** * @since 2.8 */ public static Value mergeAll(Value... values) { Value result = null; for (Value curr : values) { if (curr != null) { result = (result == null) ? curr : result.withOverrides(curr); } } return result; } public static Value forIgnoredProperties(Set propNames) { return EMPTY.withIgnored(propNames); } public static Value forIgnoredProperties(String... propNames) { if (propNames.length == 0) { return EMPTY; } return EMPTY.withIgnored(_asSet(propNames)); } public static Value forIgnoreUnknown(boolean state) { return state ? EMPTY.withIgnoreUnknown() : EMPTY.withoutIgnoreUnknown(); } /** * Mutant factory method that merges values of this value with given override * values, so that any explicitly defined inclusion in overrides has precedence over * settings of this value instance. If no overrides exist will return this * instance; otherwise new {@link Value} with changed inclusion values. */ public Value withOverrides(Value overrides) { if ((overrides == null) || (overrides == EMPTY)) { return this; } // if non merging, we'll actually end up with just the overrides don't we? // (given there's no "use default" value for anything if (!overrides._merge) { return overrides; } if (_equals(this, overrides)) { return this; } // Here's where mergeability needs to be checked Set ignored = _merge(_ignored, overrides._ignored); boolean ignoreUnknown = _ignoreUnknown || overrides._ignoreUnknown; boolean allowGetters = _allowGetters || overrides._allowGetters; boolean allowSetters = _allowSetters || overrides._allowSetters; // must have 'merge=true' to get this far return construct(ignored, ignoreUnknown, allowGetters, allowSetters, true); } public Value withIgnored(Set ignored) { return construct(ignored, _ignoreUnknown, _allowGetters, _allowSetters, _merge); } public Value withIgnored(String... ignored) { return construct(_asSet(ignored), _ignoreUnknown, _allowGetters, _allowSetters, _merge); } public Value withoutIgnored() { return construct(null, _ignoreUnknown, _allowGetters, _allowSetters, _merge); } public Value withIgnoreUnknown() { return _ignoreUnknown ? this : construct(_ignored, true, _allowGetters, _allowSetters, _merge); } public Value withoutIgnoreUnknown() { return !_ignoreUnknown ? this : construct(_ignored, false, _allowGetters, _allowSetters, _merge); } public Value withAllowGetters() { return _allowGetters ? this : construct(_ignored, _ignoreUnknown, true, _allowSetters, _merge); } public Value withoutAllowGetters() { return !_allowGetters ? this : construct(_ignored, _ignoreUnknown, false, _allowSetters, _merge); } public Value withAllowSetters() { return _allowSetters ? this : construct(_ignored, _ignoreUnknown, _allowGetters, true, _merge); } public Value withoutAllowSetters() { return !_allowSetters ? this : construct(_ignored, _ignoreUnknown, _allowGetters, false, _merge); } public Value withMerge() { return _merge ? this : construct(_ignored, _ignoreUnknown, _allowGetters, _allowSetters, true); } public Value withoutMerge() { return !_merge ? this : construct(_ignored, _ignoreUnknown, _allowGetters, _allowSetters, false); } @Override public Class valueFor() { return JsonIgnoreProperties.class; } // for JDK serialization protected Object readResolve() { if (_empty(_ignored, _ignoreUnknown, _allowGetters, _allowSetters, _merge)) { return EMPTY; } return this; } public Set getIgnored() { return _ignored; } /** * Method called to find names of properties to ignore when used for * serialization: functionally * same as {@link #getIgnored} if {@link #getAllowGetters()} is false * (that is, there is "allowGetters=false" or equivalent), * otherwise returns empty {@link java.util.Set}. */ public Set findIgnoredForSerialization() { if (_allowGetters) { return Collections.emptySet(); } return _ignored; } /** * Method called to find names of properties to ignore when used for * serialization: functionally * same as {@link #getIgnored} if {@link #getAllowSetters()} is false * (that is, there is "allowSetters=false" or equivalent), * otherwise returns empty {@link java.util.Set}. */ public Set findIgnoredForDeserialization() { if (_allowSetters) { return Collections.emptySet(); } return _ignored; } public boolean getIgnoreUnknown() { return _ignoreUnknown; } public boolean getAllowGetters() { return _allowGetters; } public boolean getAllowSetters() { return _allowSetters; } public boolean getMerge() { return _merge; } @Override public String toString() { return String.format("JsonIgnoreProperties.Value(ignored=%s,ignoreUnknown=%s,allowGetters=%s,allowSetters=%s,merge=%s)", _ignored, _ignoreUnknown, _allowGetters, _allowSetters, _merge); } @Override public int hashCode() { return (_ignored.size()) + (_ignoreUnknown ? 1 : -3) + (_allowGetters ? 3 : -7) + (_allowSetters ? 7 : -11) + (_merge ? 11 : -13) ; } @Override public boolean equals(Object o) { if (o == this) return true; if (o == null) return false; return (o.getClass() == getClass()) && _equals(this, (Value) o); } private static boolean _equals(Value a, Value b) { return (a._ignoreUnknown == b._ignoreUnknown) && (a._merge == b._merge) && (a._allowGetters == b._allowGetters) && (a._allowSetters == b._allowSetters) // this last just because it can be expensive && a._ignored.equals(b._ignored) ; } private static Set _asSet(String[] v) { if (v == null || v.length == 0) { return Collections.emptySet(); } Set s = new HashSet(v.length); for (String str : v) { s.add(str); } return s; } private static Set _merge(Set s1, Set s2) { if (s1.isEmpty()) { return s2; } else if (s2.isEmpty()) { return s1; } HashSet result = new HashSet(s1.size() + s2.size()); result.addAll(s1); result.addAll(s2); return result; } private static boolean _empty(Set ignored, boolean ignoreUnknown, boolean allowGetters, boolean allowSetters, boolean merge) { if ((ignoreUnknown == EMPTY._ignoreUnknown) && (allowGetters == EMPTY._allowGetters) && (allowSetters == EMPTY._allowSetters) && (merge == EMPTY._merge)) { return (ignored == null || ignored.size() == 0); } return false; } } }