简体   繁体   中英

Override related links in Spring Data REST

I'm using Spring Boot 2, Spring Data REST, Spring HATEOAS.

Let's say I've a model:

@EntityListeners({ContactListener.class})
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Contact extends AbstractEntity {

    @NotNull
    @Enumerated(EnumType.STRING)
    @Column(nullable = false, columnDefinition = "VARCHAR(30) DEFAULT 'CUSTOMER'")
    private ContactType type = ContactType.CUSTOMER;

    @NotNull
    @Enumerated(EnumType.STRING)
    @Column(nullable = false, columnDefinition = "VARCHAR(30) DEFAULT 'NATURAL_PERSON'")
    private PersonType personType = PersonType.NATURAL_PERSON;

    private String firstName;

    private String lastName;

    private String companyName;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "store_id", updatable = false)
    private Store store;

and Store:

@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Store extends AbstractEntity {

    @NotBlank
    @Column(nullable = false)
    private String name;

    @Username
    @NotBlank
    @Length(max = 16)
    @Column(nullable = false/*, unique = true*/)
    @ColumnTransformer(write = "UPPER(?)")
    private String code;

    private String address;

    private String zipCode;

    private String city;

    private String district;

When I get a contact the response looks like this:

{
    "sid": "962732c2-68a8-413b-9762-f676d42046b4",
    "createdBy": "1ccf2329-4aa3-4d55-8878-25517edf1522",
    "createdDate": "2019-05-28T14:06:07.011Z",
    "lastModifiedDate": "2019-06-04T08:46:02.591Z",
    "lastModifiedBy": "system",
    "createdByName": "Rossi Mario",
    "lastModifiedByName": null,
    "type": "CUSTOMER",
    "personType": "NATURAL_PERSON",
    "firstName": "Mario",
    "lastName": "Rossi",
    "companyName": null,
    "fullName": "Rossi Mario",
    "gender": "MALE",
    "birthDate": "2019-05-21T00:00:00Z",
    "birthCity": null,
    "job": null,
    "billingAddress": "Via 123",
    "billingZipCode": "14018",
    "billingCity": "Roatto",
    "billingDistrict": "AT",
    "billingCountry": "IT",
    "shippingAddress": "Via 123",
    "shippingZipCode": "14018",
    "shippingCity": "Roatto",
    "shippingDistrict": "AT",
    "shippingCountry": "IT",
    "taxCode": "XXXX",
    "vatNumber": null,
    "landlinePhone": null,
    "mobilePhone": null,
    "fax": null,
    "email": "aaa@sdfg.it",
    "certifiedEmail": null,
    "survey": null,
    "iban": null,
    "swift": null,
    "publicAdministration": false,
    "sdiAccountId": "0000000",
    "preset": false,
    "_links": {
        "self": {
            "href": "http://localhost:8082/api/v1/contacts/1"
        },
        "contact": {
            "href": "http://localhost:8082/api/v1/contacts/1{?projection}",
            "templated": true
        },
        "store": {
            "href": "http://localhost:8082/api/v1/contacts/1/store{?projection}",
            "templated": true
        }
    }
}

as you can see the link of store it's not the self link of the resource Store. I'd like to override that link setting the self resource. So I created this processor:

@Component
public class DocumentRowProcessor implements ResourceProcessor<Resource<Contact>> {

    @Autowired
    private BasePathAwareLinks service;

    @Autowired
    private EntityLinks entityLinks;

    @Override
    public Resource<Contact> process(Resource<Contact> resource) {

        Store store = resource.getContent().getStore();
        if(store != null){
           resource.add(entityLinks.linkToSingleResource(store.getClass(), store.getId()).withRel("store"));
        }

        return resource;
    }
}

Unfortunately, the link is now overriden but I find 2 links inside "store". Debugging I saw that inside the resource is present just the self link. My guess is that related links are added in following steps.

How can I accomplish my goal in a clean way?

  1. The hateoas links are added the the result during serialization (using a specific JSON serializer), so you cannot remove it using a ResourceProcessor.
  2. The hateoas link in the result is the proper link for that resource. http://localhost:8082/api/v1/contacts/1/store is the endpoint where you can check which store is linked to this contant, or you can delete/modify the association between this two object.

However in certain use-cases you need the self-link for further actions and you don't want to send an extra request from the client. Do the following: 1. Create a projection for the contant. 2. Include all the properties you need and also the store. 3. If you don't need any properties of the store here - only the self link - then create an 'empty projection' for the store entoty and include that projection as store property into the contact property.

When you get this projection of the contact then the result will contain the self-link of the store inside the store property. So the main _links collection will be still a regular hateos link-collection but there will be a store._links.self.href property which will contain the self link of the associated store.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM