I'm using RestTemplate.getForObject() to retrieve json that includes a couple of objects and arrays, I only want to convert one of the objects inside this json to a POJO, I don't care about the other objects inside this json.
What is the proper way to approach this?
Edit:
Another approach from accepted answer, we can use jacksons ObjectMapper
#Autowired
private ObjectMapper jacksonObjectMapper;
then
LinkedHashMap obj1 = restTemplate.getForObject(uri, LinkedHashMap.class, params);
LinkedHashMap obj2 = (LinkedHashMap)test.get("flightStatuses");
Flight flight = jacksonObjectMapper.convertValue(obj2, Flight.class);
You get the idea, just get a generic datatype from your json structure then use ObjectMapper to convert it to the class you need.
One solution would be to create a wrapper class, which includes the POJO you want to deserialize and ignore all other properties using #JsonIgnoreProperties. You would then retrieve the wrapper object and get the POJO from it.
#JsonIgnoreProperties(ignoreUnknown=true)
public class Wrapper {
private MyPojo myPojo;
}
MyPojo myPojo = restTemplate.getForObject("url", Wrapper.class).getMyPojo();
Related
I am new to Springboot reactive
I was asked to call the following endpoint and return todays weather data only:
https://api.weather.gov/gridpoints/MLB/33,70/forecast
I believe I need to use something like this...
WebClient.create().get()
.uri("https://api.weather.gov/gridpoints/MLB/33,70/forecast")
.retrieve()
.bodyToMono(WeatherClass.class)
.block();
Do I need to map out an entire java object to match the JSON at the endpoint? is there an easy way to perhaps just grab the a certain piece of the JSON?
How would I handle something like the #context annotation in the JSON.
The WebClient in spring boot automatically uses Jackson's ObjectMapper to unmarshall json to a java object when the content type of the response is application/json. So there is no need to pull in any additional libraries or have to write any specific unmarshalling code, unless you want to use an alternate json-to-java library.
When using Jackson, you don't need to map every field in the json to your java object. You can annotate your java class with #JsonIgnoreProperties to inform jackson to ignore any properties that may appear in the json but do not have a matching field in your java object.
An example WeatherClass in which you want only the #context and forecastGenerator unmarshalled would look something like this
#JsonIgnoreProperties
public class WeatherClass {
private final List<Object> context;
private final WeatherProperties weatherProperties;
public WeatherClass(#JsonProperty("#context") List<Object> context,
#JsonProperty("properties") WeatherProperties weatherProperties) {
this.context = context;
this.weatherProperties = weatherProperties;
}
private class WeatherProperties {
private final String forecastGenerator;
private WeatherProperties(#JsonProperty("forecastGenerator") String forecastGenerator) {
this.forecastGenerator = forecastGenerator;
}
}
}
Note
#context seems to be an array that can contain multiple types (both objects and strings in your example). I've used Object to work around this but obviously isn't the most graceful solution but should be adequate to demonstrate how Jackson works
Alternatively, you can unmarshall the response to a JsonNode, which you can then use to traverse the structure of the json without converting it to a java object. For example
String forecastGenerator = WebClient.create().get()
.uri("https://api.weather.gov/gridpoints/MLB/33,70/forecast")
.retrieve()
.bodyToMono(JsonNode.class)
.block().get("properties").get("forecastGenerator").toString()
There are many other annotations provided by Jackson that can used to define how the unmarshaller functions. Too many to cover here. See Jackson Deserialisation Annotations
I am working with Jersey Web services (2.23) and use POJO mapping for the JSON-to-Object mapping (Jersey-media-moxy). I created a class as follows:
public class DataPush {
public String asset;
public String timestamp;
public Map<String,String> aspects;
}
I expected that instances of this object have the following structure:
{"asset":"abc","timestamp":"xxx","aspects":[{"key":"sdfasd","value":"sdfsd"},{"key":"sdddfasd","value":"sdfddsd"}]}
Indeed, a further element "entry" is generated:
{"asset":"sdf","timestamp":"sdfsd","aspects":{"entry":[{"key":"sdfasd","value":"sdfsd"},{"key":"sdddfasd","value":"sdfddsd"}]}}
What is the most easiest way to get rid of the "entries" element?
I know I could write my own mapping, however I hope that there is a easy solution to manage this..
You can go to topic :
Jackson JSON – Converting JSON to Map on journaldev.com.
https://www.journaldev.com/2324/jackson-json-java-parser-api-example-tutorial
I'm trying to test a method with this signature:
#RequestMapping(value="/Employee/{id}", method=RequestMethod.PUT, consumes="application/json")
#Transactional
public #ResponseBody Map update(#PathVariable Integer id,
#RequestBody HashMap<String, Object> information) {
}
The problem is that MockMvc param attributes accept only String parameters, is there a way to pass a HashMap or an instance class object to the RequestBody as parameter?
When I try to pass a HashMap as a string, I get a MismatchException.
You need to use Jackson for this. The idea is to deserialize your objects (doesn't matter that it's HashMap) into JSON string and pass it into MockMvc.
Here is tutorial how to do that. Just search for TestClass there and take a look how it is used. Skip the unit testing of GET requests.
I'm facing a problem with Spring and restTemplate. I want to send an object (ListResponse) that contains a generic array. The defenition is as follow:
public class ListResponse<T> implements Serializable {
private long total;
private int page;
private int pageSize;
private T[] objects;
I send a request whith restTemplate.getForObject(). As a result I get an object of type ListResponse but the objects array contains an array of LinkedHashMaps instead of an array with objects of type T.
It seems like restTemplate can not convert the elements in the array to their correct type.
How can I make sure that I get an array of objects of type T back ?
I had this problem today and here is the solution that I came up with (actually, that one of my co-workers suggested). We use it with an interface that returns List<MyDto>.
When you call the RestTemplate, don't pass in the generic type.
Define: public class MyDtoListTemplate extends ListTemplate<MyDto>
Then, call
MyDtoListTemplate template = restTemplate.getForObject("url", MyDtoListTemplate .class, mapOfPathVariables);
It's a bummer that you have to define a concrete class that extends/implements the generic type, but then the generic information is available to the jackson deserializer.
I remember I was able to deserialize generic classes with Jackson 2. I had to add MappingJackson2HttpMessageConverter converter to RestTemplate before making any Http calls with it.
RestTemplate template = new RestTemplate();
template.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
Unfortunately there's no easy way of doing it that I know of. The problem is that the RestTemplate is told which object type to expect. As long as all the fields in this object has a corresponding element in the json/xml, everything works fine. In the case of generics, the serializer doesn't know which class to expect so it just turns the map it gets to a java Map.
You will have the same problem if you tried to getForObject for a generic return type.
Is there any way to force Gson to ignore any sort of parsing exception (just skip that field ) ?
Depending on the field you are looking for, you COULD just not serialize that object. For example:
public class test{
String somString;
Map<String,String> thisValueThrowsTheError;
Int somInt;
}
If you wanted to just IGNORE the Map object, you could do that like this:
public class test{
String somString;
#SerializeName("NOTAVALIDJSONOBJECTNAME")
Map<String,String> thisValueThrowsTheError;
Int somInt;
}
Gson won't see a name for that Map and it will skip that object.
Alternately (and ultimately the better solution) is just use a Deserializer to fix the issue that you have correctly. See this post as an example of a deserializer:
Gson deserialization - Trying to parse a JSON to an Object