Get Gson Key's Name In An Overriden Adapter - java

I have overriden an Integer Adapter in GSON to parse my JSON. Reason for doing this is that the GSON method parseJson simply throws the JsonSyntaxException if anything goes wrong. To avoid sending a generic exception I created this adapter. I want the adapter to throw an exception along with the name of the Key. Problem is that I can not get the key name in the overriden method deserialize of JsonDeserializer[T]
Code snippet
val integerAdapter = new JsonDeserializer[Integer] {
override def deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): Integer = {
Try(json.getAsInt) //JsonElement object has only the value
match {
case Success(value) => value
case Failure(ex) => throw new IllegalArgumentException(ex) // here i want the name of the key to be thrown in the exception and manage accordingly
}
}
}
Json:{
"supplierId":"21312",
"isClose":false,
"currency":"USD",
"statusKey":1001,
"statusValue":"Opened ",
"statusDateTime":"2014-03-10T18:46:40.000Z",
"productKey":2001,
"productValue":"Trip Cancellation",
"TypeKey":3001,
"TypeValue":"Trip Cancellation",
"SubmitChannelKey":4001,
"SubmitChannelValue":"Web asdsad",
"tripNumber":"01239231912",
"ExpiryDateTime":"2014-03-10T18:46:40.000Z",
"numberOfants":4,
"AmountReserved":901232,
"AmountRequested":91232
}
Any leads on this?

Your adapter is a deserializer for the Integer type which is a wrapper for a primitive. Because it's not a regular object, Gson will not associate a key with it.
Why not implement a deserializer for the whole JSON object to have access to all keys?
class MyObject {
private Integer supplierId;
private boolean isClose;
// TODO: the other fields in the JSON string
}
class MyObjectDeserializer implements JsonDeserializer<MyObject> {
public MyObject deserialize(JsonElement jsonElement, Type type,
JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
// TODO: construct a new MyObject instance
}
}

Related

Deserialize json by class name

How i can deserialize my object from json string, if i have only string name of my class, by canonical name invoke, and json string representation of object?
In other words, i need method like this:
public <T> T deserialize(String json, String className) {
// some code
}
We have class name and json string - and we need to deserialize json to java object.
I know how to deserialize json to object if i know the class of object, for example, we can use Jackson:
String json = "{ \"color\" : \"Black\", \"type\" : \"BMW\" }";
Car car = objectMapper.readValue(json, Car.class);
But in my task there is a different classes - it may be Cat.class, Dog.class, Car.class and etc. And every class with different state. And i need universal method for deserializing.
I write something like:
public final class Utils implements Serializable {
private Utils () {
throw new AssertionError();
}
private static ObjectMapper objectMapper = new ObjectMapper();
public static String toJson(Object obj) {
String objectToJson;
try {
objectToJson = objectMapper.writeValueAsString(obj);
} catch (JsonProcessingException e) {
throw new UncheckedIOException(String.format("Can't serialize object %s to JSON string", obj), e);
}
return objectToJson;
}
public static <T> T fromJson(String json, String className) throws ClassNotFoundException, IOException {
Class<?> clz = Class.forName(className);
return (T) objectMapper.readValue(json, clz);
}
}
And it works with example of car above, but with a warning cast exception.
But maybe there is a better way?
Oh, and not all objects will be so simple. Some of them would encapsulate collections and other objects.
The problem stems from the compiler wanting to (virtually) make a different instance of this method for every type T that it is used on. However, there is nothing in the arguments to hang its hat on.
If the caller doesn't know what class to expect, other than a String representation of that class (which I'm assuming has been saved in the JSON as well?), what is he going to do with the result of this call? Since he doesn't know, he must be using it as simply Object, in which case the method might as well simply return Object.
If the caller does know the class, then he can pass in a Class as the argument, and you won't have any issues.
It occurred to me as writing this that ObectMapper must have a similar problem for some of its readValue methods, such as the one that accepts ResolvedType instead of Class. I notice that, in that class' source code, it includes /unchecked/ before the class. I"m not sure if that is to get around this issue or not, but it makes sense.

Map to JSON - ignore specific keys

I want to serialize a java map into json and I can definitely use either jackson or gson.
But when I serialize, I want to ignore specify key. Is it possible?
Map is . I don't have/want my Map backed by a POJO because the keys are very generic and could be anything. I understand if it was a POJO, we can use Ignore annotation to achieve.
You can create a custom class that extends HashMap:
public class MyMap extends HashMap<String, Object> {
}
and then register a custom serializer, like:
public class MyMapSerializer extends JsonSerializer<MyMap> {
#Override
public JsonElement serialize(MyMap arg0, Type arg1, JsonSerializationContext arg2) {
JsonObject result = new JsonObject();
for (String k : arg0.keySet()) {
if (whatever your condition is) {
result.add(k, arg0.get(k));
}
}
return result;
}
}
Then when you create the Gson object you need to initialize it by passing an instance of the serializer:
Gson gson = new GsonBuilder().registerTypeAdapter(MyMap.class, new MyMapSerializer()).create();

