Skip to content

Instantly share code, notes, and snippets.

@iznenad
Last active December 8, 2019 21:44
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save iznenad/424d49696f78cd7563e11ff5d51f21f4 to your computer and use it in GitHub Desktop.
Save iznenad/424d49696f78cd7563e11ff5d51f21f4 to your computer and use it in GitHub Desktop.
package com.example.iznenad;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.data.mapping.context.PersistentEntities;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
import org.springframework.data.rest.core.projection.ProjectionDefinitions;
import org.springframework.data.rest.core.support.SelfLinkProvider;
import org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler;
import org.springframework.data.rest.webmvc.mapping.Associations;
import org.springframework.data.rest.webmvc.support.PersistentEntityProjector;
import org.springframework.data.rest.webmvc.support.Projector;
import org.springframework.web.context.request.NativeWebRequest;
/**
* @author Nenad Nikolic
*
*
*/
public class DefaultSpringDataRestMagic {
@Autowired
private Associations associations;
@Autowired
private RepositoryRestConfiguration repositoryRestConfiguration;
@Autowired
private ApplicationContext applicationContext;
@Autowired
private SelfLinkProvider linkProvider;
@Autowired
private PersistentEntities entities;
@Autowired
private NativeWebRequest nativeWebRequest;
public PersistentEntityResourceAssembler buildDefaultAssemblerInstance() {
SpelAwareProxyProjectionFactory projectionFactory = new SpelAwareProxyProjectionFactory();
projectionFactory.setBeanFactory(applicationContext);
projectionFactory.setResourceLoader(applicationContext);
ProjectionDefinitions projectionDefinitions = repositoryRestConfiguration.getProjectionConfiguration();
Projector projector = new PersistentEntityProjector(projectionDefinitions, projectionFactory,
nativeWebRequest.getParameter(projectionDefinitions.getParameterName()), associations.getMappings());
return new PersistentEntityResourceAssembler(
entities, projector, associations, linkProvider);
}
}
@iznenad
Copy link
Author

iznenad commented Feb 10, 2017

Overriding a spring-data-rest endpoint and using the default ResourceAssembler

Lets say you have the following repository:

public interface UserRepository extends PagingAndSortingRepository<User, String> {
}

and you need to override one of the methods.

For this example we'll override: GET /users (which is the default findAll) so that we can take a parameter from a header.

Provide the RepositoryRestController

@RepositoryRestController
public class UserController {

    @Autowired
    private EntityManager entityManager;

    @Autowired
    private HttpServletRequest request;

    @RequestMapping(method = RequestMethod.GET, path = { "/users"})
    public ResponseEntity<?> getUsers() {
        TypedQuery<User> fetchAllUsers = entityManager
                .createQuery("select user from Users user where user.tenant=:tenant", User.class);

        fetchAllUsers.setParameter("tenant", request.getHeader("Tenant-Header-Name"));

        List<User> allUsers = fetchAllUsers.getResultList();

        return ResponseEntity.ok(new Resources(users))
    }
}

While this works, it will lack some of the hateoas goodies that spring-data-rest gives us by default.

So lets reuse the default ResourceAssembler to get them back.

Create the DefaultSpringDataRestMagic class and register as bean

Just copy the class from this gist, change the package and register it as a bean like this:

    @Bean
    @Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
    public DefaultSpringDataRestMagic defaultSpringDataRestMagic() {
        return new DefaultSpringDataRestMagic();
    }

It needs to be request scoped because it injects an instance of NativeWebRequest.

Change the RepositoryRestController to use the default assembly

 @RepositoryRestController
public class UserController {

    @Autowired
    private EntityManager entityManager;

    @Autowired
    private DefaultSpringDataRestMagic defaultSpringDataRestMagic;

    @Autowired
    private HttpServletRequest request;

    @RequestMapping(method = RequestMethod.GET, path = { "/users"})
    public ResponseEntity<?> getUsers() {
        TypedQuery<User> fetchAllUsers = entityManager
                .createQuery("select user from Users user where user.tenant=:tenant", User.class);

        fetchAllUsers.setParameter("tenant", request.getHeader(""));

        List<User> allUsers = fetchAllUsers.getResultList();

        return ResponseEntity.ok(usersToResources(users))
    }

    private Resources usersToResources(List<User> users) {
        PersistentEntityResourceAssembler defaultAssemblerInstance = defaultSpringDataRestMagic
                .buildDefaultAssemblerInstance();

        List<PersistentEntityResource> userPersistentEntities = users.stream().map(user -> {
            return defaultAssemblerInstance.toFullResource(user);
        }).collect(Collectors.toList());

        return new Resources(userPersistentEntities);
    }
}

That's it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment