A MJ
A MJ

Reputation: 115

How to map different name to json property based on rest method per @JsonView in spring boot?

I have 2 set of rest APIs implemented using Spring boot using same Java POJO class. I have to return different fields and with different name for few fields, based on API. Presently I am using @JsonView for one set of API. But I also need to give different name for that @JsonView. Ex: Field 'host' needs to be named as 'ip' for a @JsonView, where as 'host' for other API. I am not sure how to map different property names as per @JsonView.

I checked some results like using MixIns. But not sure how to do in Spring Boot Rest APIs, especially at method level.

public class Con {

@JsonView(View.ConInfo.class)
private String host;

private String name;

}

Controller Method:

@JsonView(View.ConInfo.class)
@GetMapping
public Con getConInfo()  {}

@GetMapping("/raw")
public Con getCon()  {}

Expected: {"ip":"10xxx"} for getConInfo API

{"host":"10xxx", "name":"con1"} for getCon API.

Actual: Getting {"host":"10xxx"} for getConInfo API

Upvotes: 0

Views: 1625

Answers (2)

cassiomolin
cassiomolin

Reputation: 130877

Surely there's a way to achieve what you want (see details below). But I encourage you to avoid it.

As you have different payloads, you should have different classes for representing each payload.


If you still want to follow your original path, you could define two views:

public interface Views {

    interface Summary { }

    interface Details { }
}

And then annotate your payload as follows:

@Data
public class Payload {

    @JsonIgnore
    private String host;

    @JsonView(Views.Details.class)
    private String name;

    @JsonView(Views.Summary.class)
    public String getIp() {
        return host;
    }

    @JsonView(Views.Details.class)
    public String getHost() {
        return host;
    }
}

Now consider the following method, annotated with @JsonView(Views.Summary.class)

@JsonView(Views.Summary.class)
@GetMapping(path = "/summary", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Payload> getSummary() {

    Payload payload = new Payload();
    payload.setHost("0.0.0.0");
    payload.setName("example");

    return ResponseEntity.ok(payload);
}

It will produce:

{
  "ip": "0.0.0.0"
}

Now consider the following methid annotated with @JsonView(Views.Details.class):

@JsonView(Views.Details.class)
@GetMapping(path = "/details", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Payload> getDetails() {

    Payload payload = new Payload();
    payload.setHost("0.0.0.0");
    payload.setName("example");

    return ResponseEntity.ok(payload);
}

It will produce:

{
  "host": "0.0.0.0",
  "name": "example"
}

Upvotes: 2

DwB
DwB

Reputation: 38300

Based on your description of the problem, you are doing it wrong and, perhaps, do not actually know what you want.

  1. You have two different JSON structures.
  2. You want to send different JSON based on the method that returns the JSON.
  3. Each method will return one JSON structure.
  4. You have data that "maps" to the two different structures.

It seems that you already have data that is represented in one class (perhaps used to access the database); I will call this the VO class Try this:

  1. Create a class for each JSON structure (two different classes, one with hostname and one with IP).
  2. Use Jackson to represent this class in JSON (you are doing this).
  3. Create a mapper to take the data from the VO and create the JSON class of choice. This can be as simple as DataMapper.makeHostnameJsonClass and DataMapper.makeIPJsonClass.
  4. Use the mapper in the web handler to return the correct JSON class.
  5. Declare each web handler to return the correct JSON class.

Upvotes: 1

Related Questions