Spring Boot Modify Default JSON response - java

I have a REST controller that returns a list of products like so:
Current output
[
{
"id":1,
"name":"Money market"
},
{
"id":2,
"name":"Certificate of Deposit"
},
{
"id":3,
"name":"Personal Savings"
}
]
In order to get things working with our JS grid library, I need the modify the response to look like:
Desired output
{ "data" :
[
{
"id":1,
"name":"Money market"
},
{
"id":2,
"name":"Certificate of Deposit"
},
{
"id":3,
"name":"Personal Savings"
}
]
}
Controller
#RequestMapping(value = "/api/products", method = RequestMethod.GET)
public ResponseEntity<?> getAllProducts() {
List<Product> result = productService.findAll();
return ResponseEntity.ok(result);
}
Is there an easy way to modify the JSON response using native Spring libraries?

You can put result object into a Map with key "data" and value as result.
map.put("data", result);
Then return the map object from the rest method.
return ResponseEntity.ok(map);

Using org.json library:
JSONObject json = new JSONObject();
json.put("data", result);
The put methods add or replace values in an object.

Related

GroupBy in Webflux

I am getting the response in java using the following code
List<Dto> Dtos = myConsignmentDao.fetchMyData(myConsignmentRequest);
if(!Dtos.isEmpty()){
List<MyConsignmentData> myDetails = Dtos.stream()
.collect(Collectors.groupingBy(Dto::getConsignmentNumber))
.entrySet().stream()
.map(myConsData -> getMyData(myConsData))
.collect(Collectors.toList());
myResponse.setMyConsignments(myDetails);
myResponse.setMyConsignments(myDetails);
return myResponse;
}
}
And My response is
{
"myNumber": [
{
"Number": "12345",
"consignmentItems": [
{
"ItemNumber": "678954",
"deliveryDate": "2021-01-05 09:09:53+00"
}
],
"emailAddress": "myresult#gmail.com",
"mobileNumber": "+91377383",
"partyType": "Receiver",
"creationDate": "2020-12-29"
}
I have written code using flux
Flux<MtDto> myDtos = myDao.fetchMyData(myConsignmentRequest);
myDtos.groupBy(MyConsignmentsDto::getConsignmentNumber).collectList();
Because of this I am getting only root object fields i.e myNumber, mobileNumber, email address not itemNumber and delivery date can someone help me write code using webflux.

Dynamic Response from Retrofit Json to Gson Android Kotlin/Java

I have dynamic json format from rest API like this :
{
"data": {
"response_code": "success",
"value": {
"Table": [
{
"id": 5,
"username": "blahblah",
"password": "blahblah",
"role": 2,
"email": "blah#tes.com",
"tanggal_buat": "2019-01-01T00:00:00"
}
]
}
},
"meta": {
"http_status": 200
}
}
Object "value" has an object array name "Table". Table can contain value from my database dynamically depend on my query. So, Sometimes the json format will change for example :
{
"data": {
"response_code": "success",
"value": {
"Table": [
{
"id_product": 44,
"product": "blahblah",
"lot": "blahblah",
"qty": 2,
}
]
}
},
"meta": {
"http_status": 200
}
}
How to accept the json value and assign to gson directly with different subclass of "Table"
I try it in retrofit and using kotlin
override fun onResponse(call: Call<MainResp>, response: Response<MainResp>) {
mainResponse : MainResp = response.body()
}
Assuming that you have the following class among others (using sth like http://www.jsonschema2pojo.org/):
class Value {
List<Table> tables;
}
The "Table" class here cannot be completely random!
You'll need to define the possible types of "Table" e.g. Table1, Table2... TableN.
Now you can update Value class with a generic type T instead of Table and write your custom type adapter:
class Value {
List<T> tables;
}
One of the tutorials on how to write your own type adapter is here.

Mapping response JSON to DTO in Spring

I have API which returns JSON in this format:
{
"response": {
"GeoObjectCollection": {
"featureMember": [
{
"GeoObject": {
"Point": {
"pos": "37.611347 55.760241"
}
}
},
{
"GeoObject": {
"Point": {
"pos": "37.593965 55.771575"
}
}
}
]
}
}
}
I want to convert this JSON object to the DTO model in Spring Boot App. How can I do that?
I need to create classes like response, GeoObjectCollection, GeoObject etc, or it's all made easier?
My app structure contains services, model, controllers.

How do I get the url of the image tag in Java?

The ImageUrl is:
The JsonObject:
{
"type":"table",
"subtype":"attribute_list",
"doc":"https://api-v2.swissunihockey.ch/api/doc/attribute_list",
"data":{
"context":null,
"headers":[
{
"text":"Name",
"key":"teamname",
"long":"Name",
"short":"Name",
"prefer":"fit"
},
{
"text":"Logo",
"key":"logo_url",
"long":"Logo",
"short":"Logo",
"prefer":"fit"
},
{
"text":"Webseite",
"key":"website_url",
"long":"Webseite",
"short":"Webseite",
"prefer":"fit"
},
{
"text":"Teamportrait",
"key":"portrait",
"long":"Teamportrait",
"short":"Teamportrait",
"prefer":"fit"
},
{
"text":"Liga",
"key":"liga",
"long":"Liga",
"short":"Liga",
"prefer":"fit"
},
{
"text":"Anschrift",
"key":"address",
"long":"Anschrift",
"short":"Anschrift",
"prefer":"fit"
}
],
"title":"MR Krauchthal II",
"subtitle":null,
"tabs":[
],
"slider":null,
"regions":[
{
"text":null,
"rows":[
{
"highlight":false,
"cells":[
{
"text":[
"MR Krauchthal II"
]
},
{
"image":{
"alt":"",
"url":"https://res.cloudinary.com/swiss-unihockey/image/upload/t_club_logo/gin0rst7ocrcuioryacs.png"
}
},
{
"url":{
"href":null,
"text":"Webseite"
}
},
{
"image":{
"alt":"",
"url":null
}
},
{
"text":[
"4. Liga"
]
},
{
"text":[
"MR Krauchthal",
"Thomas"
]
}
]
}
]
}
]
}
}
What you need is a JSON parser. There are several libraries you can use for that like Jackson or Gson.
Here some basic Json handling with Gson:
JsonObject json = new JsonParser().parse(myJsonString).getAsJsonObject(); // will parse your string to json and return it as a JsonObject
JsonObject data = json.get("data").getAsJsonObject(); // returns the jsonObject that contains everything in "data":{...}
JsonArray regions = data.get("regions").getAsJsonArray(); // to get an array like "regions"
for(int i=0;i<regions.size();i++){ // loop through the array
JsonObject region = regions.get(i).getAsJsonObject(); // get any element in the array (as JsonObject)
String text= region.get("text").getAsString(); // get a JsonElement from your JsonObject and read it as a String (like "text")
}
it does not seem very "clean" or "easy" and other Json libraries will do this differently, but I would recommend this way if you don't want the whole "data" object to be parsed in a POJO. All you have to do now is, use the methods I showed you to walk through your json until you get the "url" or any other element you want.

How to set http header in Json response

I've a CXF RESTful service which returns both XML and Json format. I need to add a custom http header in the RESTful service. Here's a sample code snippet.
#GET
#Path("/test")
#Produces("application/xml")
public Response test(
#QueryParam("p") String var
{
TestRequest req = new TestRequest();
req.setVar(var);
TestResponse res = p.getData(req);
return Response.ok(res).header("Result", res.getResult()).build();
}
The above code shows the XML response which sets the custom http header "Result". I'm able to see the new http header in the response header. So far so good.
Now, here's the Json version which internally calls the testService() method to get the result, then use google Gson API to send the result back. This has been working well, till I decided to return the new header. Here's the code snippet.
#GET
#Path("/test/jsonp")
public String testJSONP(
#QueryParam("p") String var,
#QueryParam("cb") String callBack
{
Response resp = test(var);
XStream xs = new XStream(new JsonHierarchicalStreamDriver());
xs.setMode(XStream.NO_REFERENCES);
xs.alias("TestResponse", TestResponse.class);
StringBuilder sb = new StringBuilder();
sb.append(callBack);
sb.append("(");
GsonBuilder gb = new GsonBuilder();
gb.registerTypeAdapter(XMLGregorianCalendar.class, new XMLGregorianCalenderSerializer());
gb.setPrettyPrinting();
Gson gson = gb.create();
sb.append(gson.toJson(resp));
sb.append(")");
return sb.toString();
}
I'm not able to see the http header in Json response.
Any feedback will be highly appreciated.
-Thanks
UPDATE
I added the following code in Json method for my testing.
#GET
#Path("/test/jsonp")
public String testJSONP(
#QueryParam("p") String var,
#QueryParam("cb") String callBack
{
Response resp = test(var);
XStream xs = new XStream(new JsonHierarchicalStreamDriver());
xs.setMode(XStream.NO_REFERENCES);
xs.alias("TestResponse", TestResponse.class);
StringBuilder sb = new StringBuilder();
sb.append(callBack);
sb.append("(");
GsonBuilder gb = new GsonBuilder();
gb.registerTypeAdapter(XMLGregorianCalendar.class, new XMLGregorianCalenderSerializer());
gb.setPrettyPrinting();
Gson gson = gb.create();
sb.append(gson.toJson(resp));
sb.append(")");
return Response.ok(sb.toString(), MediaType.APPLICATION_JSON).header("Result", "50").build();
}
This sets the header value correctly,but the issue is the Json response format seems to have changed. Since this is an existing service, I'm not allowed to do that.
Here's the existing response format
null({
"status": "Completed",
"totalResult": "252",
"bin": [
{
"type": "source",
"value": "documentation",
"ndocs": "243"
},
{
"type": "source",
"value": "wikihelp",
"ndocs": "6"
},
"entries": {
"item": [
{
"url": "http://test.com/test.htm",
"title": "\u003cspan class\u003d\"vivbold qt0\"\u003eXREF\u003c/span\u003e",
"snippet": " Test data.",
"source": "documentation",
"type": "html",
"shortDescription": "Starts the TEST command.",
"category": [
"User"
],
"publishDate": "2012-02-05T12:00:00-0500",
"lastUpdateDate": "2012-03-14T12:00:00-0400",
"topicId": "GUID-7DD70C3C-B8AD-40F1-8A69-5D1EECEAB013"
}
]
}
})
Here's the response after adding this change
null({
"status": 200,
"entity": {
"status": "Completed",
"totalResult": "252",
"bin": [
{
"type": "source",
"value": "documentation",
"ndocs": "243"
},
{
"type": "source",
"value": "wikihelp",
"ndocs": "6"
}
],
"entries": {
"item": [
{
"url": "http://test.com/test.htm",
"title": "\u003cspan class\u003d\"vivbold qt0\"\u003eXREF\u003c/span\u003e",
"snippet": " Test data.",
"source": "documentation",
"type": "html",
"shortDescription": "Starts the TEST command.",
"category": [
"User"
],
"publishDate": "2012-02-05T12:00:00-0800",
"lastUpdateDate": "2012-03-14T12:00:00-0700",
"topicId": "GUID-7DD70C3C-B8AD-40F1-8A69-5D1EECEAB013"
}
]
}
},
"metadata": {
"Result": {
}
}
})
You need to change signature of your method, to return an instance of Response class, instead of a String, and then built the response manually.
From the CXF wiki page:
#Path("/example")
public ExampleResource {
#GET
public Response getSomething() {
return Response.ok(/* some entity */).header("CustomHeader", "CustomValue").build();
}
}
Update
You can also inject HttpServletResponse into your handler using #Context annotation like this:
#Path("/example")
public class Welcome {
#GET
public String getSomething(
#QueryParam("p1") String param1,
#QueryParam("p2") String param2,
#Context HttpServletResponse response) {
response.addHeader("CustomHeader", "CustomValue");
return "my awesome response";
}
}
Note, that there is a CXF-1498 bug in versions prior to 2.1 that causes HttpServletResponse not being injected, so you need a newer CXF version.

Categories

Resources