com.fasterxml.jackson.annotation.JsonSetter Maven / Gradle / Ivy
package com.fasterxml.jackson.annotation;
import java.lang.annotation.*;
/**
* Annotation that can be used to define a non-static,
* single-argument method to be used as a "setter" for a logical property
* as an alternative to recommended
* {@link JsonProperty} annotation;
* or (as of 2.9 and later), specify additional aspects of the
* assigning property a value during serialization.
*/
@Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
// ^^^ allowed on Fields, (constructor) parameters since 2.9
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonSetter
{
/**
* Optional default argument that defines logical property this
* method is used to modify ("set"); this is the property
* name used in JSON content.
*/
String value() default "";
/**
* Specifies action to take when input contains explicit `null` value
* (if format has one).
* Default action, in absence of any explicit configuration,
* is usually {@link Nulls#SET}, meaning that the `null` is set as
* value using setter.
*
* NOTE: is not usually used in case property value is missing, unless
* data format specifies that there is defaulting which would result
* in an explicit null assignment.
*/
Nulls nulls() default Nulls.DEFAULT;
/**
* Specifies action to take when input to match into content value
* (of a {@link java.util.Collection}, {@link java.util.Map}, array,
* or referential value) contains explicit `null` value
* (if format has one) to bind.
* Default action, in absence of any explicit configuration,
* is usually {@link Nulls#SET}, meaning that the `null` is included as usual.
*/
Nulls contentNulls() default Nulls.DEFAULT;
/*
/**********************************************************
/* Value class used to enclose information, allow for
/* merging of layered configuration settings.
/**********************************************************
*/
/**
* Helper class used to contain information from a single {@link JsonSetter}
* annotation, as well as to provide possible overrides from non-annotation sources.
*
* @since 2.9
*/
public static class Value
implements JacksonAnnotationValue,
java.io.Serializable
{
private static final long serialVersionUID = 1L;
private final Nulls _nulls;
private final Nulls _contentNulls;
/**
* Default instance used in place of "default settings".
*/
protected final static Value EMPTY = new Value(Nulls.DEFAULT, Nulls.DEFAULT);
protected Value(Nulls nulls, Nulls contentNulls) {
_nulls = nulls;
_contentNulls = contentNulls;
}
@Override
public Class valueFor() {
return JsonSetter.class;
}
// for JDK serialization
protected Object readResolve() {
if (_empty(_nulls, _contentNulls)) {
return EMPTY;
}
return this;
}
public static Value from(JsonSetter src) {
if (src == null) {
return EMPTY;
}
return construct(src.nulls(), src.contentNulls());
}
/**
* 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 off 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(Nulls nulls, Nulls contentNulls) {
if (nulls == null) {
nulls = Nulls.DEFAULT;
}
if (contentNulls == null) {
contentNulls = Nulls.DEFAULT;
}
if (_empty(nulls, contentNulls)) {
return EMPTY;
}
return new Value(nulls, contentNulls);
}
/**
* Accessor for default instances which has "empty" settings; that is:
*
* - Null handling using global defaults, {@link Nulls#DEFAULT}.
*
*
*/
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);
}
public static Value forValueNulls(Nulls nulls) {
return construct(nulls, Nulls.DEFAULT);
}
public static Value forValueNulls(Nulls nulls, Nulls contentNulls) {
return construct(nulls, contentNulls);
}
public static Value forContentNulls(Nulls nulls) {
return construct(Nulls.DEFAULT, nulls);
}
/**
* 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;
}
Nulls nulls = overrides._nulls;
Nulls contentNulls = overrides._contentNulls;
if (nulls == Nulls.DEFAULT) {
nulls = _nulls;
}
if (contentNulls == Nulls.DEFAULT) {
contentNulls = _contentNulls;
}
if ((nulls == _nulls) && (contentNulls == _contentNulls)) {
return this;
}
return construct(nulls, contentNulls);
}
public Value withValueNulls(Nulls nulls) {
if (nulls == null) {
nulls = Nulls.DEFAULT;
}
if (nulls == _nulls) {
return this;
}
return construct(nulls, _contentNulls);
}
public Value withValueNulls(Nulls valueNulls, Nulls contentNulls) {
if (valueNulls == null) {
valueNulls = Nulls.DEFAULT;
}
if (contentNulls == null) {
contentNulls = Nulls.DEFAULT;
}
if ((valueNulls == _nulls) && (contentNulls == _contentNulls)) {
return this;
}
return construct(valueNulls, contentNulls);
}
public Value withContentNulls(Nulls nulls) {
if (nulls == null) {
nulls = Nulls.DEFAULT;
}
if (nulls == _contentNulls) {
return this;
}
return construct(_nulls, nulls);
}
public Nulls getValueNulls() { return _nulls; }
public Nulls getContentNulls() { return _contentNulls; }
/**
* Returns same as {@link #getValueNulls()} unless value would be
* {@link Nulls#DEFAULT} in which case `null` is returned.
*/
public Nulls nonDefaultValueNulls() {
return (_nulls == Nulls.DEFAULT) ? null : _nulls;
}
/**
* Returns same as {@link #getContentNulls()} unless value would be
* {@link Nulls#DEFAULT} in which case `null` is returned.
*/
public Nulls nonDefaultContentNulls() {
return (_contentNulls == Nulls.DEFAULT) ? null : _contentNulls;
}
/*
/**********************************************************
/* Std method overrides
/**********************************************************
*/
@Override
public String toString() {
return String.format("JsonSetter.Value(valueNulls=%s,contentNulls=%s)",
_nulls, _contentNulls);
}
@Override
public int hashCode() {
return _nulls.ordinal() + (_contentNulls.ordinal() << 2);
}
@Override
public boolean equals(Object o) {
if (o == this) return true;
if (o == null) return false;
if (o.getClass() == getClass()) {
Value other = (Value) o;
return (other._nulls == _nulls)
&& (other._contentNulls == _contentNulls);
}
return false;
}
/*
/**********************************************************
/* Internal methods
/**********************************************************
*/
private static boolean _empty(Nulls nulls, Nulls contentNulls) {
return (nulls == Nulls.DEFAULT)
&& (contentNulls == Nulls.DEFAULT);
}
}
}