Skip to content
This repository has been archived by the owner on Nov 5, 2019. It is now read-only.

Commit

Permalink
Fix #56
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed Sep 10, 2015
1 parent 3380fe1 commit d68ed5e
Show file tree
Hide file tree
Showing 14 changed files with 313 additions and 60 deletions.
5 changes: 5 additions & 0 deletions release-notes/VERSION
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ Project: jackson-module-afterburner
=== Releases ===
------------------------------------------------------------------------

2.6.2 (not yet released)

#56: Afterburner does not respect DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS
(reported by shollander@github)

2.6.1 (09-Aug-2015)

No changes since 2.6.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
import java.lang.annotation.Annotation;

import com.fasterxml.jackson.core.*;

import com.fasterxml.jackson.core.JsonParser.NumberType;
import com.fasterxml.jackson.core.io.NumberInput;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.deser.*;
import com.fasterxml.jackson.databind.introspect.AnnotatedMember;
Expand Down Expand Up @@ -144,52 +145,213 @@ public int getOptimizedIndex() {
protected final boolean _deserializeBoolean(JsonParser p, DeserializationContext ctxt) throws IOException
{
JsonToken t = p.getCurrentToken();
if (t == JsonToken.VALUE_TRUE) {
return true;
if (t == JsonToken.VALUE_TRUE) return true;
if (t == JsonToken.VALUE_FALSE) return false;
if (t == JsonToken.VALUE_NULL) return false;

// [JACKSON-78]: should accept ints too, (0 == false, otherwise true)
if (t == JsonToken.VALUE_NUMBER_INT) {
// 11-Jan-2012, tatus: May be outside of int...
if (p.getNumberType() == NumberType.INT) {
return (p.getIntValue() != 0);
}
return _deserializeBooleanFromOther(p, ctxt);
}
if (t == JsonToken.VALUE_FALSE) {
return false;
// And finally, let's allow Strings to be converted too
if (t == JsonToken.VALUE_STRING) {
String text = p.getText().trim();
// [#422]: Allow aliases
if ("true".equals(text) || "True".equals(text)) {
return true;
}
if ("false".equals(text) || "False".equals(text) || text.length() == 0) {
return false;
}
if (_hasTextualNull(text)) {
return false;
}
throw ctxt.weirdStringException(text, Boolean.TYPE, "only \"true\" or \"false\" recognized");
}
return p.getValueAsBoolean();
// [databind#381]
if (t == JsonToken.START_ARRAY && ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) {
p.nextToken();
final boolean parsed = _deserializeBooleanFromOther(p, ctxt);
t = p.nextToken();
if (t != JsonToken.END_ARRAY) {
throw ctxt.wrongTokenException(p, JsonToken.END_ARRAY,
"Attempted to unwrap single value array for single 'boolean' value but there was more than a single value in the array");
}
return parsed;
}
// Otherwise, no can do:
throw ctxt.mappingException(Boolean.TYPE, t);
}

protected final String _deserializeString(JsonParser p, DeserializationContext ctxt) throws IOException
protected final short _deserializeShort(JsonParser jp, DeserializationContext ctxt)
throws IOException
{
String text = p.getValueAsString();
if (text != null) {
return text;
int value = _deserializeInt(jp, ctxt);
// So far so good: but does it fit?
if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) {
throw ctxt.weirdStringException(String.valueOf(value),
Short.TYPE, "overflow, value can not be represented as 16-bit value");
}
return _convertToString(p, ctxt);
return (short) value;
}

/**
* Helper method for coercing JSON values other than Strings into
* Java String value.
*/
protected final String _convertToString(JsonParser p, DeserializationContext ctxt) throws IOException
protected final int _deserializeInt(JsonParser p, DeserializationContext ctxt)
throws IOException
{
JsonToken curr = p.getCurrentToken();
if (curr == JsonToken.VALUE_NULL) { // should this ever happen?
if (_valueDeserializer == null) {
return null;
if (p.hasToken(JsonToken.VALUE_NUMBER_INT)) {
return p.getIntValue();
}
JsonToken t = p.getCurrentToken();
if (t == JsonToken.VALUE_STRING) { // let's do implicit re-parse
String text = p.getText().trim();
if (_hasTextualNull(text)) {
return 0;
}
try {
int len = text.length();
if (len > 9) {
long l = Long.parseLong(text);
if (l < Integer.MIN_VALUE || l > Integer.MAX_VALUE) {
throw ctxt.weirdStringException(text, Integer.TYPE,
"Overflow: numeric value ("+text+") out of range of int ("+Integer.MIN_VALUE+" - "+Integer.MAX_VALUE+")");
}
return (int) l;
}
if (len == 0) {
return 0;
}
return NumberInput.parseInt(text);
} catch (IllegalArgumentException iae) {
throw ctxt.weirdStringException(text, Integer.TYPE, "not a valid int value");
}
return (String) _valueDeserializer.getNullValue(ctxt);
}
if (curr == JsonToken.VALUE_EMBEDDED_OBJECT) {
if (t == JsonToken.VALUE_NUMBER_FLOAT) {
if (!ctxt.isEnabled(DeserializationFeature.ACCEPT_FLOAT_AS_INT)) {
_failDoubleToIntCoercion(p, ctxt, "int");
}
return p.getValueAsInt();
}
if (t == JsonToken.VALUE_NULL) {
return 0;
}
if (t == JsonToken.START_ARRAY && ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) {
p.nextToken();
final int parsed = _deserializeInt(p, ctxt);
t = p.nextToken();
if (t != JsonToken.END_ARRAY) {
throw ctxt.wrongTokenException(p, JsonToken.END_ARRAY,
"Attempted to unwrap single value array for single 'int' value but there was more than a single value in the array");
}
return parsed;
}
// Otherwise, no can do:
throw ctxt.mappingException(Integer.TYPE, t);
}

protected final long _deserializeLong(JsonParser p, DeserializationContext ctxt)
throws IOException
{
switch (p.getCurrentTokenId()) {
case JsonTokenId.ID_NUMBER_INT:
return p.getLongValue();
case JsonTokenId.ID_NUMBER_FLOAT:
if (!ctxt.isEnabled(DeserializationFeature.ACCEPT_FLOAT_AS_INT)) {
_failDoubleToIntCoercion(p, ctxt, "long");
}
return p.getValueAsLong();
case JsonTokenId.ID_STRING:
String text = p.getText().trim();
if (text.length() == 0 || _hasTextualNull(text)) {
return 0L;
}
try {
return NumberInput.parseLong(text);
} catch (IllegalArgumentException iae) { }
throw ctxt.weirdStringException(text, Long.TYPE, "not a valid long value");
case JsonTokenId.ID_NULL:
return 0L;
case JsonTokenId.ID_START_ARRAY:
if (ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) {
p.nextToken();
final long parsed = _deserializeLong(p, ctxt);
JsonToken t = p.nextToken();
if (t != JsonToken.END_ARRAY) {
throw ctxt.wrongTokenException(p, JsonToken.END_ARRAY,
"Attempted to unwrap single value array for single 'long' value but there was more than a single value in the array");
}
return parsed;
}
break;
}
throw ctxt.mappingException(Long.TYPE, p.getCurrentToken());
}

protected final String _deserializeString(JsonParser p, DeserializationContext ctxt) throws IOException
{
switch (p.getCurrentTokenId()) {
case JsonTokenId.ID_STRING:
return p.getText();
case JsonTokenId.ID_NULL:
return null;
case JsonTokenId.ID_START_ARRAY:
if (ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) {
p.nextToken();
final String parsed = _deserializeString(p, ctxt);
if (p.nextToken() != JsonToken.END_ARRAY) {
throw ctxt.wrongTokenException(p, JsonToken.END_ARRAY,
"Attempted to unwrap single value array for single 'String' value but there was more than a single value in the array");
}
return parsed;
}
break;
case JsonTokenId.ID_EMBEDDED_OBJECT:
Object ob = p.getEmbeddedObject();
if (ob == null) {
return null;
}
if (ob instanceof byte[]) {
return Base64Variants.getDefaultVariant().encode((byte[]) ob, false);
}
// otherwise, try conversion using toString()...
return ob.toString();
default:
// allow coercions for other scalar types
String text = p.getValueAsString();
if (text != null) {
return text;
}
}
// Can deserialize any scalar value
if (curr.isScalarValue()) { // should have been handled earlier, but just in case...
return p.getText();
throw ctxt.mappingException(String.class, p.getCurrentToken());
}

protected final boolean _deserializeBooleanFromOther(JsonParser p, DeserializationContext ctxt)
throws IOException
{
if (p.getNumberType() == NumberType.LONG) {
return (p.getLongValue() == 0L) ? Boolean.FALSE : Boolean.TRUE;
}
// but not markers:
throw ctxt.mappingException(String.class);
// no really good logic; let's actually resort to textual comparison
String str = p.getText();
if ("0.0".equals(str) || "0".equals(str)) {
return Boolean.FALSE;
}
return Boolean.TRUE;
}

// // More helper methods from StdDeserializer

protected void _failDoubleToIntCoercion(JsonParser p, DeserializationContext ctxt,
String type) throws IOException
{
throw ctxt.mappingException("Can not coerce a floating-point value ('%s') into %s; enable `DeserializationFeature.ACCEPT_FLOAT_AS_INT` to allow",
p.getValueAsString(), type);
}

protected boolean _hasTextualNull(String value) {
return "null".equals(value);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,17 @@ public SettableBooleanFieldProperty withMutator(BeanPropertyMutator mut) {
*/

@Override
public void deserializeAndSet(JsonParser jp, DeserializationContext ctxt, Object bean) throws IOException {
_propertyMutator.booleanField(bean, _deserializeBoolean(jp, ctxt));
public void deserializeAndSet(JsonParser p, DeserializationContext ctxt, Object bean) throws IOException {
boolean b;
JsonToken t = p.getCurrentToken();
if (t == JsonToken.VALUE_TRUE) {
b = true;
} else if (t == JsonToken.VALUE_FALSE) {
b = false;
} else {
b = _deserializeBoolean(p, ctxt);
}
_propertyMutator.booleanField(bean, b);
}

@Override
Expand All @@ -60,9 +69,18 @@ public void set(Object bean, Object value) throws IOException {
}

@Override
public Object deserializeSetAndReturn(JsonParser jp,
public Object deserializeSetAndReturn(JsonParser p,
DeserializationContext ctxt, Object instance) throws IOException
{
return setAndReturn(instance, _deserializeBoolean(jp, ctxt));
boolean b;
JsonToken t = p.getCurrentToken();
if (t == JsonToken.VALUE_TRUE) {
b = true;
} else if (t == JsonToken.VALUE_FALSE) {
b = false;
} else {
b = _deserializeBoolean(p, ctxt);
}
return setAndReturn(instance, b);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,17 @@ public SettableBooleanMethodProperty withMutator(BeanPropertyMutator mut) {
*/

@Override
public void deserializeAndSet(JsonParser jp, DeserializationContext ctxt, Object bean) throws IOException {
_propertyMutator.booleanSetter(bean, _deserializeBoolean(jp, ctxt));
public void deserializeAndSet(JsonParser p, DeserializationContext ctxt, Object bean) throws IOException {
boolean b;
JsonToken t = p.getCurrentToken();
if (t == JsonToken.VALUE_TRUE) {
b = true;
} else if (t == JsonToken.VALUE_FALSE) {
b = false;
} else {
b = _deserializeBoolean(p, ctxt);
}
_propertyMutator.booleanSetter(bean, b);
}

@Override
Expand All @@ -58,9 +67,18 @@ public void set(Object bean, Object value) throws IOException {
}

@Override
public Object deserializeSetAndReturn(JsonParser jp,
public Object deserializeSetAndReturn(JsonParser p,
DeserializationContext ctxt, Object instance) throws IOException
{
return setAndReturn(instance, _deserializeBoolean(jp, ctxt));
boolean b;
JsonToken t = p.getCurrentToken();
if (t == JsonToken.VALUE_TRUE) {
b = true;
} else if (t == JsonToken.VALUE_FALSE) {
b = false;
} else {
b = _deserializeBoolean(p, ctxt);
}
return setAndReturn(instance, b);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ public SettableIntFieldProperty withMutator(BeanPropertyMutator mut) {
public void deserializeAndSet(JsonParser p, DeserializationContext ctxt,
Object bean) throws IOException
{
_propertyMutator.intField(bean, p.getValueAsInt());
int v = p.hasToken(JsonToken.VALUE_NUMBER_INT) ? p.getIntValue() : _deserializeInt(p, ctxt);
_propertyMutator.intField(bean, v);
}

@Override
Expand All @@ -65,6 +66,7 @@ public void set(Object bean, Object value) throws IOException {
public Object deserializeSetAndReturn(JsonParser p,
DeserializationContext ctxt, Object instance) throws IOException
{
return setAndReturn(instance, p.getValueAsInt());
int v = p.hasToken(JsonToken.VALUE_NUMBER_INT) ? p.getIntValue() : _deserializeInt(p, ctxt);
return setAndReturn(instance, v);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ public SettableIntMethodProperty withMutator(BeanPropertyMutator mut) {
public void deserializeAndSet(JsonParser p, DeserializationContext ctxt,
Object bean) throws IOException
{
_propertyMutator.intSetter(bean, p.getValueAsInt());
int v = p.hasToken(JsonToken.VALUE_NUMBER_INT) ? p.getIntValue() : _deserializeInt(p, ctxt);
_propertyMutator.intSetter(bean, v);
}

@Override
Expand All @@ -64,6 +65,7 @@ public Object deserializeSetAndReturn(JsonParser p,
DeserializationContext ctxt, Object instance)
throws IOException
{
return setAndReturn(instance, p.getValueAsInt());
int v = p.hasToken(JsonToken.VALUE_NUMBER_INT) ? p.getIntValue() : _deserializeInt(p, ctxt);
return setAndReturn(instance, v);
}
}
Loading

0 comments on commit d68ed5e

Please sign in to comment.