Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In the context of SpringMVC, how to have web services that provide different JSON representation of a same class?

I have a data class, something like this:

public class Person {
   private String name;
   private Long code;

   // corresponding getters and setters
}

I want to write two web services that provide two different JSON representation of Person. For example, one of them provide {"name":"foo"} but the other one {"name":"foo", "code":"123"}.

As a more complicated scenario, suppose that Person has a reference property, for example address. Address has its own properties as well and I expect that both of my web services consider this property but each of which do this in their own manner.

How should my SpringMVC views be like?

Please note that I'm new to SpringMVC. So give me a sample code beside your answer, please.

UPDATE 1: After few days, all answers push me to solve the problem in controllers or by annotating the data classes. But I want to do this in views, without any more java codes. Can I do it in JSP files or thymeleaf templates or even in .properties files?

UPDATE 2: I found json-taglib. But somehow it is left out of new upgrades. Is there any similar solution?

like image 535
vahidreza Avatar asked May 24 '18 14:05

vahidreza


2 Answers

You're using Spring-MVC so Jackson is in charge of JSON serialize and deserializing.

In this case, you can use @JsonInclude(Include.NON_NULL) to ignore null field during serialization.

public class Person {
   @JsonInclude(Include.NON_NULL)
   private String name;

   @JsonInclude(Include.NON_NULL)
   private Long code;

   // corresponding getters and setters
}

If your name or code is null then it is excluded from output JSON

So if you pass code as null, your ouput JSON will look like {"name":"foo"}

like image 67
Mạnh Quyết Nguyễn Avatar answered Oct 27 '22 00:10

Mạnh Quyết Nguyễn


When creating JSon with Spring MVC the "view renderer", by default, is Jackson. There is no need to use things like JSP or other view technology. What you want to do, is to tell Jackson how to render an object for a given situation. Multiple options are available, but I would suggest to use projections. An example:

@RestController
@RequestMapping(value = "person")
public class PersonController {

    private final ProjectionFactory projectionFactory;

    public PersonController(ProjectionFactory projectionFactory) {
        this.projectionFactory = projectionFactory;
    }

    @GetMapping("...")
    public PersonBase getPerson(..., @RequestParam(value = "view", required = false, defaultValue = "base") String view) {
        ...

        if(view.equals("extended")) {
            return projectionFactory.createProjection(PersonExtended.class, person);
        } else {
            return projectionFactory.createProjection(PersonBase.class, person);
        }
    }
}



public interface PersonBase {
    String getName();
}

public interface PersonExtended extends PersonBase {
    Long getCode;
}

The view layer of your application are the projection classes (put then in one package, the view package if you wish). A Controller can choose what view to render, or you could make the result dynamic as in the example.

Your question on how to render the address could be solved with another projection like this:

public interface PersonWithAddress extends PersonExtended {
    AddressProjection getAddress();
}

public interface AddressProjection {
    String getStreetName();
    String getZipcode();
    ...
}
like image 44
JohanB Avatar answered Oct 27 '22 01:10

JohanB