DATACMNS-344 - Allow Repositories to work with non-CrudRepositories.
Introduced CrudMethods abstraction obtainable via a RepositoryInformation to inspect a repository for the presence of individual CRUD methods. The default implementation favors more special methods (e.g. the findAll(Pageable) over a simple findAll()). Introduced a CrudInvoker to be able to easily invoke findOne(…) and save(…) independently of whether the target methods are declared explicitly or inherited from CrudRepository. Fixed some test case names to make sure they're executed during the Maven build.
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2013 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.core;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
/**
|
||||
* Interface for components that can invoke simple CRUD operations on repositories. Useful to be able to abstract being
|
||||
* backed by a {@link CrudRepository} implementation or a raw repository declaration with signature compatible methods
|
||||
* for {@link CrudRepository#findOne(Serializable)} and {@link CrudRepository#save(Object)}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 1.6
|
||||
*/
|
||||
public interface CrudInvoker<T> {
|
||||
|
||||
/**
|
||||
* Invokes the method equivalent to {@link CrudRepository#save(Object)}.
|
||||
*
|
||||
* @param object must not be {@literal null}.
|
||||
*/
|
||||
T invokeSave(T object);
|
||||
|
||||
/**
|
||||
* Invokes the method equivalent to {@link CrudRepository#findOne(Serializable)}.
|
||||
*
|
||||
* @param id must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
T invokeFindOne(Serializable id);
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright 2013 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.core;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
|
||||
/**
|
||||
* Meta-information about the CRUD methods of a repository.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 1.6
|
||||
*/
|
||||
public interface CrudMethods {
|
||||
|
||||
/**
|
||||
* Returns the method to be used for saving entities. Usually siganture compatible to
|
||||
* {@link CrudRepository#save(Object)}.
|
||||
*
|
||||
* @return the method to save entities or {@literal null} if noen exposed.
|
||||
* @see #hasSaveMethod()
|
||||
*/
|
||||
Method getSaveMethod();
|
||||
|
||||
/**
|
||||
* Returns whether the repository exposes a save method at all.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean hasSaveMethod();
|
||||
|
||||
/**
|
||||
* Returns the find all method of the repository. Implementations should prefer more detailled methods like
|
||||
* {@link PagingAndSortingRepository}'s taking a {@link Pageable} or {@link Sort} instance.
|
||||
*
|
||||
* @return the find all method of the repository or {@literal null} if not available.
|
||||
* @see #hasFindAllMethod()
|
||||
*/
|
||||
Method getFindAllMethod();
|
||||
|
||||
/**
|
||||
* Returns whether the repository exposes a find all method at all.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean hasFindAllMethod();
|
||||
|
||||
/**
|
||||
* Returns the find one method of the repository. Usually signature compatible to
|
||||
* {@link CrudRepository#findOne(java.io.Serializable)}
|
||||
*
|
||||
* @return the find one method of the repository or {@literal null} if not available.
|
||||
* @see #hasFindOneMethod()
|
||||
*/
|
||||
Method getFindOneMethod();
|
||||
|
||||
/**
|
||||
* Returns whether the repository exposes a find one method.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean hasFindOneMethod();
|
||||
|
||||
/**
|
||||
* Returns the delete method of the repository. Will prefer a delete-by-id method over a delete-by-entity method.
|
||||
*
|
||||
* @return the delete method of the repository or {@literal null} if not available.
|
||||
* @see #hasDelete()
|
||||
*/
|
||||
Method getDeleteMethod();
|
||||
|
||||
/**
|
||||
* Returns whether the repository esposes a delete method.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean hasDelete();
|
||||
}
|
||||
@@ -55,6 +55,15 @@ public interface RepositoryInformation extends RepositoryMetadata {
|
||||
*/
|
||||
boolean isQueryMethod(Method method);
|
||||
|
||||
/**
|
||||
* Returns whether the given method is logically a base class method. This also includes methods (re)declared in the
|
||||
* repository interface that match the signatures of the base implementation.
|
||||
*
|
||||
* @param method must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
boolean isBaseClassMethod(Method method);
|
||||
|
||||
/**
|
||||
* Returns all methods considered to be query methods.
|
||||
*
|
||||
@@ -62,6 +71,13 @@ public interface RepositoryInformation extends RepositoryMetadata {
|
||||
*/
|
||||
Iterable<Method> getQueryMethods();
|
||||
|
||||
/**
|
||||
* Returns {@link CrudMethods} meta information for the repository.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
CrudMethods getCrudMethods();
|
||||
|
||||
/**
|
||||
* Returns the target 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
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* Copyright 2013 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.core.support;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.core.GenericTypeResolver;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.data.repository.core.CrudMethods;
|
||||
import org.springframework.data.repository.core.RepositoryInformation;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* Default implementation to discover CRUD methods based on a given {@link RepositoryInformation}. Will detect methods
|
||||
* exposed in {@link CrudRepository} but also hand crafted CRUD methods that are signature compatible with the ones on
|
||||
* {@link CrudRepository}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 1.6
|
||||
*/
|
||||
class DefaultCrudMethods implements CrudMethods {
|
||||
|
||||
private final RepositoryInformation information;
|
||||
|
||||
private Method findAllMethod;
|
||||
private boolean findAllHasPaging;
|
||||
|
||||
private Method findOneMethod;
|
||||
private Method saveMethod;
|
||||
private Method deleteMethod;
|
||||
|
||||
/**
|
||||
* Creates a new {@link DefaultCrudMethods} using the given {@link RepositoryInformation}.
|
||||
*
|
||||
* @param information must not be {@literal null}.
|
||||
*/
|
||||
public DefaultCrudMethods(RepositoryInformation information) {
|
||||
|
||||
Assert.notNull(information, "RepositoryInformation must not be null!");
|
||||
this.information = information;
|
||||
|
||||
for (Method method : ReflectionUtils.getAllDeclaredMethods(information.getRepositoryInterface())) {
|
||||
|
||||
if (!information.isBaseClassMethod(method)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (method.getName().equals("findAll")) {
|
||||
findAllDetected(method);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (method.getName().equals("findOne")) {
|
||||
this.findOneMethod = method;
|
||||
}
|
||||
|
||||
if (method.getName().equals("save")) {
|
||||
this.saveMethod = method;
|
||||
}
|
||||
|
||||
if (method.getName().equals("delete")) {
|
||||
deleteDetected(method);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given method is a more usable find all method. Will prefer methods taking a {@link Pageable} and
|
||||
* sort over a simple one.
|
||||
*
|
||||
* @param method
|
||||
*/
|
||||
private void findAllDetected(Method method) {
|
||||
|
||||
if (findAllMethod != null && findAllHasPaging) {
|
||||
return;
|
||||
}
|
||||
|
||||
Class<?>[] parameterType = method.getParameterTypes();
|
||||
|
||||
if (parameterType.length > 0) {
|
||||
|
||||
if (parameterType[0].equals(Pageable.class)) {
|
||||
this.findAllMethod = method;
|
||||
this.findAllHasPaging = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (parameterType[0].equals(Sort.class)) {
|
||||
this.findAllMethod = method;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (findAllMethod == null) {
|
||||
this.findAllMethod = method;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given method is a more usable delete method. Will prefer delete-by-id methods over
|
||||
* delete-by-instance ones.
|
||||
*
|
||||
* @param method
|
||||
*/
|
||||
private void deleteDetected(Method method) {
|
||||
|
||||
MethodParameter parameter = new MethodParameter(method, 0);
|
||||
Class<?> parameterType = GenericTypeResolver.resolveParameterType(parameter, information.getRepositoryInterface());
|
||||
|
||||
if (information.getIdType().isAssignableFrom(parameterType)) {
|
||||
this.deleteMethod = method;
|
||||
}
|
||||
|
||||
if (this.deleteMethod == null) {
|
||||
this.deleteMethod = method;
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.core.support.CrudMethods#getSaveMethod()
|
||||
*/
|
||||
@Override
|
||||
public Method getSaveMethod() {
|
||||
return saveMethod;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.core.support.CrudMethods#hasSaveMethod()
|
||||
*/
|
||||
@Override
|
||||
public boolean hasSaveMethod() {
|
||||
return saveMethod != null;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.core.support.CrudMethods#getFindAllMethod()
|
||||
*/
|
||||
@Override
|
||||
public Method getFindAllMethod() {
|
||||
return findAllMethod;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.core.support.CrudMethods#hasFindAllMethod()
|
||||
*/
|
||||
@Override
|
||||
public boolean hasFindAllMethod() {
|
||||
return findAllMethod != null;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.core.support.CrudMethods#getFindOneMethod()
|
||||
*/
|
||||
@Override
|
||||
public Method getFindOneMethod() {
|
||||
return findOneMethod;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.core.support.CrudMethods#hasFindOneMethod()
|
||||
*/
|
||||
@Override
|
||||
public boolean hasFindOneMethod() {
|
||||
return findOneMethod != null;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.core.support.CrudMethods#hasDelete()
|
||||
*/
|
||||
@Override
|
||||
public boolean hasDelete() {
|
||||
return this.deleteMethod != null;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.core.support.CrudMethods#getDeleteMethod()
|
||||
*/
|
||||
@Override
|
||||
public Method getDeleteMethod() {
|
||||
return this.deleteMethod;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2012 the original author or authors.
|
||||
* Copyright 2011-2013 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.
|
||||
@@ -30,6 +30,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.data.repository.Repository;
|
||||
import org.springframework.data.repository.core.CrudMethods;
|
||||
import org.springframework.data.repository.core.RepositoryInformation;
|
||||
import org.springframework.data.repository.core.RepositoryMetadata;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -42,8 +43,8 @@ import org.springframework.util.ClassUtils;
|
||||
*/
|
||||
class DefaultRepositoryInformation extends AbstractRepositoryMetadata implements RepositoryInformation {
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private static final TypeVariable<Class<Repository>>[] PARAMETERS = Repository.class.getTypeParameters();
|
||||
@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();
|
||||
|
||||
@@ -52,12 +53,13 @@ class DefaultRepositoryInformation extends AbstractRepositoryMetadata implements
|
||||
private final RepositoryMetadata metadata;
|
||||
private final Class<?> repositoryBaseClass;
|
||||
private final Class<?> customImplementationClass;
|
||||
private final CrudMethods crudMethods;
|
||||
|
||||
/**
|
||||
* Creates a new {@link DefaultRepositoryMetadata} for the given repository interface and repository base class.
|
||||
*
|
||||
* @param metadata
|
||||
* @param repositoryBaseClass
|
||||
* @param metadata must not be {@literal null}.
|
||||
* @param repositoryBaseClass must not be {@literal null}.
|
||||
* @param customImplementationClass
|
||||
*/
|
||||
public DefaultRepositoryInformation(RepositoryMetadata metadata, Class<?> repositoryBaseClass,
|
||||
@@ -71,12 +73,14 @@ class DefaultRepositoryInformation extends AbstractRepositoryMetadata implements
|
||||
this.metadata = metadata;
|
||||
this.repositoryBaseClass = repositoryBaseClass;
|
||||
this.customImplementationClass = customImplementationClass;
|
||||
this.crudMethods = new DefaultCrudMethods(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.support.RepositoryMetadata#getRepositoryInterface()
|
||||
*/
|
||||
@Override
|
||||
public Class<?> getRepositoryInterface() {
|
||||
return metadata.getRepositoryInterface();
|
||||
}
|
||||
@@ -85,6 +89,7 @@ class DefaultRepositoryInformation extends AbstractRepositoryMetadata implements
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.support.RepositoryMetadata#getDomainClass()
|
||||
*/
|
||||
@Override
|
||||
public Class<?> getDomainType() {
|
||||
return metadata.getDomainType();
|
||||
}
|
||||
@@ -93,6 +98,7 @@ class DefaultRepositoryInformation extends AbstractRepositoryMetadata implements
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.support.RepositoryMetadata#getIdClass()
|
||||
*/
|
||||
@Override
|
||||
public Class<? extends Serializable> getIdType() {
|
||||
return metadata.getIdType();
|
||||
}
|
||||
@@ -101,6 +107,7 @@ class DefaultRepositoryInformation extends AbstractRepositoryMetadata implements
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.support.RepositoryInformation#getRepositoryBaseClass()
|
||||
*/
|
||||
@Override
|
||||
public Class<?> getRepositoryBaseClass() {
|
||||
return this.repositoryBaseClass;
|
||||
}
|
||||
@@ -109,6 +116,7 @@ class DefaultRepositoryInformation extends AbstractRepositoryMetadata implements
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.support.RepositoryInformation#getTargetClassMethod(java.lang.reflect.Method)
|
||||
*/
|
||||
@Override
|
||||
public Method getTargetClassMethod(Method method) {
|
||||
|
||||
if (methodCache.containsKey(method)) {
|
||||
@@ -152,6 +160,7 @@ class DefaultRepositoryInformation extends AbstractRepositoryMetadata implements
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.support.RepositoryInformation#getQueryMethods()
|
||||
*/
|
||||
@Override
|
||||
public Set<Method> getQueryMethods() {
|
||||
|
||||
Set<Method> result = new HashSet<Method>();
|
||||
@@ -170,6 +179,7 @@ class DefaultRepositoryInformation extends AbstractRepositoryMetadata implements
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.support.RepositoryInformation#isCustomMethod(java.lang.reflect.Method)
|
||||
*/
|
||||
@Override
|
||||
public boolean isCustomMethod(Method method) {
|
||||
return isTargetClassMethod(method, customImplementationClass);
|
||||
}
|
||||
@@ -178,17 +188,19 @@ class DefaultRepositoryInformation extends AbstractRepositoryMetadata implements
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.core.RepositoryInformation#isQueryMethod(java.lang.reflect.Method)
|
||||
*/
|
||||
@Override
|
||||
public boolean isQueryMethod(Method method) {
|
||||
return getQueryMethods().contains(method);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given method is a method covered by the base implementation.
|
||||
*
|
||||
* @param method
|
||||
* @return
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.core.RepositoryInformation#isBaseClassMethod(java.lang.reflect.Method)
|
||||
*/
|
||||
@Override
|
||||
public boolean isBaseClassMethod(Method method) {
|
||||
|
||||
Assert.notNull(method, "Method must not be null!");
|
||||
return isTargetClassMethod(method, repositoryBaseClass);
|
||||
}
|
||||
|
||||
@@ -234,6 +246,7 @@ class DefaultRepositoryInformation extends AbstractRepositoryMetadata implements
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.support.RepositoryInformation#hasCustomMethod()
|
||||
*/
|
||||
@Override
|
||||
public boolean hasCustomMethod() {
|
||||
|
||||
Class<?> repositoryInterface = getRepositoryInterface();
|
||||
@@ -252,6 +265,15 @@ class DefaultRepositoryInformation extends AbstractRepositoryMetadata implements
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.core.RepositoryInformation#getCrudMethods()
|
||||
*/
|
||||
@Override
|
||||
public CrudMethods getCrudMethods() {
|
||||
return crudMethods;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
package org.springframework.data.repository.init;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
@@ -27,7 +26,7 @@ import org.springframework.context.ApplicationEventPublisherAware;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.data.repository.core.CrudInvoker;
|
||||
import org.springframework.data.repository.support.Repositories;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -152,10 +151,12 @@ public class ResourceReaderRepositoryPopulator implements RepositoryPopulator, A
|
||||
* @param object must not be {@literal null}.
|
||||
* @param repositories must not be {@literal null}.
|
||||
*/
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
private void persist(Object object, Repositories repositories) {
|
||||
|
||||
CrudRepository<Object, Serializable> repository = repositories.getRepositoryFor(object.getClass());
|
||||
LOGGER.debug(String.format("Persisting %s using repository %s", object, repository));
|
||||
repository.save(object);
|
||||
CrudInvoker<Object> invoker = (CrudInvoker<Object>) repositories.getCrudInvoker(object.getClass());
|
||||
LOGGER.debug(String.format("Persisting %s using repository %s", object, invoker));
|
||||
|
||||
invoker.invokeSave(object);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2013 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.io.Serializable;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.data.repository.core.CrudInvoker;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link CrudRepository} based {@link CrudInvoker} calling methods on {@link CrudRepository} directly.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 1.6
|
||||
*/
|
||||
class CrudRepositoryInvoker<T> implements CrudInvoker<T> {
|
||||
|
||||
private final CrudRepository<T, Serializable> repository;
|
||||
|
||||
/**
|
||||
* Creates a new {@link CrudRepositoryInvoker} using the given {@link CrudRepository}.
|
||||
*
|
||||
* @param repository must not be {@literal null}.
|
||||
*/
|
||||
public CrudRepositoryInvoker(CrudRepository<T, Serializable> repository) {
|
||||
|
||||
Assert.notNull(repository, "Repository must not be null!");
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.core.CrudInvoker#findOne(java.io.Serializable)
|
||||
*/
|
||||
@Override
|
||||
public T invokeFindOne(Serializable id) {
|
||||
return repository.findOne(id);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.core.CrudInvoker#save(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public T invokeSave(T object) {
|
||||
return repository.save(object);
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package org.springframework.data.repository.support;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -26,6 +25,7 @@ import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.converter.ConditionalGenericConverter;
|
||||
import org.springframework.core.convert.converter.ConverterRegistry;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.data.repository.core.CrudInvoker;
|
||||
import org.springframework.data.repository.core.RepositoryInformation;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -65,11 +65,12 @@ public class DomainClassConverter<T extends ConversionService & ConverterRegistr
|
||||
return null;
|
||||
}
|
||||
|
||||
RepositoryInformation info = repositories.getRepositoryInformationFor(targetType.getType());
|
||||
Class<?> domainType = targetType.getType();
|
||||
|
||||
CrudRepository<?, Serializable> repository = repositories.getRepositoryFor(targetType.getType());
|
||||
Serializable id = conversionService.convert(source, info.getIdType());
|
||||
return repository.findOne(id);
|
||||
RepositoryInformation info = repositories.getRepositoryInformationFor(domainType);
|
||||
CrudInvoker<?> invoker = repositories.getCrudInvoker(domainType);
|
||||
|
||||
return invoker.invokeFindOne(conversionService.convert(source, info.getIdType()));
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2008-2011 the original author or authors.
|
||||
* Copyright 2008-2013 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.
|
||||
@@ -22,6 +22,7 @@ import java.io.Serializable;
|
||||
import org.springframework.beans.PropertyEditorRegistry;
|
||||
import org.springframework.beans.SimpleTypeConverter;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.data.repository.core.CrudInvoker;
|
||||
import org.springframework.data.repository.core.EntityInformation;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -33,26 +34,26 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
public class DomainClassPropertyEditor<T, ID extends Serializable> extends PropertyEditorSupport {
|
||||
|
||||
private final CrudRepository<T, ID> repository;
|
||||
private final CrudInvoker<?> invoker;
|
||||
private final EntityInformation<T, ID> information;
|
||||
private final PropertyEditorRegistry registry;
|
||||
|
||||
/**
|
||||
* Creates a new {@link DomainClassPropertyEditor} for the given {@link CrudRepository}, {@link EntityInformation} and
|
||||
* Creates a new {@link DomainClassPropertyEditor} for the given repository, {@link EntityInformation} and
|
||||
* {@link PropertyEditorRegistry}.
|
||||
*
|
||||
* @param repository must not be {@literal null}.
|
||||
* @param invoker must not be {@literal null}.
|
||||
* @param information must not be {@literal null}.
|
||||
* @param registry must not be {@literal null}.
|
||||
*/
|
||||
public DomainClassPropertyEditor(CrudRepository<T, ID> repository, EntityInformation<T, ID> information,
|
||||
public DomainClassPropertyEditor(CrudInvoker<?> invoker, EntityInformation<T, ID> information,
|
||||
PropertyEditorRegistry registry) {
|
||||
|
||||
Assert.notNull(repository);
|
||||
Assert.notNull(invoker);
|
||||
Assert.notNull(information);
|
||||
Assert.notNull(registry);
|
||||
|
||||
this.repository = repository;
|
||||
this.invoker = invoker;
|
||||
this.information = information;
|
||||
this.registry = registry;
|
||||
}
|
||||
@@ -69,7 +70,7 @@ public class DomainClassPropertyEditor<T, ID extends Serializable> extends Prope
|
||||
return;
|
||||
}
|
||||
|
||||
setValue(repository.findOne(getId(idAsString)));
|
||||
setValue(invoker.invokeFindOne(getId(idAsString)));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -142,7 +143,7 @@ public class DomainClassPropertyEditor<T, ID extends Serializable> extends Prope
|
||||
|
||||
DomainClassPropertyEditor<?, ?> that = (DomainClassPropertyEditor<?, ?>) obj;
|
||||
|
||||
return this.repository.equals(that.repository) && this.registry.equals(that.registry)
|
||||
return this.invoker.equals(that.invoker) && this.registry.equals(that.registry)
|
||||
&& this.information.equals(that.information);
|
||||
}
|
||||
|
||||
@@ -154,7 +155,7 @@ public class DomainClassPropertyEditor<T, ID extends Serializable> extends Prope
|
||||
public int hashCode() {
|
||||
|
||||
int hashCode = 17;
|
||||
hashCode += repository.hashCode() * 32;
|
||||
hashCode += invoker.hashCode() * 32;
|
||||
hashCode += information.hashCode() * 32;
|
||||
hashCode += registry.hashCode() * 32;
|
||||
return hashCode;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2008-2012 the original author or authors.
|
||||
* Copyright 2008-2013 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.
|
||||
@@ -16,12 +16,14 @@
|
||||
package org.springframework.data.repository.support;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.springframework.beans.PropertyEditorRegistrar;
|
||||
import org.springframework.beans.PropertyEditorRegistry;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.data.repository.core.CrudInvoker;
|
||||
import org.springframework.data.repository.core.RepositoryInformation;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
|
||||
/**
|
||||
* Simple helper class to use Hades DAOs to provide {@link java.beans.PropertyEditor}s for domain classes. To get this
|
||||
@@ -56,10 +58,10 @@ public class DomainClassPropertyEditorRegistrar implements PropertyEditorRegistr
|
||||
for (Class<?> domainClass : repositories) {
|
||||
|
||||
RepositoryInformation repositoryInformation = repositories.getRepositoryInformationFor(domainClass);
|
||||
CrudRepository<Object, Serializable> repository = repositories.getRepositoryFor(domainClass);
|
||||
CrudInvoker<?> invoker = repositories.getCrudInvoker(domainClass);
|
||||
|
||||
DomainClassPropertyEditor<Object, Serializable> editor = new DomainClassPropertyEditor<Object, Serializable>(
|
||||
repository, repositories.getEntityInformationFor(repositoryInformation.getDomainType()), registry);
|
||||
invoker, repositories.getEntityInformationFor(repositoryInformation.getDomainType()), registry);
|
||||
|
||||
registry.registerCustomEditor(repositoryInformation.getDomainType(), editor);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2013 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 java.lang.String.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.springframework.data.repository.core.CrudInvoker;
|
||||
import org.springframework.data.repository.core.CrudMethods;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* {@link CrudInvoker} that uses reflection to invoke repository methods based on the {@link CrudMethods} meta
|
||||
* information.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 1.6
|
||||
*/
|
||||
class ReflectionRepositoryInvoker<T> implements CrudInvoker<T> {
|
||||
|
||||
private final Object repository;
|
||||
private final CrudMethods methods;
|
||||
|
||||
/**
|
||||
* Creates a new {@link ReflectionRepositoryInvoker} using the given repository and {@link CrudMethods}.
|
||||
*
|
||||
* @param repository must not be {@literal null}.
|
||||
* @param methods must not be {@literal null}.
|
||||
*/
|
||||
public ReflectionRepositoryInvoker(Object repository, CrudMethods methods) {
|
||||
|
||||
Assert.notNull(repository, "Repository must not be null!");
|
||||
Assert.notNull(methods, "CrudMethods must not be null!");
|
||||
|
||||
Class<?> type = repository.getClass();
|
||||
Assert.isTrue(methods.hasFindOneMethod(), format("Repository %s does not expose a findOne(…) method!", type));
|
||||
Assert.isTrue(methods.hasSaveMethod(), format("Repository %s does not expose a save(…) method!", type));
|
||||
|
||||
this.repository = repository;
|
||||
this.methods = methods;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.core.CrudInvoker#save(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public T invokeSave(T object) {
|
||||
return (T) ReflectionUtils.invokeMethod(methods.getSaveMethod(), repository, object);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.core.CrudInvoker#findOne(java.io.Serializable)
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public T invokeFindOne(Serializable id) {
|
||||
return (T) ReflectionUtils.invokeMethod(methods.getFindOneMethod(), id);
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,7 @@ import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.data.repository.core.CrudInvoker;
|
||||
import org.springframework.data.repository.core.EntityInformation;
|
||||
import org.springframework.data.repository.core.RepositoryInformation;
|
||||
import org.springframework.data.repository.core.support.RepositoryFactoryInformation;
|
||||
@@ -92,8 +93,7 @@ public class Repositories implements Iterable<Class<?>> {
|
||||
* @param domainClass must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T, S extends Serializable> CrudRepository<T, S> getRepositoryFor(Class<?> domainClass) {
|
||||
public Object getRepositoryFor(Class<?> domainClass) {
|
||||
|
||||
RepositoryFactoryInformation<Object, Serializable> information = getRepoInfoFor(domainClass);
|
||||
|
||||
@@ -101,7 +101,7 @@ public class Repositories implements Iterable<Class<?>> {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (CrudRepository<T, S>) beanFactory.getBean(repositories.get(information));
|
||||
return beanFactory.getBean(repositories.get(information));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -118,11 +118,11 @@ public class Repositories implements Iterable<Class<?>> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link EntityInformation} for the given domain class.
|
||||
* Returns the {@link RepositoryInformation} for the given domain class.
|
||||
*
|
||||
* @param domainClass must not be {@literal null}.
|
||||
* @return the {@link EntityInformation} for the given domain class or {@literal null} if no repository registered for
|
||||
* this domain class.
|
||||
* @return the {@link RepositoryInformation} for the given domain class or {@literal null} if no repository registered
|
||||
* for this domain class.
|
||||
*/
|
||||
public RepositoryInformation getRepositoryInformationFor(Class<?> domainClass) {
|
||||
|
||||
@@ -156,6 +156,19 @@ public class Repositories implements Iterable<Class<?>> {
|
||||
return information == null ? Collections.<QueryMethod> emptyList() : information.getQueryMethods();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> CrudInvoker<T> getCrudInvoker(Class<T> domainClass) {
|
||||
|
||||
RepositoryInformation information = getRepositoryInformationFor(domainClass);
|
||||
Object repository = getRepositoryFor(domainClass);
|
||||
|
||||
if (repository instanceof CrudRepository) {
|
||||
return new CrudRepositoryInvoker<T>((CrudRepository<T, Serializable>) repository);
|
||||
} else {
|
||||
return new ReflectionRepositoryInvoker<T>(repository, information.getCrudMethods());
|
||||
}
|
||||
}
|
||||
|
||||
private RepositoryFactoryInformation<Object, Serializable> getRepoInfoFor(Class<?> domainClass) {
|
||||
|
||||
Assert.notNull(domainClass);
|
||||
@@ -200,11 +213,6 @@ public class Repositories implements Iterable<Class<?>> {
|
||||
RepositoryFactoryInformation.class);
|
||||
|
||||
RepositoryInformation info = information.getRepositoryInformation();
|
||||
Class<?> repositoryInterface = info.getRepositoryInterface();
|
||||
|
||||
if (!CrudRepository.class.isAssignableFrom(repositoryInterface)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
repositories.put(information, BeanFactoryUtils.transformedBeanName(repositoryFactoryName));
|
||||
domainClassToBeanName.put(info.getDomainType(), information);
|
||||
|
||||
Reference in New Issue
Block a user