DATAREST-67 Can now using Spring Data REST without having to have any JPA dependencies in the classpath. The JPA-specific interceptor that is being used has been moved into a support class that is only created if JPA is in the classpath.
This commit is contained in:
@@ -5,9 +5,6 @@ import static org.springframework.util.StringUtils.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.persistence.PersistenceContext;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletRequestWrapper;
|
||||
|
||||
@@ -17,6 +14,7 @@ import org.springframework.data.repository.core.RepositoryInformation;
|
||||
import org.springframework.data.repository.support.Repositories;
|
||||
import org.springframework.data.rest.config.RepositoryRestConfiguration;
|
||||
import org.springframework.data.rest.config.ResourceMapping;
|
||||
import org.springframework.data.rest.webmvc.support.JpaHelper;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
@@ -32,113 +30,108 @@ import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandl
|
||||
*/
|
||||
public class RepositoryRestHandlerMapping extends RequestMappingHandlerMapping {
|
||||
|
||||
@Autowired
|
||||
private Repositories repositories;
|
||||
@Autowired
|
||||
private RepositoryRestConfiguration config;
|
||||
private EntityManagerFactory entityManagerFactory;
|
||||
@Autowired
|
||||
private Repositories repositories;
|
||||
@Autowired
|
||||
private RepositoryRestConfiguration config;
|
||||
@Autowired(required = false)
|
||||
private JpaHelper jpaHelper;
|
||||
|
||||
public RepositoryRestHandlerMapping() {
|
||||
setOrder(Ordered.LOWEST_PRECEDENCE);
|
||||
}
|
||||
public RepositoryRestHandlerMapping() {
|
||||
setOrder(Ordered.LOWEST_PRECEDENCE);
|
||||
}
|
||||
|
||||
@PersistenceContext
|
||||
public void setEntityManager(EntityManager entityManager) {
|
||||
this.entityManagerFactory = entityManager.getEntityManagerFactory();
|
||||
}
|
||||
@SuppressWarnings({"unchecked"})
|
||||
@Override
|
||||
protected HandlerMethod lookupHandlerMethod(String lookupPath,
|
||||
HttpServletRequest origRequest) throws Exception {
|
||||
String acceptType = origRequest.getHeader("Accept");
|
||||
if(null == acceptType) {
|
||||
acceptType = config.getDefaultMediaType().toString();
|
||||
}
|
||||
List<MediaType> acceptHeaderTypes = MediaType.parseMediaTypes(acceptType);
|
||||
List<MediaType> acceptableTypes = new ArrayList<MediaType>();
|
||||
for(MediaType mt : acceptHeaderTypes) {
|
||||
if(("*".equals(mt.getType()) && ("*".equals(mt.getSubtype()))
|
||||
|| ("application".equals(mt.getType()) && "*".equals(mt.getSubtype())))) {
|
||||
mt = config.getDefaultMediaType();
|
||||
}
|
||||
if(!acceptableTypes.contains(mt)) {
|
||||
acceptableTypes.add(mt);
|
||||
}
|
||||
}
|
||||
if(acceptableTypes.size() > 1) {
|
||||
acceptType = collectionToDelimitedString(acceptableTypes, ",");
|
||||
} else if(acceptableTypes.size() == 1) {
|
||||
acceptType = acceptableTypes.get(0).toString();
|
||||
} else {
|
||||
acceptType = config.getDefaultMediaType().toString();
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
@Override
|
||||
protected HandlerMethod lookupHandlerMethod(String lookupPath,
|
||||
HttpServletRequest origRequest) throws Exception {
|
||||
String acceptType = origRequest.getHeader("Accept");
|
||||
if(null == acceptType) {
|
||||
acceptType = config.getDefaultMediaType().toString();
|
||||
}
|
||||
List<MediaType> acceptHeaderTypes = MediaType.parseMediaTypes(acceptType);
|
||||
List<MediaType> acceptableTypes = new ArrayList<MediaType>();
|
||||
for(MediaType mt : acceptHeaderTypes) {
|
||||
if(("*".equals(mt.getType()) && ("*".equals(mt.getSubtype()))
|
||||
|| ("application".equals(mt.getType()) && "*".equals(mt.getSubtype())))) {
|
||||
mt = config.getDefaultMediaType();
|
||||
}
|
||||
if(!acceptableTypes.contains(mt)) {
|
||||
acceptableTypes.add(mt);
|
||||
}
|
||||
}
|
||||
if(acceptableTypes.size() > 1) {
|
||||
acceptType = collectionToDelimitedString(acceptableTypes, ",");
|
||||
} else if(acceptableTypes.size() == 1) {
|
||||
acceptType = acceptableTypes.get(0).toString();
|
||||
} else {
|
||||
acceptType = config.getDefaultMediaType().toString();
|
||||
}
|
||||
HttpServletRequest request = new DefaultAcceptTypeHttpServletRequest(origRequest, acceptType);
|
||||
|
||||
HttpServletRequest request = new DefaultAcceptTypeHttpServletRequest(origRequest, acceptType);
|
||||
if(acceptType.contains("javascript")) {
|
||||
if(null != request.getParameter(config.getJsonpParamName())
|
||||
|| null != request.getParameter(config.getJsonpOnErrParamName())) {
|
||||
return super.lookupHandlerMethod(lookupPath, request);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
String requestUri = lookupPath;
|
||||
if(requestUri.startsWith("/")) {
|
||||
requestUri = requestUri.substring(1);
|
||||
}
|
||||
if(!hasText(requestUri)) {
|
||||
return super.lookupHandlerMethod(lookupPath, request);
|
||||
}
|
||||
String[] parts = requestUri.split("/");
|
||||
if(parts.length == 0) {
|
||||
// Root request
|
||||
return super.lookupHandlerMethod(lookupPath, request);
|
||||
}
|
||||
|
||||
if(acceptType.contains("javascript")) {
|
||||
if(null != request.getParameter(config.getJsonpParamName())
|
||||
|| null != request.getParameter(config.getJsonpOnErrParamName())) {
|
||||
return super.lookupHandlerMethod(lookupPath, request);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
String requestUri = lookupPath;
|
||||
if(requestUri.startsWith("/")) {
|
||||
requestUri = requestUri.substring(1);
|
||||
}
|
||||
if(!hasText(requestUri)) {
|
||||
return super.lookupHandlerMethod(lookupPath, request);
|
||||
}
|
||||
String[] parts = requestUri.split("/");
|
||||
if(parts.length == 0) {
|
||||
// Root request
|
||||
return super.lookupHandlerMethod(lookupPath, request);
|
||||
}
|
||||
for(Class<?> domainType : repositories) {
|
||||
RepositoryInformation repoInfo = repositories.getRepositoryInformationFor(domainType);
|
||||
ResourceMapping mapping = getResourceMapping(config, repoInfo);
|
||||
if(mapping.getPath().equals(parts[0]) && mapping.isExported()) {
|
||||
return super.lookupHandlerMethod(lookupPath, request);
|
||||
}
|
||||
}
|
||||
|
||||
for(Class<?> domainType : repositories) {
|
||||
RepositoryInformation repoInfo = repositories.getRepositoryInformationFor(domainType);
|
||||
ResourceMapping mapping = getResourceMapping(config, repoInfo);
|
||||
if(mapping.getPath().equals(parts[0]) && mapping.isExported()) {
|
||||
return super.lookupHandlerMethod(lookupPath, request);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
@Override protected boolean isHandler(Class<?> beanType) {
|
||||
return (RepositoryController.class.isAssignableFrom(beanType)
|
||||
|| RepositoryEntityController.class.isAssignableFrom(beanType)
|
||||
|| RepositoryPropertyReferenceController.class.isAssignableFrom(beanType)
|
||||
|| RepositorySearchController.class.isAssignableFrom(beanType));
|
||||
}
|
||||
|
||||
@Override protected boolean isHandler(Class<?> beanType) {
|
||||
return (RepositoryController.class.isAssignableFrom(beanType)
|
||||
|| RepositoryEntityController.class.isAssignableFrom(beanType)
|
||||
|| RepositoryPropertyReferenceController.class.isAssignableFrom(beanType)
|
||||
|| RepositorySearchController.class.isAssignableFrom(beanType));
|
||||
}
|
||||
@Override protected void extendInterceptors(List<Object> interceptors) {
|
||||
if(null != jpaHelper) {
|
||||
Object jpaInterceptor = jpaHelper.getInterceptor();
|
||||
interceptors.add(jpaInterceptor);
|
||||
}
|
||||
}
|
||||
|
||||
@Override protected void extendInterceptors(List<Object> interceptors) {
|
||||
if(null != entityManagerFactory) {
|
||||
OpenEntityManagerInViewInterceptor omivi = new OpenEntityManagerInViewInterceptor();
|
||||
omivi.setEntityManagerFactory(entityManagerFactory);
|
||||
interceptors.add(omivi);
|
||||
}
|
||||
}
|
||||
private static class DefaultAcceptTypeHttpServletRequest extends HttpServletRequestWrapper {
|
||||
private final String defaultAcceptType;
|
||||
|
||||
private static class DefaultAcceptTypeHttpServletRequest extends HttpServletRequestWrapper {
|
||||
private final String defaultAcceptType;
|
||||
private DefaultAcceptTypeHttpServletRequest(HttpServletRequest request,
|
||||
String defaultAcceptType) {
|
||||
super(request);
|
||||
this.defaultAcceptType = defaultAcceptType;
|
||||
}
|
||||
|
||||
private DefaultAcceptTypeHttpServletRequest(HttpServletRequest request,
|
||||
String defaultAcceptType) {
|
||||
super(request);
|
||||
this.defaultAcceptType = defaultAcceptType;
|
||||
}
|
||||
|
||||
@Override public String getHeader(String name) {
|
||||
if("accept".equals(name.toLowerCase())) {
|
||||
return defaultAcceptType;
|
||||
} else {
|
||||
return super.getHeader(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override public String getHeader(String name) {
|
||||
if("accept".equals(name.toLowerCase())) {
|
||||
return defaultAcceptType;
|
||||
} else {
|
||||
return super.getHeader(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ import org.springframework.data.rest.webmvc.RepositoryRestRequestHandlerMethodAr
|
||||
import org.springframework.data.rest.webmvc.RepositorySearchController;
|
||||
import org.springframework.data.rest.webmvc.ServerHttpRequestMethodArgumentResolver;
|
||||
import org.springframework.data.rest.webmvc.convert.UriListHttpMessageConverter;
|
||||
import org.springframework.data.rest.webmvc.support.JpaHelper;
|
||||
import org.springframework.data.rest.webmvc.support.RepositoryEntityLinks;
|
||||
import org.springframework.data.rest.webmvc.support.ValidationExceptionHandler;
|
||||
import org.springframework.format.support.DefaultFormattingConversionService;
|
||||
@@ -44,7 +45,6 @@ import org.springframework.hateoas.EntityLinks;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;
|
||||
@@ -68,6 +68,10 @@ public class RepositoryRestMvcConfiguration {
|
||||
"javax.validation.ConstraintViolationException",
|
||||
RepositoryRestMvcConfiguration.class.getClassLoader()
|
||||
);
|
||||
private static final boolean IS_JPA_AVAILABLE = ClassUtils.isPresent(
|
||||
"javax.persistence.EntityManager",
|
||||
RepositoryRestMvcConfiguration.class.getClassLoader()
|
||||
);
|
||||
|
||||
@Bean public RepositoriesFactoryBean repositories() {
|
||||
return new RepositoriesFactoryBean();
|
||||
@@ -107,6 +111,14 @@ public class RepositoryRestMvcConfiguration {
|
||||
}
|
||||
}
|
||||
|
||||
@Bean @Lazy public JpaHelper jpaHelper() {
|
||||
if(IS_JPA_AVAILABLE) {
|
||||
return new JpaHelper();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Main configuration for the REST exporter.
|
||||
*/
|
||||
@@ -116,15 +128,6 @@ public class RepositoryRestMvcConfiguration {
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* For getting access to the {@link javax.persistence.EntityManagerFactory}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Bean public PersistenceAnnotationBeanPostProcessor persistenceAnnotationBeanPostProcessor() {
|
||||
return new PersistenceAnnotationBeanPostProcessor();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link org.springframework.beans.factory.config.BeanPostProcessor} to turn beans annotated as {@link
|
||||
* org.springframework.data.rest.repository.annotation.RepositoryEventHandler}s.
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package org.springframework.data.rest.webmvc.support;
|
||||
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
|
||||
import org.springframework.beans.BeanInstantiationException;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor;
|
||||
|
||||
/**
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
public class JpaHelper implements BeanFactoryAware {
|
||||
|
||||
private Object interceptor = null;
|
||||
|
||||
@Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
|
||||
(ListableBeanFactory)beanFactory,
|
||||
EntityManagerFactory.class
|
||||
);
|
||||
if(beanNames.length != 1) {
|
||||
throw new BeanInstantiationException(JpaHelper.class,
|
||||
String.format("Only one EntityManagerFactory expected but %s found",
|
||||
beanNames.length));
|
||||
}
|
||||
String unitName = beanNames[0];
|
||||
EntityManagerFactory emf = (EntityManagerFactory)beanFactory.getBean(unitName);
|
||||
OpenEntityManagerInViewInterceptor omivi = new OpenEntityManagerInViewInterceptor();
|
||||
omivi.setEntityManagerFactory(emf);
|
||||
this.interceptor = omivi;
|
||||
}
|
||||
|
||||
public Object getInterceptor() {
|
||||
return interceptor;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user