#RequestBody Object does not deserialize automatically - java

I use Spring-boot 2.0.1 with WebFlux as Rest server.
In me RestController I would like to automatically deserialize an object (Product). But I get a Jackson error as if ParameterNamesModule was not registered.
Caused by:
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot
construct instance of com.truc.Product (no Creators, like default
construct, exist): cannot deserialize from Object value (no delegate-
or property-based Creator) at [Source: UNKNOWN; line: -1, column: -1]
at
com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67)
at
com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1451)
at
com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1027)
at
com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1290)
at
com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:326)
at
com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:159)
at
com.fasterxml.jackson.databind.ObjectReader._bind(ObjectReader.java:1574)
at
com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:965)
at
org.springframework.http.codec.json.AbstractJackson2Decoder.lambda$decodeInternal$0(AbstractJackson2Decoder.java:113)
... 287 common frames omitted
I have jackson-module-parameter-names in my pom
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-parameter-names</artifactId>
</dependency>
And this the route in RestController
#ResponseStatus(HttpStatus.CREATED)
#RequestMapping(method = RequestMethod.POST)
public Mono<Entity<Product>> postProduct(#RequestBody Product product) {
return productService.insert(product);
}
If I try to deserialize manually it works :
#Autowired
private ObjectMapper objectMapper;
...
#ResponseStatus(HttpStatus.CREATED)
#RequestMapping(method = RequestMethod.POST)
public Mono<Entity<Product>> postProduct(ServerWebExchange exchange) {
return exchange.getRequest().getBody()
.last().flatMap(buffer -> {
try {
Product product = objectMapper.readValue(buffer.asInputStream(), Product.class);
return productService.insert(product);
} catch (IOException e) {
throw new RuntimeException(e);
}
});
}
This is my Product.class
package com.truc;
import java.time.LocalDate; import java.util.Optional;
public final class Product {
public static final String PREFIX = "PT";
public final String description;
public final String shortDescription;
public final String sku;
public final float weight;
public final LocalDate newSince;
public final LocalDate newUntil;
public final Status status;
public final Visibility visibility;
public final String metaKeywords;
public Product(String description, String shortDescription, String sku, Float weight,
LocalDate newSince, LocalDate newUntil, Status status, Visibility visibility, String metaKeywords) {
this.description = description;
this.shortDescription = shortDescription;
this.sku = sku;
this.weight = Optional.ofNullable(weight).orElse(0f);
this.newSince = newSince;
this.newUntil = newUntil;
this.status = status;
this.visibility = visibility;
this.metaKeywords = metaKeywords;
}
public enum Status {
ACTIVE, INACTIVE
}
public enum Visibility {
FULL, CATALOG, SEARCH, NONE
}
}
If I understand #JsonCreator is not required after jackson-databind 2.9, I use jackson 2.9.5
If I add #JsonCreator I get a new error 415 Unsupported Content-Type 'application/json' ...
I don't understand where I'm wrong ?
Thanks

You have to add default constructor in your RequestBody class which is ProductClass then it will work

As explain here #EnableWebFlux deactivate all the webflux auto-configuration. And I use it in Configuration class without extend the class with WebFluxConfigurer.
When I remove #EnableWebFlux it work again, the ObjectMapper is configured as expected.
So it's ok
Thanks

Related

How to deserialize the generic response using Spring WebClient

