Start work on #1000, UUIDDeserializer will now throw `InvalidFormatException`
diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/FromStringDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/FromStringDeserializer.java
index 1012352..609e61e 100644
--- a/src/main/java/com/fasterxml/jackson/databind/deser/std/FromStringDeserializer.java
+++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/FromStringDeserializer.java
@@ -98,20 +98,20 @@
@SuppressWarnings("unchecked")
@Override
- public T deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException
+ public T deserialize(JsonParser p, DeserializationContext ctxt) throws IOException
{
// Issue#381
- if (jp.getCurrentToken() == JsonToken.START_ARRAY && ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) {
- jp.nextToken();
- final T value = deserialize(jp, ctxt);
- if (jp.nextToken() != JsonToken.END_ARRAY) {
- throw ctxt.wrongTokenException(jp, JsonToken.END_ARRAY,
+ if (p.getCurrentToken() == JsonToken.START_ARRAY && ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) {
+ p.nextToken();
+ final T value = deserialize(p, ctxt);
+ if (p.nextToken() != JsonToken.END_ARRAY) {
+ throw ctxt.wrongTokenException(p, JsonToken.END_ARRAY,
"Attempted to unwrap single value array for single '" + _valueClass.getName() + "' value but there was more than a single value in the array");
}
return value;
}
// 22-Sep-2012, tatu: For 2.1, use this new method, may force coercion:
- String text = jp.getValueAsString();
+ String text = p.getValueAsString();
if (text != null) { // has String representation
if (text.length() == 0 || (text = text.trim()).length() == 0) {
// 04-Feb-2013, tatu: Usually should become null; but not always
@@ -140,9 +140,9 @@
throw e;
// nothing to do here, yet? We'll fail anyway
}
- if (jp.getCurrentToken() == JsonToken.VALUE_EMBEDDED_OBJECT) {
+ if (p.getCurrentToken() == JsonToken.VALUE_EMBEDDED_OBJECT) {
// Trivial cases; null to null, instance of type itself returned as is
- Object ob = jp.getEmbeddedObject();
+ Object ob = p.getEmbeddedObject();
if (ob == null) {
return null;
}
diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/UUIDDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/UUIDDeserializer.java
index 01f969c..03f3bf6 100644
--- a/src/main/java/com/fasterxml/jackson/databind/deser/std/UUIDDeserializer.java
+++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/UUIDDeserializer.java
@@ -5,8 +5,10 @@
import java.util.UUID;
import com.fasterxml.jackson.core.Base64Variants;
-
+import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.exc.InvalidFormatException;
public class UUIDDeserializer extends FromStringDeserializer<UUID>
{
@@ -37,24 +39,24 @@
byte[] stuff = Base64Variants.getDefaultVariant().decode(id);
return _fromBytes(stuff, ctxt);
}
- _badFormat(id);
+ _badFormat(id, ctxt);
}
// verify hyphens first:
if ((id.charAt(8) != '-') || (id.charAt(13) != '-')
|| (id.charAt(18) != '-') || (id.charAt(23) != '-')) {
- _badFormat(id);
+ _badFormat(id, ctxt);
}
- long l1 = intFromChars(id, 0);
+ long l1 = intFromChars(id, 0, ctxt);
l1 <<= 32;
- long l2 = ((long) shortFromChars(id, 9)) << 16;
- l2 |= shortFromChars(id, 14);
+ long l2 = ((long) shortFromChars(id, 9, ctxt)) << 16;
+ l2 |= shortFromChars(id, 14, ctxt);
long hi = l1 + l2;
- int i1 = (shortFromChars(id, 19) << 16) | shortFromChars(id, 24);
+ int i1 = (shortFromChars(id, 19, ctxt) << 16) | shortFromChars(id, 24, ctxt);
l1 = i1;
l1 <<= 32;
- l2 = intFromChars(id, 28);
+ l2 = intFromChars(id, 28, ctxt);
l2 = (l2 << 32) >>> 32; // sign removal, Java-style. Ugh.
long lo = l1 | l2;
@@ -71,19 +73,26 @@
return null; // never gets here
}
- private void _badFormat(String uuidStr) {
- throw new NumberFormatException("UUID has to be represented by the standard 36-char representation");
+ private void _badFormat(String uuidStr, DeserializationContext ctxt)
+ throws JsonMappingException
+ {
+ throw InvalidFormatException.from(ctxt.getParser(),
+ "UUID has to be represented by standard 36-char representation",
+ uuidStr, handledType());
}
- static int intFromChars(String str, int index) {
- return (byteFromChars(str, index) << 24) + (byteFromChars(str, index+2) << 16) + (byteFromChars(str, index+4) << 8) + byteFromChars(str, index+6);
+ static int intFromChars(String str, int index, DeserializationContext ctxt) throws JsonMappingException {
+ return (byteFromChars(str, index, ctxt) << 24)
+ + (byteFromChars(str, index+2, ctxt) << 16)
+ + (byteFromChars(str, index+4, ctxt) << 8)
+ + byteFromChars(str, index+6, ctxt);
}
- static int shortFromChars(String str, int index) {
- return (byteFromChars(str, index) << 8) + byteFromChars(str, index+2);
+ static int shortFromChars(String str, int index, DeserializationContext ctxt) throws JsonMappingException {
+ return (byteFromChars(str, index, ctxt) << 8) + byteFromChars(str, index+2, ctxt);
}
- static int byteFromChars(String str, int index)
+ static int byteFromChars(String str, int index, DeserializationContext ctxt) throws JsonMappingException
{
final char c1 = str.charAt(index);
final char c2 = str.charAt(index+1);
@@ -95,20 +104,23 @@
}
}
if (c1 > 127 || HEX_DIGITS[c1] < 0) {
- return _badChar(str, index, c1);
+ return _badChar(str, index, ctxt, c1);
}
- return _badChar(str, index+1, c2);
+ return _badChar(str, index+1, ctxt, c2);
}
- static int _badChar(String uuidStr, int index, char c) {
- throw new NumberFormatException("Non-hex character '"+c+"', not valid character for a UUID String"
- +"' (value 0x"+Integer.toHexString(c)+") for UUID String \""+uuidStr+"\"");
+ static int _badChar(String uuidStr, int index, DeserializationContext ctxt, char c) throws JsonMappingException {
+ String msg = String.format(
+"Non-hex character '%c' (value 0x%s), not valid for UUID String: input String '%s'",
+ c, Integer.toHexString(c), uuidStr);
+ throw InvalidFormatException.from(ctxt.getParser(), msg, uuidStr, UUID.class);
}
- private UUID _fromBytes(byte[] bytes, DeserializationContext ctxt) throws IOException {
+ private UUID _fromBytes(byte[] bytes, DeserializationContext ctxt) throws JsonMappingException {
if (bytes.length != 16) {
- ctxt.mappingException("Can only construct UUIDs from byte[16]; got %d bytes",
- bytes.length);
+ throw InvalidFormatException.from(ctxt.getParser(),
+ "Can only construct UUIDs from byte[16]; got "+bytes.length+" bytes",
+ bytes, handledType());
}
return new UUID(_long(bytes, 0), _long(bytes, 8));
}
diff --git a/src/main/java/com/fasterxml/jackson/databind/exc/InvalidFormatException.java b/src/main/java/com/fasterxml/jackson/databind/exc/InvalidFormatException.java
index 771fd76..e7593d1 100644
--- a/src/main/java/com/fasterxml/jackson/databind/exc/InvalidFormatException.java
+++ b/src/main/java/com/fasterxml/jackson/databind/exc/InvalidFormatException.java
@@ -67,7 +67,7 @@
_value = value;
_targetType = targetType;
}
-
+
public static InvalidFormatException from(JsonParser p, String msg,
Object value, Class<?> targetType)
{
diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/TestSimpleTypes.java b/src/test/java/com/fasterxml/jackson/databind/deser/TestSimpleTypes.java
index 4500453..8fe48cf 100644
--- a/src/test/java/com/fasterxml/jackson/databind/deser/TestSimpleTypes.java
+++ b/src/test/java/com/fasterxml/jackson/databind/deser/TestSimpleTypes.java
@@ -11,6 +11,7 @@
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
+import com.fasterxml.jackson.databind.exc.InvalidFormatException;
import com.fasterxml.jackson.databind.util.TokenBuffer;
/**
@@ -628,6 +629,24 @@
mapper.readValue(quote(base64), UUID.class));
}
+ public void testUUIDInvalid() throws Exception
+ {
+ // and finally, exception handling too [databind#1000], for invalid cases
+ try {
+ MAPPER.readValue(quote("abcde"), UUID.class);
+ fail("Should fail on invalid UUID string");
+ } catch (InvalidFormatException e) {
+ verifyException(e, "UUID has to be represented by standard");
+ }
+ try {
+ MAPPER.readValue(quote("76e6d183-5f68-4afa-b94a-922c1fdb83fx"), UUID.class);
+ fail("Should fail on invalid UUID string");
+ } catch (InvalidFormatException e) {
+ verifyException(e, "non-hex character 'x'");
+ }
+ // should also test from-bytes version, but that's trickier... leave for now.
+ }
+
public void testUUIDAux() throws Exception
{
// [JACKSON-393] fix: