blob: b177b2effc78bd4f011c2eb05681768b4e4c1b37 [file] [log] [blame]
package org.codehaus.jackson.map.deser.std;
import java.io.IOException;
import org.codehaus.jackson.*;
import org.codehaus.jackson.map.*;
import org.codehaus.jackson.map.deser.BeanDeserializer;
import org.codehaus.jackson.map.deser.SettableBeanProperty;
/**
* Deserializer that builds on basic {@link BeanDeserializer} but
* override some aspects like instance construction.
*<p>
* Note that this deserializer was significantly changed in Jackson 1.7
* (due to massive changes in {@link BeanDeserializer}).
*
* @since 1.9 (renamed from 'org.codehaus.jackson.map.deser.ThrowableDeserializer')
*/
public class ThrowableDeserializer
extends BeanDeserializer
{
protected final static String PROP_NAME_MESSAGE = "message";
/*
/************************************************************
/* Construction
/************************************************************
*/
public ThrowableDeserializer(BeanDeserializer baseDeserializer)
{
super(baseDeserializer);
}
/**
* Alternative constructor used when creating "unwrapping" deserializers
*
* @since 1.9
*/
protected ThrowableDeserializer(BeanDeserializer src, boolean ignoreAllUnknown)
{
super(src, ignoreAllUnknown);
}
@Override
public JsonDeserializer<Object> unwrappingDeserializer()
{
if (getClass() != ThrowableDeserializer.class) {
return this;
}
/* main thing really is to just enforce ignoring of unknown
* properties; since there may be multiple unwrapped values
* and properties for all may be interleaved...
*/
return new ThrowableDeserializer(this, true);
}
/*
/************************************************************
/* Overridden methods
/************************************************************
*/
@Override
public Object deserializeFromObject(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException
{
// 30-Sep-2010, tatu: Need to allow use of @JsonCreator, so:
if (_propertyBasedCreator != null) { // proper @JsonCreator
return _deserializeUsingPropertyBased(jp, ctxt);
}
if (_delegateDeserializer != null) {
return _valueInstantiator.createUsingDelegate(_delegateDeserializer.deserialize(jp, ctxt));
}
if (_beanType.isAbstract()) { // for good measure, check this too
throw JsonMappingException.from(jp, "Can not instantiate abstract type "+_beanType
+" (need to add/enable type information?)");
}
boolean hasStringCreator = _valueInstantiator.canCreateFromString();
boolean hasDefaultCtor = _valueInstantiator.canCreateUsingDefault();
// and finally, verify we do have single-String arg constructor (if no @JsonCreator)
if (!hasStringCreator && !hasDefaultCtor) {
throw new JsonMappingException("Can not deserialize Throwable of type "+_beanType
+" without having a default contructor, a single-String-arg constructor; or explicit @JsonCreator");
}
Object throwable = null;
Object[] pending = null;
int pendingIx = 0;
for (; jp.getCurrentToken() != JsonToken.END_OBJECT; jp.nextToken()) {
String propName = jp.getCurrentName();
SettableBeanProperty prop = _beanProperties.find(propName);
jp.nextToken(); // to point to field value
if (prop != null) { // normal case
if (throwable != null) {
prop.deserializeAndSet(jp, ctxt, throwable);
continue;
}
// nope; need to defer
if (pending == null) {
int len = _beanProperties.size();
pending = new Object[len + len];
}
pending[pendingIx++] = prop;
pending[pendingIx++] = prop.deserialize(jp, ctxt);
continue;
}
// Maybe it's "message"?
if (PROP_NAME_MESSAGE.equals(propName)) {
if (hasStringCreator) {
throwable = _valueInstantiator.createFromString(jp.getText());
// any pending values?
if (pending != null) {
for (int i = 0, len = pendingIx; i < len; i += 2) {
prop = (SettableBeanProperty)pending[i];
prop.set(throwable, pending[i+1]);
}
pending = null;
}
continue;
}
}
/* As per [JACKSON-313], things marked as ignorable should not be
* passed to any setter
*/
if (_ignorableProps != null && _ignorableProps.contains(propName)) {
jp.skipChildren();
continue;
}
if (_anySetter != null) {
_anySetter.deserializeAndSet(jp, ctxt, throwable, propName);
continue;
}
// Unknown: let's call handler method
handleUnknownProperty(jp, ctxt, throwable, propName);
}
// Sanity check: did we find "message"?
if (throwable == null) {
/* 15-Oct-2010, tatu: Can't assume missing message is an error, since it may be
* suppressed during serialization, as per [JACKSON-388].
*
* Should probably allow use of default constructor, too...
*/
//throw new JsonMappingException("No 'message' property found: could not deserialize "+_beanType);
if (hasStringCreator) {
throwable = _valueInstantiator.createFromString(null);
} else {
throwable = _valueInstantiator.createUsingDefault();
}
// any pending values?
if (pending != null) {
for (int i = 0, len = pendingIx; i < len; i += 2) {
SettableBeanProperty prop = (SettableBeanProperty)pending[i];
prop.set(throwable, pending[i+1]);
}
}
}
return throwable;
}
}