package com.fasterxml.jackson.databind.deser.std;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.annotation.JacksonStdImpl;
import com.fasterxml.jackson.databind.deser.*;
import com.fasterxml.jackson.databind.introspect.AnnotatedParameter;
import com.fasterxml.jackson.databind.introspect.AnnotatedWithParams;
import com.fasterxml.jackson.databind.util.ClassUtil;
/**
* Default {@link ValueInstantiator} implementation, which supports
* Creator methods that can be indicated by standard Jackson
* annotations.
*/
@JacksonStdImpl
public class StdValueInstantiator
extends ValueInstantiator
implements java.io.Serializable
{
private static final long serialVersionUID = 1L;
/**
* Type of values that are instantiated; used
* for error reporting purposes.
*/
protected final String _valueTypeDesc;
/**
* @since 2.8
*/
protected final Class<?> _valueClass;
// // // Default (no-args) construction
/**
* Default (no-argument) constructor to use for instantiation
* (with {@link #createUsingDefault})
*/
protected AnnotatedWithParams _defaultCreator;
// // // With-args (property-based) construction
protected AnnotatedWithParams _withArgsCreator;
protected SettableBeanProperty[] _constructorArguments;
// // // Delegate construction
protected JavaType _delegateType;
protected AnnotatedWithParams _delegateCreator;
protected SettableBeanProperty[] _delegateArguments;
// // // Array delegate construction
protected JavaType _arrayDelegateType;
protected AnnotatedWithParams _arrayDelegateCreator;
protected SettableBeanProperty[] _arrayDelegateArguments;
// // // Scalar construction
protected AnnotatedWithParams _fromStringCreator;
protected AnnotatedWithParams _fromIntCreator;
protected AnnotatedWithParams _fromLongCreator;
protected AnnotatedWithParams _fromDoubleCreator;
protected AnnotatedWithParams _fromBooleanCreator;
// // // Incomplete creator
protected AnnotatedParameter _incompleteParameter;
/*
/**********************************************************
/* Life-cycle
/**********************************************************
*/
/**
* @deprecated Since 2.7 use constructor that takes {@link JavaType} instead
*/
@Deprecated
public StdValueInstantiator(DeserializationConfig config, Class<?> valueType) {
_valueTypeDesc = ClassUtil.nameOf(valueType);
_valueClass = (valueType == null) ? Object.class : valueType;
}
public StdValueInstantiator(DeserializationConfig config, JavaType valueType) {
_valueTypeDesc = (valueType == null) ? "UNKNOWN TYPE" : valueType.toString();
_valueClass = (valueType == null) ? Object.class : valueType.getRawClass();
}
/**
* Copy-constructor that sub-classes can use when creating new instances
* by fluent-style construction
*/
protected StdValueInstantiator(StdValueInstantiator src)
{
_valueTypeDesc = src._valueTypeDesc;
_valueClass = src._valueClass;
_defaultCreator = src._defaultCreator;
_constructorArguments = src._constructorArguments;
_withArgsCreator = src._withArgsCreator;
_delegateType = src._delegateType;
_delegateCreator = src._delegateCreator;
_delegateArguments = src._delegateArguments;
_arrayDelegateType = src._arrayDelegateType;
_arrayDelegateCreator = src._arrayDelegateCreator;
_arrayDelegateArguments = src._arrayDelegateArguments;
_fromStringCreator = src._fromStringCreator;
_fromIntCreator = src._fromIntCreator;
_fromLongCreator = src._fromLongCreator;
_fromDoubleCreator = src._fromDoubleCreator;
_fromBooleanCreator = src._fromBooleanCreator;
}
/**
* Method for setting properties related to instantiating values
* from JSON Object. We will choose basically only one approach (out of possible
* three), and clear other properties
*/
public void configureFromObjectSettings(AnnotatedWithParams defaultCreator,
AnnotatedWithParams delegateCreator, JavaType delegateType, SettableBeanProperty[] delegateArgs,
AnnotatedWithParams withArgsCreator, SettableBeanProperty[] constructorArgs)
{
_defaultCreator = defaultCreator;
_delegateCreator = delegateCreator;
_delegateType = delegateType;
_delegateArguments = delegateArgs;
_withArgsCreator = withArgsCreator;
_constructorArguments = constructorArgs;
}
public void configureFromArraySettings(
AnnotatedWithParams arrayDelegateCreator,
JavaType arrayDelegateType,
SettableBeanProperty[] arrayDelegateArgs)
{
_arrayDelegateCreator = arrayDelegateCreator;
_arrayDelegateType = arrayDelegateType;
_arrayDelegateArguments = arrayDelegateArgs;
}
public void configureFromStringCreator(AnnotatedWithParams creator) {
_fromStringCreator = creator;
}
public void configureFromIntCreator(AnnotatedWithParams creator) {
_fromIntCreator = creator;
}
public void configureFromLongCreator(AnnotatedWithParams creator) {
_fromLongCreator = creator;
}
public void configureFromDoubleCreator(AnnotatedWithParams creator) {
_fromDoubleCreator = creator;
}
public void configureFromBooleanCreator(AnnotatedWithParams creator) {
_fromBooleanCreator = creator;
}
public void configureIncompleteParameter(AnnotatedParameter parameter) {
_incompleteParameter = parameter;
}
/*
/**********************************************************
/* Public API implementation; metadata
/**********************************************************
*/
@Override
public String getValueTypeDesc() {
return _valueTypeDesc;
}
@Override
public Class<?> getValueClass() {
return _valueClass;
}
@Override
public boolean canCreateFromString() {
return (_fromStringCreator != null);
}
@Override
public boolean canCreateFromInt() {
return (_fromIntCreator != null);
}
@Override
public boolean canCreateFromLong() {
return (_fromLongCreator != null);
}
@Override
public boolean canCreateFromDouble() {
return (_fromDoubleCreator != null);
}
@Override
public boolean canCreateFromBoolean() {
return (_fromBooleanCreator != null);
}
@Override
public boolean canCreateUsingDefault() {
return (_defaultCreator != null);
}
@Override
public boolean canCreateUsingDelegate() {
return _delegateType != null;
}
@Override
public boolean canCreateUsingArrayDelegate() {
return _arrayDelegateType != null;
}
@Override
public boolean canCreateFromObjectWith() {
return (_withArgsCreator != null);
}
@Override
public JavaType getDelegateType(DeserializationConfig config) {
return _delegateType;
}
@Override
public JavaType getArrayDelegateType(DeserializationConfig config) {
return _arrayDelegateType;
}
@Override
public SettableBeanProperty[] getFromObjectArguments(DeserializationConfig config) {
return _constructorArguments;
}
/*
/**********************************************************
/* Public API implementation; instantiation from JSON Object
/**********************************************************
*/
@Override
public Object createUsingDefault(DeserializationContext ctxt) throws IOException
{
if (_defaultCreator == null) { // sanity-check; caller should check
return super.createUsingDefault(ctxt);
}
try {
return _defaultCreator.call();
} catch (Exception e) { // 19-Apr-2017, tatu: Let's not catch Errors, just Exceptions
return ctxt.handleInstantiationProblem(_valueClass, null, rewrapCtorProblem(ctxt, e));
}
}
@Override
public Object createFromObjectWith(DeserializationContext ctxt, Object[] args) throws IOException
{
if (_withArgsCreator == null) { // sanity-check; caller should check
return super.createFromObjectWith(ctxt, args);
}
try {
return _withArgsCreator.call(args);
} catch (Exception e) { // 19-Apr-2017, tatu: Let's not catch Errors, just Exceptions
return ctxt.handleInstantiationProblem(_valueClass, args, rewrapCtorProblem(ctxt, e));
}
}
@Override
public Object createUsingDelegate(DeserializationContext ctxt, Object delegate) throws IOException
{
// 04-Oct-2016, tatu: Need delegation to work around [databind#1392]...
if (_delegateCreator == null) {
if (_arrayDelegateCreator != null) {
return _createUsingDelegate(_arrayDelegateCreator, _arrayDelegateArguments, ctxt, delegate);
}
}
return _createUsingDelegate(_delegateCreator, _delegateArguments, ctxt, delegate);
}
@Override
public Object createUsingArrayDelegate(DeserializationContext ctxt, Object delegate) throws IOException
{
if (_arrayDelegateCreator == null) {
if (_delegateCreator != null) { // sanity-check; caller should check
// fallback to the classic delegate creator
return createUsingDelegate(ctxt, delegate);
}
}
return _createUsingDelegate(_arrayDelegateCreator, _arrayDelegateArguments, ctxt, delegate);
}
/*
/**********************************************************
/* Public API implementation; instantiation from JSON scalars
/**********************************************************
*/
@Override
public Object createFromString(DeserializationContext ctxt, String value) throws IOException
{
if (_fromStringCreator == null) {
return _createFromStringFallbacks(ctxt, value);
}
try {
return _fromStringCreator.call1(value);
} catch (Throwable t) {
return ctxt.handleInstantiationProblem(_fromStringCreator.getDeclaringClass(),
value, rewrapCtorProblem(ctxt, t));
}
}
@Override
public Object createFromInt(DeserializationContext ctxt, int value) throws IOException
{
// First: "native" int methods work best:
if (_fromIntCreator != null) {
Object arg = Integer.valueOf(value);
try {
return _fromIntCreator.call1(arg);
} catch (Throwable t0) {
return ctxt.handleInstantiationProblem(_fromIntCreator.getDeclaringClass(),
arg, rewrapCtorProblem(ctxt, t0));
}
}
// but if not, can do widening conversion
if (_fromLongCreator != null) {
Object arg = Long.valueOf(value);
try {
return _fromLongCreator.call1(arg);
} catch (Throwable t0) {
return ctxt.handleInstantiationProblem(_fromLongCreator.getDeclaringClass(),
arg, rewrapCtorProblem(ctxt, t0));
}
}
return super.createFromInt(ctxt, value);
}
@Override
public Object createFromLong(DeserializationContext ctxt, long value) throws IOException
{
if (_fromLongCreator == null) {
return super.createFromLong(ctxt, value);
}
Object arg = Long.valueOf(value);
try {
return _fromLongCreator.call1(arg);
} catch (Throwable t0) {
return ctxt.handleInstantiationProblem(_fromLongCreator.getDeclaringClass(),
arg, rewrapCtorProblem(ctxt, t0));
}
}
@Override
public Object createFromDouble(DeserializationContext ctxt, double value) throws IOException
{
if (_fromDoubleCreator == null) {
return super.createFromDouble(ctxt, value);
}
Object arg = Double.valueOf(value);
try {
return _fromDoubleCreator.call1(arg);
} catch (Throwable t0) {
return ctxt.handleInstantiationProblem(_fromDoubleCreator.getDeclaringClass(),
arg, rewrapCtorProblem(ctxt, t0));
}
}
@Override
public Object createFromBoolean(DeserializationContext ctxt, boolean value) throws IOException
{
if (_fromBooleanCreator == null) {
return super.createFromBoolean(ctxt, value);
}
final Boolean arg = Boolean.valueOf(value);
try {
return _fromBooleanCreator.call1(arg);
} catch (Throwable t0) {
return ctxt.handleInstantiationProblem(_fromBooleanCreator.getDeclaringClass(),
arg, rewrapCtorProblem(ctxt, t0));
}
}
/*
/**********************************************************
/* Extended API: configuration mutators, accessors
/**********************************************************
*/
@Override
public AnnotatedWithParams getDelegateCreator() {
return _delegateCreator;
}
@Override
public AnnotatedWithParams getArrayDelegateCreator() {
return _arrayDelegateCreator;
}
@Override
public AnnotatedWithParams getDefaultCreator() {
return _defaultCreator;
}
@Override
public AnnotatedWithParams getWithArgsCreator() {
return _withArgsCreator;
}
@Override
public AnnotatedParameter getIncompleteParameter() {
return _incompleteParameter;
}
/*
/**********************************************************
/* Internal methods
/**********************************************************
*/
/**
* @deprecated Since 2.7 call either {@link #unwrapAndWrapException} or
* {@link #wrapAsJsonMappingException}
*/
@Deprecated // since 2.7
protected JsonMappingException wrapException(Throwable t)
{
// 05-Nov-2015, tatu: This used to always unwrap the whole exception, but now only
// does so if and until `JsonMappingException` is found.
for (Throwable curr = t; curr != null; curr = curr.getCause()) {
if (curr instanceof JsonMappingException) {
return (JsonMappingException) curr;
}
}
return new JsonMappingException(null,
"Instantiation of "+getValueTypeDesc()+" value failed: "+t.getMessage(), t);
}
/**
* @since 2.7
*/
protected JsonMappingException unwrapAndWrapException(DeserializationContext ctxt, Throwable t)
{
// 05-Nov-2015, tatu: This used to always unwrap the whole exception, but now only
// does so if and until `JsonMappingException` is found.
for (Throwable curr = t; curr != null; curr = curr.getCause()) {
if (curr instanceof JsonMappingException) {
return (JsonMappingException) curr;
}
}
return ctxt.instantiationException(getValueClass(), t);
}
/**
* @since 2.7
*/
protected JsonMappingException wrapAsJsonMappingException(DeserializationContext ctxt,
Throwable t)
{
// 05-Nov-2015, tatu: Only avoid wrapping if already a JsonMappingException
if (t instanceof JsonMappingException) {
return (JsonMappingException) t;
}
return ctxt.instantiationException(getValueClass(), t);
}
/**
* @since 2.7
*/
protected JsonMappingException rewrapCtorProblem(DeserializationContext ctxt,
Throwable t)
{
// 05-Nov-2015, tatu: Seems like there are really only 2 useless wrapper errors/exceptions,
// so just peel those, and nothing else
if ((t instanceof ExceptionInInitializerError) // from static initialization block
|| (t instanceof InvocationTargetException) // from constructor/method
) {
Throwable cause = t.getCause();
if (cause != null) {
t = cause;
}
}
return wrapAsJsonMappingException(ctxt, t);
}
/*
/**********************************************************
/* Helper methods
/**********************************************************
*/
private Object _createUsingDelegate(
AnnotatedWithParams delegateCreator,
SettableBeanProperty[] delegateArguments,
DeserializationContext ctxt,
Object delegate)
throws IOException
{
if (delegateCreator == null) { // sanity-check; caller should check
throw new IllegalStateException("No delegate constructor for "+getValueTypeDesc());
}
try {
// First simple case: just delegate, no injectables
if (delegateArguments == null) {
return delegateCreator.call1(delegate);
}
// And then the case with at least one injectable...
final int len = delegateArguments.length;
Object[] args = new Object[len];
for (int i = 0; i < len; ++i) {
SettableBeanProperty prop = delegateArguments[i];
if (prop == null) { // delegate
args[i] = delegate;
} else { // nope, injectable:
args[i] = ctxt.findInjectableValue(prop.getInjectableValueId(), prop, null);
}
}
// and then try calling with full set of arguments
return delegateCreator.call(args);
} catch (Throwable t) {
throw rewrapCtorProblem(ctxt, t);
}
}
}