Skip to content

Commit 16bddc1

Browse files
committed
Start work on #1000, UUIDDeserializer will now throw InvalidFormatException
1 parent a67f353 commit 16bddc1

File tree

4 files changed

+64
-33
lines changed

4 files changed

+64
-33
lines changed

src/main/java/com/fasterxml/jackson/databind/deser/std/FromStringDeserializer.java

+9-9
Original file line numberDiff line numberDiff line change
@@ -98,20 +98,20 @@ public static Std findDeserializer(Class<?> rawType)
9898

9999
@SuppressWarnings("unchecked")
100100
@Override
101-
public T deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException
101+
public T deserialize(JsonParser p, DeserializationContext ctxt) throws IOException
102102
{
103103
// Issue#381
104-
if (jp.getCurrentToken() == JsonToken.START_ARRAY && ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) {
105-
jp.nextToken();
106-
final T value = deserialize(jp, ctxt);
107-
if (jp.nextToken() != JsonToken.END_ARRAY) {
108-
throw ctxt.wrongTokenException(jp, JsonToken.END_ARRAY,
104+
if (p.getCurrentToken() == JsonToken.START_ARRAY && ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) {
105+
p.nextToken();
106+
final T value = deserialize(p, ctxt);
107+
if (p.nextToken() != JsonToken.END_ARRAY) {
108+
throw ctxt.wrongTokenException(p, JsonToken.END_ARRAY,
109109
"Attempted to unwrap single value array for single '" + _valueClass.getName() + "' value but there was more than a single value in the array");
110110
}
111111
return value;
112112
}
113113
// 22-Sep-2012, tatu: For 2.1, use this new method, may force coercion:
114-
String text = jp.getValueAsString();
114+
String text = p.getValueAsString();
115115
if (text != null) { // has String representation
116116
if (text.length() == 0 || (text = text.trim()).length() == 0) {
117117
// 04-Feb-2013, tatu: Usually should become null; but not always
@@ -140,9 +140,9 @@ public T deserialize(JsonParser jp, DeserializationContext ctxt) throws IOExcept
140140
throw e;
141141
// nothing to do here, yet? We'll fail anyway
142142
}
143-
if (jp.getCurrentToken() == JsonToken.VALUE_EMBEDDED_OBJECT) {
143+
if (p.getCurrentToken() == JsonToken.VALUE_EMBEDDED_OBJECT) {
144144
// Trivial cases; null to null, instance of type itself returned as is
145-
Object ob = jp.getEmbeddedObject();
145+
Object ob = p.getEmbeddedObject();
146146
if (ob == null) {
147147
return null;
148148
}

src/main/java/com/fasterxml/jackson/databind/deser/std/UUIDDeserializer.java

+35-23
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55
import java.util.UUID;
66

77
import com.fasterxml.jackson.core.Base64Variants;
8-
8+
import com.fasterxml.jackson.core.JsonParser;
99
import com.fasterxml.jackson.databind.DeserializationContext;
10+
import com.fasterxml.jackson.databind.JsonMappingException;
11+
import com.fasterxml.jackson.databind.exc.InvalidFormatException;
1012

1113
public class UUIDDeserializer extends FromStringDeserializer<UUID>
1214
{
@@ -37,24 +39,24 @@ protected UUID _deserialize(String id, DeserializationContext ctxt) throws IOExc
3739
byte[] stuff = Base64Variants.getDefaultVariant().decode(id);
3840
return _fromBytes(stuff, ctxt);
3941
}
40-
_badFormat(id);
42+
_badFormat(id, ctxt);
4143
}
4244

4345
// verify hyphens first:
4446
if ((id.charAt(8) != '-') || (id.charAt(13) != '-')
4547
|| (id.charAt(18) != '-') || (id.charAt(23) != '-')) {
46-
_badFormat(id);
48+
_badFormat(id, ctxt);
4749
}
48-
long l1 = intFromChars(id, 0);
50+
long l1 = intFromChars(id, 0, ctxt);
4951
l1 <<= 32;
50-
long l2 = ((long) shortFromChars(id, 9)) << 16;
51-
l2 |= shortFromChars(id, 14);
52+
long l2 = ((long) shortFromChars(id, 9, ctxt)) << 16;
53+
l2 |= shortFromChars(id, 14, ctxt);
5254
long hi = l1 + l2;
5355

54-
int i1 = (shortFromChars(id, 19) << 16) | shortFromChars(id, 24);
56+
int i1 = (shortFromChars(id, 19, ctxt) << 16) | shortFromChars(id, 24, ctxt);
5557
l1 = i1;
5658
l1 <<= 32;
57-
l2 = intFromChars(id, 28);
59+
l2 = intFromChars(id, 28, ctxt);
5860
l2 = (l2 << 32) >>> 32; // sign removal, Java-style. Ugh.
5961
long lo = l1 | l2;
6062

@@ -71,19 +73,26 @@ protected UUID _deserializeEmbedded(Object ob, DeserializationContext ctxt) thro
7173
return null; // never gets here
7274
}
7375

74-
private void _badFormat(String uuidStr) {
75-
throw new NumberFormatException("UUID has to be represented by the standard 36-char representation");
76+
private void _badFormat(String uuidStr, DeserializationContext ctxt)
77+
throws JsonMappingException
78+
{
79+
throw InvalidFormatException.from(ctxt.getParser(),
80+
"UUID has to be represented by standard 36-char representation",
81+
uuidStr, handledType());
7682
}
7783

78-
static int intFromChars(String str, int index) {
79-
return (byteFromChars(str, index) << 24) + (byteFromChars(str, index+2) << 16) + (byteFromChars(str, index+4) << 8) + byteFromChars(str, index+6);
84+
static int intFromChars(String str, int index, DeserializationContext ctxt) throws JsonMappingException {
85+
return (byteFromChars(str, index, ctxt) << 24)
86+
+ (byteFromChars(str, index+2, ctxt) << 16)
87+
+ (byteFromChars(str, index+4, ctxt) << 8)
88+
+ byteFromChars(str, index+6, ctxt);
8089
}
8190

82-
static int shortFromChars(String str, int index) {
83-
return (byteFromChars(str, index) << 8) + byteFromChars(str, index+2);
91+
static int shortFromChars(String str, int index, DeserializationContext ctxt) throws JsonMappingException {
92+
return (byteFromChars(str, index, ctxt) << 8) + byteFromChars(str, index+2, ctxt);
8493
}
8594

86-
static int byteFromChars(String str, int index)
95+
static int byteFromChars(String str, int index, DeserializationContext ctxt) throws JsonMappingException
8796
{
8897
final char c1 = str.charAt(index);
8998
final char c2 = str.charAt(index+1);
@@ -95,20 +104,23 @@ static int byteFromChars(String str, int index)
95104
}
96105
}
97106
if (c1 > 127 || HEX_DIGITS[c1] < 0) {
98-
return _badChar(str, index, c1);
107+
return _badChar(str, index, ctxt, c1);
99108
}
100-
return _badChar(str, index+1, c2);
109+
return _badChar(str, index+1, ctxt, c2);
101110
}
102111

103-
static int _badChar(String uuidStr, int index, char c) {
104-
throw new NumberFormatException("Non-hex character '"+c+"', not valid character for a UUID String"
105-
+"' (value 0x"+Integer.toHexString(c)+") for UUID String \""+uuidStr+"\"");
112+
static int _badChar(String uuidStr, int index, DeserializationContext ctxt, char c) throws JsonMappingException {
113+
String msg = String.format(
114+
"Non-hex character '%c' (value 0x%s), not valid for UUID String: input String '%s'",
115+
c, Integer.toHexString(c), uuidStr);
116+
throw InvalidFormatException.from(ctxt.getParser(), msg, uuidStr, UUID.class);
106117
}
107118

108-
private UUID _fromBytes(byte[] bytes, DeserializationContext ctxt) throws IOException {
119+
private UUID _fromBytes(byte[] bytes, DeserializationContext ctxt) throws JsonMappingException {
109120
if (bytes.length != 16) {
110-
ctxt.mappingException("Can only construct UUIDs from byte[16]; got %d bytes",
111-
bytes.length);
121+
throw InvalidFormatException.from(ctxt.getParser(),
122+
"Can only construct UUIDs from byte[16]; got "+bytes.length+" bytes",
123+
bytes, handledType());
112124
}
113125
return new UUID(_long(bytes, 0), _long(bytes, 8));
114126
}

src/main/java/com/fasterxml/jackson/databind/exc/InvalidFormatException.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ public InvalidFormatException(JsonParser p,
6767
_value = value;
6868
_targetType = targetType;
6969
}
70-
70+
7171
public static InvalidFormatException from(JsonParser p, String msg,
7272
Object value, Class<?> targetType)
7373
{

src/test/java/com/fasterxml/jackson/databind/deser/TestSimpleTypes.java

+19
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
import com.fasterxml.jackson.core.*;
1313
import com.fasterxml.jackson.databind.*;
14+
import com.fasterxml.jackson.databind.exc.InvalidFormatException;
1415
import com.fasterxml.jackson.databind.util.TokenBuffer;
1516

1617
/**
@@ -628,6 +629,24 @@ public void testUUID() throws Exception
628629
mapper.readValue(quote(base64), UUID.class));
629630
}
630631

632+
public void testUUIDInvalid() throws Exception
633+
{
634+
// and finally, exception handling too [databind#1000], for invalid cases
635+
try {
636+
MAPPER.readValue(quote("abcde"), UUID.class);
637+
fail("Should fail on invalid UUID string");
638+
} catch (InvalidFormatException e) {
639+
verifyException(e, "UUID has to be represented by standard");
640+
}
641+
try {
642+
MAPPER.readValue(quote("76e6d183-5f68-4afa-b94a-922c1fdb83fx"), UUID.class);
643+
fail("Should fail on invalid UUID string");
644+
} catch (InvalidFormatException e) {
645+
verifyException(e, "non-hex character 'x'");
646+
}
647+
// should also test from-bytes version, but that's trickier... leave for now.
648+
}
649+
631650
public void testUUIDAux() throws Exception
632651
{
633652
// [JACKSON-393] fix:

0 commit comments

Comments
 (0)