Added extra checks to make sure that query methods marked with @RestResource(exported=false) aren't accidentally exported anyway.
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
package org.springframework.data.rest.repository.invoke;
|
||||
|
||||
import static org.springframework.data.rest.repository.support.ResourceMappingUtils.getResourceMapping;
|
||||
import static org.springframework.util.ReflectionUtils.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
@@ -11,211 +10,213 @@ import java.util.Map;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
import org.springframework.data.repository.core.RepositoryInformation;
|
||||
import org.springframework.data.rest.config.RepositoryRestConfiguration;
|
||||
import org.springframework.data.rest.config.ResourceMapping;
|
||||
import org.springframework.data.rest.repository.support.ResourceMappingUtils;
|
||||
|
||||
/**
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
public class RepositoryMethodInvoker implements PagingAndSortingRepository<Object, Serializable> {
|
||||
|
||||
private final Object repository;
|
||||
private final Map<String, RepositoryMethod> queryMethods = new HashMap<String, RepositoryMethod>();
|
||||
private RepositoryMethod saveOne;
|
||||
private RepositoryMethod saveSome;
|
||||
private RepositoryMethod findOne;
|
||||
private RepositoryMethod exists;
|
||||
private RepositoryMethod findAll;
|
||||
private RepositoryMethod findAllSorted;
|
||||
private RepositoryMethod findAllPaged;
|
||||
private RepositoryMethod findSome;
|
||||
private RepositoryMethod count;
|
||||
private RepositoryMethod deleteOne;
|
||||
private RepositoryMethod deleteOneById;
|
||||
private RepositoryMethod deleteSome;
|
||||
private RepositoryMethod deleteAll;
|
||||
private final Object repository;
|
||||
private final Map<String, RepositoryMethod> queryMethods = new HashMap<String, RepositoryMethod>();
|
||||
private RepositoryMethod saveOne;
|
||||
private RepositoryMethod saveSome;
|
||||
private RepositoryMethod findOne;
|
||||
private RepositoryMethod exists;
|
||||
private RepositoryMethod findAll;
|
||||
private RepositoryMethod findAllSorted;
|
||||
private RepositoryMethod findAllPaged;
|
||||
private RepositoryMethod findSome;
|
||||
private RepositoryMethod count;
|
||||
private RepositoryMethod deleteOne;
|
||||
private RepositoryMethod deleteOneById;
|
||||
private RepositoryMethod deleteSome;
|
||||
private RepositoryMethod deleteAll;
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
public RepositoryMethodInvoker(Object repository,
|
||||
RepositoryInformation repoInfo) {
|
||||
this.repository = repository;
|
||||
Class<?> repoType = repoInfo.getRepositoryInterface();
|
||||
@SuppressWarnings({"unchecked"})
|
||||
public RepositoryMethodInvoker(Object repository,
|
||||
RepositoryInformation repoInfo) {
|
||||
this.repository = repository;
|
||||
Class<?> repoType = repoInfo.getRepositoryInterface();
|
||||
|
||||
doWithMethods(repoType, new MethodCallback() {
|
||||
@Override public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
|
||||
String name = method.getName();
|
||||
int cardinality = method.getParameterTypes().length;
|
||||
Class<?> paramType = (cardinality == 1 ? method.getParameterTypes()[0] : null);
|
||||
boolean someMethod = (null != paramType && Iterable.class.isAssignableFrom(paramType));
|
||||
boolean byIdMethod = (null != paramType && paramType == Serializable.class);
|
||||
boolean sortable = (null != paramType && Sort.class.isAssignableFrom(paramType));
|
||||
boolean pageable = (null != paramType && Pageable.class.isAssignableFrom(paramType));
|
||||
RepositoryMethod repoMethod = new RepositoryMethod(method);
|
||||
doWithMethods(repoType, new MethodCallback() {
|
||||
@Override public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
|
||||
boolean exported = ResourceMappingUtils.findExported(method);
|
||||
if(!exported) {
|
||||
return;
|
||||
}
|
||||
String name = method.getName();
|
||||
int cardinality = method.getParameterTypes().length;
|
||||
Class<?> paramType = (cardinality == 1 ? method.getParameterTypes()[0] : null);
|
||||
boolean someMethod = (null != paramType && Iterable.class.isAssignableFrom(paramType));
|
||||
boolean byIdMethod = (null != paramType && paramType == Serializable.class);
|
||||
boolean sortable = (null != paramType && Sort.class.isAssignableFrom(paramType));
|
||||
boolean pageable = (null != paramType && Pageable.class.isAssignableFrom(paramType));
|
||||
RepositoryMethod repoMethod = new RepositoryMethod(method);
|
||||
|
||||
if("save".equals(name) && someMethod) {
|
||||
saveSome = repoMethod;
|
||||
} else if("save".equals(name)) {
|
||||
saveOne = repoMethod;
|
||||
} else if("findOne".equals(name)) {
|
||||
findOne = repoMethod;
|
||||
} else if("exists".equals(name)) {
|
||||
exists = repoMethod;
|
||||
} else if("findAll".equals(name) && someMethod) {
|
||||
findSome = repoMethod;
|
||||
} else if("findAll".equals(name) && sortable) {
|
||||
findAllSorted = repoMethod;
|
||||
} else if("findAll".equals(name) && pageable) {
|
||||
findAllPaged = repoMethod;
|
||||
} else if("findAll".equals(name)) {
|
||||
findAll = repoMethod;
|
||||
} else if("count".equals(name)) {
|
||||
count = repoMethod;
|
||||
} else if("delete".equals(name) && byIdMethod) {
|
||||
deleteOneById = repoMethod;
|
||||
} else if("delete".equals(name) && someMethod) {
|
||||
deleteSome = repoMethod;
|
||||
} else if("delete".equals(name)) {
|
||||
deleteOne = repoMethod;
|
||||
} else if("deleteAll".equals(name)) {
|
||||
deleteAll = repoMethod;
|
||||
} else {
|
||||
queryMethods.put(name, repoMethod);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
if("save".equals(name) && someMethod) {
|
||||
saveSome = repoMethod;
|
||||
} else if("save".equals(name)) {
|
||||
saveOne = repoMethod;
|
||||
} else if("findOne".equals(name)) {
|
||||
findOne = repoMethod;
|
||||
} else if("exists".equals(name)) {
|
||||
exists = repoMethod;
|
||||
} else if("findAll".equals(name) && someMethod) {
|
||||
findSome = repoMethod;
|
||||
} else if("findAll".equals(name) && sortable) {
|
||||
findAllSorted = repoMethod;
|
||||
} else if("findAll".equals(name) && pageable) {
|
||||
findAllPaged = repoMethod;
|
||||
} else if("findAll".equals(name)) {
|
||||
findAll = repoMethod;
|
||||
} else if("count".equals(name)) {
|
||||
count = repoMethod;
|
||||
} else if("delete".equals(name) && byIdMethod) {
|
||||
deleteOneById = repoMethod;
|
||||
} else if("delete".equals(name) && someMethod) {
|
||||
deleteSome = repoMethod;
|
||||
} else if("delete".equals(name)) {
|
||||
deleteOne = repoMethod;
|
||||
} else if("deleteAll".equals(name)) {
|
||||
deleteAll = repoMethod;
|
||||
} else {
|
||||
queryMethods.put(name, repoMethod);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
@Override public <S extends Object> S save(S entity) {
|
||||
return (S)invokeMethod(saveOne.getMethod(), repository, entity);
|
||||
}
|
||||
@SuppressWarnings({"unchecked"})
|
||||
@Override public <S extends Object> S save(S entity) {
|
||||
return (S)invokeMethod(saveOne.getMethod(), repository, entity);
|
||||
}
|
||||
|
||||
public boolean hasSaveOne() {
|
||||
return null != saveOne;
|
||||
}
|
||||
public boolean hasSaveOne() {
|
||||
return null != saveOne;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
@Override public <S extends Object> Iterable<S> save(Iterable<S> entities) {
|
||||
return (Iterable<S>)invokeMethod(saveSome.getMethod(), repository, entities);
|
||||
}
|
||||
@SuppressWarnings({"unchecked"})
|
||||
@Override public <S extends Object> Iterable<S> save(Iterable<S> entities) {
|
||||
return (Iterable<S>)invokeMethod(saveSome.getMethod(), repository, entities);
|
||||
}
|
||||
|
||||
public boolean hasSaveSome() {
|
||||
return null != saveSome;
|
||||
}
|
||||
public boolean hasSaveSome() {
|
||||
return null != saveSome;
|
||||
}
|
||||
|
||||
@Override public Object findOne(Serializable serializable) {
|
||||
return invokeMethod(findOne.getMethod(), repository, serializable);
|
||||
}
|
||||
@Override public Object findOne(Serializable serializable) {
|
||||
return invokeMethod(findOne.getMethod(), repository, serializable);
|
||||
}
|
||||
|
||||
public boolean hasFindOne() {
|
||||
return null != findOne;
|
||||
}
|
||||
public boolean hasFindOne() {
|
||||
return null != findOne;
|
||||
}
|
||||
|
||||
@Override public boolean exists(Serializable serializable) {
|
||||
return (Boolean)invokeMethod(exists.getMethod(), repository, serializable);
|
||||
}
|
||||
@Override public boolean exists(Serializable serializable) {
|
||||
return (Boolean)invokeMethod(exists.getMethod(), repository, serializable);
|
||||
}
|
||||
|
||||
public boolean hasExists() {
|
||||
return null != exists;
|
||||
}
|
||||
public boolean hasExists() {
|
||||
return null != exists;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
@Override public Iterable<Object> findAll() {
|
||||
return (Iterable<Object>)invokeMethod(findAll.getMethod(), repository);
|
||||
}
|
||||
@SuppressWarnings({"unchecked"})
|
||||
@Override public Iterable<Object> findAll() {
|
||||
return (Iterable<Object>)invokeMethod(findAll.getMethod(), repository);
|
||||
}
|
||||
|
||||
public boolean hasFindAll() {
|
||||
return null != findAll;
|
||||
}
|
||||
public boolean hasFindAll() {
|
||||
return null != findAll;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
@Override public Iterable<Object> findAll(Iterable<Serializable> serializables) {
|
||||
return (Iterable<Object>)invokeMethod(findSome.getMethod(), repository, serializables);
|
||||
}
|
||||
@SuppressWarnings({"unchecked"})
|
||||
@Override public Iterable<Object> findAll(Iterable<Serializable> serializables) {
|
||||
return (Iterable<Object>)invokeMethod(findSome.getMethod(), repository, serializables);
|
||||
}
|
||||
|
||||
public boolean hasFindSome() {
|
||||
return null != findSome;
|
||||
}
|
||||
public boolean hasFindSome() {
|
||||
return null != findSome;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
@Override public Iterable<Object> findAll(Sort sort) {
|
||||
return (Iterable<Object>)invokeMethod(findAllSorted.getMethod(), repository, sort);
|
||||
}
|
||||
@SuppressWarnings({"unchecked"})
|
||||
@Override public Iterable<Object> findAll(Sort sort) {
|
||||
return (Iterable<Object>)invokeMethod(findAllSorted.getMethod(), repository, sort);
|
||||
}
|
||||
|
||||
public boolean hasFindAllSorted() {
|
||||
return null != findAllSorted;
|
||||
}
|
||||
public boolean hasFindAllSorted() {
|
||||
return null != findAllSorted;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
@Override public Page<Object> findAll(Pageable pageable) {
|
||||
return (Page<Object>)invokeMethod(findAllPaged.getMethod(), repository, pageable);
|
||||
}
|
||||
@SuppressWarnings({"unchecked"})
|
||||
@Override public Page<Object> findAll(Pageable pageable) {
|
||||
return (Page<Object>)invokeMethod(findAllPaged.getMethod(), repository, pageable);
|
||||
}
|
||||
|
||||
public boolean hasFindAllPageable() {
|
||||
return null != findAllPaged;
|
||||
}
|
||||
public boolean hasFindAllPageable() {
|
||||
return null != findAllPaged;
|
||||
}
|
||||
|
||||
@Override public void delete(Serializable serializable) {
|
||||
invokeMethod(deleteOneById.getMethod(), repository, serializable);
|
||||
}
|
||||
@Override public void delete(Serializable serializable) {
|
||||
invokeMethod(deleteOneById.getMethod(), repository, serializable);
|
||||
}
|
||||
|
||||
public boolean hasDeleteOneById() {
|
||||
return null != deleteOneById;
|
||||
}
|
||||
public boolean hasDeleteOneById() {
|
||||
return null != deleteOneById;
|
||||
}
|
||||
|
||||
@Override public long count() {
|
||||
return (Long)invokeMethod(count.getMethod(), repository);
|
||||
}
|
||||
@Override public long count() {
|
||||
return (Long)invokeMethod(count.getMethod(), repository);
|
||||
}
|
||||
|
||||
public boolean hasCount() {
|
||||
return null != count;
|
||||
}
|
||||
public boolean hasCount() {
|
||||
return null != count;
|
||||
}
|
||||
|
||||
@Override public void delete(Object entity) {
|
||||
invokeMethod(deleteOne.getMethod(), repository, entity);
|
||||
}
|
||||
@Override public void delete(Object entity) {
|
||||
invokeMethod(deleteOne.getMethod(), repository, entity);
|
||||
}
|
||||
|
||||
public boolean hasDeleteOne() {
|
||||
return null != deleteOne;
|
||||
}
|
||||
public boolean hasDeleteOne() {
|
||||
return null != deleteOne;
|
||||
}
|
||||
|
||||
@Override public void delete(Iterable<?> entities) {
|
||||
invokeMethod(deleteSome.getMethod(), repository, entities);
|
||||
}
|
||||
@Override public void delete(Iterable<?> entities) {
|
||||
invokeMethod(deleteSome.getMethod(), repository, entities);
|
||||
}
|
||||
|
||||
public boolean hasDeleteSome() {
|
||||
return null != deleteSome;
|
||||
}
|
||||
public boolean hasDeleteSome() {
|
||||
return null != deleteSome;
|
||||
}
|
||||
|
||||
@Override public void deleteAll() {
|
||||
invokeMethod(deleteAll.getMethod(), repository);
|
||||
}
|
||||
@Override public void deleteAll() {
|
||||
invokeMethod(deleteAll.getMethod(), repository);
|
||||
}
|
||||
|
||||
public boolean hasDeleteAll() {
|
||||
return null != deleteAll;
|
||||
}
|
||||
public boolean hasDeleteAll() {
|
||||
return null != deleteAll;
|
||||
}
|
||||
|
||||
public Map<String, RepositoryMethod> getQueryMethods() {
|
||||
return queryMethods;
|
||||
}
|
||||
public Map<String, RepositoryMethod> getQueryMethods() {
|
||||
return queryMethods;
|
||||
}
|
||||
|
||||
public RepositoryMethod getRepositoryMethod(String name) {
|
||||
return queryMethods.get(name);
|
||||
}
|
||||
public RepositoryMethod getRepositoryMethod(String name) {
|
||||
return queryMethods.get(name);
|
||||
}
|
||||
|
||||
public Object invokeQueryMethod(String name, Object... params) {
|
||||
RepositoryMethod repoMethod = queryMethods.get(name);
|
||||
if(null == repoMethod) {
|
||||
throw new NoSuchMethodError(name);
|
||||
}
|
||||
return invokeMethod(repoMethod.getMethod(), repository, params);
|
||||
}
|
||||
public Object invokeQueryMethod(String name, Object... params) {
|
||||
RepositoryMethod repoMethod = queryMethods.get(name);
|
||||
if(null == repoMethod) {
|
||||
throw new NoSuchMethodError(name);
|
||||
}
|
||||
return invokeMethod(repoMethod.getMethod(), repository, params);
|
||||
}
|
||||
|
||||
public Object invokeQueryMethod(RepositoryMethod method, Object... params) {
|
||||
return invokeMethod(method.getMethod(), repository, params);
|
||||
}
|
||||
public Object invokeQueryMethod(RepositoryMethod method, Object... params) {
|
||||
return invokeMethod(method.getMethod(), repository, params);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -329,6 +329,9 @@ public class AbstractRepositoryRestController implements ApplicationContextAware
|
||||
LinkBuilder linkBuilder = BaseUriLinkBuilder.create(buildUri(baseUri, repoMapping.getPath(), "search"));
|
||||
ResourceMapping methodMapping = ResourceMappingUtils.merge(method,
|
||||
repoMapping.getResourceMappingFor(method.getName()));
|
||||
if(!methodMapping.isExported()) {
|
||||
continue;
|
||||
}
|
||||
links.add(linkBuilder.slash(methodMapping.getPath())
|
||||
.withRel(repoMapping.getRel() + "." + methodMapping.getRel()));
|
||||
}
|
||||
|
||||
@@ -57,10 +57,13 @@ public class RepositorySearchController extends AbstractRepositoryRestController
|
||||
}
|
||||
)
|
||||
@ResponseBody
|
||||
public Resource<?> list(RepositoryRestRequest repoRequest) {
|
||||
public Resource<?> list(RepositoryRestRequest repoRequest) throws ResourceNotFoundException {
|
||||
List<Link> links = new ArrayList<Link>();
|
||||
links.addAll(queryMethodLinks(repoRequest.getBaseUri(),
|
||||
repoRequest.getPersistentEntity().getType()));
|
||||
if(links.isEmpty()) {
|
||||
throw new ResourceNotFoundException();
|
||||
}
|
||||
return new Resource<Object>(Collections.emptyList(), links);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user