Generics and JSON - java

I am using the Play framework.
I want to use the function renderJSON with 2 Objects as an argument. It doesn't seem to be possible so I am trying to create a class that contains the 2 objects. In order not to have to create a new class everytime, I want to use Generics but it doesn't seem to work:
Model :
public class JSONContainer<T> extends Model {
private T myT;
private StatusMessage mySm;
public JSONContainer(T myT, StatusMessage mySm) {
this.myT = myT;
this.mySm = mySm;
}
}
and then :
In a function of a Controller:
JSONContainer<User> myJ = new JSONContainer(logged,sm);
renderJSON(myJ);
where logged is a User, sm is a StatusMessage. I get the error:
type: 'play.exceptions.JavaExecutionException'
If I don't use Generics, it works fine. Any idea?
The console gives this output, where the line 43 is:
JSONContainer<User> myJ = new JSONContainer(logged,sm);

Generic entities can't be mapped by Hibernate.
You should do the generic class abstract and create specific implementations (using User and any other possible values of T). This should solve the issue

Instead of using a JSONContainer like I did, I think the best way is to go with Collection as shown in this user guide for GSON made by Google (the JSON mapper used by Play apparently) at http://sites.google.com/site/gson/gson-user-guide#TOC-Collections-Examples:
Collection collection = new ArrayList();
collection.add(logged);
collection.add(sm);
renderJSON(collection);
Collection are good for serializing (Java object to JSON) but not good for deserializing (see the GSON user guide for more insight).
It is better, IMHO, to use Collection than JSONContainer as JSONContainer are not useful in that case and don't give more possibilities.

Related

Can you rename a variable in a generic Class?

I have got a Class PagedResult. The class is there to help me realize a JSON output with different objects in a pages format. The E is the object, that is wrapped in the List. It works all fine, but one thing still bothers me. I would like that the list with the objects does not always get the same name. I would like to adapt the name to the corresponding objects.
Class PagedResult:
public class PagedResult<E> {
Long totalItems;
Integer totalPages;
Integer currentPage;
List<E> elements;
[... Getter & Setter ...]
}
The actual JSON Output with an Object like MyPojo looks like this:
{
"totalItems": 2,
"totalPages": 1,
"currentPage": 1,
"elements": [
{
"myPojoAttr1": "hello",
"myPojoAttr2": "there"
},
{
"myPojoAttr1": "hello",
"myPojoAttr2": "folks"
}
]
}
So for each response, no matter which objects, the array is namend as "elements". I don´t want the ugly name in my JSON response, because of the changing objects in the PagedResult-class. When I get a response with objects like MyPojo the name of the JSON-Array should be "myPojos" and when I want to get a response with objects like MyWin the name "myWins".
I tried alot with #JsonProperty, but I can´t find a way, to do this "object-array-name" also generic. Can someone assist me with the problem please? Thanks in advance.
No. You can't do that. Generic types have parameters for types, not for identifiers. AFAIK, nothing in the Java language allows you to treat a Java identifier as a parameter when producing a type. (Certainly, nothing you could use in this context!)
Alternatives:
Don't do it. (Take a good hard look at your reasons for wanting the JSON attribute name to vary. What does it actually achieve? Is it worth the effort?)
Don't use a generic type. Define a different class for each kind of "paged result". (Clunky. Not recommended.)
Use a map, and populate it with a different map key for the elements attribute of each kind of "paged result". (The disadvantage is that you lose static type checking, and take a small performance and storage penalty. But these are unlikely to be significant.)
Write a custom mapper to serialize and deserialize the PagedResult as per your requirements.
For what it is worth, identifiers as parameters is the kind of thing you could do with a macro pre-processor. That Java language doesn't have standard support for that kind of thing.
Yes it's possible, using custom serializers. But even with a custom serializer you still have a problem: Generics are removed at compile time. So we need to somehow get the type during runtime.
Here is an example that will just check the type of the first element in the elements list. Definietly not the cleanest way to do it, but you don't have to adjust your PagedResult class.
public class PagedResultSerializer<T> extends JsonSerializer<PagedResult<Object>> {
#Override
public void serialize(PagedResult<Object> value, JsonGenerator gen, SerializerProvider provider) throws IOException {
gen.writeStartObject();
gen.writeNumberField("totalItems", value.getTotalItems());
// Your other attributes
if (!value.getElements().isEmpty()) {
Object firstElement = value.getElements().get(0);
String elementsFieldName;
if (firstElement instanceof MyPojo) {
elementsFieldName = "myPojos";
} else if (firstElement instanceof MyWin) {
elementsFieldName = "myWins";
} else {
throw new IllegalArumentException("Unknown type");
}
serializers.defaultSerializeField(elementsFieldName, value.getElements(), gen);
}
gen.writeEndObject();
}
}
Now you just need to tell Jackson to use this serializer instead of the default one.
#JsonSerialize(using = PagedResultSerializer.class)
public class PagedResult<T> {
// Your code
}
Improvments: Add a Class<T> elementsType attribute to your PagedResult and use this attribute in your serializer instead of checking the first element in the list.
Another approach: use inheritance.
Have an abstract base class PagedResult that contains all the common fields, to then distinctively subclass it to PagedResultWithElements, PagedResultWithMyPojo and so on. And the subclasses contain just that "type" specific list.
As a drawback: you get some code duplication. But on the other side, you get quite more control over what happens without doing overly complicated (de)serialization based on custom code.
So, when you know the different flavors of "element types", and we talk say 3, max 5 different classes, using inheritance might be a viable solution.

