Added Gson serialization/deserialization exception

This commit is contained in:
Andrea Paternesi 2018-11-22 12:51:04 +01:00
parent 243ec7802c
commit 747238a479
6 changed files with 297 additions and 0 deletions

48
extensions/gson/pom.xml Normal file
View File

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2018 JWTK
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-root</artifactId>
<version>0.11.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>jjwt-gson</artifactId>
<name>JJWT :: Extensions :: Gson</name>
<packaging>jar</packaging>
<properties>
<jjwt.root>${basedir}/../..</jjwt.root>
</properties>
<dependencies>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,42 @@
package io.jsonwebtoken.io;
import com.google.gson.Gson;
import io.jsonwebtoken.lang.Assert;
import java.io.IOException;
public class GsonDeserializer<T> implements Deserializer<T> {
private final Class<T> returnType;
private final Gson gson;
@SuppressWarnings("unused") //used via reflection by RuntimeClasspathDeserializerLocator
public GsonDeserializer() {
this(GsonSerializer.DEFAULT_GSON);
}
@SuppressWarnings({"unchecked", "WeakerAccess", "unused"}) // for end-users providing a custom gson
public GsonDeserializer(Gson gson) {
this(gson, (Class<T>) Object.class);
}
private GsonDeserializer(Gson gson, Class<T> returnType) {
Assert.notNull(gson, "gson cannot be null.");
Assert.notNull(returnType, "Return type cannot be null.");
this.gson = gson;
this.returnType = returnType;
}
@Override
public T deserialize(byte[] bytes) throws DeserializationException {
try {
return readValue(bytes);
} catch (IOException e) {
String msg = "Unable to deserialize bytes into a " + returnType.getName() + " instance: " + e.getMessage();
throw new DeserializationException(msg, e);
}
}
protected T readValue(byte[] bytes) throws IOException {
return gson.fromJson(new String(bytes), returnType);
}
}

View File

@ -0,0 +1,43 @@
package io.jsonwebtoken.io;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import io.jsonwebtoken.lang.Assert;
import io.jsonwebtoken.lang.Strings;
public class GsonSerializer<T> implements Serializer<T> {
static final Gson DEFAULT_GSON = new GsonBuilder().disableHtmlEscaping().create();
private Gson gson;
@SuppressWarnings("unused") //used via reflection by RuntimeClasspathDeserializerLocator
public GsonSerializer() {
this(DEFAULT_GSON);
}
@SuppressWarnings("WeakerAccess") //intended for end-users to use when providing a custom gson
public GsonSerializer(Gson gson) {
Assert.notNull(gson, "gson cannot be null.");
this.gson = gson;
}
@Override
public byte[] serialize(T t) throws SerializationException {
Assert.notNull(t, "Object to serialize cannot be null.");
//Gson never throws any serialization exception
return writeValueAsBytes(t);
}
@SuppressWarnings("WeakerAccess") //for testing
protected byte[] writeValueAsBytes(T t) {
Object o;
if (t instanceof byte[]) {
o = Encoders.BASE64.encode((byte[]) t);
} else if (t instanceof char[]) {
o = new String((char[]) t);
} else {
o = t;
}
return this.gson.toJson(o).getBytes(Strings.UTF_8);
}
}

View File

