DATACMNS-589 - Integrated RepositoryInvoker abstraction from Spring Data REST.
Replaced CrudInvoker with the more sophisticated and flexible RepositoryInvoker originating from Spring Data REST. Slightly refined the API and added a lot more unit tests. Refactored usage of CrudInvoker to use a DefaultRepositoryInvokerFactory and create RepositoryInvokers for the domain types.
This commit is contained in:
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
@@ -26,7 +26,9 @@ 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.core.CrudInvoker;
|
||||
import org.springframework.data.repository.invoker.DefaultRepositoryInvokerFactory;
|
||||
import org.springframework.data.repository.invoker.RepositoryInvoker;
|
||||
import org.springframework.data.repository.invoker.RepositoryInvokerFactory;
|
||||
import org.springframework.data.repository.support.Repositories;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -107,6 +109,8 @@ public class ResourceReaderRepositoryPopulator implements RepositoryPopulator, A
|
||||
*/
|
||||
public void populate(Repositories repositories) {
|
||||
|
||||
RepositoryInvokerFactory invokerFactory = new DefaultRepositoryInvokerFactory(repositories);
|
||||
|
||||
for (Resource resource : resources) {
|
||||
|
||||
LOGGER.info(String.format("Reading resource: %s", resource));
|
||||
@@ -116,13 +120,13 @@ public class ResourceReaderRepositoryPopulator implements RepositoryPopulator, A
|
||||
if (result instanceof Collection) {
|
||||
for (Object element : (Collection<?>) result) {
|
||||
if (element != null) {
|
||||
persist(element, repositories);
|
||||
persist(element, invokerFactory);
|
||||
} else {
|
||||
LOGGER.info("Skipping null element found in unmarshal result!");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
persist(result, repositories);
|
||||
persist(result, invokerFactory);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,12 +155,10 @@ 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) {
|
||||
private void persist(Object object, RepositoryInvokerFactory invokerFactory) {
|
||||
|
||||
CrudInvoker<Object> invoker = (CrudInvoker<Object>) repositories.getCrudInvoker(object.getClass());
|
||||
RepositoryInvoker invoker = invokerFactory.getInvokerFor(object.getClass());
|
||||
LOGGER.debug(String.format("Persisting %s using repository %s", object, invoker));
|
||||
|
||||
invoker.invokeSave(object);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright 2013-2014 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.invoker;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
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.data.repository.core.RepositoryMetadata;
|
||||
|
||||
/**
|
||||
* {@link RepositoryInvoker} to shortcut execution of CRUD methods into direct calls on a {@link CrudRepository}. Used
|
||||
* to avoid reflection overhead introduced by the base class if we know we work with a {@link CrudRepository}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
class CrudRepositoryInvoker extends ReflectionRepositoryInvoker {
|
||||
|
||||
private final CrudRepository<Object, Serializable> repository;
|
||||
private final CrudMethods crudMethods;
|
||||
|
||||
private final boolean customSaveMethod;
|
||||
private final boolean customFindOneMethod;
|
||||
private final boolean customFindAllMethod;
|
||||
private final boolean customDeleteMethod;
|
||||
|
||||
/**
|
||||
* Creates a new {@link CrudRepositoryInvoker} for the given {@link CrudRepository}, {@link RepositoryInformation} and
|
||||
* {@link ConversionService}.
|
||||
*
|
||||
* @param repository must not be {@literal null}.
|
||||
* @param metadata must not be {@literal null}.
|
||||
* @param conversionService must not be {@literal null}.
|
||||
*/
|
||||
public CrudRepositoryInvoker(CrudRepository<Object, Serializable> repository, RepositoryMetadata metadata,
|
||||
ConversionService conversionService) {
|
||||
|
||||
super(repository, metadata, conversionService);
|
||||
|
||||
this.repository = repository;
|
||||
this.crudMethods = metadata.getCrudMethods();
|
||||
|
||||
this.customSaveMethod = isRedeclaredMethod(crudMethods.getSaveMethod());
|
||||
this.customFindOneMethod = isRedeclaredMethod(crudMethods.getFindOneMethod());
|
||||
this.customDeleteMethod = isRedeclaredMethod(crudMethods.getDeleteMethod());
|
||||
this.customFindAllMethod = isRedeclaredMethod(crudMethods.getFindAllMethod());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.core.invoke.RepositoryInvoker#invokeFindAll(org.springframework.data.domain.Sort)
|
||||
*/
|
||||
@Override
|
||||
public Iterable<Object> invokeFindAll(Sort sort) {
|
||||
return customFindAllMethod ? super.invokeFindAll(sort) : repository.findAll();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.core.invoke.RepositoryInvoker#invokeFindAll(org.springframework.data.domain.Pageable)
|
||||
*/
|
||||
@Override
|
||||
public Iterable<Object> invokeFindAll(Pageable pageable) {
|
||||
return customFindAllMethod ? super.invokeFindAll(pageable) : repository.findAll();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.core.invoke.RepositoryInvoker#invokeFindOne(java.io.Serializable)
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T invokeFindOne(Serializable id) {
|
||||
return customFindOneMethod ? super.<T> invokeFindOne(id) : (T) repository.findOne(convertId(id));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.core.invoke.ReflectionRepositoryInvoker#invokeSave(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public <T> T invokeSave(T entity) {
|
||||
return customSaveMethod ? super.invokeSave(entity) : repository.save(entity);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.core.invoke.RepositoryInvoker#invokeDelete(java.io.Serializable)
|
||||
*/
|
||||
@Override
|
||||
public void invokeDelete(Serializable id) {
|
||||
|
||||
if (customDeleteMethod) {
|
||||
super.invokeDelete(id);
|
||||
} else {
|
||||
repository.delete(convertId(id));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isRedeclaredMethod(Method method) {
|
||||
return !method.getDeclaringClass().equals(CrudRepository.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright 2013-2014 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.invoker;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
import org.springframework.data.repository.core.RepositoryInformation;
|
||||
import org.springframework.data.repository.support.Repositories;
|
||||
import org.springframework.format.support.DefaultFormattingConversionService;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link RepositoryInvokerFactory} to inspect the requested repository type and create a
|
||||
* matching {@link RepositoryInvoker} that suits the repository best. That means, the more concrete the base interface
|
||||
* of the repository is, the more concrete will the actual invoker become - which means it will favor concrete method
|
||||
* invocations over reflection ones.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class DefaultRepositoryInvokerFactory implements RepositoryInvokerFactory {
|
||||
|
||||
private final Repositories repositories;
|
||||
private final ConversionService conversionService;
|
||||
private final Map<Class<?>, RepositoryInvoker> invokers;
|
||||
|
||||
/**
|
||||
* Creates a new {@link DefaultRepositoryInvokerFactory} for the given {@link Repositories}.
|
||||
*
|
||||
* @param repositories must not be {@literal null}.
|
||||
*/
|
||||
public DefaultRepositoryInvokerFactory(Repositories repositories) {
|
||||
this(repositories, new DefaultFormattingConversionService());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link DefaultRepositoryInvokerFactory} for the given {@link Repositories} and
|
||||
* {@link ConversionService}.
|
||||
*
|
||||
* @param repositories must not be {@literal null}.
|
||||
* @param conversionService must not be {@literal null}.
|
||||
*/
|
||||
public DefaultRepositoryInvokerFactory(Repositories repositories, ConversionService conversionService) {
|
||||
|
||||
Assert.notNull(repositories, "Repositories must not be null!");
|
||||
Assert.notNull(conversionService, "ConversionService must not be null!");
|
||||
|
||||
this.repositories = repositories;
|
||||
this.conversionService = conversionService;
|
||||
this.invokers = new HashMap<Class<?>, RepositoryInvoker>();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.core.invoke.RepositoryInvokerFactory#getInvokerFor(java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public RepositoryInvoker getInvokerFor(Class<?> domainType) {
|
||||
|
||||
RepositoryInvoker invoker = invokers.get(domainType);
|
||||
|
||||
if (invoker != null) {
|
||||
return invoker;
|
||||
}
|
||||
|
||||
invoker = prepareInvokers(domainType);
|
||||
invokers.put(domainType, invoker);
|
||||
|
||||
return invoker;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link RepositoryInvoker} for the repository managing the given domain type.
|
||||
*
|
||||
* @param domainType
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private RepositoryInvoker prepareInvokers(Class<?> domainType) {
|
||||
|
||||
Object repository = repositories.getRepositoryFor(domainType);
|
||||
Assert.notNull(repository, String.format("No repository found for domain type: %s", domainType));
|
||||
RepositoryInformation information = repositories.getRepositoryInformationFor(domainType);
|
||||
|
||||
if (repository instanceof PagingAndSortingRepository) {
|
||||
return new PagingAndSortingRepositoryInvoker((PagingAndSortingRepository<Object, Serializable>) repository,
|
||||
information, conversionService);
|
||||
} else if (repository instanceof CrudRepository) {
|
||||
return new CrudRepositoryInvoker((CrudRepository<Object, Serializable>) repository, information,
|
||||
conversionService);
|
||||
} else {
|
||||
return new ReflectionRepositoryInvoker(repository, information, conversionService);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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.invoker;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
import org.springframework.data.repository.core.CrudMethods;
|
||||
import org.springframework.data.repository.core.RepositoryInformation;
|
||||
import org.springframework.data.repository.core.RepositoryMetadata;
|
||||
|
||||
/**
|
||||
* A special {@link RepositoryInvoker} that shortcuts invocations to methods on {@link PagingAndSortingRepository} to
|
||||
* avoid reflection overhead introduced by the superclass.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
class PagingAndSortingRepositoryInvoker extends CrudRepositoryInvoker {
|
||||
|
||||
private final PagingAndSortingRepository<Object, Serializable> repository;
|
||||
|
||||
private final boolean customFindAll;
|
||||
|
||||
/**
|
||||
* Creates a new {@link PagingAndSortingRepositoryInvoker} using the given repository, {@link RepositoryInformation}
|
||||
* and {@link ConversionService}.
|
||||
*
|
||||
* @param repository must not be {@literal null}.
|
||||
* @param metadata must not be {@literal null}.
|
||||
* @param conversionService must not be {@literal null}.
|
||||
*/
|
||||
public PagingAndSortingRepositoryInvoker(PagingAndSortingRepository<Object, Serializable> repository,
|
||||
RepositoryMetadata metadata, ConversionService conversionService) {
|
||||
|
||||
super(repository, metadata, conversionService);
|
||||
|
||||
CrudMethods crudMethods = metadata.getCrudMethods();
|
||||
|
||||
this.repository = repository;
|
||||
this.customFindAll = isRedeclaredMethod(crudMethods.getFindAllMethod());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.core.invoke.CrudRepositoryInvoker#invokeFindAll(org.springframework.data.domain.Sort)
|
||||
*/
|
||||
@Override
|
||||
public Iterable<Object> invokeFindAll(Sort sort) {
|
||||
return customFindAll ? invokeFindAllReflectively(sort) : repository.findAll(sort);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.core.invoke.CrudRepositoryInvoker#invokeFindAll(org.springframework.data.domain.Pageable)
|
||||
*/
|
||||
@Override
|
||||
public Iterable<Object> invokeFindAll(Pageable pageable) {
|
||||
return customFindAll ? invokeFindAllReflectively(pageable) : repository.findAll(pageable);
|
||||
}
|
||||
|
||||
private boolean isRedeclaredMethod(Method method) {
|
||||
return !method.getDeclaringClass().equals(PagingAndSortingRepository.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,280 @@
|
||||
/*
|
||||
* Copyright 2013-2014 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.invoker;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.repository.core.CrudMethods;
|
||||
import org.springframework.data.repository.core.RepositoryInformation;
|
||||
import org.springframework.data.repository.core.RepositoryMetadata;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.hateoas.core.AnnotationAttribute;
|
||||
import org.springframework.hateoas.core.MethodParameters;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Base {@link RepositoryInvoker} using reflection to invoke methods on Spring Data Repositories.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
class ReflectionRepositoryInvoker implements RepositoryInvoker {
|
||||
|
||||
private static final AnnotationAttribute PARAM_ANNOTATION = new AnnotationAttribute(Param.class);
|
||||
|
||||
private final Object repository;
|
||||
private final CrudMethods methods;
|
||||
private final Class<? extends Serializable> idType;
|
||||
private final ConversionService conversionService;
|
||||
|
||||
/**
|
||||
* Creates a new {@link ReflectionRepositoryInvoker} for the given repository, {@link RepositoryInformation} and
|
||||
* {@link ConversionService}.
|
||||
*
|
||||
* @param repository must not be {@literal null}.
|
||||
* @param metadata must not be {@literal null}.
|
||||
* @param conversionService must not be {@literal null}.
|
||||
*/
|
||||
public ReflectionRepositoryInvoker(Object repository, RepositoryMetadata metadata, ConversionService conversionService) {
|
||||
|
||||
Assert.notNull(repository, "Repository must not be null!");
|
||||
Assert.notNull(metadata, "RepositoryMetadata must not be null!");
|
||||
Assert.notNull(conversionService, "ConversionService must not be null!");
|
||||
|
||||
this.repository = repository;
|
||||
this.methods = metadata.getCrudMethods();
|
||||
this.idType = metadata.getIdType();
|
||||
this.conversionService = conversionService;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.core.invoke.RepositoryInvocationInformation#hasFindAllMethod()
|
||||
*/
|
||||
@Override
|
||||
public boolean hasFindAllMethod() {
|
||||
return methods.hasFindAllMethod();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.core.invoke.RepositoryInvoker#invokeFindAll(org.springframework.data.domain.Sort)
|
||||
*/
|
||||
@Override
|
||||
public Iterable<Object> invokeFindAll(Sort sort) {
|
||||
return invokeFindAllReflectively(sort);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.core.invoke.RepositoryInvoker#invokeFindAll(org.springframework.data.domain.Pageable)
|
||||
*/
|
||||
@Override
|
||||
public Iterable<Object> invokeFindAll(Pageable pageable) {
|
||||
return invokeFindAllReflectively(pageable);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.core.invoke.RepositoryInvocationInformation#hasSaveMethod()
|
||||
*/
|
||||
@Override
|
||||
public boolean hasSaveMethod() {
|
||||
return methods.hasSaveMethod();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.core.invoke.RepositoryInvoker#invokeSave(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public <T> T invokeSave(T object) {
|
||||
|
||||
Assert.state(hasSaveMethod(), "Repository doesn't have a save-method declared!");
|
||||
return invoke(methods.getSaveMethod(), object);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.core.invoke.RepositoryInvocationInformation#hasFindOneMethod()
|
||||
*/
|
||||
@Override
|
||||
public boolean hasFindOneMethod() {
|
||||
return methods.hasFindOneMethod();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.core.invoke.RepositoryInvoker#invokeFindOne(java.io.Serializable)
|
||||
*/
|
||||
@Override
|
||||
public <T> T invokeFindOne(Serializable id) {
|
||||
|
||||
Assert.state(hasFindOneMethod(), "Repository doesn't have a find-one-method declared!");
|
||||
return invoke(methods.getFindOneMethod(), convertId(id));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.core.invoke.RepositoryInvocationInformation#hasDeleteMethod()
|
||||
*/
|
||||
@Override
|
||||
public boolean hasDeleteMethod() {
|
||||
return methods.hasDelete();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.core.invoke.RepositoryInvoker#invokeDelete(java.io.Serializable)
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void invokeDelete(Serializable id) {
|
||||
|
||||
Assert.notNull(id, "Identifier must not be null!");
|
||||
Assert.state(hasDeleteMethod(), "Repository doesn't have a delete-method declared!");
|
||||
|
||||
Method method = methods.getDeleteMethod();
|
||||
Class<?> parameterType = method.getParameterTypes()[0];
|
||||
List<Class<? extends Serializable>> idTypes = Arrays.asList(idType, Serializable.class);
|
||||
|
||||
if (idTypes.contains(parameterType)) {
|
||||
invoke(method, convertId(id));
|
||||
} else {
|
||||
invoke(method, invokeFindOne(id));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.core.invoke.RepositoryInvoker#invokeQueryMethod(java.lang.reflect.Method, java.util.Map, org.springframework.data.domain.Pageable, org.springframework.data.domain.Sort)
|
||||
*/
|
||||
@Override
|
||||
public Object invokeQueryMethod(Method method, Map<String, String[]> parameters, Pageable pageable, Sort sort) {
|
||||
|
||||
Assert.notNull(method, "Method must not be null!");
|
||||
Assert.notNull(parameters, "Parameters must not be null!");
|
||||
|
||||
return invoke(method, prepareParameters(method, parameters, pageable, sort));
|
||||
}
|
||||
|
||||
private Object[] prepareParameters(Method method, Map<String, String[]> rawParameters, Pageable pageable, Sort sort) {
|
||||
|
||||
List<MethodParameter> parameters = new MethodParameters(method, PARAM_ANNOTATION).getParameters();
|
||||
|
||||
if (parameters.isEmpty()) {
|
||||
return new Object[0];
|
||||
}
|
||||
|
||||
Object[] result = new Object[parameters.size()];
|
||||
Sort sortToUse = pageable == null ? sort : pageable.getSort();
|
||||
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
|
||||
MethodParameter param = parameters.get(i);
|
||||
Class<?> targetType = param.getParameterType();
|
||||
|
||||
if (Pageable.class.isAssignableFrom(targetType)) {
|
||||
result[i] = pageable;
|
||||
} else if (Sort.class.isAssignableFrom(targetType)) {
|
||||
result[i] = sortToUse;
|
||||
} else {
|
||||
|
||||
String parameterName = param.getParameterName();
|
||||
|
||||
if (!StringUtils.hasText(parameterName)) {
|
||||
throw new IllegalArgumentException("No @Param annotation found on query method " + method.getName()
|
||||
+ " for parameter " + parameterName);
|
||||
}
|
||||
|
||||
String[] parameterValue = rawParameters.get(parameterName);
|
||||
Object value = parameterValue == null ? null : parameterValue.length == 1 ? parameterValue[0] : parameterValue;
|
||||
|
||||
result[i] = conversionService.convert(value, TypeDescriptor.forObject(value), new TypeDescriptor(param));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the given method with the given arguments on the backing repository.
|
||||
*
|
||||
* @param method
|
||||
* @param arguments
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T invoke(Method method, Object... arguments) {
|
||||
|
||||
ReflectionUtils.makeAccessible(method);
|
||||
return (T) ReflectionUtils.invokeMethod(method, repository, arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given id into the id type of the backing repository.
|
||||
*
|
||||
* @param id must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
protected Serializable convertId(Serializable id) {
|
||||
|
||||
Assert.notNull(id, "Id must not be null!");
|
||||
return conversionService.convert(id, idType);
|
||||
}
|
||||
|
||||
protected Iterable<Object> invokeFindAllReflectively(Pageable pageable) {
|
||||
|
||||
Assert.state(hasFindAllMethod(), "Repository doesn't have a find-all-method declared!");
|
||||
|
||||
Method method = methods.getFindAllMethod();
|
||||
Class<?>[] types = method.getParameterTypes();
|
||||
|
||||
if (types.length == 0) {
|
||||
return invoke(method);
|
||||
}
|
||||
|
||||
if (Pageable.class.isAssignableFrom(types[0])) {
|
||||
return invoke(method, pageable);
|
||||
}
|
||||
|
||||
Sort sort = pageable == null ? null : pageable.getSort();
|
||||
|
||||
return invokeFindAll(sort);
|
||||
}
|
||||
|
||||
protected Iterable<Object> invokeFindAllReflectively(Sort sort) {
|
||||
|
||||
Assert.state(hasFindAllMethod(), "Repository doesn't have a find-all-method declared!");
|
||||
|
||||
Method method = methods.getFindAllMethod();
|
||||
Class<?>[] types = method.getParameterTypes();
|
||||
|
||||
if (types.length == 0) {
|
||||
return invoke(method);
|
||||
}
|
||||
|
||||
return invoke(method, sort);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2013-2014 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.invoker;
|
||||
|
||||
/**
|
||||
* Meta-information about the methods a repository exposes.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface RepositoryInvocationInformation {
|
||||
|
||||
/**
|
||||
* Returns whether the repository has a method to save objects.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean hasSaveMethod();
|
||||
|
||||
/**
|
||||
* Returns whether the repository has a method to delete objects.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean hasDeleteMethod();
|
||||
|
||||
/**
|
||||
* Returns whether the repository has a method to find a single object.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean hasFindOneMethod();
|
||||
|
||||
/**
|
||||
* Returns whether the repository has a method to find all objects.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean hasFindAllMethod();
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2013-2014 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.invoker;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
|
||||
/**
|
||||
* API to invoke (CRUD) methods on Spring Data repository instances independently of the base interface they expose.
|
||||
* Clients should check the availability of the methods before invoking them by using the methods of
|
||||
* {@link RepositoryInvocationInformation}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface RepositoryInvoker extends RepositoryInvocationInformation {
|
||||
|
||||
/**
|
||||
* Invokes the method equivalent to {@link CrudRepository#save(Object)} on the repository.
|
||||
*
|
||||
* @param object
|
||||
* @return the result of the invocation of the save method
|
||||
* @throws IllegalStateException if the repository does not expose a save method.
|
||||
*/
|
||||
<T> T invokeSave(T object);
|
||||
|
||||
/**
|
||||
* Invokes the method equivalent to {@link CrudRepository#findOne(Serializable)}.
|
||||
*
|
||||
* @param id must not be {@literal null}.
|
||||
* @return the entity with the given id.
|
||||
* @throws IllegalStateException if the repository does not expose a find-one-method.
|
||||
*/
|
||||
<T> T invokeFindOne(Serializable id);
|
||||
|
||||
/**
|
||||
* Invokes the find-all method of the underlying repository using the method taking a {@link Pageable} as parameter if
|
||||
* available (i.e. the equivalent to {@link PagingAndSortingRepository#findAll(Pageable)}), using the method taking a
|
||||
* {@link Sort} if available (i.e. the equivalent to {@link PagingAndSortingRepository#findAll(Sort)} by extracting
|
||||
* the {@link Sort} contained in the given {@link Pageable}) or the plain equivalent to
|
||||
* {@link CrudRepository#findAll()}.
|
||||
*
|
||||
* @param pageable can be {@literal null}.
|
||||
* @return the result of the invocation of the find-all method.
|
||||
* @throws IllegalStateException if the repository does not expose a find-all-method.
|
||||
*/
|
||||
Iterable<Object> invokeFindAll(Pageable pageable);
|
||||
|
||||
/**
|
||||
* Invokes the find-all method of the underlying repository using the method taking a {@link Sort} as parameter if
|
||||
* available (i.e. the equivalent to {@link PagingAndSortingRepository#findAll(Sort)}) or the plain equivalent to
|
||||
* {@link CrudRepository#findAll()}.
|
||||
*
|
||||
* @param pageable can be {@literal null}.
|
||||
* @return the result of the invocation of the find-all method.
|
||||
* @throws IllegalStateException if the repository does not expose a find-all-method.
|
||||
*/
|
||||
Iterable<Object> invokeFindAll(Sort sort);
|
||||
|
||||
/**
|
||||
* Invokes the method equivalent to {@link CrudRepository#delete(Serializable)}. The given id is assumed to be of a
|
||||
* type convertable into the actual identifier type of the backing repository.
|
||||
*
|
||||
* @param id must not be {@literal null}. throws {@link IllegalStateException} if the repository does not expose a
|
||||
* delete-method.
|
||||
*/
|
||||
void invokeDelete(Serializable id);
|
||||
|
||||
/**
|
||||
* Invokes the query method backed by the given {@link Method} using the given parameters, {@link Pageable} and
|
||||
* {@link Sort}.
|
||||
*
|
||||
* @param method must not be {@literal null}.
|
||||
* @param parameters must not be {@literal null}.
|
||||
* @param pageable can be {@literal null}.
|
||||
* @param sort can be {@literal null}.
|
||||
* @return the result of the invoked query method.
|
||||
*/
|
||||
Object invokeQueryMethod(Method method, Map<String, String[]> parameters, Pageable pageable, Sort sort);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.invoker;
|
||||
|
||||
/**
|
||||
* Interface for a factory to create {@link RepositoryInvoker} instances for repositories managing a particular domain
|
||||
* type.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface RepositoryInvokerFactory {
|
||||
|
||||
/**
|
||||
* Returns the {@link RepositoryInvoker} for a repository managing the given domain type.
|
||||
*
|
||||
* @param domainType must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
RepositoryInvoker getInvokerFor(Class<?> domainType);
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
@@ -25,8 +25,10 @@ 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.data.repository.invoker.DefaultRepositoryInvokerFactory;
|
||||
import org.springframework.data.repository.invoker.RepositoryInvoker;
|
||||
import org.springframework.data.repository.invoker.RepositoryInvokerFactory;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -43,6 +45,7 @@ public class DomainClassConverter<T extends ConversionService & ConverterRegistr
|
||||
|
||||
private final T conversionService;
|
||||
private Repositories repositories = Repositories.NONE;
|
||||
private RepositoryInvokerFactory repositoryInvokerFactory;
|
||||
|
||||
public DomainClassConverter(T conversionService) {
|
||||
this.conversionService = conversionService;
|
||||
@@ -73,7 +76,7 @@ public class DomainClassConverter<T extends ConversionService & ConverterRegistr
|
||||
Class<?> domainType = targetType.getType();
|
||||
|
||||
RepositoryInformation info = repositories.getRepositoryInformationFor(domainType);
|
||||
CrudInvoker<?> invoker = repositories.getCrudInvoker(domainType);
|
||||
RepositoryInvoker invoker = repositoryInvokerFactory.getInvokerFor(domainType);
|
||||
|
||||
return invoker.invokeFindOne(conversionService.convert(source, info.getIdType()));
|
||||
}
|
||||
@@ -104,5 +107,6 @@ public class DomainClassConverter<T extends ConversionService & ConverterRegistr
|
||||
|
||||
this.repositories = new Repositories(context);
|
||||
this.conversionService.addConverter(this);
|
||||
this.repositoryInvokerFactory = new DefaultRepositoryInvokerFactory(repositories, conversionService);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,8 +22,8 @@ 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.data.repository.invoker.RepositoryInvoker;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -34,7 +34,7 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
public class DomainClassPropertyEditor<T, ID extends Serializable> extends PropertyEditorSupport {
|
||||
|
||||
private final CrudInvoker<?> invoker;
|
||||
private final RepositoryInvoker invoker;
|
||||
private final EntityInformation<T, ID> information;
|
||||
private final PropertyEditorRegistry registry;
|
||||
|
||||
@@ -46,7 +46,7 @@ public class DomainClassPropertyEditor<T, ID extends Serializable> extends Prope
|
||||
* @param information must not be {@literal null}.
|
||||
* @param registry must not be {@literal null}.
|
||||
*/
|
||||
public DomainClassPropertyEditor(CrudInvoker<?> invoker, EntityInformation<T, ID> information,
|
||||
public DomainClassPropertyEditor(RepositoryInvoker invoker, EntityInformation<T, ID> information,
|
||||
PropertyEditorRegistry registry) {
|
||||
|
||||
Assert.notNull(invoker);
|
||||
|
||||
@@ -21,8 +21,10 @@ 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.core.CrudInvoker;
|
||||
import org.springframework.data.repository.core.RepositoryInformation;
|
||||
import org.springframework.data.repository.invoker.DefaultRepositoryInvokerFactory;
|
||||
import org.springframework.data.repository.invoker.RepositoryInvoker;
|
||||
import org.springframework.data.repository.invoker.RepositoryInvokerFactory;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
|
||||
/**
|
||||
@@ -44,10 +46,13 @@ import org.springframework.web.servlet.DispatcherServlet;
|
||||
* {@link org.springframework.web.context.WebApplicationContext}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @deprecated use {@link DomainClassConverter} instead, will be removed in 1.10
|
||||
*/
|
||||
@Deprecated
|
||||
public class DomainClassPropertyEditorRegistrar implements PropertyEditorRegistrar, ApplicationContextAware {
|
||||
|
||||
private Repositories repositories = Repositories.NONE;
|
||||
private RepositoryInvokerFactory repositoryInvokerFactory;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
@@ -58,7 +63,7 @@ public class DomainClassPropertyEditorRegistrar implements PropertyEditorRegistr
|
||||
for (Class<?> domainClass : repositories) {
|
||||
|
||||
RepositoryInformation repositoryInformation = repositories.getRepositoryInformationFor(domainClass);
|
||||
CrudInvoker<?> invoker = repositories.getCrudInvoker(domainClass);
|
||||
RepositoryInvoker invoker = repositoryInvokerFactory.getInvokerFor(domainClass);
|
||||
|
||||
DomainClassPropertyEditor<Object, Serializable> editor = new DomainClassPropertyEditor<Object, Serializable>(
|
||||
invoker, repositories.getEntityInformationFor(repositoryInformation.getDomainType()), registry);
|
||||
@@ -72,6 +77,8 @@ public class DomainClassPropertyEditorRegistrar implements PropertyEditorRegistr
|
||||
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
|
||||
*/
|
||||
public void setApplicationContext(ApplicationContext context) {
|
||||
|
||||
this.repositories = new Repositories(context);
|
||||
this.repositoryInvokerFactory = new DefaultRepositoryInvokerFactory(repositories);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
* @author Thomas Darimont
|
||||
* @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(), repository, id);
|
||||
}
|
||||
}
|
||||
@@ -27,8 +27,6 @@ import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
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;
|
||||
@@ -193,20 +191,6 @@ public class Repositories implements Iterable<Class<?>> {
|
||||
return getRepositoryFactoryInfoFor(domainClass).getQueryMethods();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> CrudInvoker<T> getCrudInvoker(Class<T> domainClass) {
|
||||
|
||||
Object repository = getRepositoryFor(domainClass);
|
||||
|
||||
Assert.notNull(repository, String.format("No repository found for domain class: %s", domainClass));
|
||||
|
||||
if (repository instanceof CrudRepository) {
|
||||
return new CrudRepositoryInvoker<T>((CrudRepository<T, Serializable>) repository);
|
||||
} else {
|
||||
return new ReflectionRepositoryInvoker<T>(repository, getRepositoryInformationFor(domainClass).getCrudMethods());
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Iterable#iterator()
|
||||
|
||||
Reference in New Issue
Block a user