drenda
drenda

Reputation: 6244

How to create custom PersistentEntityResourceAssembler with Spring Data REST

I'm using Spring Boot 2.1, Spring Data REST, Spring HATEOAS, Hibernate 5.

I'm looking for a way to filter fields in REST calls. I'm going to use https://github.com/bohnman/squiggly-java but I want to integrate it in Spring resource assembler.

I'm looking for a way to customize the PersistentEntityResourceAssembler that is automatically available in REST controllers. This is the code of the class:

public class PersistentEntityResourceAssembler implements ResourceAssembler<Object, PersistentEntityResource> {
    @NonNull
    private final PersistentEntities entities;
    @NonNull
    private final Projector projector;
    @NonNull
    private final Associations associations;
    @NonNull
    private final SelfLinkProvider linkProvider;
    @NonNull
    private final EmbeddedWrappers wrappers = new EmbeddedWrappers(false);

    public PersistentEntityResource toResource(Object instance) {
        Assert.notNull(instance, "Entity instance must not be null!");
        return this.wrap(this.projector.projectExcerpt(instance), instance).build();
    }

    public PersistentEntityResource toFullResource(Object instance) {
        Assert.notNull(instance, "Entity instance must not be null!");
        return this.wrap(this.projector.project(instance), instance).build();
    }

    private Builder wrap(Object instance, Object source) {
        PersistentEntity<?, ?> entity = this.entities.getRequiredPersistentEntity(source.getClass());
        return PersistentEntityResource.build(instance, entity).withEmbedded(this.getEmbeddedResources(source)).withLink(this.getSelfLinkFor(source)).withLink(this.linkProvider.createSelfLinkFor(source));
    }

    private Iterable<EmbeddedWrapper> getEmbeddedResources(Object instance) {
        return (new EmbeddedResourcesAssembler(this.entities, this.associations, this.projector)).getEmbeddedResources(instance);
    }

    public Link getSelfLinkFor(Object instance) {
        Link link = this.linkProvider.createSelfLinkFor(instance);
        return new Link(link.expand(new Object[0]).getHref(), "self");
    }

    public PersistentEntityResourceAssembler(@NonNull PersistentEntities entities, @NonNull Projector projector, @NonNull Associations associations, @NonNull SelfLinkProvider linkProvider) {
        if (entities == null) {
            throw new IllegalArgumentException("entities is marked @NonNull but is null");
        } else if (projector == null) {
            throw new IllegalArgumentException("projector is marked @NonNull but is null");
        } else if (associations == null) {
            throw new IllegalArgumentException("associations is marked @NonNull but is null");
        } else if (linkProvider == null) {
            throw new IllegalArgumentException("linkProvider is marked @NonNull but is null");
        } else {
            this.entities = entities;
            this.projector = projector;
            this.associations = associations;
            this.linkProvider = linkProvider;
        }
    }
}

My guess is that it's injected somewhere into Spring. I want to customize the JSON content dynamically filtering out fields that I don't want. I tried to create a copya of the class and annotating it with @Component but it's missing Projector.

What's the right way to customize PersistentEntityResourceAssembler in Spring Data REST?

Upvotes: 0

Views: 1009

Answers (1)

Selindek
Selindek

Reputation: 3423

You have to create a PersistentEntityResourceAssemblerArgumentResolver which creates the PersistentEntityResourceAssembler on the fly if a controller method needs it.

It works this way, because PersistentEntityResourceAssembler needs the projection parameter from the request, so it cannot be a bean.

The argument resolver itself is registered in the RepositoryRestMvcConfiguration class. It's defined in its protected method: defaultMethodArgumentResolvers(). Unfortunately it cannot be configured via RepositoryRestConfigurer, so you need to extend the RepositoryRestMvcConfiguration configuration class itself then override the defaultMethodArgumentResolvers() method.

Unfortunately this method creates a lot of other argumentResolvers too, so I think the best approach is if you call the super method, removes the original PersistentEntityResourceAssemblerArgumentResolver from the returning list and adds your custom one into it.

It won't be as easy task... good luck!

Upvotes: 2

Related Questions