Gson toJson method returning empty - java

I am attempting to take List of objects of type SearchResultView that I have and convert it to a Json string using Googles Gson library, v 2.3.
The following is the relevant code(which I wrote by mimiking the documentation https://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/com/google/gson/Gson.html#getAdapter-com.google.gson.reflect.TypeToken-
Type typeResults = new TypeToken<List<SearchResultView>>(){}.getType();
String resultsJSON = (new Gson()).toJson(resultsView.getResults(), typeResults);
System.out.println(resultsJSON); //To test output.
The printline prints the following:
[{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}...
I have already verified that
resultsView.getResults()
returns an object of type
List<SearchResultView>
and that the list itself is not null and nonempty. What could be the issue here?
EDIT(Upon request): SearchResultView is an interface of all 'get' and 'has' methods. The object in the list is just a bunch of objects which implement that interface.

Related

Converting xml string to Object class using jackson

Can someone please help in deserializing xml string : List<A> to Object.class using jackson in java.Xml looks like :
<list> <A><id>1</id><name>Jeff</name> <id>2</id><name>John</name> </A>
It returns a HashMap object if I convert it to Object.class . I have created a utility function XMLToObject which returns Object class. This will be typcasted on the caller function end to get the required type of Object.
public Object XMLtoObject(String xml){
return mapper.readValue(xml,Object.class)
}
But if I use List.class in place of Object.class it deserializes it to list of hashmaps.
public Object XMLtoObject(String xml){
return mapper.readValue(xml,List.class)
}
I am looking a way to convert it into Object.class which I can typecast on caller function . Is that possible in jackson ? I know we can do it through xstream
The problem with List.class is that it doesn't have any information about its elements. You need one of the overloaded readValue methods. For instance, using TypeReference:
return mapper.readValue(xml, new TypeReference<List<Object>>() {});
This creates an anonymous sub class of TypeReference, from which the complete generic type (List<Object>) can be read by Jackson. The result should therefore be a List<Object> instead of a List<HashMap>.

How to determine class of object from GSON parse?

I am parsing JSON string from a byte-array and casting it as an object.
How do I determine the class of the object?
Object objDeserialized = gson.fromJson(jsonFromString, Object.class);
//It could be type Message or RoomDetail
gson.fromJson(jsonFromString, Object.class);
In general, this won't work because of Object.class. Gson prohibits overriding the Object class deserialization and uses ObjectTypeAdapter (see the primary Gson constructor as of Gson 2.8.0 and probably much earlier):
// built-in type adapters that cannot be overridden
factories.add(TypeAdapters.JSON_ELEMENT_FACTORY);
factories.add(ObjectTypeAdapter.FACTORY);
// the excluder must precede all adapters that handle user-defined types
factories.add(excluder);
// user's type adapters
factories.addAll(typeAdapterFactories);
If you want to use Object.class, you have to cast the result to either a primitive wrapper, null, or a List<E> or Map<K,V> -- and make some sort of analysis yourself. The rationale behind it is that you must know the result class in advance to make sure you're getting a proper deserialized object.
The best thing you can do here is making your custom parent super-type (does not really matter if it's a class or an interface), say class Message extends Base and class RoomDetail extends Base, and then registering a JsonDeserializer<Base> implementation to a GsonBuilder which can attempt to detect the real type of the Base instance. After that you can do:
gson.fromJson(jsonSource, Base.class);
See more:
Polymorphic objects deserialization:
How to parse dynamic json in android with retrofit 2 using annotations
How do I parse a nested JSON array of object with a custom Gson deserializer?
Json response parser for Array or Object
Google Gson extras, never been published as artifacts, but may be an inspiration point for you:
https://github.com/google/gson/blob/master/extras/src/main/java/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.java
If you do not know the type of the JSON you want to parse you could use the JsonParser from the Gson lib to parse the JSON instead of the Gson class directly. e.g.
JsonParser parser = new JsonParser(jsonFromString);
JsonObject obj = parser.parse().getAsJsonObject();
You could then look at the properties of the JsonObject you have created to see what it is. e.g.
if (obj.has("somePropertyNameIKnownIsAMemberOfRoomDetail")) {
RoomDetail roomDetail = gson.fromJson(jsonFromString, RoomDetail.class);
} else {
Message message = gson.fromJson(jsonFromString, Message.class);
}

Is there some way for a Jackson Delegate-based Creator to access the raw Json String?

Is there some way for a Jackson Delegate-based creator to access the raw Json String?
#JsonCreator
private static MyClass createFromJson(Map<String, Object> jsonProperties) {
return new MyClass(rawJson);
}
I am able to get the raw input as a Map of Strings to Objects in the code above, but I want to be able to access the json as a string. I tried the code below (based off of http://www.cowtowncoder.com/blog/archives/2011/07/entry_457.html) but that code as written is never invoked.
#JsonCreator
private static MyClass createFromJson(String rawJson) {
return new MyClass(rawJson);
}
Note: This is a spring boot application (1.3.1.RELEASE) that uses Jackson 2.6.4.
Looks like this type of functionality would not make sense in this context. In fact, it appears to me now that requesting the JSON string in this instance defeats the purpose of using jackson in the first place. However if anyone finds themselves here, then the comments from Sotirios Delimanolis may be useful:
"Hack: you can receive a JsonNode as the parameter type and use its toString method to get the corresponding JSON."
"It looks like you want a JsonDeserializer"

SpEL Cannot Be Cast to Map

Having read the documentation on "Inline Maps" for Spring Expression Language, I am passing an object to a SpelExpressionParser and .toString()ing the Object, so to speak; however, in doing so, I am receiving the following error:
org.springframework.expression.spel.standard.SpelExpression cannot be
cast to java.util.Map
The Object passed to as the argument to the .parseExpression function is the result of the annotation #PreAuthorize("hasPermission(#object, {name: 'roofus', animal: 'dog'}) "affixed" to a method.
Through the PermissionEvaluator interface implementation, it is passed in its Object form to a method:
private boolean doSomething (Object animal) { //....
Within this method is found an #Autowired SpelExpressionEvaluator. This is used in the following way:
Map animalMap = (Map) parser.parseExpression(animal.toString());
Through debugging, I know that the .toString() method results in: {name=roofus, animal=dog}
Resulting in the aforementioned error. Am I missing something? The goal is to be able to pass in a "JSON"-esque String (as specified by the linked documentation) for evaluation purposes.
Your problem that parser.parseExpression can't return Map independently of circumstances .
Looks like you misunderstood the architecture a bit. The SpelParser is for building Expression object from the the String. After that you can evaluate that expression using one of its getValue() method.
So, only after the evaluation you can get your Map object:
Expression expression = parser.parseExpression("{name: 'roofus', animal: 'dog'}");
Map map = expression.getValue(Map.class);
animal is already a Map (notice the formatting in the OP of the .toString() result) and not in the correct format expected by the parser. In this case, you don't even need the parser if the objective is to retrieve information from the Map:
((Map<String, String>)animal).get("animal")
So, in response to the solution proposed by Artem Bilan, this would actually work:
Map animalMap = (Map) parser.parseExpression("{name: 'roofus', animal: 'dog'}").getValue();
However, again, what is actually received (and the cause of the problem in the OP) is: parser.parseExpression("{name=roofus, animal=dog}")

Weird behaviour of GSON

I'm using Google's JSON library called Gson in one of my project.
I have a code for converting JSON String into object using GSON. I have following method to do that:
public static <T> ApiResponse<T> fromJson(String json)
{
return new Gson().fromJson(json, new TypeToken<ApiResponse<T>>() {}.getType());
}
And it seems to work fine when I do something like that:
ApiResponse<List<JobModel>> response = ApiResponse.fromJson(new String(bytes));
OR
ApiResponse<Double> response = ApiResponse.fromJson(new String(bytes));
But when I try do this:
ApiResponse<JobModel> response = ApiResponse.fromJson(new String(bytes));
Where JobModel is my own class I get the following error:
com.google.gson.internal.LinkedTreeMap cannot be cast to com.pcf.api.model.JobModel
So then I went and implemented another method in ApiResponse:
public static <T> ApiResponse<T> fromJson(String json, TypeToken<ApiResponse<T>> token)
{
return new Gson().fromJson(json, token.getType());
}
And this time call it using function above:
ApiResponse<JobModel> response = ApiResponse.fromJson(new String(bytes), new TypeToken<ApiResponse<JobModel>>() {});
It seems to work fine.
I just can't get my head around this as two functions do exactly same thing. The only difference is that in first it purely relies on Java's generics where in second one I pass TypeToken as a parameter.
Can anyone explain me why is that happening and is there any way to fix it ?
A TypeToken is kind of a hack with generics. It depends on subclassing the type, either with an anonymous or normal class, and using Class#getGenericSuperclass() which states
If the superclass is a parameterized type, the Type object returned
must accurately reflect the actual type parameters used in the source
code.
In other words, in an anonymous class declaration like this
new TypeToken<ApiResponse<T>>() {}.getType())
the superclass is TypeToken<ApiResponse<T>>. It's equivalent to
class Subclass extends TypeToken<ApiResponse<T>>
assuming T was in scope. So when you call Class#getGenericSuperclass(), it will return a ParameterizedType that knows about ApiReponse<T> since that is the actual type parameters used in the source code.
When you call your original function with any of
ApiResponse<List<JobModel>> response = ApiResponse.fromJson(new String(bytes));
ApiResponse<Double> response = ApiResponse.fromJson(new String(bytes));
ApiResponse<JobModel> response = ApiResponse.fromJson(new String(bytes));
although the compiler will infer and bind the corresponding type as a type argument to the method invocation, the internals of the method will pass the same TypeToken object with ApiResponse<T>. Since Gson doesn't know what T is, it will use a default that depends on what it sees in the JSON. If it sees an object, it will use a LinkedTreeMap. If it sees a numeric primitive, it will use the double. Etc.
In the case where you pass a TypeToken,
ApiResponse.fromJson(new String(bytes), new TypeToken<ApiResponse<JobModel>>() {});
it's equivalent to
class Subclass extends TypeToken<ApiResponse<JobModel>>
In other words, Class#getGenericSuperclass() will return a ParameterizedType that has ApiResponse<JobModel>. Gson can extract the JobModel and use it as a hint for deserializing the JSON.
Can anyone explain me why is that happening and is there any way to
fix it ?
There's nothing really to fix. That's just how it works.
Additional reading:
is it possible to use Gson.fromJson() to get ArrayList<ArrayList<String>>?
Gson TypeToken with dynamic ArrayList item type
how does the method infer the type of <T>
Generics work at compile-time,due to lack of reified Generics in Java (it isn't possible to do a T t = new T()), Gson itself is forced to use the TypeToken approach, as you see. Otherwise Gson would have done it in a much more elegant manner.

Categories