UUIDDeserializationTest.java
package tools.jackson.databind.deser.jdk;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.nio.ByteBuffer;
import java.util.Base64;
import java.util.UUID;
import org.junit.jupiter.api.Test;
import tools.jackson.core.Base64Variants;
import tools.jackson.core.ObjectReadContext;
import tools.jackson.databind.DeserializationContext;
import tools.jackson.databind.DeserializationFeature;
import tools.jackson.databind.ObjectMapper;
import tools.jackson.databind.ObjectReader;
import tools.jackson.databind.exc.InvalidFormatException;
import tools.jackson.databind.util.TokenBuffer;
import static org.junit.jupiter.api.Assertions.*;
import static tools.jackson.databind.testutil.DatabindTestUtil.newJsonMapper;
import static tools.jackson.databind.testutil.JacksonTestUtilBase.q;
import static tools.jackson.databind.testutil.JacksonTestUtilBase.verifyException;
// Tests for [databind#4394]
public class UUIDDeserializationTest
{
private static final UUID TEST_UUID = UUID.fromString("a7161c6c-be14-4ae3-a3c4-f27c2b2c6ef4");
private final TestableUUIDDeserializer UUID_DESERIALIZER = new TestableUUIDDeserializer();
static class TestableUUIDDeserializer extends UUIDDeserializer
{
@Override
public UUID _deserialize(String id, DeserializationContext ctxt)
{
return super._deserialize(id, ctxt);
}
}
/*
/**********************************************************************
/* Test methods
/**********************************************************************
*/
private final ObjectMapper MAPPER = newJsonMapper();
@Test
public void testUUID() throws Exception
{
final String NULL_UUID = "00000000-0000-0000-0000-000000000000";
final ObjectReader r = MAPPER.readerFor(UUID.class);
// first, couple of generated UUIDs:
for (String value : new String[] {
"76e6d183-5f68-4afa-b94a-922c1fdb83f8",
"540a88d1-e2d8-4fb1-9396-9212280d0a7f",
"2c9e441d-1cd0-472d-9bab-69838f877574",
"591b2869-146e-41d7-8048-e8131f1fdec5",
"82994ac2-7b23-49f2-8cc5-e24cf6ed77be",
"00000007-0000-0000-0000-000000000000"
}) {
UUID uuid = UUID.fromString(value);
assertEquals(uuid,
r.without(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)
.readValue(q(value)));
}
// then use templating; note that these are not exactly valid UUIDs
// wrt spec (type bits etc), but JDK UUID should deal ok
final String TEMPL = NULL_UUID;
final String chars = "123456789abcdefABCDEF";
for (int i = 0; i < chars.length(); ++i) {
String value = TEMPL.replace('0', chars.charAt(i));
assertEquals(UUID.fromString(value).toString(),
r.readValue(q(value)).toString());
}
// also: see if base64 encoding works as expected
String base64 = Base64Variants.getDefaultVariant().encode(new byte[16]);
assertEquals(UUID.fromString(NULL_UUID),
r.readValue(q(base64)));
}
@Test
public void testUUIDInvalid() throws Exception
{
// and finally, exception handling too [databind#1000], for invalid cases
try {
MAPPER.readValue(q("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(q("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.
}
@Test
public void testUUIDAux() throws Exception
{
final UUID value = UUID.fromString("76e6d183-5f68-4afa-b94a-922c1fdb83f8");
// first, null should come as null
try (TokenBuffer buf = TokenBuffer.forGeneration()) {
buf.writePOJO(null);
assertNull(MAPPER.readValue(buf.asParser(ObjectReadContext.empty()), UUID.class));
}
// then, UUID itself come as is:
try (TokenBuffer buf = TokenBuffer.forGeneration()) {
buf.writePOJO(value);
assertSame(value, MAPPER.readValue(buf.asParser(ObjectReadContext.empty()), UUID.class));
// and finally from byte[]
// oh crap; JDK UUID just... sucks. Not even byte[] accessors or constructors? Huh?
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
DataOutputStream out = new DataOutputStream(bytes);
out.writeLong(value.getMostSignificantBits());
out.writeLong(value.getLeastSignificantBits());
out.close();
byte[] data = bytes.toByteArray();
assertEquals(16, data.length);
// Let's create fresh TokenBuffer, not reuse one
try (TokenBuffer buf2 = TokenBuffer.forGeneration()) {
buf2.writePOJO(data);
UUID value2 = MAPPER.readValue(buf2.asParser(), UUID.class);
assertEquals(value, value2);
}
}
}
@Test
void testCanDeserializeUUIDFromString() throws Exception {
assertEquals(TEST_UUID, UUID_DESERIALIZER._deserialize(TEST_UUID.toString(), null));
}
@Test
void testCanDeserializeUUIDFromBase64() throws Exception {
assertEquals(TEST_UUID, UUID_DESERIALIZER._deserialize(Base64.getEncoder().encodeToString(getBytesFromUUID(TEST_UUID)), null));
}
@Test
void testCanDeserializeUUIDFromBase64WithoutPadding() throws Exception {
assertEquals(TEST_UUID, UUID_DESERIALIZER._deserialize(Base64.getEncoder().withoutPadding().encodeToString(getBytesFromUUID(TEST_UUID)), null));
}
@Test
void testCanDeserializeUUIDFromBase64Url() throws Exception {
assertEquals(TEST_UUID, UUID_DESERIALIZER._deserialize(Base64.getUrlEncoder().encodeToString(getBytesFromUUID(TEST_UUID)), null));
}
@Test
void testCanDeserializeUUIDFromBase64UrlWithoutPadding() throws Exception {
assertEquals(TEST_UUID, UUID_DESERIALIZER._deserialize(Base64.getUrlEncoder().withoutPadding().encodeToString(getBytesFromUUID(TEST_UUID)), null));
}
private static byte[] getBytesFromUUID(UUID uuid) {
final ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
bb.putLong(uuid.getMostSignificantBits());
bb.putLong(uuid.getLeastSignificantBits());
return bb.array();
}
}