avaje / avaje-inject

Dependency injection via APT (source code generation) ala "Server-Side Dagger DI"
https://avaje.io/inject
Apache License 2.0
240 stars 24 forks source link

Need Json Deserializers for collections #33

Closed NitishBangera closed 5 years ago

NitishBangera commented 5 years ago

In my controller, I am posting List of a Pojo. The route that is created is of ctx.bodyAsClass(List.class). Hence, it doesn't deserialize the Pojos as the values are in LinkedHashMap.

java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to <Pojo>

Currently I am accepting the data as Object and then converting it using Gson to the appropriate Collection of Pojos that the Api requires.

rbygrave commented 5 years ago

What does the generated code that would work look like? What should be used instead of ctx.bodyAsClass ?

NitishBangera commented 5 years ago

Hello @rbygrave,

Thank you for your reply. Well in my opinion, rather than having bodyAsClass; it should be bodyAsType(needs to be included in Context) and the Type can be from the TypeToken of Gson if we include Gson as the base deserializer. Of course, this is only true for Content-Type: application/json.

rbygrave commented 5 years ago

But bodyAsType() does not exist. If you want that you'll have to get that added to Javalin.

Note that it probably does not exist because generally the expectation is that the top level content of a POST is an object and not an array.

I think you need to log an issue with Javalin and see if you can get that added ... or POST an object and not an array.

NitishBangera commented 5 years ago

Hello @rbygrave Well the top level can be Object but what I am proposing is generic deserialization to a specific type built in the framework for Collections. Currently, the support is for normal POJOs but if we have a Collection of Children within that Pojo, it won't work.

Well I have raised a question in Javalin here https://github.com/tipsy/javalin/issues/737.

NitishBangera commented 5 years ago

Hello @rbygrave ,

Javalin folks have updated with the following which can be included in DInject as well to fulfill the requirement.

app.before(ctx -> ctx.register(MyMapper.class, new MyMapper(ctx));
app.get("/", ctx -> ctx.use(MyMapper.class).bodyAsType(type)); // use MyMapper to deserialize object

MyMapper is something we can think of registering for custom serialization and deserialization.

rbygrave commented 5 years ago

but if we have a Collection of Children within that Pojo, it won't work.

Yes it does? We do that all the time. I'm not sure what you think doesn't work there.

deserialization to a specific type built in the framework for Collections

As far as I am concerned that is not a good thing to do. It is not recommended to post a collection (json array) as the top level of a body content. As far as I am concerned that is something to be avoided - it provides no way to evolve an API and would be considered not good form.

NitishBangera commented 5 years ago

@rbygrave It's not what I think. It's what I have implemented and my code fails mentioning that LinkedHashMap cannot be deserialized to a POJO when its List. Hence as I have mentioned, I take the List or any collection as Object and deserialize manually. Thank you for your inputs on this issue.