ObjectMapper using TypeReference not working when passed type in generic method

This is the method:
protected <T> TestPageResult<T> getTestPageResutForRequest(MockHttpServletRequestBuilder request) throws Exception {
String responseJson = mockMvc.perform(request).andReturn().getResponse()
.getContentAsString();
TestPageResult<T> response = getObjectMapper().readValue(responseJson,
new TypeReference<TestPageResult<T>>() {
});
return response;
}
I call it like this:
TestPageResult<SomeDto> pageResult = this.<SomeDto>getTestPageResutForRequest(getRequest());
TestPageResult is:
protected static class TestPageResult<T> {
private List<T> items;
private long totalCount = -1;
public TestPageResult() {
}
//omitted getters and setters
}
The resulting pageResult.getItems() contains a List of LinkedHashMap instead of a list of SomeDto. If I were to just hardcode the SomeDto type in the objectMapper.readValue method I'd get the correct results.
What's the problem?
edit: The suggested duplicated did solve my problem - kind of.
I used:
JavaType type = getObjectMapper().getTypeFactory().constructParametricType(TestPageResult.class, clazz);
TestPageResult<T> response = getObjectMapper().readValue(responseJson, type);
Problem is there is no going around not passing down a Class argument to the method. So the method looks ugly due to both passing a generic type and the same thing as a Class. Obviously you can just not pass the generic now but this way a casting would be required and adding SuppressWarnings and so on.
The problem is erasure. All these <T> parameters don't exist in the compiled code, after they're erased. This means that source new TypeReference<TestPageResult<T>>() looks like new TypeReference<TestPageResult>() once compiled, which is not what you want. (Similar to how a List<String> ends up being a List in compiled code, and it's just compile-time validation that you don't add Integers to your String List.)
I think there's roughly two ways to deal with this (in this case), both of these you already stumbled upon:
Either you create a type that properly represents what you want, such as: new TypeReference<TestPageResult<SomeDto>>(), or class SomeDtoPageResult extends TestPageResult<SomeDto> which you can then use in places like readValue(..., SomeDtoPageResult.class);
Or you create a complete class representation, like you were doing with JavaType
What you really want won't work. Your best bet is to tinker and come up with the cleanest code that solves it. Generics let you express really elaborate structures, and when you serialize an actual instance (nested objects), that comes out just fine, but when the classes need to be introspected at runtime, e.g. for deserialization (your use case) or to build a model (e.g. to generate Swagger docs), this becomes problematic.

Complex object (de)serialization into JSON using GSON

I have a problem with serializing and deserializing my object structure with GSON. In order to describe the problem i'll have to describe my class structure a bit:
I have a java abstract class, let's name it "A". There are also classes "BA", "CA", "DA" that are abstract too and they extend class "A". Each of them has it's own constructor, non of which is non-arg. Finally there are several (many!) classes those extend "BC", or "CA" or "DA". Instances of those "bottom" classes are kept in "ArrayList" list.
Now, i'm trying to "jsonize" that array list. For creating Json string I'm using this code:
Gson gs = new Gson();
Type listOfTestObject = new TypeToken<List<A>>(){}.getType();
String rez = gs.toJson(getListOfAs(), listOfTestObject);
And i'm trying to deserialize that json using this (in another class):
Type listOfTestObject = new TypeToken<ArrayList<A>>(){}.getType();
ArrayList<A> listOfAs = gs.fromJson(jsonREZString, listOfTestObject);
but above code throws this:
Unable to invoke no-args constructor for class packagename.A. Register an InstanceCreator with Gson for this type may fix this problem.
Now, I have create a non-args constructor in the class "A", but no luck. I have read about "InstanceCreator" but it looks like I would have to create an "InstanceCreator" for each concrete class that extends "A"! Right? I can't do it, because I have many (many!) classes that extend "A" through "BA", "CA" or "DA".
What am I missing? How can I simply deserialize (serialization seems fine) this complex structure without adding custom deserialializastion code for each type?
In fact you might have here 2 distinct problems.
1) You have polymorphic types thus you probably want to serialize objects as their concrete type and not A.
2) You want to deserialize to the concrete types that do not provide no arg ctrs.
Gson does not support 1 & 2, there is an extension for 1 but I never used it.
Maybe Genson solves your problem, it supports both 1 & 2.
Genson genson = new Genson.Builder()
// enables polymorphic types support
.setWithClassMetadata(true)
// enables no arg support
.setWithDebugInfoPropertyNameResolver(true)
.create();
// will look like: [{"#class": "com.xxx.SomeConcreteClass", ...}, {"#class": "com.XXX.OtherClass"}]
String json = genson.serialize(getListOfAs());
List<A> listOfA = genson.deserialize(json, new GenericType<List<A>>() {});
You don't need to specify the type during serialization, except if you want that only parent fields be present in the output.
ex: genson.serialize(getListOfAs(), GenericType>() {}) will serialize only attributes from A, you can also force genson to always use runtime types by setting setUseRuntimeTypeForSerialization(true) on the builder.
Also if you don't want impl details to leak in the json representation, you can define aliases (builder.addAlias("someAlias", SomeClass.class) for your types, they will be used instead of full package+classname.

