diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestHandlerMapping.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestHandlerMapping.java index a98c86b09..6c6346259 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestHandlerMapping.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestHandlerMapping.java @@ -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 acceptHeaderTypes = MediaType.parseMediaTypes(acceptType); + List acceptableTypes = new ArrayList(); + 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 acceptHeaderTypes = MediaType.parseMediaTypes(acceptType); - List acceptableTypes = new ArrayList(); - 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 interceptors) { + if(null != jpaHelper) { + Object jpaInterceptor = jpaHelper.getInterceptor(); + interceptors.add(jpaInterceptor); + } + } - @Override protected void extendInterceptors(List 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); + } + } + } } diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/config/RepositoryRestMvcConfiguration.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/config/RepositoryRestMvcConfiguration.java index 9005a4663..0fec964e6 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/config/RepositoryRestMvcConfiguration.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/config/RepositoryRestMvcConfiguration.java @@ -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. diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/support/JpaHelper.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/support/JpaHelper.java new file mode 100644 index 000000000..d6f656603 --- /dev/null +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/support/JpaHelper.java @@ -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; + } + +}