diff --git a/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/RepositoryMetadata.java b/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/RepositoryMetadata.java index 2b4d35f78..3857e0743 100644 --- a/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/RepositoryMetadata.java +++ b/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/RepositoryMetadata.java @@ -1,7 +1,6 @@ package org.springframework.data.rest.repository; import java.io.Serializable; -import java.lang.reflect.Method; import java.util.Map; import org.springframework.data.repository.Repository; @@ -19,8 +18,8 @@ public interface RepositoryMetadata queryMethods(); + Map queryMethods(); } diff --git a/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/RepositoryQueryMethod.java b/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/RepositoryQueryMethod.java new file mode 100644 index 000000000..f92c0e950 --- /dev/null +++ b/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/RepositoryQueryMethod.java @@ -0,0 +1,62 @@ +package org.springframework.data.rest.repository; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; + +import org.springframework.core.LocalVariableTableParameterNameDiscoverer; +import org.springframework.data.repository.query.Param; + +/** + * @author Jon Brisbin + */ +public class RepositoryQueryMethod { + + private static final Class[] SIMPLE_TYPES = new Class[]{ + String.class, + Integer.class, + Long.class, + Boolean.class + }; + private static final LocalVariableTableParameterNameDiscoverer nameLookup = new LocalVariableTableParameterNameDiscoverer(); + + private Method method; + private Class[] paramTypes; + private String[] paramNames; + + public RepositoryQueryMethod(Method method) { + this.method = method; + paramTypes = method.getParameterTypes(); + paramNames = nameLookup.getParameterNames(method); + if (null == paramNames) { + paramNames = new String[paramTypes.length]; + } + Annotation[][] paramAnnos = method.getParameterAnnotations(); + for (int i = 0; i < paramAnnos.length; i++) { + if (paramAnnos[i].length > 0) { + for (Annotation anno : paramAnnos[i]) { + if (Param.class.isAssignableFrom(anno.getClass())) { + Param p = (Param) anno; + paramNames[i] = p.value(); + break; + } + } + } + if (null == paramNames[i]) { + paramNames[i] = "arg" + i; + } + } + } + + public Class[] paramTypes() { + return paramTypes; + } + + public String[] paramNames() { + return paramNames; + } + + public Method method() { + return method; + } + +} diff --git a/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/jpa/JpaAttributeMetadata.java b/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/jpa/JpaAttributeMetadata.java index 707d1c9a4..706b4671a 100644 --- a/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/jpa/JpaAttributeMetadata.java +++ b/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/jpa/JpaAttributeMetadata.java @@ -139,4 +139,15 @@ public class JpaAttributeMetadata implements AttributeMetadata { return this; } + @Override public String toString() { + return "JpaAttributeMetadata{" + + "name='" + name + '\'' + + ", attribute=" + attribute + + ", type=" + type + + ", field=" + field + + ", getter=" + getter + + ", setter=" + setter + + '}'; + } + } diff --git a/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/jpa/JpaEntityMetadata.java b/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/jpa/JpaEntityMetadata.java index 050c0ceb5..1d8e57543 100644 --- a/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/jpa/JpaEntityMetadata.java +++ b/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/jpa/JpaEntityMetadata.java @@ -35,7 +35,9 @@ public class JpaEntityMetadata implements EntityMetadata { if (repositories.hasRepositoryFor(attrType)) { linkedAttributes.put(attr.getName(), new JpaAttributeMetadata(entityType, attr)); } else { - embeddedAttributes.put(attr.getName(), new JpaAttributeMetadata(entityType, attr)); + if (attr != idAttribute && attr != versionAttribute) { + embeddedAttributes.put(attr.getName(), new JpaAttributeMetadata(entityType, attr)); + } } } } @@ -73,4 +75,14 @@ public class JpaEntityMetadata implements EntityMetadata { return null; } + @Override public String toString() { + return "JpaEntityMetadata{" + + "type=" + type + + ", idAttribute=" + idAttribute + + ", versionAttribute=" + versionAttribute + + ", embeddedAttributes=" + embeddedAttributes + + ", linkedAttributes=" + linkedAttributes + + '}'; + } + } diff --git a/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/jpa/JpaRepositoryMetadata.java b/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/jpa/JpaRepositoryMetadata.java index a667b4d5e..21e9cb54c 100644 --- a/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/jpa/JpaRepositoryMetadata.java +++ b/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/jpa/JpaRepositoryMetadata.java @@ -13,6 +13,7 @@ import org.springframework.data.repository.Repository; import org.springframework.data.repository.core.EntityInformation; import org.springframework.data.repository.support.Repositories; import org.springframework.data.rest.repository.RepositoryMetadata; +import org.springframework.data.rest.repository.RepositoryQueryMethod; import org.springframework.data.rest.repository.annotation.RestPathSegment; import org.springframework.util.ReflectionUtils; @@ -25,7 +26,7 @@ public class JpaRepositoryMetadata> i private final Class repoClass; private final R repository; private final EntityInformation entityInfo; - private final Map queryMethods = new HashMap(); + private final Map queryMethods = new HashMap(); private JpaEntityMetadata entityMetadata; @SuppressWarnings({"unchecked"}) @@ -46,7 +47,7 @@ public class JpaRepositoryMetadata> i @Override public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException { String pathSeg = AnnotationUtils.findAnnotation(method, RestPathSegment.class).value(); ReflectionUtils.makeAccessible(method); - queryMethods.put(pathSeg, method); + queryMethods.put(pathSeg, new RepositoryQueryMethod(method)); } }, new ReflectionUtils.MethodFilter() { @@ -80,12 +81,23 @@ public class JpaRepositoryMetadata> i return entityMetadata; } - @Override public Method queryMethod(String key) { + @Override public RepositoryQueryMethod queryMethod(String key) { return queryMethods.get(key); } - @Override public Map queryMethods() { + @Override public Map queryMethods() { return Collections.unmodifiableMap(queryMethods); } + @Override public String toString() { + return "JpaRepositoryMetadata{" + + "name='" + name + '\'' + + ", repoClass=" + repoClass + + ", repository=" + repository + + ", entityInfo=" + entityInfo + + ", queryMethods=" + queryMethods + + ", entityMetadata=" + entityMetadata + + '}'; + } + } diff --git a/spring-data-rest-repository/src/test/groovy/org/springframework/data/rest/repository/spec/JpaMetadataSpec.groovy b/spring-data-rest-repository/src/test/groovy/org/springframework/data/rest/repository/spec/JpaMetadataSpec.groovy index c2e4d4d86..09eeb983a 100644 --- a/spring-data-rest-repository/src/test/groovy/org/springframework/data/rest/repository/spec/JpaMetadataSpec.groovy +++ b/spring-data-rest-repository/src/test/groovy/org/springframework/data/rest/repository/spec/JpaMetadataSpec.groovy @@ -5,7 +5,8 @@ import javax.persistence.PersistenceContext import org.springframework.beans.factory.annotation.Autowired import org.springframework.context.ApplicationContext import org.springframework.data.repository.CrudRepository -import org.springframework.data.rest.repository.JpaRepositoryMetadata +import org.springframework.data.rest.repository.RepositoryExporter +import org.springframework.data.rest.repository.RepositoryMetadata import org.springframework.data.rest.repository.test.Family import org.springframework.data.rest.repository.test.FamilyRepository import org.springframework.data.rest.repository.test.Person @@ -26,19 +27,23 @@ class JpaMetadataSpec extends Specification { @Autowired Collection repositories @Autowired - JpaRepositoryMetadata repoMeta + List exporters + + RepositoryMetadata repositoryMetadataFor(name) { + exporters.find { null != it.repositoryMetadataFor(name) }?.repositoryMetadataFor(name) + } def "finds repositories in ApplicationContext"() { when: "find repo by String identifier" - def repo = repoMeta.repositoryFor("person") + def repo = repositoryMetadataFor("person").repository() then: null != repo repo instanceof PersonRepository when: "find repo by domain Class" - repo = repoMeta.repositoryFor(Family) + repo = repositoryMetadataFor(Family).repository() then: null != repo @@ -49,8 +54,8 @@ class JpaMetadataSpec extends Specification { def "provides entity metadata"() { given: - def personRepo = repoMeta.repositoryFor(Person) - def familyRepo = repoMeta.repositoryFor(Family) + def personRepo = repositoryMetadataFor(Person).repository() + def familyRepo = repositoryMetadataFor(Family).repository() def johnDoe = personRepo.save(new Person("John Doe")) def janeDoe = personRepo.save(new Person("Jane Doe")) def doeFamily = familyRepo.save(new Family( @@ -59,13 +64,13 @@ class JpaMetadataSpec extends Specification { )) when: - def personMeta = repoMeta.entityMetadataFor(Person) - def familyMeta = repoMeta.entityMetadataFor(Family) + def personMeta = repositoryMetadataFor(Person).entityMetadata() + def familyMeta = repositoryMetadataFor(Family).entityMetadata() then: - personMeta.get("name", johnDoe) == "John Doe" - familyMeta.get("surname", doeFamily) == "Doe" - familyMeta.get("members", doeFamily).size() == 2 + personMeta.attribute("name").get(johnDoe) == "John Doe" + familyMeta.attribute("surname").get(doeFamily) == "Doe" + familyMeta.attribute("members").get(doeFamily).size() == 2 personMeta.embeddedAttributes().size() == 1 familyMeta.linkedAttributes().size() == 1 diff --git a/spring-data-rest-repository/src/test/java/org/springframework/data/rest/repository/test/PersonRepository.java b/spring-data-rest-repository/src/test/java/org/springframework/data/rest/repository/test/PersonRepository.java index 7678d816e..6a6371b59 100644 --- a/spring-data-rest-repository/src/test/java/org/springframework/data/rest/repository/test/PersonRepository.java +++ b/spring-data-rest-repository/src/test/java/org/springframework/data/rest/repository/test/PersonRepository.java @@ -1,9 +1,16 @@ package org.springframework.data.rest.repository.test; +import java.util.List; + import org.springframework.data.repository.CrudRepository; +import org.springframework.data.rest.repository.annotation.RestPathSegment; /** * @author Jon Brisbin */ public interface PersonRepository extends CrudRepository { + + @RestPathSegment("byName") + public List findByName(String name); + } diff --git a/spring-data-rest-repository/src/test/resources/JpaMetadataSpec-test.xml b/spring-data-rest-repository/src/test/resources/JpaMetadataSpec-test.xml index ecc285c52..dea85fab1 100644 --- a/spring-data-rest-repository/src/test/resources/JpaMetadataSpec-test.xml +++ b/spring-data-rest-repository/src/test/resources/JpaMetadataSpec-test.xml @@ -28,6 +28,6 @@ -