Consuming RestTemplate API response - java

I need same help. I have the POJO class, I need to consume the starwar API, take the result and transform it into objects.
#JsonIgnoreProperties(ignoreUnknown = true)
public class Planeta {
private String name;
private String climate;
private String terrain;
Getters and Setters...
Application.java
package hello;
#SpringBootApplication
public class Application {
private static final Logger log = LoggerFactory.getLogger(Application.class);
public static void main(String args[]) {
SpringApplication.run(Application.class);
}
#Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.build();
}
#Bean
public CommandLineRunner run(RestTemplate restTemplate) throws Exception {
return args -> {
Planeta planeta = restTemplate.getForObject("http://localhost:8080/planeta/name/terra", Planeta.class);
log.info(planeta.getName());
};
}
}
for some reason I'm getting null values.
The url api result is
{"data":[{"id":"5c378401c0ac520ffc670019","name":"terra","climate":"tropical","terrain":"earth"}],"erros":null}
logs
Application : Planeta [name=null, climate=null, terrain=null]
edited;

The JSON response doesn't match to you POJO, response is JSONObject with JsonArray (key = "data") and array consists of Planeta objects
#JsonIgnoreProperties(ignoreUnknown = true)
public class Response{
#JsonProperty("data")
List<Planeta> data;
}
If you have only one Planeta object in List,
Planeta p = data.stream().findFirst().get();
System.out.println(p.getName());
If you have multiple objects in List
for each
for(Planeta p :data) {
System.out.println(p.getName());
// same for climate and terrain
}
java-8
data.forEach(planeta-> System.out.println(planeta.getName()));

The API is returning an object with key data, inside which there is an array of planets not one. You are expecting just one, without the data field. The JSON doesn't match your expected Planeta class.

Related

Reading a list in another object from a restTemplate response

