From 9c81264d520abcbcf721531f7d553923f2300d45 Mon Sep 17 00:00:00 2001 From: Jon Brisbin Date: Tue, 26 Mar 2013 14:00:25 -0500 Subject: [PATCH] Added extra checks to make sure that query methods marked with `@RestResource(exported=false)` aren't accidentally exported anyway. --- .../invoke/RepositoryMethodInvoker.java | 333 +++++++++--------- .../AbstractRepositoryRestController.java | 3 + .../webmvc/RepositorySearchController.java | 5 +- 3 files changed, 174 insertions(+), 167 deletions(-) diff --git a/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/invoke/RepositoryMethodInvoker.java b/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/invoke/RepositoryMethodInvoker.java index f5f48ff9e..736164bde 100644 --- a/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/invoke/RepositoryMethodInvoker.java +++ b/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/invoke/RepositoryMethodInvoker.java @@ -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 { - private final Object repository; - private final Map queryMethods = new HashMap(); - 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 queryMethods = new HashMap(); + 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 save(S entity) { - return (S)invokeMethod(saveOne.getMethod(), repository, entity); - } + @SuppressWarnings({"unchecked"}) + @Override public 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 Iterable save(Iterable entities) { - return (Iterable)invokeMethod(saveSome.getMethod(), repository, entities); - } + @SuppressWarnings({"unchecked"}) + @Override public Iterable save(Iterable entities) { + return (Iterable)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 findAll() { - return (Iterable)invokeMethod(findAll.getMethod(), repository); - } + @SuppressWarnings({"unchecked"}) + @Override public Iterable findAll() { + return (Iterable)invokeMethod(findAll.getMethod(), repository); + } - public boolean hasFindAll() { - return null != findAll; - } + public boolean hasFindAll() { + return null != findAll; + } - @SuppressWarnings({"unchecked"}) - @Override public Iterable findAll(Iterable serializables) { - return (Iterable)invokeMethod(findSome.getMethod(), repository, serializables); - } + @SuppressWarnings({"unchecked"}) + @Override public Iterable findAll(Iterable serializables) { + return (Iterable)invokeMethod(findSome.getMethod(), repository, serializables); + } - public boolean hasFindSome() { - return null != findSome; - } + public boolean hasFindSome() { + return null != findSome; + } - @SuppressWarnings({"unchecked"}) - @Override public Iterable findAll(Sort sort) { - return (Iterable)invokeMethod(findAllSorted.getMethod(), repository, sort); - } + @SuppressWarnings({"unchecked"}) + @Override public Iterable findAll(Sort sort) { + return (Iterable)invokeMethod(findAllSorted.getMethod(), repository, sort); + } - public boolean hasFindAllSorted() { - return null != findAllSorted; - } + public boolean hasFindAllSorted() { + return null != findAllSorted; + } - @SuppressWarnings({"unchecked"}) - @Override public Page findAll(Pageable pageable) { - return (Page)invokeMethod(findAllPaged.getMethod(), repository, pageable); - } + @SuppressWarnings({"unchecked"}) + @Override public Page findAll(Pageable pageable) { + return (Page)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 getQueryMethods() { - return queryMethods; - } + public Map 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); + } } diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/AbstractRepositoryRestController.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/AbstractRepositoryRestController.java index a2aba2672..6c2c72e4b 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/AbstractRepositoryRestController.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/AbstractRepositoryRestController.java @@ -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())); } diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositorySearchController.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositorySearchController.java index 5addea431..0fe3ee3e8 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositorySearchController.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositorySearchController.java @@ -57,10 +57,13 @@ public class RepositorySearchController extends AbstractRepositoryRestController } ) @ResponseBody - public Resource list(RepositoryRestRequest repoRequest) { + public Resource list(RepositoryRestRequest repoRequest) throws ResourceNotFoundException { List links = new ArrayList(); links.addAll(queryMethodLinks(repoRequest.getBaseUri(), repoRequest.getPersistentEntity().getType())); + if(links.isEmpty()) { + throw new ResourceNotFoundException(); + } return new Resource(Collections.emptyList(), links); }