io.honeybadger.com.fasterxml.jackson.databind.cfg.ConstructorDetector Maven / Gradle / Ivy
package com.fasterxml.jackson.databind.cfg;
import com.fasterxml.jackson.databind.util.ClassUtil;
/**
* Configurable handler used to select aspects of selecting
* constructor to use as "Creator" for POJOs.
* Defines the API for handlers, a pre-defined set of standard instances
* and methods for constructing alternative configurations.
*
* @since 2.12
*/
public final class ConstructorDetector
implements java.io.Serializable
{
private static final long serialVersionUID = 1L;
/**
* Definition of alternate handling modes of single-argument constructors
* that are annotated with {@link com.fasterxml.jackson.annotation.JsonCreator}
* but without "mode" definition (or explicit name for the argument):
* this is the case where two interpretations
* are possible -- "properties" (in which case the argument is named parameter
* of a JSON Object) and "delegating (in which case the argument maps to the
* whole JSON value).
*
* Default choice is {@code HEURISTIC} (which is Jackson pre-2.12 always uses)
*
* NOTE: does NOT have any effect if explicit {@code @JsonCreator}} annotation
* is required.
*
* @since 2.12
*/
public enum SingleArgConstructor {
/**
* Assume "delegating" mode if not explicitly annotated otherwise
*/
DELEGATING,
/**
* Assume "properties" mode if not explicitly annotated otherwise
*/
PROPERTIES,
/**
* Use heuristics to see if "properties" mode is to be used (POJO has a
* property with the same name as the implicit name [if available] of
* the constructor argument).
* Note: this is the default choice for Jackson versions before 2.12.
*/
HEURISTIC,
/**
* Refuse to decide implicit mode and instead throw a
* {@link com.fasterxml.jackson.databind.exc.InvalidDefinitionException}
* in ambiguous case.
*/
REQUIRE_MODE;
}
/*
/**********************************************************************
/* Global default instances to use
/**********************************************************************
*/
/**
* Instance used by default, which:
*
* - Uses {@link SingleArgConstructor#HEURISTIC} for single-argument constructor case
*
* - Does not require explicit {@code @JsonCreator} annotations (so allows
* auto-detection of Visible constructors} (except for JDK types)
*
* - Does not allow auto-detection of Visible constructors for so-called JDK
* types; that is, classes in packages {@code java.*} and {@code javax.*}
*
*
*/
public final static ConstructorDetector DEFAULT
= new ConstructorDetector(SingleArgConstructor.HEURISTIC);
/**
* Instance similar to {@link #DEFAULT} except that for single-argument case
* uses setting of {@link SingleArgConstructor#PROPERTIES}.
*/
public final static ConstructorDetector USE_PROPERTIES_BASED
= new ConstructorDetector(SingleArgConstructor.PROPERTIES);
/**
* Instance similar to {@link #DEFAULT} except that for single-argument case
* uses setting of {@link SingleArgConstructor#DELEGATING}.
*/
public final static ConstructorDetector USE_DELEGATING
= new ConstructorDetector(SingleArgConstructor.DELEGATING);
/**
* Instance similar to {@link #DEFAULT} except that for single-argument case
* uses setting of {@link SingleArgConstructor#REQUIRE_MODE}.
*/
public final static ConstructorDetector EXPLICIT_ONLY
= new ConstructorDetector(SingleArgConstructor.REQUIRE_MODE);
/*
/**********************************************************************
/* Configuration
/**********************************************************************
*/
protected final SingleArgConstructor _singleArgMode;
/**
* Whether explicit {@link com.fasterxml.jackson.annotation.JsonCreator}
* is always required for detecting constructors (even if visible) other
* than the default (no argument) constructor.
*/
protected final boolean _requireCtorAnnotation;
/**
* Whether auto-detection of constructors of "JDK types" (those in
* packages {@code java.} and {@code javax.}) is allowed or not
*/
protected final boolean _allowJDKTypeCtors;
/*
/**********************************************************************
/* Life-cycle
/**********************************************************************
*/
protected ConstructorDetector(SingleArgConstructor singleArgMode,
boolean requireCtorAnnotation,
boolean allowJDKTypeCtors)
{
_singleArgMode = singleArgMode;
_requireCtorAnnotation = requireCtorAnnotation;
_allowJDKTypeCtors = allowJDKTypeCtors;
}
/**
* Constructors used for default configurations which only varies
* by {@code _singleArgMode}
*/
protected ConstructorDetector(SingleArgConstructor singleArgMode) {
this(singleArgMode, false, false);
}
public ConstructorDetector withSingleArgMode(SingleArgConstructor singleArgMode) {
return new ConstructorDetector(singleArgMode,
_requireCtorAnnotation, _allowJDKTypeCtors);
}
public ConstructorDetector withRequireAnnotation(boolean state) {
return new ConstructorDetector(_singleArgMode,
state, _allowJDKTypeCtors);
}
public ConstructorDetector withAllowJDKTypeConstructors(boolean state) {
return new ConstructorDetector(_singleArgMode,
_requireCtorAnnotation, state);
}
/*
/**********************************************************************
/* API
/**********************************************************************
*/
public SingleArgConstructor singleArgMode() {
return _singleArgMode;
}
public boolean requireCtorAnnotation() {
return _requireCtorAnnotation;
}
public boolean allowJDKTypeConstructors() {
return _allowJDKTypeCtors;
}
public boolean singleArgCreatorDefaultsToDelegating() {
return _singleArgMode == SingleArgConstructor.DELEGATING;
}
public boolean singleArgCreatorDefaultsToProperties() {
return _singleArgMode == SingleArgConstructor.PROPERTIES;
}
/**
* Accessor that combines checks for whether implicit creators are allowed
* and, if so, whether JDK type constructors are allowed (if type is JDK type)
* to determine whether implicit constructor
* detection should be enabled for given type or not.
*
* @param rawType Value type to consider
*
* @return True if implicit constructor detection should be enabled; false if not
*/
public boolean shouldIntrospectorImplicitConstructors(Class rawType) {
// May not allow implicit creator introspection at all:
if (_requireCtorAnnotation) {
return false;
}
// But if it is allowed, may further limit use for JDK types
if (!_allowJDKTypeCtors) {
if (ClassUtil.isJDKClass(rawType)) {
// 18-Sep-2020, tatu: Looks like must make an exception for Exception
// types (ha!) -- at this point, single-String-arg constructor
// is to be auto-detected
if (!Throwable.class.isAssignableFrom(rawType)) {
return false;
}
}
}
return true;
}
}