package com.fasterxml.jackson.databind.deser.impl;
import java.io.IOException;
import java.lang.reflect.Constructor;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.deser.SettableBeanProperty;
import com.fasterxml.jackson.databind.introspect.*;
import com.fasterxml.jackson.databind.util.ClassUtil;
/**
* This sub-class is used to handle special case of value being a
* non-static inner class. If so, we will have to use a special
* alternative for default constructor; but otherwise can delegate
* to regular implementation.
*/
public final class InnerClassProperty
extends SettableBeanProperty.Delegating
{
private static final long serialVersionUID = 1L;
/**
* Constructor used when deserializing this property.
* Transient since there is no need to persist; only needed during
* construction of objects.
*/
final protected transient Constructor<?> _creator;
/**
* Serializable version of single-arg constructor we use for value instantiation.
*/
protected AnnotatedConstructor _annotated;
public InnerClassProperty(SettableBeanProperty delegate,
Constructor<?> ctor)
{
super(delegate);
_creator = ctor;
}
/**
* Constructor used with JDK Serialization; needed to handle transient
* Constructor, wrap/unwrap in/out-of Annotated variant.
*/
protected InnerClassProperty(SettableBeanProperty src, AnnotatedConstructor ann)
{
super(src);
_annotated = ann;
_creator = (_annotated == null) ? null : _annotated.getAnnotated();
if (_creator == null) {
throw new IllegalArgumentException("Missing constructor (broken JDK (de)serialization?)");
}
}
@Override
protected SettableBeanProperty withDelegate(SettableBeanProperty d) {
if (d == this.delegate) {
return this;
}
return new InnerClassProperty(d, _creator);
}
/*
/**********************************************************
/* Deserialization methods
/**********************************************************
*/
@Override
public void deserializeAndSet(JsonParser p, DeserializationContext ctxt, Object bean)
throws IOException
{
JsonToken t = p.getCurrentToken();
Object value;
if (t == JsonToken.VALUE_NULL) {
value = _valueDeserializer.getNullValue(ctxt);
} else if (_valueTypeDeserializer != null) {
value = _valueDeserializer.deserializeWithType(p, ctxt, _valueTypeDeserializer);
} else { // the usual case
try {
value = _creator.newInstance(bean);
} catch (Exception e) {
ClassUtil.unwrapAndThrowAsIAE(e, "Failed to instantiate class "+_creator.getDeclaringClass().getName()+", problem: "+e.getMessage());
value = null;
}
_valueDeserializer.deserialize(p, ctxt, value);
}
set(bean, value);
}
@Override
public Object deserializeSetAndReturn(JsonParser p, DeserializationContext ctxt, Object instance)
throws IOException
{
return setAndReturn(instance, deserialize(p, ctxt));
}
// these are fine with defaults
// public final void set(Object instance, Object value) throws IOException { }
// public Object setAndReturn(Object instance, Object value) throws IOException { }
/*
/**********************************************************
/* JDK serialization handling
/**********************************************************
*/
// When reading things back,
Object readResolve() {
return new InnerClassProperty(this, _annotated);
}
Object writeReplace() {
// need to construct a fake instance to support serialization
if (_annotated == null) {
return new InnerClassProperty(this, new AnnotatedConstructor(null, _creator, null, null));
}
return this;
}
}