2

I am trying to add HATEOAS links with Resource<>, while also filtering with @JsonView. However, I don't know how to add the links to nested objects.

In the project on on Github, I've expanded on this project (adding in the open pull request to make it work without nested resources), adding the "Character" entity which has a nested User.

When accessing the ~/characters/resource-filtered route, it is expected that the nested User "player" appear with the firstNm and bioDetails fields, and with Spring generated links to itself, but without the userId and lastNm fields.

I have the filtering working correctly, but I cannot find an example of nested resources which fits with the ResourceAssembler paradigm. It appears to be necessary to use a ResourceAssembler to make @JsonView work.

Any help reconciling these two concepts would be appreciated. If you can crack it entirely, consider sending me a pull request.

User.java

//package and imports
...

public class User implements Serializable {

    @JsonView(UserView.Detail.class)
    private Long userId;

    @JsonView({ UserView.Summary.class, CharacterView.Summary.class })
    private String bioDetails;

    @JsonView({ UserView.Summary.class, CharacterView.Summary.class })
    private String firstNm;

    @JsonView({ UserView.Detail.class, CharacterView.Detail.class })
    private String lastNm;

    public User(Long userId, String firstNm, String lastNm) {
        this.userId = userId;
        this.firstNm = firstNm;
        this.lastNm = lastNm;
    }

    public User(Long userId) {
        this.userId = userId;
    }

    ...
    // getters and setters
    ...

}

CharacterModel.java

//package and imports
...

@Entity
public class CharacterModel implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @JsonView(CharacterView.Summary.class)
    private Long characterId;

    @JsonView(CharacterView.Detail.class)
    private String biography;

    @JsonView(CharacterView.Summary.class)
    private String name;

    @JsonView(CharacterView.Summary.class)
    private User player;

    public CharacterModel(Long characterId, String name, String biography, User player) {
        this.characterId = characterId;
        this.name = name;
        this.biography = biography;
        this.player = player;
    }

    public CharacterModel(Long characterId) {
        this.characterId = characterId;
    }

    ...
    // getters and setters
    ...
}

CharacterController.java

//package and imports
...

@RestController
@RequestMapping("/characters")
public class CharacterController {

    @Autowired
    private CharacterResourceAssembler characterResourceAssembler;

    ...

    @JsonView(CharacterView.Summary.class)
    @RequestMapping(value = "/resource-filtered", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    @ResponseStatus(HttpStatus.OK)
    public Resource<CharacterModel> getFilteredCharacterWithResource() {
        CharacterModel model = new CharacterModel(1L, "TEST NAME", "TEST BIOGRAPHY", new User(1L, "Fred", "Flintstone"));
        return characterResourceAssembler.toResource(model);
    }

    ...
}

CharacterResourceAssembler.java

//package and imports
...

@Component
public class CharacterResourceAssembler implements ResourceAssembler<CharacterModel, Resource<CharacterModel>>{

    @Override
    public Resource<CharacterModel> toResource(CharacterModel user) {
        Resource<CharacterModel> resource = new Resource<CharacterModel>(user);
        resource.add(linkTo(CharacterController.class).withSelfRel());
        return resource;
    }

}
Don Subert
  • 2,636
  • 4
  • 27
  • 37

0 Answers0