How to make a custom list deserializer in Gson?

I need to deserialize a Json file that has an array. I know how to deserialize it so that I get a List object, but in the framework I am using a custom list object that does not implement the Java List interface. My question is, how do I write a deserializer for my custom list object?
EDIT: I want the deserializer to be universal, meaning that I want it ot work for every kind of list, like CustomList<Integer>, CustomList<String>, CustomList<CustomModel> not just a specific kind of list since it would be annoying to make deserializer for every kind I use.
This is what I came up with:
class CustomListConverter implements JsonDeserializer<CustomList<?>> {
public CustomList deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext ctx) {
Type valueType = ((ParameterizedType) typeOfT).getActualTypeArguments()[0];
CustomList<Object> list = new CustomList<Object>();
for (JsonElement item : json.getAsJsonArray()) {
list.add(ctx.deserialize(item, valueType));
}
return list;
}
}
Register it like this:
Gson gson = new GsonBuilder()
.registerTypeAdapter(CustomList.class, new CustomListConverter())
.create();

An RPC mechanism which handles type hierarchy correctly in java

I need a mechanism for calling remote methods on server which handles type hierarchy correctly. For example GWT can do this, but my client isn't javascript! By handling type hierarchy, I mean transfering child objects even when the type is declared as a parent class! Suppose we have a class Container:
class Parent {
String name;
}
class Child extends Parent {
String family;
}
class Container {
Parent p;
}
And I have a method on server with the following signature:
void doSomethingImportant(Container c) {}
If I call this method on client, and pass an instance of Container, which has an instance of Child as property "p", I expect to get an instance of Child on server too (which would have "family" property)!
GWT handles this without any problem, is there any other technologies that can handle this?
I didn't find a RPC mechanism for this, but I managed to use JSON in order to handle this. I found Gson which is google's API for using JSON in java. It converts objects to JsonElements which can be interpretted as Strings and vice versa.
So the key feature that helped me develop this, was Gson's custom Serializer/Deserializer. I implemented a class which is Serializer and Deserializer for Object, and I send the class name for source class along the class's content:
class MySerializerAndDeserializer implements JsonSerializer<Object>, JsonDeserializer<Object>{
public JsonElement serialize(Object src, Type typeOfSrc,
JsonSerializationContext context) {
Class clazz = src.getClass();
JsonElement serialize = context.serialize(src);
JsonArray array = new JsonArray();
array.add(new JsonPrimitive(clazz.getName()));
array.add(serialize);
return array;
}
public Object deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context) throws JsonParseException {
JsonArray array = json.getAsJsonArray();
String asString = array.get(0).getAsString();
Object deserialize = null;
try {
deserialize = context.deserialize(array.get(1).getAsJsonObject(), Class.forName(asString));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return deserialize;
}
}
and then I registered MySerializerAndDeserializer for Parent.class:
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(Parent.class, new MySerializerAndDeserializer());
And finally used gson and got the Instance I expected correctly:
String json = gson.toJson(container, Container.class);
Container containerFromJson = gson.fromJson(json, Container.class);
Using sfnrpc (http://code.google.com/p/sfnrpc) you can specify which type must be used optionally in the class arguments.
Hope this helps.
Object [] objArr = new Object[1];
TestObject to = new TestObject();
to.data = "HELLO,";
objArr[0] = to;
**Class [] classArr = new Class[1];
classArr[0] = TestObject.class;**
TestObject response = (TestObject)rpcc.invoke("#URN1","127.0.0.1:6878","echo",true,60,"", objArr,classArr);
sl.debug("The response was:"+response.data);

Gson, auto-initialize and avoid null exceptions

when deserializing a json into a class Foo{int id; List<String> items; List<Long> dates;} How could I auto initialize fields that are null after deserialization. Is there such a possiblity with Gson lib?
ex:
Foo foo = new Gson().fromJson("{\"id\":\"test\", \"items\":[1234, 1235, 1336]}", Foo.class)
foo.dates.size(); -> 0 and not null pointerException
I know I could do if (foo.attr == null) foo.attr = ...
but I'm looking for more generic code, without knowledge of Foo class
thx
edit: sorry just putting Getters in Foo is enough
closed
You need to create your custom deserializer.
Assuming your class is called MyAwesomeClass, you implement something like
MyAwesomeClassDeserializer implements JsonDeserializer<MyAwesomeClass> {
#Override
public MyAwesomeClass deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext ctx) throws JsonParseException
{
// TODO: Do your null-magic here
}
and register it with GSON, like this:
Gson gson = new GsonBuilder()
.registerTypeAdapter(MyAwesomeClass.class, new MyAwesomeClassDeserializer())
.create();
Now, you just call a fromJson(String, TypeToken) method, to get your deserialized object.
MyAweSomeClass instance = gson.fromJson(json, new TypeToken<MyAwesomeClass>(){}.getType());

Categories

Resources