I have a problem during the deserialization of a response. Let's suppose I have this response from third party using webclient .
Response :
{
"name":"FirstName",
"type":"Steel",
"Fee":{
"id":"1234",
"name":"FeeFirstName"
},
"address":"2nd Street"
}
This is how my pojo classes looks like
public class Fee{} //generic OR empty class
public class Foo{
private String name;
private String type;
private Fee fee;
private String address;
}
My webclient get response code :
#Autowired
private WebClient fooWebClient;
public Foo getFoo()
{
try{
return fooWebClient.get()
.uri(uriBuilder -> uriBuilder.path("/foo/fee").build("123"))
.header(HttpHeaders.CONTENT_TYPE,MediaType.APPLICATION_JSON_VALUE)
.accept(MediaType.APPLICATION_JSON)
.retrieve()
.bodyToMono(Foo.class)
.block();
}catch(Exception e){throw new ApiClientException(e.getMessage());}
}
The above webclient getFoo() code is not giving me the full response, the Fee is coming blank stating "Class has no fields". Rest of the values are coming properly in response.
Fee needs to be empty as any other object can also come.
Please let me know how to deserialize the whole response.
You don't need the Fee class, you can get rid of it entirely and use a Map instead:
public class Foo {
private String name;
private String type;
private Map<String, Object> fee;
private String address;
}
We cannot dynamically create POJO and hence we are left with two options.
Add necessary fields to the 'Fee' class (If you know Fee structure upfront)
If you are not sure about the 'Fee' structure go for Map.
Because spring integrates Jackson you can create a custom Jackson JSON Deserializer for the Fee class that gives you more control:
#JsonDeserialize(using = FeeDeserializer.class)
public class Fee {
private String id;
private String name;
public Fee(String id, String name) {
this.id = id;
this.name = name;
}
}
import com.fasterxml.jackson.*;
public class FeeDeserializer extends JsonDeserializer<Fee> {
#Override
public Fee deserialize(JsonParser jsonParser, DeserializationContext ctxt) throws IOException {
ObjectCodec codec = jsonParser.getCodec();
JsonNode tree = codec.readTree(jsonParser);
JsonNode id = tree.get("id");
JsonNode name = tree.get("name");
return (id != null && name != null) ? new Fee(id.asText(), name.asText()) : null;
}
}
For more details see
https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#features.json.jackson.custom-serializers-and-deserializers
https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html#webflux-codecs-jackson

Cannot deserialize instance of <DataModel> out of START_OBJECT token

I am facing with problem with Spring and Jackson. I was trying to fetch the input from this API. I've created Java model using http://www.jsonschema2pojo.org/
The model is
package io.github.mat3e.earthquake.jsonObject;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import java.util.List;
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"type",
"metadata",
"features",
"bbox"
})
public class DataModel {
#JsonProperty("type")
private String type;
#JsonProperty("metadata")
private Metadata metadata;
#JsonProperty("features")
private List<Feature> features = null;
#JsonProperty("bbox")
private List<Double> bbox = null;
#JsonProperty("type")
public String getType() {
return type;
}
#JsonProperty("type")
public void setType(String type) {
this.type = type;
}
#JsonProperty("metadata")
public Metadata getMetadata() {
return metadata;
}
#JsonProperty("metadata")
public void setMetadata(Metadata metadata) {
this.metadata = metadata;
}
#JsonProperty("features")
public List<Feature> getFeatures() {
return features;
}
#JsonProperty("features")
public void setFeatures(List<Feature> features) {
this.features = features;
}
#JsonProperty("bbox")
public List<Double> getBbox() {
return bbox;
}
#JsonProperty("bbox")
public void setBbox(List<Double> bbox) {
this.bbox = bbox;
}
}
Of course all dependencies (subclasses are appended in the same strture).
Code to fetch data from external API is;
#GetMapping("/3")
public String getCostam() {
RestTemplate rest = new RestTemplate();
ResponseEntity<DataModel[]> responseEntity = restTemplate.getForEntity(url2, DataModel[].class);
Object[] objects = responseEntity.getBody();
MediaType contentType = responseEntity.getHeaders().getContentType();
HttpStatus statusCode = responseEntity.getStatusCode();
return statusCode.toString();
}
When I run the code and I am trying to get for adress "api/3" following error occurs:
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `[Lio.github.DataModel;` out of START_OBJECT token
at [Source: (PushbackInputStream); line: 1, column: 1]
Thanks #Willem and #mkarasik for your help:
I made following changes in code
#GetMapping("/3")
public String getCostam() {
RestTemplate rest = new RestTemplate();
ResponseEntity<DataModel> responseEntity = restTemplate.getForEntity(url2, DataModel.class);
MediaType contentType = responseEntity.getHeaders().getContentType();
HttpStatus statusCode = responseEntity.getStatusCode();
System.out.println(responseEntity
.getBody().getFeatures());
return statusCode.toString();
}
To get an array of places where earthquake took place I just ovverided method in Feature class
#Override
public String toString() {
return properties.getPlace();
}
Thanks guys for you help. I got what I needed.
Now I want to map parameters from FrontEnd to provide it to my backend instead of hardcoded String.