I have gone through some of the questions here and their answers like this one which tells us how to extract a list of objects from a restTemplate response. It does not, however, solve my problem which is, I have an Entry class
#JsonIgnoreProperties(ignoreUnknown = true)
public class Entry {
private String API;
private String Description;
private String Auth;
private boolean HTTPS;
private String Cors;
private String Link;
private String Category;
// getters and setters
}
then I have an Entry implementation class which has
#JsonIgnoreProperties(ignoreUnknown = true)
public class EntryImpl {
private Long count;
private ArrayList<Entry> entries;
public EntryImpl () {
}
// getters and setters
}
and here is my request implementation to consume this api
public class RestConsump {
public static void main (String [] args) {
RestTemplate restTemplate = new RestTemplate();
String url = "https://api.publicapis.org/entries";
EntryImpl entries = restTemplate.getForObject(url, EntryImpl.class);
System.out.println(entries.getEntries().get(0)); // returns null for all entries
System.out.println(entries.getCount()); // prints the numbers of entries
}
}
My question is, how do I implement it so that EntryImpl returns the list of entries and the count.
I executed the code above and got this response:
{API=AdoptAPet, Description=Resource to help get pets adopted, Auth=apiKey, HTTPS=true, Cors=yes, Link=https://www.adoptapet.com/public/apis/pet_list.html, Category=Animals}
1417
I used spring-web:5.3.8 for the RestTemplate, java version 15. Perhaps you are using an outdated RestTemplate?

Multiple DTOs manual initialize

in Microservice, we post multiple dtos data as string json.
Controller:
#RequestMapping(value="/json",method = RequestMethod.POST)
public String getjson(#RequestBody String json) {
///Service process
}
Post Json:
{
"dtos":{
"Dto1":{
"name":"Dto1 Name Field",
"filter":[
{"key":"f1","value":1},
{"key":"f2","value":10}
]
},
"Dto2":{
"city":"Newyork",
"filter":[
{"key":"f1","value":1},
{"key":"f2","value":10},
{"key":"f3","value":10}
]
}
},
"page":1
}
DTO:
public class Dto1{
private String name;
}
public class Dto2{
private String city;
}
Dto1 and Dto2 is java DTO object name.
how to convert string json to java objects?
You can create a new DTO that contains all attrs and receive in request:
public class Filter{
private String key;
private int value;
}
public class Dto1{
private String name;
private List<Filter> filter;
}
public class Dto2{
private String city;
private List<Filter> filter;
}
public class Dtos{
public Dto1 dto1;
public Dto2 dto2;
}
public class DtoToReceiveInRequest{
private Dtos dtos;
private int page;
}
Controller
#PostMapping
public String getjson(#RequestBody DtoToReceiveInRequest json) {
///Service process
}
You can use the ObjectMapper from the jackson library, like below.
String json = "";
ObjectMapper objectMapper = new ObjectMapper();
Dto1 dto = objectMapper.readValue(json, Dto1.class);
But in your particular example, you don't have to have two DTO classes. You can encapsulate values in one DTO and have the list of different instances of that DTO in a json format.
NB. The json string should be a representation of the preferred class you want to retrieve, eg Dto1.java.

How to change JSON key from camelCase to snake case for POJO?

I am doing testing with Wiremock and I have following example for POJO:
#Data
public class DataResponse {
private Supply supply;
private static class Supply {
private List<TimeSeries> timeSeries;
}
#JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
public static class TimeSeries {
private LocalDate date;
}
}
And I am stubbing some external API which should response with this POJO as json:
DataResponse dataResponse = DataResponse.builder()
.supply(DataResponse.Supply.builder()
.timeSeries(List.of(
DataResponse.TimeSeries.builder()
.date("2021-11-16")
build()
))
.build()
.build()
String jsonDataResponse = mapper.writeValueAsString(dataResponse); //mapper is instance of ObjectMapper
stubFor(WireMock.get(urlEqualTo("/someUrl"))
.willReturn(aResponse()
.withBody(jsonDataResponse)));
The issue is when I do serialization with ObjectMapper I get "timeSeries" instead of "time_series". Is there any way to get the right JSON string format only with changes in the test file?
timeSeries is field of Supply, you should change place of #JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class), move to Supply class like below
#Data
public class DataResponse {
private Supply supply;
#JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
private static class Supply {
private List<TimeSeries> timeSeries;
}
public static class TimeSeries {
private LocalDate date;
}
}

Using #JsonCreator to create two instances of same class in one JSON DTO

I would like to deserialize JSON of this structure:
{
"employee_pricing_type":"COMPUTE_BY_OWN_RATE",
"employee_rate":10,
"customer_pricing_type":"COMPUTE_BY_OWN_RATE",
"customer_rate":200
}
I have such POJO to create price setting from a HTTP request:
public class ObjectPricingSetting {
#JsonProperty("pricing_type") // describes output
private final ObjectPricingType pricingType;
#JsonProperty("own_rate") // describes output
private final BigDecimal ownRate;
public ObjectPricingSetting(final ObjectPricingType pricingType, final BigDecimal ownRate) {
AssertUtils.notNull(pricingType, "pricingType");
this.pricingType = pricingType;
if (ownRate != null) {
AssertUtils.isGtZero(ownRate, "ownRate");
this.ownRate = ownRate;
} else {
this.ownRate = null;
}
}
public ObjectPricingType getPricingType() {
return pricingType;
}
public BigDecimal getOwnRate() {
return ownRate;
}
}
this is DTO:
#JsonInclude(JsonInclude.Include.NON_NULL)
public class ObjectPricingCommand extends BaseDto<ObjectId> {
#JsonProperty(value = "employee_pricing_setting")
private ObjectPricingSetting employeePricingSetting;
#JsonProperty(value = "customer_pricing_setting")
private ObjectPricingSetting customerPricingSetting;
}
I would like to create these two instances of ObjectPricingSetting with #JsonCreator.
Q: How should I anotate #JsonProperty parameter in ObjectPricingSetting constructor to recognize what JSON value should use to create these two instances?
You can use #JsonUnwrapped with a prefix in your parent class:
#JsonInclude(JsonInclude.Include.NON_NULL)
public class ObjectPricingCommand extends BaseDto<ObjectId> {
#JsonUnwrapped(prefix = "employee_")
private ObjectPricingSetting employeePricingSetting;
#JsonUnwrapped(prefix = "customer_")
private ObjectPricingSetting customerPricingSetting;
}
Then you can use the normal #JsonCreator/#JsonProperty in your nested DTO, without the prefix:
public class ObjectPricingSetting {
#JsonCreator
public ObjectPricingSetting(
#JsonProperty("pricing_type") final ObjectPricingType pricingType,
#JsonProperty("rate") final BigDecimal ownRate) {
...

Why are some of the variables in POJO equal to null after converting JSON RESTful Webservice?

I am consuming a RESTful webservice that returns a JSON payload. I can successfully consume the RESTful webservice and manage to populate some of the POJO attributes with JSON data. However, some other attributes are null when they are supposed to contain a value. How can I ensure that there are no more nulls?
I have defined 4 POJO classes. I have so far debugged by systematically by testing the variables for each class. This is using Springboot 2.2.0 and Jackson-databind.
The JSON schema I am trying to consume:
{
"items":[
{
"timestamp":"2019-09-18T16:42:54.203Z",
"carpark_data":[
{
"total_lots":"string",
"lot_type":"string",
"lots_available":"string"
}
]
}
]
}
For the above, I defined 4 classes:
public class Response {
#JsonProperty
private List<items> i;
#JsonIgnoreProperties(ignoreUnknown = true)
public class items {
private String timestamp;
private List<carpark_data> cpd;
#JsonIgnoreProperties(ignoreUnknown = true)
public class carpark_data {
private List<carpark_info> cpi;
private String carpark_number;
private String update_datetime;
#JsonIgnoreProperties(ignoreUnknown = true)
public class carpark_info {
private int total_lots;
private String lot_type;
private int lots_available;
When I run the below in Spring boot Main: I get null. Is my POJO modeling OK?
Response resp = restTemplate.getForObject("")
c = resp.getItems().get(0).getCarpark_data().get(0);
log.info("The last update time for the car park data = " +
c.getUpdateDatetime());
Your model does not fit to JSON payload. If we assume that JSON payload has a structure like below:
{
"items": [
{
"timestamp": "2019-09-18T16:42:54.203Z",
"carpark_data": [
{
"total_lots": "1000",
"lot_type": "string",
"lots_available": "800"
}
]
}
]
}
We can deserialise it as below:
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.File;
import java.util.List;
public class JsonApp {
public static void main(String[] args) throws Exception {
File jsonFile = new File("./resource/test.json").getAbsoluteFile();
ObjectMapper mapper = new ObjectMapper();
Response response = mapper.readValue(jsonFile, Response.class);
System.out.println(response.getItems().get(0).getData().get(0));
}
}
class Response {
private List<Item> items;
//getters, setters, toString
}
class Item {
private String timestamp;
#JsonProperty("carpark_data")
private List<CarParkInfo> data;
//getters, setters, toString
}
class CarParkInfo {
#JsonProperty("total_lots")
private int totalLots;
#JsonProperty("lot_type")
private String lotType;
#JsonProperty("lots_available")
private int lotsAvailable;
//getters, setters, toString
}
Above code prints:
CarParkInfo{totalLots=1000, lotType='string', lotsAvailable=800}
Hope you find the solution.
It is in POJO, you need to check the fieldName and object structure.
Seeing the Json above, your response model returns list of items and in each item you have list of carpark_data. So, basic modelling should be like this. And you can include respective setter and getter.
public class Response {
#JsonProperty
private List<items> items;
#JsonIgnoreProperties(ignoreUnknown = true)
public class items {
private String timestamp;
private List<carpark_data> carpark_data;
#JsonIgnoreProperties(ignoreUnknown = true)
public class carpark_data {
private int total_lots;
private String lot_type;
private int lots_available;
}
You need to have fields name in POJO class same in the Json response or you can set JsonProperty for that field. Like this
#JsonProperty("items")
private List<items> i;
#JsonProperty("carpark_data")
private List<carpark_data> cpd;

Categories