Search code examples
springspring-bootjacksonspring-restcontrollerspring-rest

How can I make jackson to use different views on nested entities of the same type?


Before I start questioning let me give you a simplified example of my case:
Imagine you have Views:

public final class Views {
    public interface Id { }

    public interface IdText extends Id { }

    public interface FullProfile extends IdText { }
}

You also have a class User which has subscribers that are of the same type User. The properties id and username are serialized in the Views.IdText.class view. And the property subscribers is serialized in the Views.FullProfile.class view.

@Entity
public class User implements UserDetails {
    @Id
    @JsonView(Views.IdText.class)
    private Long id;

    @JsonView(Views.IdText.class)
    private String username;

    @JsonIdentityReference
    @JsonIdentityInfo(
            property = "id",
            generator = ObjectIdGenerators.PropertyGenerator.class
    )
    @JsonView(Views.FullProfile.class)
    private Set<User> subscribers = new HashSet<>();
}

And a controller (ProfileController) that has a method called get that returns a user's profile.

@RestController
public class ProfileController {
    
    @GetMapping("{id}")
    @JsonView(Views.FullProfile.class)
    public User get(@PathVariable("id") User user) {
        // ... some service methods that has the necessary logic.
        return user;
    }
    
}

As you can see, the method serializes the user's profile in the Views.FullProfile.class view, so the output is:

{
  "id": 39,
  "username": "ryan",
  "subscribers": [
    {
      "id": 42,
      "username": "elliott",
      "subscribers": [
        {
          "id": 432,
          "username": "oliver",
          "subscribers": [
            {
              "id": 2525,
              "username": "james",
              "subscribers": [
                39,
                432
              ]
            },
            {
              // ... a lot of useless data goes on.
            }
          ]
        },
        {
          "id": 94923,
          "username": "lucas",
          "subscribers": [
            345, 42
          ]
        }
      ]
    },
    {
      "id": 345,
      "username": "jocko",
      "subscribers": [
        94923
      ]
    }
  ]
}

When a user's profile is being serialized, I don't need the user's subscribers to be serialized in the Views.FullProfile.class view but in the Views.IdText.class view so that the output would be:

{
  "id": 39,
  "username": "ryan",
  "subscriptions": [
    {
      "id": 42,
      "username": "elliott"
    },
    {
      "id": 345,
      "username": "jocko"
    }
  ]
}

How can I make jackson to use different views on nested entities of the same type? Or what else do I have to do to make that happen?


Solution

  • After some time of continuous searching I found someone issued the same problem on Github: @JsonIgnoreProperties should support nested properties #2940
    As stated in that issue:

    No plans to ever implement this (due to delegating design, will not be possible with current Jackson architecture), closing.