Parse Json to object containing objects

I have the following code with json, that I got from accuweather
{
"Headline":{
"EffectiveDate":"2019-07-29T07:00:00+06:00",
"EffectiveEpochDate":1564362000,
"Severity":3,
"Text":"The heat wave will continue through Friday",
"Category":"heat",
"EndDate":"2019-08-02T19:00:00+06:00",
"EndEpochDate":1564750800
},
"DailyForecasts":[
{
"Date":"2019-07-29T07:00:00+06:00",
"EpochDate":1564362000,
"Temperature":{
"Minimum":{
"Value":19.1,
"Unit":"C",
"UnitType":17
},
"Maximum":{
"Value":36.7,
"Unit":"C",
"UnitType":17
}
},
"Day":{
"Icon":30,
"IconPhrase":"Hot",
"HasPrecipitation":false
},
"Night":{
"Icon":35,
"IconPhrase":"Partly cloudy",
"HasPrecipitation":false
},
"Sources":[
"AccuWeather"
]
}
]
}
I try to parse this object to the POJO via jackson
public static void main( String[] args )
{
String x = "{\"Headline\":{\"EffectiveDate\":\"2019-07-29T07:00:00+06:00\",\"EffectiveEpochDate\":1564362000,\"Severity\":3,\"Text\":\"The heat wave will continue through Friday\",\"Category\":\"heat\",\"EndDate\":\"2019-08-02T19:00:00+06:00\",\"EndEpochDate\":1564750800},\"DailyForecasts\":[{\"Date\":\"2019-07-29T07:00:00+06:00\",\"EpochDate\":1564362000,\"Temperature\":{\"Minimum\":{\"Value\":19.1,\"Unit\":\"C\",\"UnitType\":17},\"Maximum\":{\"Value\":36.7,\"Unit\":\"C\",\"UnitType\":17}},\"Day\":{\"Icon\":30,\"IconPhrase\":\"Hot\",\"HasPrecipitation\":false},\"Night\":{\"Icon\":35,\"IconPhrase\":\"Partly cloudy\",\"HasPrecipitation\":false},\"Sources\":[\"AccuWeather\"]}]}";
ObjectMapper objectMapper = new ObjectMapper();
try {
Weather weather = objectMapper.readValue(x, Weather.class);
System.out.println(weather);
} catch (IOException e) {
e.printStackTrace();
}
}
I have all the models specified in the json like Headline, array of DailyForecasts, Temperature that consists of TemperatureItems(named minimum and maximum as in json) and etc, all of them have private fields and public constructor, getters and setters. However I do not have some of the fields as I want to omit them(Day, Night, EpochDate, Source).
When I run the program I get the error
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of test.models.weather.Weather (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
I have also tried Gson but it return object with Null values
Am I doing something wrong? Is there another way to do it?
Edit: These are the models, #LazerBass was right, as I firstly didn't include default constructors, now the error has changed:
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "Headline" (class test.models.weather.Weather), not marked as ignorable (2 known properties: "headline", "dailyForecasts"])
public class TemperatureItem {
public double value;
public String unit;
public String unitType;
public TemperatureItem() {
}
//Getters and setters
}
public class Temperature {
private TemperatureItem maximum;
private TemperatureItem minimum;
public Temperature(TemperatureItem maximum, TemperatureItem minimum) {
this.maximum = maximum;
this.minimum = minimum;
}
public Temperature() {
}
//Getters and setters
}
public class DailyForecasts {
private LocalDateTime date;
private Temperature temperature;
public DailyForecasts(LocalDateTime date, Temperature temperature) {
this.date = date;
this.temperature = temperature;
}
public DailyForecasts() {
}
//Getters and setters
}
public class Headline {
private LocalDateTime effectiveDate;
private int severity;
private String text;
private String category;
private LocalDateTime endDate;
public Headline() {
}
public Headline(LocalDateTime effectiveDate, Integer severity, String text, String category, LocalDateTime endDate) {
this.effectiveDate = effectiveDate;
this.severity = severity;
this.text = text;
this.category = category;
this.endDate = endDate;
}
//Getters and setters
}
public class Weather {
private Headline headline;
private DailyForecasts[] dailyForecasts;
public Weather() {
}
public Weather(Headline headline, DailyForecasts[] dailyForecasts) {
this.headline = headline;
this.dailyForecasts = dailyForecasts;
}
//Getters and setters
}
I have found out, that if I convert json string to lowercase, I can get some values, although Array and LocalDateTime weren't parsed
To generate the Weather classes and its corresponding classes, use the following link and select the source type as json. It will generate the required classes as per the json string.
http://www.jsonschema2pojo.org/
After generating the classes, you can annotate the fields with #JsonIgnore which are not required.
When Jackson fails with message like "no Creators, like default construct, exist" it needs default, public no-argument constructor for each POJO class you have in your model.
When it fails with message like "Unrecognized field ... not marked as ignorable ..." you need to disable FAIL_ON_UNKNOWN_PROPERTIES feature.
See also:
Jackson Unmarshalling JSON with Unknown Properties
jackson delay deserializing field
Judging from the exception message I would guess that your Weather class is laking an no-argument constructor. Try adding one. E.g.
public class Weather {
public Weather() {
// no arg constructor needed for jackson
}
}

SpringBoot RestTemplate exchange having issue with ParameterizedTypeReference conversion for ResponseEntity

I am building two microservices which are supposed to talk to each other.
I am using Eureka as service registry.
Microservice 1 -
Microservice1.java
#SpringBootApplication
public class Microservice1Application {
public static void main(String[] args) {
SpringApplication.run(Microservice1Application.class, args);
}
}
Microservice1Controller.java
#RestController
#RequestMapping("/getdata")
public class Microservice1Controller {
#GetMapping(value = "/")
public ResponseEntity<Microservice1ResponseWrapper<List<Customer1>>> getAll() {
List<Customer1> list = //get data from repository
return new ResponseEntity<Microservice1ResponseWrapper<List<Customer1>>>(new Microservice1ResponseWrapper<List<Customer1>>(Microservice1ResponseStatus.SUCCESS,list);
}
}
Microservice1ResponseWrapper.java - this is generic wrapper
public class Microservice1ResponseWrapper<T> {
private Microservice1ResponseStatus status;
private T data;
//constructor, getter and setters
}
applicationProperties.yaml
spring:
application:
name: microservice1
server:
port: 8073
Microservice2
Microservice2 that will get data from Microservice1
#SpringBootApplication
public class Microservice2Application {
public static void main(String[] args) {
SpringApplication.run(Microservice2Application.class, args);
}
}
#Configuration
class Config {
#LoadBalanced
#Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
Microservice2Controller.java
#RestController
#RequestMapping("/fetchdata")
public class Microservice2Controller {
#Autowired
private RestTemplate restTemplate;
#GetMapping(value = "/")
public ResponseEntity<Microservice2ResponseWrapper<List<Customer2>>> getAll() {
String getAllUrl = "http://microservice1/getdata/";
ParameterizedTypeReference<Microservice2ResponseWrapper<List<Customer2>>> parameterizedTypeReference =
new ParameterizedTypeReference<Microservice2ResponseWrapper<List<Customer2>>>(){};
ResponseEntity<Microservice2ResponseWrapper<List<Customer2>>> listData =
restTemplate.exchange(getAllUrl, HttpMethod.GET, null,parameterizedTypeReference);
return listData;
}
}
Microservice2ResponseWrapper.java - this is generic wrapper
public class Microservice2ResponseWrapper<T> {
private Microservice2ResponseStatus status;
private T data;
//constructor, getter and setters
}
applicationProperties.yaml
spring:
application:
name: microservice2
server:
port: 8074
Customer1(in Microservice1) and Customer2(Microservice2) are almost identical objects.
public class Customer1 implements Serializable {
private static final long serialVersionUID = 1L;
private Long custId;
private String custName;
private String firstName;
private String lastName;
private Long age;
public Customer1() {
}
public Customer1(String custName, String firstName, String lastName, Long age) {
this.custName = custName;
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
}
public Customer1(Long custId, String custName, String firstName, String lastName, Long age) {
this.custId = custId;
this.custName = custName;
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
}
//getter, setter and toString
}
Customer2.java in Microservice2
public class Customer2 implements Serializable {
private static final long serialVersionUID = 1L;
private Long custId;
private String custName;
private String firstName;
private String lastName;
private Long age;
public Customer2() {
}
//getter, setter and toString
}
When I run Microservice1 : http://localhost:8073/getdata it gets data from database and works fine. Here is the response I see on screen:
<Microservice1ResponseWrapper>
<status>SUCCESS</status>
<data>
<custId>1</custId>
<custName>string1</custName>
<firstName>string1</firstName>
<lastName>string1</lastName>
<age>30</age>
</data>
</Microservice1ResponseWrapper>
When I run Microservice2 : http://localhost:8074/fetchdata it should go to Microservice 1 and get data.
However, I am getting error like:
org.springframework.web.client.RestClientException: Error while extracting response for type
at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:117)
at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:994)
at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:977)
Caused by: org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot construct instance of `com.rest.Customer2` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('1'); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `com.rest.Customer2` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('1')
at [Source: (PushbackInputStream); line: 1, column: 61] (through reference chain: com.rest.wrapper.Microservice2ResponseWrapper["data"]->java.util.ArrayList[0])
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:245)
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(AbstractJackson2HttpMessageConverter.java:227)
at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:102)
... 77 more
Caused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `com.rest.Customer2` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('1')
at [Source: (PushbackInputStream); line: 1, column: 61] (through reference chain: com.rest.wrapper.Microservice2ResponseWrapper["data"]->java.util.ArrayList[0])
at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:63)
at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1343)
at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1032)
at com.fasterxml.jackson.databind.deser.ValueInstantiator._createFromStringFallbacks(ValueInstantiator.java:371)
at com.fasterxml.jackson.databind.deser.std.StdValueInstantiator.createFromString(StdValueInstantiator.java:323)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromString(BeanDeserializerBase.java:1373)
at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:171)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:161)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:286)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:245)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:27)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:127)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:369)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:159)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4013)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3084)
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:239)
Am I making any mistake in ParameterizedTypeReference or resttemplate exchange call?
NOTE: If I run these two microservices without Eureka registry, they work absolutely fine. But the moment I introduce Eureka and register these two services with Eureka, I get issue as stated above.
For this I just made the change to Miroservice2 controller:
String getAllUrl = "http://localhost:8073/getdata/";
Update - 02/22/19
here's what I tried
updated Microservice1Controller-getAll()as below:
#GetMapping(value = "/")
public ResponseEntity<List<Customer1>> getAll() {
List<Customer1> list = //get data from repository
return new ResponseEntity<List<Customer1>>(list);
}
Updated Microservice2Controller- getAll() method
#GetMapping(value = "/")
public ResponseEntity<List<Customer2>> getAll() {
String getAllUrl = "http://microservice1/getdata/";
ParameterizedTypeReference<List<Customer2>> parameterizedTypeReference =
new ParameterizedTypeReference<List<Customer2>>(){};
ResponseEntity<List<Customer2>> listData =
restTemplate.exchange(getAllUrl, HttpMethod.GET, null,parameterizedTypeReference);
return listData;
}
This worked fine- call Microservice1 from Microservice2 as stated in earlier description.
Microservice1 returning ResponseEntity> to Microservice2 and Microservice2 converting that to ResponseEntity>.
However,
Microservice1 returning ResponseEntity<Microservice1ResponseWrapper<List<Customer1>>> to Microservice2 and Microservice2 can't be able to convert to ResponseEntity<Microservice2ResponseWrapper<List<Customer2>>>.
UPDATE 06/28/19
If I make following change in Microservice2 Controller then I see 2 issues:
start getting LinkedHashMap error.
java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to java.util.List
It doesn't pull all records, it just pulls last element from List. e.g. There are 2 users, then it just shows last one user and not all.
ParameterizedTypeReference<Microservice2ResponseWrapper> parameterizedTypeReference =
new ParameterizedTypeReference<Microservice2ResponseWrapper>(){};
ResponseEntity<Microservice2ResponseWrapper> listData =
restTemplate.exchange(getAllUrl, HttpMethod.GET, null,parameterizedTypeReference);
List ls = (List) listData.getBody().getData();
//if I print listData.getBody().getData() then it just shows only one record of users.
You need to create a default constructor for Customer2 class.
Customer2(){}
I couldn't able to resolve it using RestTemplate. So I went ahead with alternative of using Open Feign.
Step 1. in pom.xml I added dependency
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-openfeign-core</artifactId>
</dependency>
Step 2. Add client interface
#FeignClient(name = "microservice1")
public interface Microservice1Client {
#GetMapping(value = "/getdata/")
ResponseEntity<Microservice1ResponseWrapper<List<Customer1>>> getAll();
}
Step 3. in Microservice2Controller inject FeignClient bean Microservice1Client
#RestController
#RequestMapping("/fetchdata")
public class Microservice2Controller {
#Autowired
Microservice1Client microservice1Client;
#GetMapping(value = "/")
public ResponseEntity<Microservice2ResponseWrapper<List<Customer2>>> getAll() {
return microservice1Client.getAll();
}
}

