Passing json "data" array in Retrofit 2 - gson

I'm trying retrofit 2 for the first time and I have no idea how to tell it to get "Category" objects from an jsonarray named "data".
Method 1
If I do it like this it fails:
#GET("category")
Call<List<Category>> listCategories();
Method 2
But when I make a new model, called "Categories", which holds a List and is annotated with #SerializedName("data"), it works flawlessly.
#GET("category")
Call<Categories> listCategories();
My Question
Should I annotate something in the interface, like this
#GET("category")
#Annotation to look inside "data"
Call<List<Category>> listCategories();
Or should I annotate my "Category" model to tell Retrofit (or GSON)
that it lives inside the json array "data"?
JSON
{"data":[{"id":1,"name":"Fist Name","parent":0},{"id":2,"name":"Second Name","parent":1}]}

Method 2 Is correct and we use it when we dont want to use/define the json response object/arrays key names(field names). instead provide our own. Eg. In below code List object name is items but while Serialization and Deserialization it uses, what you have defined in #SerializedName annotation that is data.
public class Categories {
//solution 1
List<Category> data;//object name must match with the json response
//solution 2
#SerializedName("data")
List<Category> items;
}
Should I annotate something in the interface
No. There is no such annotation available and everything you can do is only in Response type class.

Related

Decompose incoming JSON to Objects by fields with Spring MVC

I need to decompose my incoming JSON by fields in me REST Controller with Spring Boot.
My request body:
{
"text": "my text",
"myEnum": "VALUE1"
}
And my controller:
#PatchMapping("/{id}")
Object updateEntity(#PathVariable Long id, String text, MyEnum myEnum) {
/* ... */
}
#RequestParam doesn't work because it's just for query string params, #RequestBody doesn't work too because it handle whole body. But I need decompose incoming body by fields and inject into controller. I know what I can use Map <String, String> for this, but I would like validate my incoming fields, and I have the fields with difference types. And I don't want to create one class by incoming body for each controller.
If I haven't misunderstood your requirement, the usual way to deal with incoming JSON is to define a class that reflects your expected input, and make that the controller method parameter annotated as RequestBody.
Spring Boot, by default, uses Jackson to deserialize to your class, and so if you use matching property names then you won't need any special annotations or setup. I think enums will be handled by default, as are other types (though you may need to provide some guidance for strings representing dates or timestamps). Any bad value will fail deserialisation, which I think you can handle in ControllerAdvice (though you'll want to double check that)

Deserialize nested Kotlin object in springMVC

I'm trying to deserialize a complex GET request into a structure of nested objects.
The GET requests looks like:
curl 'localhost:8080/?id=1&inner.id=1'
and the code should look like this:
class RootObj(val id: Int, inner: InnerObject)
class InnerObject(val id: Int)
#RestController
class SearchController {
#GetMapping(path = ["/"])
fun getRoot(rootObj: RootObj): String {
return "ok"
}
}
This doesn't work out of the box I guess because spring doesn't know how properly create this nested structure.
Parameter specified as non-null is null: [...] parameter inner","path":"/"}%
Is there a way to overcome this problem? Maybe providing a totally custom deserializer code?
As alternative solution, I guess I could flatten the object hierarchy but for doing so I must be able to map a query parameter like inner.id to a field named innerId
Spring can actually map the query params to the custom object directly, but you need to provide defaults to the params of the custom object constructor.
So you need to define your classes as below for it to work
class RootObj(val id: Int = 0, val inner: InnerObject = InnerObject(0))
class InnerObject(var id: Int = 0)
Do note that the id field of InnerObject would have to be declared as var for Spring to be able to map it. Then curl 'localhost:8080/?id=1&inner.id=1' would work fine.

Custom serializer with django 2

I would like to create a serializer that given an input JSON object select certain attributes.
There is an legacy system that sends an object, for example:
{
"a": {
"b": "test"
}
}
I need to keep certain properties of the object. For example a.b. I have created the following serializer, but it is not working:
class CustomSerializer(serializers.Serializer):
b = serializers.CharField(source='a.b', required=True)
Does anyone know what is failing?
Thanks!
You need to implement nested serializer. For your example, you can try something like this :
class BSerializer(serializers.Serializer):
b = serializers.CharField()
class ASerializer(serializers.Serializer):
a = BSerializer()
Note : this is just an example of nested serializer. You might need to add few things to make it work properly for you (adding Meta, other fields if needed, use it in view etc. )

Spring Data Rest Mongo - how to create a DBRef using an id instead of a URI?

I have the following entity, that references another entity.
class Foo {
String id;
String name supplierName;
**#DBRef** TemplateSchema templateSchema;
...
}
I want to be able to use the following JSON (or similar) to create a new entity.
{
"supplierName": "Stormkind",
"templateSchema": "572878138b749120341e6cbf"
}
...but it looks like Spring forces you to use a URI like this:
{
"supplierName": "Stormkind",
"templateSchema": "/template-schema/572878138b749120341e6cbf"
}
Is there a way to create the DBRef by posting an ID instead of a URI?
Thanks!
In REST, the only form of ID's that exist are URIs (hence the name Unique Resource Identifier). Something like 572878138b749120341e6cbf does not identify a resource, /template-schema/572878138b749120341e6cbf does.
On the HTTP level, entities do not exist, only resources identified by URIs. That's why Spring Data REST expects you to use URIs as identifiers.

What is the difference between Collections from casted from a HashMap over entryset() and casted ArrayList for Jackson?

I am developing a Spring Rest application. One of my methods is that:
#RequestMapping(method = RequestMethod.GET)
public #ResponseBody
Collection<Configuration> getConfigurationInJSON() {
Collection<Configuration> confList = new ArrayList<Configuration>();
...
I fill my confList and send it for GET request, it works. However when I want to keep that confList in a HashMap and send it after got it's entrySet as like that:
#RequestMapping(method = RequestMethod.GET)
public
#ResponseBody
Collection<Configuration> getAllConfigurationsInJSON() {
return configurationMap.values();
}
It gives me 406 error, so it means there is a wrong. What are the differences between that collections and why the second one is not same with first example?
For the sake of simplicity, can you just copy the values() collection?
new ArrayList<Configuration>(configurationMap.values());
Only thing that comes to my mind is that Spring expects mutable collection, but don't really understand why. Hard to say without debugging, try enabling org.springframework.web full logging.
The obvious difference is that configurationMap.values() is a Set.
You need to check if the JSON marshaller expects a List to be returned and is not able to marshal Set instances, as the marshaller will check the actual type of the returned value instead of the declared return type of the method, which is Collection.
By the way, isn't there any clue in the logs about this ?

Resources