Search code examples
javaspringspring-data-restcglib

How to use WebMvcLinkBuilder with repository's findById?


I'm trying to use Spring Data Rest to implement a full set of services for about 60 entities. Right now, I'm getting by with just letting Spring use my repositories rather than implementing controllers, which is great!

The data I'm having to model isn't ideal--I'd prefer to have customerId come as part of the order object.

{
  "tenantId": 42,
  "id": "00000001",
  "customer": {
    "tenantId": 42,
    "id": "CUST001",
    "name": "Arthur Dent"
  }
}

I have the ID for a related entity as a property on my JSON object.

public class Order {
  Long tenantId;
  String id;
  String customerId;
}

I don't really want to pull the full Customer entity and all of the other related entities and place them as members on my Order object. Instead, I'd just like to add some links to the _links collection.

I believe I've figured out WebMvcLinkBuilder finally and I have the basic idea in place. However, JpaRepository.findById returns a java.util.Optional.

@Bean
public RepresentationModelProcessor<EntityModel<Order>> orderProcessor() {
  return new RepresentationModelProcessor<EntityModel<Order>>() {
    @Override
    public EntityModel<Order> process(final EntityModel<Order> model) {
      final CustomerRepository controller = WebMvcLinkBuilder.methodOn(CustomerRepository);
      final CustomerId id = new CustomerId(model.getContent().getTenantId(), model.getContent().getCustomerId());
      model.add(WebMvcLinkBuilder.linkTo(controller.findById(id)).withRel("customer"));
      return model;
    }
  };
}

The error I get is:

Could not generate CGLIB subclass of class java.util.Optional: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Cannot subclass final class java.util.Optional

How can I add a link to my resource?


Solution

  • I had the same problem as you and I solved it by creating a function findByIdOrThrowError(Integer id) that get the Customer from the Controller, and check if there is no result to throw an error with .orElseThrow().

    Then you call the function inside your linkTo().