Jackson ignores JsonProperty annotation in deserialization

I've got a bit of a conundrum. I'm trying to deserialize a json message into a pojo using the builder pattern and I'm getting the following error:
Caused by: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "Information"
(class com.verification.client.models.response.Response$Builder), not marked as ignorable (3 known properties: "status", "products", "information"])
This is very confusing to me as I've clearly marked the field in the pojo with a JsonProperty annotation:
#JsonDeserialize(builder = Response.Builder.class)
#JsonInclude(JsonInclude.Include.NON_EMPTY)
public class Response {
#JsonProperty("Status")
private final Optional<Status> status;
#JsonProperty("Products")
private final Optional<List<ResponseProduct>> products;
#JsonProperty("Information") //Here's where the field is defined
private final Optional<List<ResponseInformation>> information;
private Response(final Builder b){
this.status = b.status;
this.products = b.products;
this.information = b.information;
}
public Optional<Status> getStatus() {
return status;
}
public Optional<List<ResponseProduct>> getProducts() {
return products;
}
public Optional<List<ResponseInformation>> getInformation() {
return information;
}
#JsonPOJOBuilder(buildMethodName = "build", withPrefix = "")
public static class Builder{
private Optional<Status> status;
private Optional<List<ResponseProduct>> products = Optional.empty();
private Optional<List<ResponseInformation>> information = Optional.empty();
public Builder(){}
public Builder status(final Status status){
this.status = Optional.of(status);
return this;
}
public Builder products(final List<ResponseProduct> products){
this.products = Optional.of(products);
return this;
}
public Builder information(final List<ResponseInformation> information){
this.information = Optional.of(information);
return this;
}
public Response build(){
return new Response(this);
}
}
}
I have a feeling it's something small, but at this point I am at a loss for why my code is behaving this way.
P.S.
Here's the json I'm deserializing
{
"Information": [{
"InformationType": "error-details",
"Code": "internal_application_error",
"Description": "Error: Internal",
"DetailDescription": []
}]
}
Solved this a while back, answering for posterity.
The issue I was having is that the build methods were not being correctly interpreted, but by defining #JsonSetter annotations on the methods of the static build class Jackson was able to correctly interpret the input and build the object.

Categories