How to deserialize the generic response using Spring WebClient

Viewed 198

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.

3 Answers

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.

  1. Add necessary fields to the 'Fee' class (If you know Fee structure upfront)
  2. 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

Related