Reading a list in another object from a restTemplate response - java

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?

Related

Deserialize two different JSON representations into one object

I have Java class like
#Data
public class Comment {
private Integer id; // should be used anyhow
private Long refId; // for internal purpose -> not be serialized
private String text; // should be used in QuickComment
private String patch; // should be included in PatchComment ONLY
private String status; // should be included in StatusComment ONLY
}
and I have
#Data
public class Response{
private Comment statusComment;
private Comment patchComment;
}
I thought about using JsonView like
public class Views{
public interface StatusComment{}
public interface PatchComment{}
}
and apply them to the inital class
#Data
public class Comment {
#JsonView({Views.StatusComment.class, Views.PatchComment.class})
private Integer id; // should be used anyhow
private Long refId; // for internal purpose -> not be serialized
#JsonView({Views.StatusComment.class, Views.PatchComment.class})
private String text; // should be used anyhow
#JsonView(Views.PatchComment.class)
private String patch; // should be included in PatchComment ONLY
#JsonView(Views.StatusComment.class)
private String status; // should be included in StatusComment ONLY
}
and the Response
#Data
public class Response{
#JsonView(Views.StatusComment.class)
private Comment statusComment;
#JsonView(Views.PatchComment.class)
private Comment patchComment;
}
But somehow it fails completely. It fails completly, ie. nothing is filtered. Is it problem with Lombok. Or is it defined incorrect?
How do you serialize your objects? Are you using Spring? Are you using the ObjectMapper directly?
If you're using Spring then what you need to do is annotate method of your controllers with #JsonView(Views.StatusComment.class) or #JsonView(Views.PatchComment.class) like:
For reading GET endpoints
#JsonView(Views.StatusComment.class)
#RequestMapping("/comments/{id}")
public Comment getStatusComments(#PathVariable int id) {
return statusService.getStatuscommentById(id);
}
For writing:
#RequestMapping(value = "/persons", consumes = APPLICATION_JSON_VALUE, method = RequestMethod.POST)
public Comment saveStatusComment(#JsonView(View.StatusComment.class) #RequestBody Comment c) {
return statusService.saveStatusComment(c);
}
If you're using the ObjectMapper directly, then what you need to do is specify the used View:
When writing:
ObjectMapper mapper = new ObjectMapper();
String result = mapper
.writerWithView(Views.StatusComment.class)
.writeValueAsString(comment);
When reading:
ObjectMapper mapper = new ObjectMapper();
Comment comment = mapper
.readerWithView(Views.StatusComment.class)
.forType(Comment.class)
.readValue(json);

How to get an arrayJSON in webService Rest?

I am developing a WEb Service Rest in java, netbeans.
This is the JSON I want to receive:
{
"ticket":"2132158645161654561651616",
"avaliacoes":[
{
"id":1,
"nome":"Atendimento",
"nota":5,
"observacoes":"testeTEste"
},
{
"id":2,
"nome":"Atendimento",
"nota":5,
"observacoes":"testeTEste"
}
]
}
Reception Class
#PUT
#Consumes(MediaType.APPLICATION_JSON)
#Path("venda/enviardados")
public String postVenda(#QueryParam("key") String key, #QueryParam("serial") String serial, VendaAvaliacao va) {
...
}
Entity Classes
public class VendaAvaliacao {
private int id;
private String ticket;
//private List<VendaAvaliacaoInner> avaliacoes = new ArrayList<>(); //I've tried it too
private VendaAvaliacaoInner[] teste;
}
public class VendaAvaliacaoInner {
private int id;
private String nome;
private int nota;
private String observacao;
}
The ticket is received and populated, but array = null.
I've read other similar topics but they did not help .... how can I do?
https://pt.stackoverflow.com/questions/6046/convers%C3%A3o-de-string-json-para-objeto-java?rq=1
https://pt.stackoverflow.com/questions/159725/receber-valor-de-array-json-para-string-java
https://pt.stackoverflow.com/questions/290759/como-obter-objetos-de-um-array-de-json-usando-jsonarray-no-java
Maybe the service REST you are consuming don't populate the data in the array.
As an advice i would work with List<T> rather than T[]
Also i see that you are mapping 3 properties in you object but the id property don't exist in raw JSON isn't it ?