@ -0,0 +1,64 @@
package io.jsonwebtoken.io
import com.google.gson.Gson
import io.jsonwebtoken.lang.Strings
import org.junit.Test
import static org.easymock.EasyMock.*
import static org.junit.Assert.*
class GsonDeserializerTest {
@Test
void testDefaultConstructor() {
def deserializer = new GsonDeserializer()
assertNotNull deserializer.gson
}
@Test
void testObjectMapperConstructor() {
def customGSON = new Gson()
def deserializer = new GsonDeserializer(customGSON)
assertSame customGSON, deserializer.gson
}
@Test(expected = IllegalArgumentException)
void testObjectMapperConstructorWithNullArgument() {
new GsonDeserializer<>(null)
}
@Test
void testDeserialize() {
byte[] serialized = '{"hello":"世界"}'.getBytes(Strings.UTF_8)
def expected = [hello: '世界']
def result = new GsonDeserializer().deserialize(serialized)
assertEquals expected, result
}
@Test
void testDeserializeFailsWithJsonProcessingException() {
def ex = createMock(java.io.IOException)
expect(ex.getMessage()).andReturn('foo')
def deserializer = new GsonDeserializer() {
@Override
protected Object readValue(byte[] bytes) throws java.io.IOException {
throw ex
}
}
replay ex
try {
deserializer.deserialize('{"hello":"世界"}'.getBytes(Strings.UTF_8))
fail()
} catch (DeserializationException se) {
assertEquals 'Unable to deserialize bytes into a java.lang.Object instance: foo', se.getMessage()
assertSame ex, se.getCause()
}
verify ex
}
}

View File

@ -0,0 +1,99 @@
package io.jsonwebtoken.io
import io.jsonwebtoken.lang.Strings
import org.junit.Test
import static org.easymock.EasyMock.*
import static org.junit.Assert.*
import com.google.gson.Gson
class GsonSerializerTest {
@Test
void testDefaultConstructor() {
def serializer = new GsonSerializer()
assertNotNull serializer.gson
}
@Test
void testObjectMapperConstructor() {
def customGSON = new Gson()
def serializer = new GsonSerializer<>(customGSON)
assertSame customGSON, serializer.gson
}
@Test(expected = IllegalArgumentException)
void testObjectMapperConstructorWithNullArgument() {
new GsonSerializer<>(null)
}
@Test
void testByte() {
byte[] expected = "120".getBytes(Strings.UTF_8) //ascii("x") = 120
byte[] bytes = "x".getBytes(Strings.UTF_8)
byte[] result = new GsonSerializer().serialize(bytes[0]) //single byte
assertTrue Arrays.equals(expected, result)
}
@Test
void testByteArray() { //expect Base64 string by default:
byte[] bytes = "hi".getBytes(Strings.UTF_8)
String expected = '"aGk="' as String //base64(hi) --> aGk=
byte[] result = new GsonSerializer().serialize(bytes)
assertEquals expected, new String(result, Strings.UTF_8)
}
@Test
void testEmptyByteArray() { //expect Base64 string by default:
byte[] bytes = new byte[0]
byte[] result = new GsonSerializer().serialize(bytes)
assertEquals '""', new String(result, Strings.UTF_8)
}
@Test
void testChar() { //expect Base64 string by default:
byte[] result = new GsonSerializer().serialize('h' as char)
assertEquals "\"h\"", new String(result, Strings.UTF_8)
}
@Test
void testCharArray() { //expect Base64 string by default:
byte[] result = new GsonSerializer().serialize("hi".toCharArray())
assertEquals "\"hi\"", new String(result, Strings.UTF_8)
}
@Test
void testSerialize() {
byte[] expected = '{"hello":"世界"}'.getBytes(Strings.UTF_8)
byte[] result = new GsonSerializer().serialize([hello: '世界'])
assertTrue Arrays.equals(expected, result)
}
//THIS IS COMMENTED OUT BECAUSE GSN NEVER THROWS ANY SERIALIZATION EXCEPTION
// @Test
// void testSerializeFailsWithJsonProcessingException() {
//
// def ex = createMock(JsonProcessingException)
//
// expect(ex.getMessage()).andReturn('foo')
//
// def serializer = new GsonSerializer() {
// @Override
// protected byte[] writeValueAsBytes(Object o) throws JsonProcessingException {
// throw ex
// }
// }
//
// replay ex
//
// try {
// serializer.serialize([hello: 'world'])
// fail()
// } catch (SerializationException se) {
// assertEquals 'Unable to serialize object: foo', se.getMessage()
// assertSame ex, se.getCause()
// }
//
// verify ex
// }
}

View File

@ -36,6 +36,7 @@
<modules>
<module>jackson</module>
<module>orgjson</module>
<module>gson</module>
</modules>
</project>