Merge branch 'master' of github.com:SpringSource/spring-data-commons
This commit is contained in:
@@ -35,24 +35,10 @@
|
||||
</dependency>
|
||||
|
||||
<!-- Logging -->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>jcl-over-slf4j</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
<scope>runtime</scope>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
@@ -38,8 +38,8 @@ import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
@@ -75,7 +75,7 @@ public class BasicMappingContext implements MappingContext, InitializingBean, Ap
|
||||
|
||||
private static final Set<String> UNMAPPED_FIELDS = new HashSet<String>(Arrays.asList("class", "this$0"));
|
||||
|
||||
protected Logger log = LoggerFactory.getLogger(getClass());
|
||||
protected Log log = LogFactory.getLog(getClass());
|
||||
protected ApplicationEventPublisher applicationEventPublisher;
|
||||
protected ConcurrentMap<TypeInformation, PersistentEntity<?>> persistentEntities = new ConcurrentHashMap<TypeInformation, PersistentEntity<?>>();
|
||||
protected ConcurrentMap<PersistentEntity<?>, List<Validator>> validators = new ConcurrentHashMap<PersistentEntity<?>, List<Validator>>();
|
||||
|
||||
@@ -48,13 +48,21 @@ public abstract class MappingBeanHelper {
|
||||
|
||||
static {
|
||||
simpleTypes.add(boolean.class);
|
||||
simpleTypes.add(boolean[].class);
|
||||
simpleTypes.add(long.class);
|
||||
simpleTypes.add(long[].class);
|
||||
simpleTypes.add(short.class);
|
||||
simpleTypes.add(short[].class);
|
||||
simpleTypes.add(int.class);
|
||||
simpleTypes.add(int[].class);
|
||||
simpleTypes.add(byte.class);
|
||||
simpleTypes.add(byte[].class);
|
||||
simpleTypes.add(float.class);
|
||||
simpleTypes.add(float[].class);
|
||||
simpleTypes.add(double.class);
|
||||
simpleTypes.add(double[].class);
|
||||
simpleTypes.add(char.class);
|
||||
simpleTypes.add(char[].class);
|
||||
simpleTypes.add(Boolean.class);
|
||||
simpleTypes.add(Long.class);
|
||||
simpleTypes.add(Short.class);
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2011 by the original author(s).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.mapping.context;
|
||||
|
||||
import org.springframework.data.mapping.model.MappingContext;
|
||||
|
||||
/**
|
||||
* An interface to make beans aware of the active MappingContext in the current ApplicationContext.
|
||||
*
|
||||
* @author Jon Brisbin <jbrisbin@vmware.com>
|
||||
*/
|
||||
public interface MappingContextAware {
|
||||
|
||||
/**
|
||||
* The active MappingContext for the environment.
|
||||
*
|
||||
* @param mappingContext
|
||||
*/
|
||||
void setMappingContext(MappingContext mappingContext);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2011 by the original author(s).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.mapping.context;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.data.mapping.model.MappingContext;
|
||||
|
||||
/**
|
||||
* BeanPostProcessor to make Spring beans aware of the current MappingContext. If a MappingContext exists with the
|
||||
* default bean name ("mappingContext"), then that bean is used. If there is no MappingContext registered under the
|
||||
* default bean name, then the first MappingContext it finds is the one it chooses.
|
||||
*
|
||||
* @author Jon Brisbin <jbrisbin@vmware.com>
|
||||
*/
|
||||
public class MappingContextAwareBeanPostProcessor implements BeanPostProcessor, ApplicationContextAware {
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
private String mappingContextBeanName = "mappingContext";
|
||||
private MappingContext mappingContext;
|
||||
|
||||
public MappingContextAwareBeanPostProcessor() {
|
||||
}
|
||||
|
||||
public MappingContextAwareBeanPostProcessor(MappingContext mappingContext) {
|
||||
this.mappingContext = mappingContext;
|
||||
}
|
||||
|
||||
public String getMappingContextBeanName() {
|
||||
return mappingContextBeanName;
|
||||
}
|
||||
|
||||
public void setMappingContextBeanName(String mappingContextBeanName) {
|
||||
this.mappingContextBeanName = mappingContextBeanName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (bean instanceof MappingContextAware) {
|
||||
if (null == mappingContext) {
|
||||
Map<String, MappingContext> mappingContexts = applicationContext.getBeansOfType(MappingContext.class);
|
||||
if (mappingContexts.containsKey(mappingContextBeanName)) {
|
||||
this.mappingContext = mappingContexts.get(mappingContextBeanName);
|
||||
} else {
|
||||
String firstBean = mappingContexts.keySet().iterator().next();
|
||||
this.mappingContext = applicationContext.getBean(firstBean, MappingContext.class);
|
||||
}
|
||||
}
|
||||
((MappingContextAware) bean).setMappingContext(mappingContext);
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package org.springframework.data.persistence;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import sun.reflect.ReflectionFactory;
|
||||
|
||||
@@ -18,7 +18,7 @@ import java.util.Map;
|
||||
*/
|
||||
public abstract class AbstractConstructorEntityInstantiator<BACKING_INTERFACE, STATE> implements EntityInstantiator<BACKING_INTERFACE, STATE> {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||
private final Log log = LogFactory.getLog(getClass());
|
||||
private final Map<Class<? extends BACKING_INTERFACE>,StateBackedCreator<? extends BACKING_INTERFACE,STATE>> cache = new HashMap<Class<? extends BACKING_INTERFACE>,StateBackedCreator<? extends BACKING_INTERFACE,STATE>>();
|
||||
|
||||
public <T extends BACKING_INTERFACE> T createEntityFromState(STATE n, Class<T> c) {
|
||||
|
||||
@@ -23,8 +23,8 @@ import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
@@ -58,8 +58,8 @@ import org.w3c.dom.Element;
|
||||
public abstract class AbstractRepositoryConfigDefinitionParser<S extends GlobalRepositoryConfigInformation<T>, T extends SingleRepositoryConfigInformation<S>>
|
||||
implements BeanDefinitionParser {
|
||||
|
||||
private static final Logger LOG = LoggerFactory
|
||||
.getLogger(AbstractRepositoryConfigDefinitionParser.class);
|
||||
private static final Log LOG = LogFactory.getLog(
|
||||
AbstractRepositoryConfigDefinitionParser.class);
|
||||
|
||||
private static final String REPOSITORY_INTERFACE_POST_PROCESSOR =
|
||||
"org.springframework.data.repository.support.RepositoryInterfaceAwareBeanPostProcessor";
|
||||
@@ -223,12 +223,13 @@ public abstract class AbstractRepositoryConfigDefinitionParser<S extends GlobalR
|
||||
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
|
||||
beanDefinition.setSource(beanSource);
|
||||
|
||||
LOG.debug(
|
||||
"Registering repository: {} - Interface: {} - Factory: {}, - Custom implementation: {}",
|
||||
new Object[] { context.getBeanId(),
|
||||
context.getInterfaceName(),
|
||||
context.getRepositoryFactoryBeanClassName(),
|
||||
customImplementationBeanName });
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug(
|
||||
"Registering repository: " + context.getBeanId() +
|
||||
" - Interface: " + context.getInterfaceName() +
|
||||
" - Factory: " + context.getRepositoryFactoryBeanClassName() +
|
||||
", - Custom implementation: " + customImplementationBeanName);
|
||||
}
|
||||
|
||||
BeanComponentDefinition definition =
|
||||
new BeanComponentDefinition(beanDefinition,
|
||||
@@ -285,9 +286,11 @@ public abstract class AbstractRepositoryConfigDefinitionParser<S extends GlobalR
|
||||
return null;
|
||||
}
|
||||
|
||||
LOG.debug("Registering custom repository implementation: {} {}",
|
||||
config.getImplementationBeanName(),
|
||||
beanDefinition.getBeanClassName());
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Registering custom repository implementation: " +
|
||||
config.getImplementationBeanName() + " " +
|
||||
beanDefinition.getBeanClassName());
|
||||
}
|
||||
|
||||
beanDefinition.setSource(source);
|
||||
parser.registerBeanComponent(new BeanComponentDefinition(
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.data.repository.query;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.springframework.data.repository.support.RepositoryMetadata;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
|
||||
@@ -54,8 +55,8 @@ public interface QueryLookupStrategy {
|
||||
* that can be executed afterwards.
|
||||
*
|
||||
* @param method
|
||||
* @param domainClass
|
||||
* @param metadata
|
||||
* @return
|
||||
*/
|
||||
RepositoryQuery resolveQuery(Method method, Class<?> domainClass);
|
||||
RepositoryQuery resolveQuery(Method method, RepositoryMetadata metadata);
|
||||
}
|
||||
@@ -24,6 +24,7 @@ import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.repository.support.EntityMetadata;
|
||||
import org.springframework.data.repository.support.RepositoryMetadata;
|
||||
import org.springframework.data.repository.util.ClassUtils;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -42,6 +43,7 @@ public class QueryMethod {
|
||||
SINGLE_ENTITY, PAGING, COLLECTION, MODIFYING;
|
||||
}
|
||||
|
||||
private final RepositoryMetadata metadata;
|
||||
private final Method method;
|
||||
private final Parameters parameters;
|
||||
|
||||
@@ -52,7 +54,7 @@ public class QueryMethod {
|
||||
*
|
||||
* @param method must not be {@literal null}
|
||||
*/
|
||||
public QueryMethod(Method method) {
|
||||
public QueryMethod(Method method, RepositoryMetadata metadata) {
|
||||
|
||||
Assert.notNull(method, "Method must not be null!");
|
||||
|
||||
@@ -75,6 +77,7 @@ public class QueryMethod {
|
||||
|
||||
this.method = method;
|
||||
this.parameters = new Parameters(method);
|
||||
this.metadata = metadata;
|
||||
}
|
||||
|
||||
|
||||
@@ -103,8 +106,12 @@ public class QueryMethod {
|
||||
|
||||
|
||||
protected Class<?> getDomainClass() {
|
||||
|
||||
Class<?> repositoryDomainClass = metadata.getDomainClass();
|
||||
Class<?> methodDomainClass = ClassUtils.getReturnedDomainClass(method);
|
||||
|
||||
return ClassUtils.getReturnedDomainClass(method);
|
||||
return repositoryDomainClass == null || repositoryDomainClass.isAssignableFrom(methodDomainClass) ? methodDomainClass
|
||||
: repositoryDomainClass;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,289 @@
|
||||
/*
|
||||
* Copyright 2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.repository.support;
|
||||
|
||||
import static org.springframework.data.repository.util.ClassUtils.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.springframework.data.repository.Repository;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link RepositoryInformation}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
class DefaultRepositoryInformation implements RepositoryInformation {
|
||||
|
||||
private static final TypeVariable<Class<Repository>>[] PARAMETERS = Repository.class.getTypeParameters();
|
||||
private static final String DOMAIN_TYPE_NAME = PARAMETERS[0].getName();
|
||||
private static final String ID_TYPE_NAME = PARAMETERS[1].getName();
|
||||
|
||||
private final Map<Method, Method> methodCache = new ConcurrentHashMap<Method, Method>();
|
||||
|
||||
private final RepositoryMetadata metadata;
|
||||
private final Class<?> repositoryBaseClass;
|
||||
|
||||
/**
|
||||
* Creates a new {@link DefaultRepositoryMetadata} for the given repository interface and repository base class.
|
||||
*
|
||||
* @param repositoryInterface
|
||||
*/
|
||||
public DefaultRepositoryInformation(RepositoryMetadata metadata, Class<?> repositoryBaseClass) {
|
||||
|
||||
Assert.notNull(metadata);
|
||||
Assert.notNull(repositoryBaseClass);
|
||||
this.metadata = metadata;
|
||||
this.repositoryBaseClass = repositoryBaseClass;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.support.RepositoryMetadata#getRepositoryInterface()
|
||||
*/
|
||||
@Override
|
||||
public Class<?> getRepositoryInterface() {
|
||||
return metadata.getRepositoryInterface();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.support.RepositoryMetadata#getDomainClass()
|
||||
*/
|
||||
@Override
|
||||
public Class<?> getDomainClass() {
|
||||
return metadata.getDomainClass();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.support.RepositoryMetadata#getIdClass()
|
||||
*/
|
||||
@Override
|
||||
public Class<?> getIdClass() {
|
||||
return metadata.getIdClass();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.data.repository.support.RepositoryMetadata#
|
||||
* getRepositoryBaseClass()
|
||||
*/
|
||||
public Class<?> getRepositoryBaseClass() {
|
||||
|
||||
return this.repositoryBaseClass;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.data.repository.support.RepositoryMetadata#
|
||||
* getBaseClassMethod(java.lang.reflect.Method)
|
||||
*/
|
||||
public Method getBaseClassMethod(Method method) {
|
||||
|
||||
Assert.notNull(method);
|
||||
|
||||
Method result = methodCache.get(method);
|
||||
|
||||
if (null != result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = getBaseClassMethodFor(method);
|
||||
methodCache.put(method, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given method is considered to be a repository base class method.
|
||||
*
|
||||
* @param method
|
||||
* @return
|
||||
*/
|
||||
private boolean isBaseClassMethod(Method method) {
|
||||
|
||||
Assert.notNull(method);
|
||||
|
||||
if (method.getDeclaringClass().isAssignableFrom(repositoryBaseClass)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return !method.equals(getBaseClassMethod(method));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.data.repository.support.RepositoryMetadata#
|
||||
* getFinderMethods()
|
||||
*/
|
||||
public Iterable<Method> getQueryMethods() {
|
||||
|
||||
Set<Method> result = new HashSet<Method>();
|
||||
|
||||
for (Method method : getRepositoryInterface().getDeclaredMethods()) {
|
||||
if (!isCustomMethod(method) && !isBaseClassMethod(method)) {
|
||||
result.add(method);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.springframework.data.repository.support.RepositoryMetadata#isCustomMethod
|
||||
* (java.lang.reflect.Method)
|
||||
*/
|
||||
public boolean isCustomMethod(Method method) {
|
||||
|
||||
Class<?> declaringClass = method.getDeclaringClass();
|
||||
|
||||
boolean isQueryMethod = declaringClass.equals(getRepositoryInterface());
|
||||
boolean isRepositoryInterface = isGenericRepositoryInterface(declaringClass);
|
||||
boolean isBaseClassMethod = isBaseClassMethod(method);
|
||||
|
||||
return !(isRepositoryInterface || isBaseClassMethod || isQueryMethod);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the given base class' method if the given method (declared in the repository interface) was also declared
|
||||
* at the repository base class. Returns the given method if the given base class does not declare the method given.
|
||||
* Takes generics into account.
|
||||
*
|
||||
* @param method
|
||||
* @return
|
||||
*/
|
||||
Method getBaseClassMethodFor(Method method) {
|
||||
|
||||
for (Method baseClassMethod : repositoryBaseClass.getMethods()) {
|
||||
|
||||
// Wrong name
|
||||
if (!method.getName().equals(baseClassMethod.getName())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Wrong number of arguments
|
||||
if (!(method.getParameterTypes().length == baseClassMethod.getParameterTypes().length)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check whether all parameters match
|
||||
if (!parametersMatch(method, baseClassMethod)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return baseClassMethod;
|
||||
}
|
||||
|
||||
return method;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.data.repository.support.RepositoryMetadata#
|
||||
* hasCustomMethod()
|
||||
*/
|
||||
public boolean hasCustomMethod() {
|
||||
|
||||
Class<?> repositoryInterface = getRepositoryInterface();
|
||||
|
||||
// No detection required if no typing interface was configured
|
||||
if (isGenericRepositoryInterface(repositoryInterface)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (Method method : repositoryInterface.getMethods()) {
|
||||
if (isCustomMethod(method) && !isBaseClassMethod(method)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the given method's parameters to match the ones of the given base class method. Matches generic arguments
|
||||
* agains the ones bound in the given repository interface.
|
||||
*
|
||||
* @param method
|
||||
* @param baseClassMethod
|
||||
* @return
|
||||
*/
|
||||
private boolean parametersMatch(Method method, Method baseClassMethod) {
|
||||
|
||||
Type[] genericTypes = baseClassMethod.getGenericParameterTypes();
|
||||
Class<?>[] types = baseClassMethod.getParameterTypes();
|
||||
Class<?>[] methodParameters = method.getParameterTypes();
|
||||
|
||||
for (int i = 0; i < genericTypes.length; i++) {
|
||||
|
||||
Type type = genericTypes[i];
|
||||
|
||||
if (type instanceof TypeVariable<?>) {
|
||||
|
||||
String name = ((TypeVariable<?>) type).getName();
|
||||
|
||||
if (!matchesGenericType(name, methodParameters[i])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (!types[i].equals(methodParameters[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given parameter type matches the generic type of the given parameter. Thus when {@literal PK} is
|
||||
* declared, the method ensures that given method parameter is the primary key type declared in the given repository
|
||||
* interface e.g.
|
||||
*
|
||||
* @param name
|
||||
* @param parameterType
|
||||
* @return
|
||||
*/
|
||||
private boolean matchesGenericType(String name, Class<?> parameterType) {
|
||||
|
||||
Class<?> entityType = getDomainClass();
|
||||
Class<?> idClass = getIdClass();
|
||||
|
||||
if (ID_TYPE_NAME.equals(name) && parameterType.equals(idClass)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (DOMAIN_TYPE_NAME.equals(name) && parameterType.equals(entityType)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -37,17 +37,7 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public class DefaultRepositoryMetadata implements RepositoryMetadata {
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private static final TypeVariable<Class<Repository>>[] PARAMETERS =
|
||||
Repository.class.getTypeParameters();
|
||||
private static final String DOMAIN_TYPE_NAME = PARAMETERS[0].getName();
|
||||
private static final String ID_TYPE_NAME = PARAMETERS[1].getName();
|
||||
|
||||
private final Map<Method, Method> methodCache =
|
||||
new ConcurrentHashMap<Method, Method>();
|
||||
|
||||
private final Class<?> repositoryInterface;
|
||||
private final Class<?> repositoryBaseClass;
|
||||
|
||||
|
||||
/**
|
||||
@@ -56,13 +46,10 @@ public class DefaultRepositoryMetadata implements RepositoryMetadata {
|
||||
*
|
||||
* @param repositoryInterface
|
||||
*/
|
||||
public DefaultRepositoryMetadata(Class<?> repositoryInterface,
|
||||
Class<?> repositoryBaseClass) {
|
||||
public DefaultRepositoryMetadata(Class<?> repositoryInterface) {
|
||||
|
||||
Assert.notNull(repositoryInterface);
|
||||
Assert.notNull(repositoryBaseClass);
|
||||
this.repositoryInterface = repositoryInterface;
|
||||
this.repositoryBaseClass = repositoryBaseClass;
|
||||
}
|
||||
|
||||
|
||||
@@ -78,17 +65,6 @@ public class DefaultRepositoryMetadata implements RepositoryMetadata {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.data.repository.support.RepositoryMetadata#
|
||||
* getRepositoryBaseClass()
|
||||
*/
|
||||
public Class<?> getRepositoryBaseClass() {
|
||||
|
||||
return this.repositoryBaseClass;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
@@ -118,211 +94,4 @@ public class DefaultRepositoryMetadata implements RepositoryMetadata {
|
||||
resolveTypeArguments(repositoryInterface, Repository.class);
|
||||
return arguments == null ? null : arguments[1];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.data.repository.support.RepositoryMetadata#
|
||||
* getBaseClassMethod(java.lang.reflect.Method)
|
||||
*/
|
||||
public Method getBaseClassMethod(Method method) {
|
||||
|
||||
Assert.notNull(method);
|
||||
|
||||
Method result = methodCache.get(method);
|
||||
|
||||
if (null != result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = getBaseClassMethodFor(method);
|
||||
methodCache.put(method, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns whether the given method is considered to be a repository base
|
||||
* class method.
|
||||
*
|
||||
* @param method
|
||||
* @return
|
||||
*/
|
||||
private boolean isBaseClassMethod(Method method) {
|
||||
|
||||
Assert.notNull(method);
|
||||
|
||||
if (method.getDeclaringClass().isAssignableFrom(repositoryBaseClass)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return !method.equals(getBaseClassMethod(method));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.data.repository.support.RepositoryMetadata#
|
||||
* getFinderMethods()
|
||||
*/
|
||||
public Iterable<Method> getQueryMethods() {
|
||||
|
||||
Set<Method> result = new HashSet<Method>();
|
||||
|
||||
for (Method method : repositoryInterface.getDeclaredMethods()) {
|
||||
if (!isCustomMethod(method) && !isBaseClassMethod(method)) {
|
||||
result.add(method);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.springframework.data.repository.support.RepositoryMetadata#isCustomMethod
|
||||
* (java.lang.reflect.Method)
|
||||
*/
|
||||
public boolean isCustomMethod(Method method) {
|
||||
|
||||
Class<?> declaringClass = method.getDeclaringClass();
|
||||
|
||||
boolean isQueryMethod = declaringClass.equals(repositoryInterface);
|
||||
boolean isRepositoryInterface =
|
||||
isGenericRepositoryInterface(declaringClass);
|
||||
boolean isBaseClassMethod = isBaseClassMethod(method);
|
||||
|
||||
return !(isRepositoryInterface || isBaseClassMethod || isQueryMethod);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the given base class' method if the given method (declared in the
|
||||
* repository interface) was also declared at the repository base class.
|
||||
* Returns the given method if the given base class does not declare the
|
||||
* method given. Takes generics into account.
|
||||
*
|
||||
* @param method
|
||||
* @return
|
||||
*/
|
||||
Method getBaseClassMethodFor(Method method) {
|
||||
|
||||
for (Method baseClassMethod : repositoryBaseClass.getMethods()) {
|
||||
|
||||
// Wrong name
|
||||
if (!method.getName().equals(baseClassMethod.getName())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Wrong number of arguments
|
||||
if (!(method.getParameterTypes().length == baseClassMethod
|
||||
.getParameterTypes().length)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check whether all parameters match
|
||||
if (!parametersMatch(method, baseClassMethod)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return baseClassMethod;
|
||||
}
|
||||
|
||||
return method;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.data.repository.support.RepositoryMetadata#
|
||||
* hasCustomMethod()
|
||||
*/
|
||||
public boolean hasCustomMethod() {
|
||||
|
||||
// No detection required if no typing interface was configured
|
||||
if (isGenericRepositoryInterface(repositoryInterface)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (Method method : repositoryInterface.getMethods()) {
|
||||
if (isCustomMethod(method) && !isBaseClassMethod(method)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks the given method's parameters to match the ones of the given base
|
||||
* class method. Matches generic arguments agains the ones bound in the
|
||||
* given repository interface.
|
||||
*
|
||||
* @param method
|
||||
* @param baseClassMethod
|
||||
* @return
|
||||
*/
|
||||
private boolean parametersMatch(Method method, Method baseClassMethod) {
|
||||
|
||||
Type[] genericTypes = baseClassMethod.getGenericParameterTypes();
|
||||
Class<?>[] types = baseClassMethod.getParameterTypes();
|
||||
Class<?>[] methodParameters = method.getParameterTypes();
|
||||
|
||||
for (int i = 0; i < genericTypes.length; i++) {
|
||||
|
||||
Type type = genericTypes[i];
|
||||
|
||||
if (type instanceof TypeVariable<?>) {
|
||||
|
||||
String name = ((TypeVariable<?>) type).getName();
|
||||
|
||||
if (!matchesGenericType(name, methodParameters[i])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (!types[i].equals(methodParameters[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks whether the given parameter type matches the generic type of the
|
||||
* given parameter. Thus when {@literal PK} is declared, the method ensures
|
||||
* that given method parameter is the primary key type declared in the given
|
||||
* repository interface e.g.
|
||||
*
|
||||
* @param name
|
||||
* @param parameterType
|
||||
* @return
|
||||
*/
|
||||
private boolean matchesGenericType(String name, Class<?> parameterType) {
|
||||
|
||||
Class<?> entityType = getDomainClass();
|
||||
Class<?> idClass = getIdClass();
|
||||
|
||||
if (ID_TYPE_NAME.equals(name) && parameterType.equals(idClass)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (DOMAIN_TYPE_NAME.equals(name) && parameterType.equals(entityType)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,12 +124,12 @@ public abstract class RepositoryFactorySupport {
|
||||
public <T> T getRepository(Class<T> repositoryInterface,
|
||||
Object customImplementation) {
|
||||
|
||||
RepositoryMetadata metadata =
|
||||
getRepositoryMetadata(repositoryInterface);
|
||||
RepositoryMetadata metadata = getRepositoryMetadata(repositoryInterface);
|
||||
RepositoryInformation information = getRepositoryInformation(metadata);
|
||||
|
||||
validate(metadata, customImplementation);
|
||||
validate(information, customImplementation);
|
||||
|
||||
Object target = getTargetRepository(metadata);
|
||||
Object target = getTargetRepository(information);
|
||||
|
||||
// Create proxy
|
||||
ProxyFactory result = new ProxyFactory();
|
||||
@@ -140,22 +140,31 @@ public abstract class RepositoryFactorySupport {
|
||||
processor.postProcess(result);
|
||||
}
|
||||
|
||||
result.addAdvice(new QueryExecuterMethodInterceptor(metadata,
|
||||
result.addAdvice(new QueryExecuterMethodInterceptor(information,
|
||||
customImplementation, target));
|
||||
|
||||
return (T) result.getProxy();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the {@link RepositoryMetadata} for the given repository interface.
|
||||
*
|
||||
* @param repositoryInterface
|
||||
* @return
|
||||
*/
|
||||
protected RepositoryMetadata getRepositoryMetadata(Class<?> repositoryInterface) {
|
||||
|
||||
return new DefaultRepositoryMetadata(repositoryInterface, getRepositoryBaseClass(repositoryInterface));
|
||||
RepositoryMetadata getRepositoryMetadata(Class<?> repositoryInterface) {
|
||||
return new DefaultRepositoryMetadata(repositoryInterface);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the {@link RepositoryInformation} for the given repository interface.
|
||||
*
|
||||
* @param repositoryInterface
|
||||
* @return
|
||||
*/
|
||||
private RepositoryInformation getRepositoryInformation(RepositoryMetadata metadata) {
|
||||
return new DefaultRepositoryInformation(metadata, getRepositoryBaseClass(metadata));
|
||||
}
|
||||
|
||||
|
||||
@@ -173,7 +182,7 @@ public abstract class RepositoryFactorySupport {
|
||||
/**
|
||||
* Create a repository instance as backing for the query proxy.
|
||||
*
|
||||
* @param domainClass
|
||||
* @param metadata
|
||||
* @return
|
||||
*/
|
||||
protected abstract Object getTargetRepository(RepositoryMetadata metadata);
|
||||
@@ -184,11 +193,11 @@ public abstract class RepositoryFactorySupport {
|
||||
* {@link #getTargetRepository(RepositoryMetadata)} returns an instance of
|
||||
* this class.
|
||||
*
|
||||
* @param repositoryInterface
|
||||
* @param metadata
|
||||
* @return
|
||||
*/
|
||||
protected abstract Class<?> getRepositoryBaseClass(
|
||||
Class<?> repositoryInterface);
|
||||
RepositoryMetadata metadata);
|
||||
|
||||
/**
|
||||
* Returns the {@link QueryLookupStrategy} for the given {@link Key}.
|
||||
@@ -205,20 +214,26 @@ public abstract class RepositoryFactorySupport {
|
||||
* Validates the given repository interface as well as the given custom
|
||||
* implementation.
|
||||
*
|
||||
* @param repositoryMetadata
|
||||
* @param repositoryInformation
|
||||
* @param customImplementation
|
||||
*/
|
||||
protected void validate(RepositoryMetadata repositoryMetadata,
|
||||
private void validate(RepositoryInformation repositoryInformation,
|
||||
Object customImplementation) {
|
||||
|
||||
if (null == customImplementation
|
||||
&& repositoryMetadata.hasCustomMethod()) {
|
||||
&& repositoryInformation.hasCustomMethod()) {
|
||||
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
"You have custom methods in %s but not provided a custom implementation!",
|
||||
repositoryMetadata.getRepositoryInterface()));
|
||||
repositoryInformation.getRepositoryInterface()));
|
||||
}
|
||||
|
||||
validate(repositoryInformation);
|
||||
}
|
||||
|
||||
protected void validate(RepositoryMetadata repositoryMetadata) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -236,7 +251,7 @@ public abstract class RepositoryFactorySupport {
|
||||
new ConcurrentHashMap<Method, RepositoryQuery>();
|
||||
|
||||
private final Object customImplementation;
|
||||
private final RepositoryMetadata metadata;
|
||||
private final RepositoryInformation repositoryInformation;
|
||||
private final Object target;
|
||||
|
||||
|
||||
@@ -246,10 +261,10 @@ public abstract class RepositoryFactorySupport {
|
||||
* interface methods.
|
||||
*/
|
||||
public QueryExecuterMethodInterceptor(
|
||||
RepositoryMetadata repositoryMetadata,
|
||||
RepositoryInformation repositoryInformation,
|
||||
Object customImplementation, Object target) {
|
||||
|
||||
this.metadata = repositoryMetadata;
|
||||
this.repositoryInformation = repositoryInformation;
|
||||
this.customImplementation = customImplementation;
|
||||
this.target = target;
|
||||
|
||||
@@ -258,7 +273,7 @@ public abstract class RepositoryFactorySupport {
|
||||
|
||||
if (lookupStrategy == null) {
|
||||
|
||||
if (repositoryMetadata.hasCustomMethod()) {
|
||||
if (repositoryInformation.hasCustomMethod()) {
|
||||
throw new IllegalStateException(
|
||||
"You have defined query method in the repository but " +
|
||||
"you don't have no query lookup strategy defined. The " +
|
||||
@@ -268,19 +283,17 @@ public abstract class RepositoryFactorySupport {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Method method : metadata.getQueryMethods()) {
|
||||
for (Method method : repositoryInformation.getQueryMethods()) {
|
||||
RepositoryQuery query =
|
||||
lookupStrategy.resolveQuery(method,
|
||||
repositoryMetadata.getDomainClass());
|
||||
invokeListeners(query, metadata);
|
||||
lookupStrategy.resolveQuery(method,repositoryInformation);
|
||||
invokeListeners(query);
|
||||
queries.put(method, query);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
private void invokeListeners(RepositoryQuery query,
|
||||
RepositoryMetadata metadata) {
|
||||
private void invokeListeners(RepositoryQuery query) {
|
||||
|
||||
for (QueryCreationListener listener : queryPostProcessors) {
|
||||
Class<?> typeArgument =
|
||||
@@ -319,7 +332,7 @@ public abstract class RepositoryFactorySupport {
|
||||
|
||||
// Lookup actual method as it might be redeclared in the interface
|
||||
// and we have to use the repository instance nevertheless
|
||||
Method actualMethod = metadata.getBaseClassMethod(method);
|
||||
Method actualMethod = repositoryInformation.getBaseClassMethod(method);
|
||||
return executeMethodOn(target, actualMethod,
|
||||
invocation.getArguments());
|
||||
}
|
||||
@@ -374,7 +387,7 @@ public abstract class RepositoryFactorySupport {
|
||||
return false;
|
||||
}
|
||||
|
||||
return metadata.isCustomMethod(invocation.getMethod());
|
||||
return repositoryInformation.isCustomMethod(invocation.getMethod());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.repository.support;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* Aditional repository specific information
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
interface RepositoryInformation extends RepositoryMetadata {
|
||||
|
||||
/**
|
||||
* Returns the base class to be used to create the proxy backing instance.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Class<?> getRepositoryBaseClass();
|
||||
|
||||
|
||||
/**
|
||||
* Returns if the configured repository interface has custom methods, that
|
||||
* might have to be delegated to a custom implementation. This is used to
|
||||
* verify repository configuration.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean hasCustomMethod();
|
||||
|
||||
|
||||
/**
|
||||
* Returns whether the given method is a custom repository method.
|
||||
*
|
||||
* @param method
|
||||
* @param baseClass
|
||||
* @return
|
||||
*/
|
||||
boolean isCustomMethod(Method method);
|
||||
|
||||
|
||||
/**
|
||||
* Returns all methods considered to be query methods.
|
||||
*
|
||||
* @param repositoryInterface
|
||||
* @return
|
||||
*/
|
||||
Iterable<Method> getQueryMethods();
|
||||
|
||||
|
||||
/**
|
||||
* Returns the base class method that is backing the given method. This can
|
||||
* be necessary if a repository interface redeclares a method of the core
|
||||
* repository interface (e.g. for transaction behaviour customization).
|
||||
* Returns the method itself if the base class does not implement the given
|
||||
* method.
|
||||
*
|
||||
* @param method
|
||||
* @return
|
||||
*/
|
||||
Method getBaseClassMethod(Method method);
|
||||
}
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package org.springframework.data.repository.support;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
|
||||
/**
|
||||
@@ -24,81 +23,29 @@ import java.lang.reflect.Method;
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface RepositoryMetadata {
|
||||
|
||||
/**
|
||||
* Returns the id class the given class is declared for.
|
||||
*
|
||||
* @param clazz
|
||||
* @return the id class of the entity managed by the repository for or
|
||||
* {@code null} if none found.
|
||||
*/
|
||||
Class<?> getIdClass();
|
||||
|
||||
/**
|
||||
* Returns the repository interface.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Class<?> getRepositoryInterface();
|
||||
/**
|
||||
* Returns the domain class the repository is declared for.
|
||||
*
|
||||
* @param clazz
|
||||
* @return the domain class the repository is handling or {@code null} if
|
||||
* none found.
|
||||
*/
|
||||
Class<?> getDomainClass();
|
||||
|
||||
|
||||
/**
|
||||
* Returns the base class to be used to create the proxy backing instance.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Class<?> getRepositoryBaseClass();
|
||||
|
||||
|
||||
/**
|
||||
* Returns if the configured repository interface has custom methods, that
|
||||
* might have to be delegated to a custom implementation. This is used to
|
||||
* verify repository configuration.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean hasCustomMethod();
|
||||
|
||||
|
||||
/**
|
||||
* Returns whether the given method is a custom repository method.
|
||||
*
|
||||
* @param method
|
||||
* @param baseClass
|
||||
* @return
|
||||
*/
|
||||
boolean isCustomMethod(Method method);
|
||||
|
||||
|
||||
/**
|
||||
* Returns all methods considered to be query methods.
|
||||
*
|
||||
* @param repositoryInterface
|
||||
* @return
|
||||
*/
|
||||
Iterable<Method> getQueryMethods();
|
||||
|
||||
|
||||
/**
|
||||
* Returns the base class method that is backing the given method. This can
|
||||
* be necessary if a repository interface redeclares a method of the core
|
||||
* repository interface (e.g. for transaction behaviour customization).
|
||||
* Returns the method itself if the base class does not implement the given
|
||||
* method.
|
||||
*
|
||||
* @param method
|
||||
* @return
|
||||
*/
|
||||
Method getBaseClassMethod(Method method);
|
||||
|
||||
|
||||
/**
|
||||
* Returns the domain class the repository is declared for.
|
||||
*
|
||||
* @param clazz
|
||||
* @return the domain class the repository is handling or {@code null} if
|
||||
* none found.
|
||||
*/
|
||||
Class<?> getDomainClass();
|
||||
|
||||
|
||||
/**
|
||||
* Returns the id class the given class is declared for.
|
||||
*
|
||||
* @param clazz
|
||||
* @return the id class of the entity managed by the repository for or
|
||||
* {@code null} if none found.
|
||||
*/
|
||||
Class<?> getIdClass();
|
||||
/**
|
||||
* Returns the repository interface.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Class<?> getRepositoryInterface();
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
package org.springframework.data.transaction;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.data.persistence.ChangeSetBacked;
|
||||
import org.springframework.data.persistence.ChangeSetPersister;
|
||||
import org.springframework.transaction.support.TransactionSynchronization;
|
||||
|
||||
public class ChangeSetBackedTransactionSynchronization implements TransactionSynchronization {
|
||||
|
||||
protected final Logger log = LoggerFactory.getLogger(getClass());
|
||||
protected final Log log = LogFactory.getLog(getClass());
|
||||
|
||||
private ChangeSetPersister<Object> changeSetPersister;
|
||||
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
package org.springframework.data.repository.support;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.repository.Repository;
|
||||
import org.springframework.data.repository.support.DefaultRepositoryMetadataUnitTests.DummyGenericRepositorySupport;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class DefaultRepositoryInformationUnitTests {
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
static final Class<DummyGenericRepositorySupport> REPOSITORY = DummyGenericRepositorySupport.class;
|
||||
|
||||
@Test
|
||||
public void discoversRepositoryBaseClassMethod() throws Exception {
|
||||
|
||||
Method method = FooDao.class.getMethod("findOne", Integer.class);
|
||||
RepositoryMetadata metadata = new DefaultRepositoryMetadata(FooDao.class);
|
||||
DefaultRepositoryInformation information = new DefaultRepositoryInformation(metadata, REPOSITORY);
|
||||
|
||||
Method reference = information.getBaseClassMethodFor(method);
|
||||
assertEquals(REPOSITORY, reference.getDeclaringClass());
|
||||
assertThat(reference.getName(), is("findOne"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void discoveresNonRepositoryBaseClassMethod() throws Exception {
|
||||
|
||||
Method method = FooDao.class.getMethod("findOne", Long.class);
|
||||
|
||||
RepositoryMetadata metadata = new DefaultRepositoryMetadata(FooDao.class);
|
||||
DefaultRepositoryInformation information = new DefaultRepositoryInformation(metadata, Repository.class);
|
||||
|
||||
assertThat(information.getBaseClassMethodFor(method), is(method));
|
||||
}
|
||||
|
||||
private static interface FooDao extends Repository<User, Integer> {
|
||||
|
||||
// Redeclared method
|
||||
User findOne(Integer primaryKey);
|
||||
|
||||
// Not a redeclared method
|
||||
User findOne(Long primaryKey);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private class User {
|
||||
|
||||
private String firstname;
|
||||
|
||||
public String getAddress() {
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,11 +15,9 @@
|
||||
*/
|
||||
package org.springframework.data.repository.support;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.domain.Page;
|
||||
@@ -35,19 +33,14 @@ import org.springframework.data.repository.util.ClassUtils;
|
||||
*/
|
||||
public class DefaultRepositoryMetadataUnitTests {
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
static final Class<DummyGenericRepositorySupport> REPOSITORY =
|
||||
DummyGenericRepositorySupport.class;
|
||||
|
||||
|
||||
@Test
|
||||
public void looksUpDomainClassCorrectly() throws Exception {
|
||||
|
||||
RepositoryMetadata metadata =
|
||||
new DefaultRepositoryMetadata(UserRepository.class, REPOSITORY);
|
||||
new DefaultRepositoryMetadata(UserRepository.class);
|
||||
assertEquals(User.class, metadata.getDomainClass());
|
||||
|
||||
metadata = new DefaultRepositoryMetadata(SomeDao.class, REPOSITORY);
|
||||
metadata = new DefaultRepositoryMetadata(SomeDao.class);
|
||||
assertEquals(User.class, metadata.getDomainClass());
|
||||
}
|
||||
|
||||
@@ -57,7 +50,7 @@ public class DefaultRepositoryMetadataUnitTests {
|
||||
|
||||
RepositoryMetadata metadata =
|
||||
new DefaultRepositoryMetadata(
|
||||
ExtensionOfUserCustomExtendedDao.class, REPOSITORY);
|
||||
ExtensionOfUserCustomExtendedDao.class);
|
||||
assertEquals(User.class, metadata.getDomainClass());
|
||||
}
|
||||
|
||||
@@ -66,8 +59,7 @@ public class DefaultRepositoryMetadataUnitTests {
|
||||
public void detectsParameterizedEntitiesCorrectly() {
|
||||
|
||||
RepositoryMetadata metadata =
|
||||
new DefaultRepositoryMetadata(GenericEntityRepository.class,
|
||||
REPOSITORY);
|
||||
new DefaultRepositoryMetadata(GenericEntityRepository.class);
|
||||
assertEquals(GenericEntity.class, metadata.getDomainClass());
|
||||
}
|
||||
|
||||
@@ -76,36 +68,12 @@ public class DefaultRepositoryMetadataUnitTests {
|
||||
public void looksUpIdClassCorrectly() throws Exception {
|
||||
|
||||
RepositoryMetadata metadata =
|
||||
new DefaultRepositoryMetadata(UserRepository.class, REPOSITORY);
|
||||
new DefaultRepositoryMetadata(UserRepository.class);
|
||||
|
||||
assertEquals(Integer.class, metadata.getIdClass());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void discoversRepositoryBaseClassMethod() throws Exception {
|
||||
|
||||
Method method = FooDao.class.getMethod("findOne", Integer.class);
|
||||
DefaultRepositoryMetadata metadata =
|
||||
new DefaultRepositoryMetadata(FooDao.class, REPOSITORY);
|
||||
|
||||
Method reference = metadata.getBaseClassMethodFor(method);
|
||||
assertEquals(REPOSITORY, reference.getDeclaringClass());
|
||||
assertThat(reference.getName(), is("findOne"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void discoveresNonRepositoryBaseClassMethod() throws Exception {
|
||||
|
||||
Method method = FooDao.class.getMethod("findOne", Long.class);
|
||||
|
||||
DefaultRepositoryMetadata metadata =
|
||||
new DefaultRepositoryMetadata(FooDao.class, Repository.class);
|
||||
|
||||
assertThat(metadata.getBaseClassMethodFor(method), is(method));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private class User {
|
||||
|
||||
@@ -138,16 +106,6 @@ public class DefaultRepositoryMetadataUnitTests {
|
||||
Page<User> findByFirstname(Pageable pageable, String firstname);
|
||||
}
|
||||
|
||||
private static interface FooDao extends Repository<User, Integer> {
|
||||
|
||||
// Redeclared method
|
||||
User findOne(Integer primaryKey);
|
||||
|
||||
|
||||
// Not a redeclared method
|
||||
User findOne(Long primaryKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sample interface to test recursive lookup of domain class.
|
||||
*
|
||||
|
||||
@@ -36,24 +36,24 @@ public class QueryExecuterMethodInterceptorUnitTests {
|
||||
@Mock
|
||||
RepositoryFactorySupport factory;
|
||||
@Mock
|
||||
RepositoryMetadata metadata;
|
||||
RepositoryInformation information;
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void rejectsRepositoryInterfaceWithQueryMethodsIfNoQueryLookupStrategyIsDefined() {
|
||||
|
||||
when(metadata.hasCustomMethod()).thenReturn(true);
|
||||
when(information.hasCustomMethod()).thenReturn(true);
|
||||
when(factory.getQueryLookupStrategy(any(Key.class))).thenReturn(null);
|
||||
|
||||
factory.new QueryExecuterMethodInterceptor(metadata, null, new Object());
|
||||
factory.new QueryExecuterMethodInterceptor(information, null, new Object());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void skipsQueryLookupsIfQueryLookupStrategyIsNull() {
|
||||
|
||||
when(metadata.hasCustomMethod()).thenReturn(false);
|
||||
when(information.hasCustomMethod()).thenReturn(false);
|
||||
when(factory.getQueryLookupStrategy(any(Key.class))).thenReturn(null);
|
||||
|
||||
factory.new QueryExecuterMethodInterceptor(metadata, null, new Object());
|
||||
verify(metadata, times(0)).getQueryMethods();
|
||||
factory.new QueryExecuterMethodInterceptor(information, null, new Object());
|
||||
verify(information, times(0)).getQueryMethods();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ public class RepositoryFactorySupportUnitTests {
|
||||
|
||||
|
||||
@Override
|
||||
protected Class<?> getRepositoryBaseClass(Class<?> repositoryInterface) {
|
||||
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
|
||||
|
||||
return Object.class;
|
||||
}
|
||||
@@ -95,7 +95,7 @@ public class RepositoryFactorySupportUnitTests {
|
||||
RepositoryQuery queryTwo = mock(RepositoryQuery.class);
|
||||
|
||||
QueryLookupStrategy strategy = mock(QueryLookupStrategy.class);
|
||||
when(strategy.resolveQuery(any(Method.class), any(Class.class)))
|
||||
when(strategy.resolveQuery(any(Method.class), any(RepositoryMetadata.class)))
|
||||
.thenReturn(queryOne, queryTwo);
|
||||
|
||||
return strategy;
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
<junit.version>4.8.1</junit.version>
|
||||
<log4j.version>1.2.16</log4j.version>
|
||||
<org.mockito.version>1.8.4</org.mockito.version>
|
||||
<org.slf4j.version>1.5.10</org.slf4j.version>
|
||||
<org.springframework.version>3.0.5.RELEASE</org.springframework.version>
|
||||
</properties>
|
||||
<profiles>
|
||||
@@ -99,12 +98,6 @@
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<version>${org.springframework.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
@@ -136,23 +129,6 @@
|
||||
</dependency>
|
||||
|
||||
<!-- Logging -->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>${org.slf4j.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>jcl-over-slf4j</artifactId>
|
||||
<version>${org.slf4j.version}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
<version>${org.slf4j.version}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
|
||||
Reference in New Issue
Block a user