spring rest data serialize to-one associations as related entity

心不动则不痛 提交于 2019-12-06 22:15:31

Solved with hackage.

Steps:

  1. Add the @RestResource(exported = false) to the association on the entity.
  2. Register a ResourceProcessor<Resource<OwnedEntity>> @Bean (OwnedEntity is my base class for entities that have an owner) and change the collection of links in that method.

Details are in the Customizing the JSON output section of the Spring Data REST reference docs.

By Request, here's some code that does this:

/*
 * Copyright (c) 2017. DataVolo, Inc.  All Rights Reserved.
 */

package com.datavolo.tenant.web;

import com.datavolo.tenant.domain.Account;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.rest.webmvc.support.RepositoryEntityLinks;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.mvc.ResourceAssemblerSupport;
import org.springframework.stereotype.Component;

import javax.annotation.Nonnull;

/**
 *
 */
@Component
public class AccountResourceAssembler extends ResourceAssemblerSupport<Account, AccountResource> {

    private final RepositoryEntityLinks repositoryEntityLinks;

    @Autowired
    public AccountResourceAssembler(@Nonnull RepositoryEntityLinks repositoryEntityLinks) {
        super(AccountController.class, AccountResource.class);
        this.repositoryEntityLinks = repositoryEntityLinks;
    }

    @Override
    public AccountResource toResource(Account entity) {
        Link accountLink = repositoryEntityLinks.linkToSingleResource(Account.class, entity.getId());
        String accountHref = accountLink.getHref();
        Link selfLink = new Link(accountHref, Link.REL_SELF);

        Link subAccounts = new Link(accountHref + "/subAccounts", "subAccounts");
        Link owner = new Link(accountHref + "/owner", "owner");

        Account parent = entity.getParent();
        Link[] links;
        if (parent == null) {
            links = new Link[] {selfLink, accountLink, subAccounts, owner};
        } else {
            Link parentAccountLink = repositoryEntityLinks.linkToSingleResource(Account.class, parent.getId());
            Link parentLink = new Link(parentAccountLink.getHref(), "parent");
            links = new Link[] {selfLink, accountLink, subAccounts, owner, parentLink};
        }

        return new AccountResource(entity, links);
    }
}

That then gets injected into the Controllers (annotated with @RepositoryRestController) that, in turn, generate the response.

In this system we have a shared base class for the controllers, and we have a multi-tenant setup where all non-trivial, non-lookup domain objects (e.g., everything that's storing system data) reference either directly or indirectly the account object, which is what controls and represents the tenancy. So we do this in one place for one object and we're done. Other links are more manual and over time we've largely just shrugged and left the default Spring HATEOS output as-is and let the clients adjust to it. We change this only when the default routinely causes multiple round-trips to the backend -- which is the essential problem with that default way Spring has of handling it. But it's a tradeoff. Spring's default is meant to cause no extra overhead when the back-end resource itself is declared as lazily resolved reference. The nice enhancement to that would be to have it be smarter about those resources so that ones that are already fetched are directly referenced by their own id in the REST response.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!