Creating mixins with CGLIB that implement a new interface

First off, I don't think this is necessarily a good idea, I'm just seeing if this is really possible. I could see some benefits, such as not having to explicitly convert to objects that we're sending to the client and using an interface to blacklist certain fields that are security concerns. I'm definitely not stuck on the idea, but I'd like to give it a try.
We're using Spring MVC + Jackson to generate JSON directly from objects. We have our domain object that contains necessary data to send to the client and we have a list of error strings that are added to every outgoing JSON request as needed.
So the return JSON might be something like
{ name: 'woohoo', location : 'wahoo', errors : ['foo'] }
Currently, we have a class that models what should be on the client side, but we always extend a common base class with the error methods.
So, we have:
interface NameAndLoc {
String getName();
String getLocation();
}
and
interface ResponseErrors {
List<String> getErrors();
void appendError(String);
}
We have two classes that implement these interfaces and would like to have CGLIB generate a new class the implements:
interface NameAndLocResponse extends NameAndLoc, ResponseErrors {}
Presently, with CGLIB mixins, I can generate an object with the following:
Object mish = Mixin.create(
new Class [] {NameAndLoc.class, ResponseErrors.class},
new Object [] { new NameAndLocImpl(), new ResponseErrorsImpl() } );
I could then cast the object to either NameAndLoc or ResponseErrors, however, what I would like to do is create an object that uses the same backing classes, but implements the NameAndLocResponse interface, without having to extend our common error handling class and then implement NameAndLoc.
If I attempt to cast with what I have, it errors out. I'm sure this is possible.
I think it is very similar to this, but not quite: http://www.jroller.com/melix/entry/alternative_to_delegate_pattern_with
Simply add the NameAndLocResponse interface to the Class array in the Mixin constructor as the last argument. The resulting object will implement it. You can find an example of this in this blog entry: http://mydailyjava.blogspot.no/2013/11/cglib-missing-manual.html

Java type conversion where types are not known until runtime

I'm trying to write a data access layer for an AJAX web project. This DAL has to convert data coming in via an AJAX servlet to objects that can be passed to a PreparedStatement for execution.
Data in the AJAX servlet, retrieved by using HttpServletRequest.getParameter(...), come in as strings.
In each data class, I have a known set of fields as well as their data types, e.g. CustomerId(integer), CustomerName(string).
I can of course write a method in the Customer class to handle the conversion, but this means I have to do it for every data object's class. I would much rather have a generic method that does conversion, e.g.
Object convert(String value, Class<?> targetType) { ... }
Can anyone point me in the right direction?
Create an utility class with all conversion methods you would like to use. Inside its static initializer, make use of reflection to collect all those methods by parameter type and return type in a map. Then, in the convert() method just pick the method which suits the given source and target type and invoke it. Make use of generics to fix the return type to be the same as the target type:
public static <T> T convert(Object from, Class<T> to)
You can find an example in this article.
But as bmargulies pointed out, JSON is also an interesting option. You could let ajax to send all parameters as one JSON string. Then, you can use a JSON-to-Javabean converter like Google Gson to convert the JSON string to a fullworthy Javabean like Customer. It'll be as simple as:
String jsondata = request.getParameter("jsondata");
Customer customer = new Gson().fromJson(jsondata, Customer.class);
// ...
See also this answer for another example.
There are JSON libraries that will do data type conversion. Jackson is one. Or, you could code the whole think using a JAX-RS service framework instead of a raw servlet, and it will take care of all this for you. Apache CXF is one framework that contains this support. Since you are asking for a generic solution, why not use one that's already out there.
We do this exact thing using a plethora of static converters in a utility class. It isn't elegant but it sure is easy and effective.
class Util {
public static Long StringToLong(String s) { ... }
public static Integer StringToInt(String s) { ... }
public static Date StringToDate(String s) { ... }
public static Date StringToDateYYMMDD(String s) { ... }
public static BigDecimal StringToBigDecimal(String s) { ... }
// etc ad naseum
}
Since you want to use the parameters in your PreparedStatement, why do you have to convert them at all?
When using setString(index, parameter) SQL will be happy to do the conversion for you.
Thus the only thing you might want to do is some kind of validation that the input is really valid (or you could even leave this part to your SQL engine which will throw an exception if it doesn't understand you.

Categories

Resources