IgnorePropertiesUtil.java
package tools.jackson.databind.util;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonIncludeProperties;
import tools.jackson.databind.AnnotationIntrospector;
import tools.jackson.databind.cfg.MapperConfig;
import tools.jackson.databind.introspect.Annotated;
/**
* @since 2.12
*/
public class IgnorePropertiesUtil
{
/**
* Decide if we need to ignore a property or not, given a set of field to ignore and a set of field to include.
*/
public static boolean shouldIgnore(Object value, Collection<String> toIgnore, Collection<String> toInclude) {
if (toIgnore == null && toInclude ==null) {
return false;
}
if (toInclude == null) {
return toIgnore.contains(value);
}
if (toIgnore == null) {
return !toInclude.contains(value);
}
// NOTE: conflict between both, JsonIncludeProperties will take priority.
return !toInclude.contains(value) || toIgnore.contains(value);
}
/**
* Factory method for creating and return a {@link Checker} instance if (and only if)
* one needed.
*
* @param toIgnore Set of property names to ignore (may be null)
* @param toInclude Set of only property names to include (if null, undefined)
*
* @return Checker, if validity checks are needed; {@code null} otherwise
*/
public static Checker buildCheckerIfNeeded(Set<String> toIgnore, Set<String> toInclude) {
// First: no-op case
if ((toInclude == null) && ((toIgnore == null) || toIgnore.isEmpty())) {
return null;
}
return Checker.construct(toIgnore, toInclude);
}
/**
* Factory method for creating and returning a {@link Checker} instance, if (and only if)
* one is needed, for {@code @JsonIgnoreProperties} / {@code @JsonIncludeProperties}
* declared on given member. Used where there are no pre-configured names to merge
* with (any-getters, any-setters); applies the same rules as
* {@code MapSerializer.createContextual()} / {@code MapDeserializer.createContextual()}
* do for {@code Map}-valued properties, so changes to one should be reflected in the other.
*
* @param config Configuration to use for annotation introspection
* @param member Annotated member (accessor or mutator) to check; may be {@code null}
* @param forSerialization Whether names are needed for serialization ({@code true})
* or deserialization ({@code false}): affects handling of
* {@code JsonIgnoreProperties.allowGetters} / {@code allowSetters}
*
* @return Checker, if validity checks are needed; {@code null} otherwise
*
* @since 3.4
*/
public static Checker buildCheckerFor(MapperConfig<?> config, Annotated member,
boolean forSerialization)
{
final AnnotationIntrospector intr = config.getAnnotationIntrospector();
if ((intr == null) || (member == null)) {
return null;
}
JsonIgnoreProperties.Value ignorals = intr.findPropertyIgnoralByName(config, member);
JsonIncludeProperties.Value inclusions = intr.findPropertyInclusionByName(config, member);
Set<String> toIgnore = null;
if (ignorals != null) {
toIgnore = forSerialization ? ignorals.findIgnoredForSerialization()
: ignorals.findIgnoredForDeserialization();
}
return buildCheckerIfNeeded(toIgnore,
(inclusions == null) ? null : inclusions.getIncluded());
}
/**
* Helper that encapsulates logic for combining two sets of "included names":
* default logic is to do intersection (name must be in both to be included
* in result)
*
* @param prevToInclude Existing set of names to include, if defined; null means "not defined"
* @param newToInclude New set of names to included, if defined; null means "not defined"
*
* @return Resulting set of names, using intersection if neither {@code null}; or the
* non-null one (if only one is {@code null}); or {@code null} if both arguments {@code null}.
*/
public static Set<String> combineNamesToInclude(Set<String> prevToInclude,
Set<String> newToInclude) {
if (prevToInclude == null) {
return newToInclude;
}
if (newToInclude == null) {
return prevToInclude;
}
final Set<String> result = new HashSet<>();
// Make the intersection with the previously included properties
for (String prop : newToInclude) {
if (prevToInclude.contains(prop)) {
result.add(prop);
}
}
return result;
}
/**
* Helper that encapsulates logic for combining two sets of "ignored names":
* default logic is to do union. Neither argument is modified.
*
* @param prevToIgnore Existing set of names to ignore, if any; {@code null} if none
* @param newToIgnore New names to ignore, if any; {@code null} or empty if none
*
* @return Union of the arguments; {@code prevToIgnore} as-is if there is nothing to add
*
* @since 3.1.8
*/
public static Set<String> combineNamesToIgnore(Set<String> prevToIgnore,
Set<String> newToIgnore) {
if (newToIgnore == null || newToIgnore.isEmpty()) {
return prevToIgnore;
}
final Set<String> result = new HashSet<>(newToIgnore);
if (prevToIgnore != null) {
result.addAll(prevToIgnore);
}
return result;
}
/**
* Helper class to encapsulate logic from static {@code shouldIgnore} method
* of util class.
*/
public final static class Checker
{
private final Set<String> _toIgnore;
private final Set<String> _toInclude;
private Checker(Set<String> toIgnore, Set<String> toInclude) {
if (toIgnore == null) {
toIgnore = Collections.emptySet();
}
_toIgnore = toIgnore;
_toInclude = toInclude;
}
public static Checker construct(Set<String> toIgnore, Set<String> toInclude) {
return new Checker(toIgnore, toInclude);
}
// May seem odd but during serialization key is not cast up to String:
public boolean shouldIgnore(Object propertyName) {
return ((_toInclude != null) && !_toInclude.contains(propertyName))
|| _toIgnore.contains(propertyName);
}
}
}