my first post here. I'm working on a API and i found a trouble that i don´t know how to solve it.
I´m trying to get the remaining stock of all products in my database. I´m using Spring boot and MongoDB with the Spring Data dependency.
Here is my code:
#GetMapping("/remaining-stock")
public ResponseEntity<List<Pair<String, Integer>>> showAllStock() throws EmptyDepositException{
List<Pair<String, Integer>> allStock;
try {
allStock = depServ.showAllStock();
}catch(EmptyDepositException ex) {
allStock = null;
}
return ResponseEntity.ok(allStock);
}
When i do that GET request, this is the JSON i get:
[
{
"first": "Water",
"second": 5
},
{
"first": "Milk",
"second": 40
}
]
The values are OK but i want to rename the variables names with a better name like this:
[
{
"Product name": "Water",
"Remaining stock": 5
},
{
"Product name": "Milk",
"Remaining stock": 40
}
]
There is a way to do that?
Sorry for my english, i'm from Argentina so maybe something is not clear. I hope you can help me.
Thank you all in advance.
You can use #JsonProperty annotation which indicates that the field name is used as the property name without any modifications, but it can be specified to non-empty value to specify different name. Property name refers to name used externally, as the field name in JSON objects.
public class Product implements Serializable {
#JsonProperty("Product name")
private String first;
#JsonProperty("Remaining stock")
private long second;
// implement methods for getters and setters
}
With Pair Class, you can't do that. I suggest you to create a DTO class like below :
public class CustomPair {
#JsonProperty("Product name")
private String first;
#JsonProperty("Remaining stock")
private String second;
// standard getters and setters
}
Then your controller will be like this :
#GetMapping("/remaining-stock")
public ResponseEntity<List<CustomPair>> showAllStock() throws EmptyDepositException{
List<CustomPair> allStock;
try {
allStock = depServ.showAllStock(); // depServ.showAllStock(); should return List<CustomPair>
}catch(EmptyDepositException ex) {
allStock = null;
}
return ResponseEntity.ok(allStock);
}
Related
I can see heaps of these sorts of questions but looking through them I'm struggling to find the answer and have already spent a couple days on this issue. Could use some direction for deserializing a response I am receiving to pull the required fields into an iterable.
API: https://statsapi.web.nhl.com/api/v1/schedule?teamId=55&startDate=2022-10-01&endDate=2023-04-21
Problem for me is there are multiple levels here and I'm concerned the nested lists might be an issue. Trying to grab lower level objects continues to return a null for me. This is the example json (full output above).
{
"copyright" : "",
...
"metaData" : {
"timeStamp" : "20220723_234058"
},
"wait" : 10,
"dates" : [ {
"date" : "2022-10-12",
...
"games" : [ {
"gamePk" : 2022020009,
...
"status" : {
"abstractGameState" : "Preview",
...
},
"teams" : {
"away" : {
"leagueRecord" : {
"wins" : 0,
...
},
"score" : 0,
"team" : {
"id" : 55,
"name" : "Seattle Kraken",
"link" : "/api/v1/teams/55"
}
},
"home" : {
"leagueRecord" : {
"wins" : 0,
...
},
"score" : 0,
"team" : {
"id" : 24,
"name" : "Anaheim Ducks",
"link" : "/api/v1/teams/24"
}
}
},
"venue" : {
"id" : 5046,
"name" : "Honda Center",
"link" : "/api/v1/venues/5046"
},
"content" : {
"link" : "/api/v1/game/2022020009/content"
}
} ],
"events" : [ ],
"matches" : [ ]
}, ...
I started by just trying to slice it up on my controller for testing but going beyond the 'games' level it just starts returning null for everything. Dates were fairly easy enough to get but the actual team names just resulted in everything being returned as null.
#GetMapping("/test")
#ResponseBody
public ArrayList<String> teamSchedule(#RequestParam int team) throws JsonProcessingException {
String nhlScheduleAPI = "https://statsapi.web.nhl.com/api/v1/schedule?teamId=";
String nhlScheduleRange = "&startDate=2022-10-01&endDate=2023-04-21";
String teamScheduleURL = nhlScheduleAPI + team + nhlScheduleRange;
RestTemplate restTemplate = new RestTemplate();
JsonNode data = restTemplate.getForObject(teamScheduleURL, JsonNode.class);
ArrayList<String> dates = new ArrayList<>();
data.forEach(game -> {
dates.add(data.get("dates").toString());
});
return dates;
I've started to create a PoJo class but a bit overwhelmed by the number of fields and sub-classes being used. I am attempting to rebuild a schedule app that I previously created in Python/Django but struggling to sanitize the data from the api. I'm only needing three items for each of the 82 games.
[<date>, <home_team>, <away_team>]
Is there an easier way to do this? Really appreciate any guidance here.
If you inspect the Json node structure correctly you would access the dates like this:
JsonNode data = restTemplate.getForObject(teamScheduleURL, JsonNode.class);
data = data.get("dates");
ArrayList<String> dates = new ArrayList<>();
data.forEach(d -> {
dates.add(d.get("date").toString());
});
return dates;
For the sake of others who may be in need of learning Json with Java/Spring, or more specifically parsing the NHL API, I am adding my solution below. It likely isn't the best way to achieve a reduced list of games but it works. The problem I was having through this was not having a good understanding of how Java classes map to nested json objects.
SchedulePOjO
#JsonIgnoreProperties
public class SchedulePOjO {
private ArrayList<DatesPOjO> dates;
// Getters and Setters
}
DatesPOjO
#JsonIgnoreProperties
public class DatesPOjO {
private ArrayList<GamesPOjO> games;
public ArrayList<GamesPOjO> getGames() {
return games;
// Getters and Setters
}
GamesPOjO
#JsonIgnoreProperties
public class GamesPOjO {
private String gameDate;
private TeamsPOjO teams;
// Getters and Setters
}
TeamsPOjO
#JsonIgnoreProperties
public class TeamsPOjO {
private AwayPOjO away;
private HomePOjO home;
// Getters and Setters
}
AwayPOjO
#JsonIgnoreProperties
public class AwayPOjO {
private TeamPOjO team;
// Getters and Setters
}
TeamPOjO
#JsonIgnoreProperties
public class TeamPOjO {
private int id;
private String name;
private String link;
// Getters and Setters
}
ScheduleController
#GetMapping("/test")
#ResponseBody
public SchedulePOjO teamSchedule(#RequestParam int team) throws JsonProcessingException {
// construct url
String nhlScheduleAPI = "https://statsapi.web.nhl.com/api/v1/schedule?teamId=";
String nhlScheduleRange = "&startDate=2022-10-01&endDate=2023-04-21";
String teamScheduleURL = nhlScheduleAPI + team + nhlScheduleRange;
// collect data
RestTemplate restTemplate = new RestTemplate();
SchedulePOjO schedulePOjO = restTemplate.getForObject(teamScheduleURL, SchedulePOjO.class);
return schedulePOjO;
I'm using a pageable object to return an object ResponseDto which contains a list of record
the object is in this form:
public class ResponseDto{
private String prop1;
private String prop2;
private List<NestedDto> nestedDto;
}
i can get with 2 different queries both Page<ResponseDto> and List<NestedDto> but i have to get inside the pageable content and update it to create the nested object.
EDIT: More info
so in what i'm doing is:
Page<ResponseDto> response = repository.findRecord()
and
List<NestedDto> nested = otherRepository.findNestedRecord(someProp)
so it will be something like this
for(ResponseDto el: response.getContent()){
el.setNestedDto(otherRepository.findNestedRecord(el.getSomeProp));
}
Is there a more efficient way to create this?
I guess you haven't done anything wrong with this implementation.
{
"prop1": "anyProp1",
"prop2": "anyProp2",
"nestedDto": [
{
"attr1": "anyAttr1",
"attr2": "anyAttr2"
},
{
"attr1": "anyAttr1"
"attr2": "anyAttr2"
}
]
}
Maybe naming can change but it is pseudo so it is not important.
Also you can sort and filter by (nestedDto.attr1 or nestedDto.attr2)
I have to send a batch of instructions in JSON data format as below:
{
"batchId": "123456",
"instructions": [ {
"instructionId": "1",
"customer": {
"iban": "abc",
"name": "abc"
}
},
"instructionId": "2",
"customer": {
"iban": "abc",
"name": "abc"
}
}
.
.
.
.. . . ..
]
}
Now, i will fetch multiple records/instructions from the database via query, which I will use to generate the JSON data-set as per the format above.
What I have researched: I have traversed many solutions and thought of my own that I shall create an object class of Instruction mapping with setters and getters. I shall use a loop through each record and set values of object fields from database via setter and add entry that complete object entry to JSON via getters.
I will continue this approach until the records are read completely.
My question is: Is this solution efficient and best one to deal with such requirement or any other suggestion?
Please suggest? Any sort of code snippet or help is appreciated.
You can use com.google.gson for that.
Create the Instruction object and then add the fields and annotate the field with SerializedName if you are mapping a different json name to your java field(E.g. instruction_id to instructionId).
import com.google.gson.annotations.SerializedName;
import java.util.List;
import java.util.Map;
public class Instruction {
#SerializedName("instructionId")
private String instructionId;
#SerializedName("customer")
private List<Map<String, Object>> customer;
public String getInstructionId() {
return instructionId;
}
public void setInstructionId(String instructionId) {
this.instructionId = instructionId;
}
public List<Map<String, Object>> getCustomer() {
return customer;
}
public void setCustomer(List<Map<String, Object>> customer) {
this.customer = customer;
}
}
And then you can map your json to your instruction class.
Instruction instruction = new GsonBuilder()
.setPrettyPrinting()
.create()
.fromJson(json, Instruction.class);
My resource is
#GET
#Path("/items")
public MyCollection<Items> getItems()throws Exception{
//Code to return MyCollection<items>
}
My Item class is
#XmlRootElement
public class Item{
private int id;
private String name;
//Have getters and Setters.
}
And My collection class is Generic as below.
public class MyCollection<T> extends MyBaseCollection{
private java.util.Collection<T> items;
private int count;
}
When i try to generate doc using enunciate. The sample Json has only the item and count and the fields of Item class is not getting reflected.
My sample Json generated is
{
"items" : [ {
}, {
}, {
}, {
}, {
}, {
}, {
}, {
} ],
"count" : ...,
}
How to get id,name inside the Item in the generated sample Json?
Thanks.
This is a limitation that i have run into as well, there is no way to specify #TypeHint on a nested object. To support documentation, consider creating a custom collection that defines "items" as a collection of specific class instead of generic.
If you have an idea of how you would want this to work (using the generic type) I suggest submitting enhancement request to Enunciate team.
I have a similar problem where I am returning a Map and I can't #TypeHint this.
I was given json file and third party class:Dealer and interface IDealerAttributes (I can not change either of them);
(I remove package name and imports to make the code simple)
JSON file
{
"serviceURL": "com.mycompany.serviceURL",
"dealerAttributes": [
{
"language": "language0",
"dealerAttributeName": "dealerAttributeName0",
"updateDate": 0
},
{
"language": "language1",
"dealerAttributeName": "dealerAttributeName1",
"updateDate": 1
}
]
}
class Dealer {
private String serviceURL;
private List dealerAttributes;
public Dealer() {
dealerAttributes = new ArrayList();
}
//Getters and Setters...
}
public interface IDealerAttributes {
public String getLanguage();
public String getDealerAttributeName();
public long getUpdateDate();
}
once I use:
gson.fromJson(jsonObj.toString(), Dealer.class);
I will get exception from this line:
Exception unmarshalling json String into Object: com.google.gson.JsonParseException: The JsonDeserializer com.google.gson.DefaultTypeAdapters$CollectionTypeAdapter#60e26ffd failed to deserialize json object [{"language":"language0","dealerAttributeName":"dealerAttributeName0","updateDate":0},{"language":"language1","dealerAttributeName":"dealerAttributeName1","updateDate":1}] given the type java.util.List
How can I read this json file based on Dealer.class, IDealerAttributes?
But I can add one class, let's say:
public class DealerAttributes implements IDealerAttributes {
private String language;
private String dealerAttributeName;
private long updateDate;
public DealerAttributes() {
}
//Getters and Setters...
}
Since I am new to json/gson, would you please give detailed instruction to help me out? Thanks.
[added]
Consider if there are 100 fields in Dealer class, and there are another 100 interface used/nested in Dealer. I am thinking whether anyone have experience using this way: (MyType is interface)
gson.registerTypeAdapter(MyType.class, new MyType());`
You could map it to a List of Maps and then use a BeanMapper like http://code.google.com/p/orika/ to get some more informative error messages