Consuming RestTemplate API response

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.

Java object not populated from json request for inner class

Have searched in different sites but couldn't find correct answer, hence posting this request though it could possible duplicates.sorry for that.
I am sending the below json request to my back-end service and converting to java object for processing. I can see the request body passed to my service but when i convert from json to java object , values are not populating
{
"data":{
"username":"martin",
"customerId":1234567890,
"firstName":"john",
"lastName":"smith",
"password":"p#ssrr0rd##12",
"email":"john.smith#gmail.com",
"contactNumber":"0342323443",
"department":"sports",
"location":"texas",
"status":"unlocked",
"OrderConfigs":[
{
"vpnId":"N4234554R",
"serviceId":"connectNow",
"serviceType":"WRLIP",
"ipAddress":"10.101.10.3",
"fRoute":[
"10.255.253.0/30",
" 10.255.254.0/30"
],
"timeout":1800,
"mapId":"test_map"
}
]
}
}
My Parser class have something like,
JSONObject requestJSON = new JSONObject(requestBody).getJSONObject("data");
ObjectMapper mapper = new ObjectMapper();
final String jsonData = requestJSON.toString();
OrderDTO mappedObject= mapper.readValue(jsonData , OrderDTO .class);
// I can see value coming from front-end but not populating in the mappedObject
My OrderDTO.java
#JsonInclude(value = Include.NON_NULL)
#JsonIgnoreProperties(ignoreUnknown = true,value = {"hibernateLazyInitializer", "handler", "created"})
public class OrderDTO {
private String username;
private long customerId;
private String source;
private String firstName;
private String lastName;
private String email;
private String contactNumber;
private String password;
private String department;
private String location;
private String status;
private List<OrderConfig> OrderConfigs;
#JsonInclude(value = Include.NON_NULL)
public class OrderConfig {
private String vpnId;
private String serviceId;
private String serviceType;
private String ipAddress;
private String mapId;
private String[] fRoutes;
private Map<String, Object> attributes;
private SubConfig subConfig;
private String routeFlag;
getter/setters
.....
}
all setter/getter
}
Not sure what I'm missing here. Is this right way to do?
If your are trying to use inner class, correct way to use is to declare it static for Jackson to work with inner classes.
For reference check this
code changes made are
#JsonInclude(value = Include.NON_NULL)
#JsonIgnoreProperties(ignoreUnknown = true)
static class OrderConfig {
Make sure that your json tag names match with variable names of java object
Ex : "fRoute":[
"10.255.253.0/30",
" 10.255.254.0/30"
],
private String[] fRoutes;
OrderConfigs fields will not be initialized, just modify your bean as
#JsonProperty("OrderConfigs")
private List<OrderConfig> orderConfigs;
// setter and getter as setOrderConfigs / getOrderConfigs
See my answer here. (same issue)

Parsing JSON with Retrofit and GSON, error when trying to parse and obtain callback.

I am using to Retrofit to handle Calls to my API for an Android Application. I am trying to get Retrofit to handle the parsing of the JSON, and creating a list of Objects in accordance with the POJO i have created.
The error i receive is "com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected a string but was BEGIN_OBJECT at line 1 column 176".
I used JsonSchema2Pojo to generate my java classes. The classes and associated JSON are as follows.
{"status":"success","data":[{"sort_key":1,"event_id":1947357,"title":"2014 US Open Tennis Session 15 (Mens\/Womens Round of 16)","datetime_utc":"2014-09-01T15:00:00","venue":{"city":"Flushing","name":"Louis Armstrong Stadium","extended_address":"Flushing, NY 11368","url":"https:\/\/seatgeek.com\/venues\/louis-armstrong-stadium\/tickets\/?aid=10918","country":"US","display_location":"Flushing, NY","links":[],"slug":"louis-armstrong-stadium","state":"NY","score":0.73523,"postal_code":"11368","location":{"lat":40.7636,"lon":-73.83},"address":"1 Flushing Meadows Corona Park Road","timezone":"America\/New_York","id":2979},"images":["https:\/\/chairnerd.global.ssl.fastly.net\/images\/performers-landscape\/us-open-tennis-45e2d9\/5702\/huge.jpg","https:\/\/chairnerd.global.ssl.fastly.net\/images\/performers\/5702\/us-open-tennis-c1ccf7\/medium.jpg","https:\/\/chairnerd.global.ssl.fastly.net\/images\/performers\/5702\/us-open-tennis-01f513\/large.jpg","https:\/\/chairnerd.global.ssl.fastly.net\/images\/performers\/5702\/us-open-tennis-4e07f2\/small.jpg"]}
From this i believe i need to generate 3 POJO's, my higher level "EventObject" Class, A Location Class, and a Venue Class. These classes and their variables follow:
EventObject Class:
public class EventObject {
private Integer sortKey;
private Integer eventId;
private String title;
private String datetimeUtc;
private Venue venue;
private List<String> images = new ArrayList<String>();
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
Location Class:
public class Location {
private Float lat;
private Float lon;
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
Venue Class:
public class Venue {
private String city;
private String name;
private String extendedAddress;
private String url;
private String country;
private String displayLocation;
private List<Object> links = new ArrayList<Object>();
private String slug;
private String state;
private Float score;
private String postalCode;
private Location location;
private String address;
private String timezone;
private Integer id;
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
My interface for the Api Call is as follows:
public interface UserEvents {
#GET("/user/get_events")
void getEvents(#Header("Authorization")String token_id,
#Query("event_type")String event_type,
#Query("postal_code")int postalCode,
#Query("per_page") int perPage ,
#Query("lat") int lat,
#Query("lon") int lon,
#Query("month")int month,
#Query("page")int page,
Callback<List<EventObject>>callback) ;
}
Here is its implementation in my code :
UserEvents mUserEvents = mRestAdapter.create(UserEvents.class);
mUserEvents.getEvents(token_Id, "sports",11209,25,0, 0, 9, 2, new Callback <List<EventObject>>() {
#Override
public void success(List<EventObject> eventObjects, retrofit.client.Response response) {
Log.d(TAG,"Success");
}
There is alot going on here, but i believe that i am probably going wrong with how i am handling the JSON. When i copied and pasted in my JSON to the Pojo generator, i did not include "status:success, " data:{
I essentially just used the entire entry of an element in the Array ( everything from {sort_key onward until the next sort key ) and pushed that through the converter.
This is my first try at Retrofit and API work, and parsing anything this complicated.
I am hoping its something that someone else will be able to point out. I have googled as well i could to sort this out with no luck.
Thanks for looking.
The main problem is that you are not getting the root element of the response. You need to create an entity "response" that gets the items status and data. It would look something like this:
public class RootObject {
#Expose
private String status;
#Expose
private EventObject data;
//getters and setters here
}
Then when you make the callback you should point to your RootObject, mUserEvents.getEvents(token_Id, "sports",11209,25,0, 0, 9, 2, new Callback <RootObject>()
One more thing, Retrofit uses GSON to parse your json reponse. It means that when you create the entities, the variables need to match the name of the objects coming in the response. If it doesn't you need to tell GSON how to map the variables, like this:
#SerializedName("extended_address")
#Expose
private String extendedAddress;
In that case the value coming in the json is "extended_address" and will be mapped to the String extendedAddress. If you don't put that #SerializedName line the parsing will fail. If you want to skip that line then you can call your variable "extended_address" so it matches the response.
The #Expose is needed by GSON to parse the variable below it. If a variable doesn't have it then GSON will ignore that parsing. So you need to fix both the #Expose and #SerializedName on your entities so GSON works correctly.
Hope it helps.

Categories