Added the ability to control the exporting of Repositories, query methods or entity fields by adding "exported = true|false" to the @RestResource annotation.
This commit is contained in:
@@ -98,3 +98,34 @@ This would result in a link value of:
|
||||
} ]
|
||||
}
|
||||
|
||||
### Hiding certain Repositories, query methods, or fields
|
||||
|
||||
You may not want a certain Repository, a query method on a Repository, or a field of your entity to be exported at all. To tell the exporter to not export your these items, annotate them with `@RestResource` and set `exported = false`.
|
||||
|
||||
For example, to skip exporting a Repository:
|
||||
|
||||
@RestResource(exported = false)
|
||||
public interface PersonRepository extends CrudRepository<Person, Long> {
|
||||
}
|
||||
|
||||
To skip exporting a query method:
|
||||
|
||||
@RestResource(path = "people", rel = "people")
|
||||
public interface PersonRepository extends CrudRepository<Person, Long> {
|
||||
|
||||
@RestResource(exported = false)
|
||||
public List<Person> findByName(String name);
|
||||
|
||||
}
|
||||
|
||||
Or to skip exporting a field:
|
||||
|
||||
@Entity
|
||||
@RestResource(exported = false)
|
||||
public class Person {
|
||||
@Id @GeneratedValue private Long id;
|
||||
@OneToMany
|
||||
@RestResource(exported = false)
|
||||
private Map<String, Profile> profiles;
|
||||
}
|
||||
|
||||
|
||||
@@ -104,6 +104,8 @@ If you have a JPA entity in your domain model that looks like...
|
||||
|
||||
...your PersonRepository will by default be declared in the ApplicationContext with a bean name of "personRepository". The web exporter will strip the word "Repository" from it and expose a resource named "person". The resulting URL of this repository (assuming the exporter webapp is deployed at context path `/data` in your servlet container) will be `http://localhost:8080/data/person`.
|
||||
|
||||
You can configure under what path, or whether a resource is exported at all, by using the `@RestResource` annotation. Details are here: [Configuring the REST URL path](../wiki/Configuring-the-REST-URL-path)
|
||||
|
||||
### Discoverability
|
||||
|
||||
The Web Exporter implements some aspects of the [HATEOS](http://en.wikipedia.org/wiki/HATEOAS) methodology. That means all the services of the web exporter are discoverable and exposed to the client using links.
|
||||
|
||||
@@ -7,7 +7,6 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
@@ -124,19 +123,21 @@ public abstract class RepositoryExporter<M extends RepositoryMetadata<E>, E exte
|
||||
repositories = new Repositories(applicationContext);
|
||||
repositoryMetadata = new HashMap<String, M>();
|
||||
for (Class<?> domainType : repositories) {
|
||||
if (!exportOnlyTheseClasses.isEmpty() && !exportOnlyTheseClasses.contains(domainType.getName())) {
|
||||
// Don't export this domain type
|
||||
continue;
|
||||
if (exportOnlyTheseClasses.isEmpty() || !exportOnlyTheseClasses.contains(domainType.getName())) {
|
||||
Class<?> repoClass = repositories.getRepositoryInformationFor(domainType).getRepositoryInterface();
|
||||
String name = StringUtils.uncapitalize(repoClass.getSimpleName().replaceAll("Repository", ""));
|
||||
RestResource resourceAnno = repoClass.getAnnotation(RestResource.class);
|
||||
boolean exported = true;
|
||||
if (null != resourceAnno) {
|
||||
if (StringUtils.hasText(resourceAnno.path())) {
|
||||
name = resourceAnno.path();
|
||||
}
|
||||
exported = resourceAnno.exported();
|
||||
}
|
||||
if (exported) {
|
||||
repositoryMetadata.put(name, createRepositoryMetadata(name, domainType, repoClass, repositories));
|
||||
}
|
||||
}
|
||||
Class<?> repoClass = repositories.getRepositoryInformationFor(domainType).getRepositoryInterface();
|
||||
String name;
|
||||
RestResource pathSeg = repoClass.getAnnotation(RestResource.class);
|
||||
if (null != pathSeg) {
|
||||
name = pathSeg.path();
|
||||
} else {
|
||||
name = StringUtils.uncapitalize(repoClass.getSimpleName().replaceAll("Repository", ""));
|
||||
}
|
||||
repositoryMetadata.put(name, createRepositoryMetadata(name, domainType, repoClass, repositories));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import java.lang.annotation.Target;
|
||||
* @author Jon Brisbin <jbrisbin@vmware.com>
|
||||
*/
|
||||
@Target({
|
||||
ElementType.FIELD,
|
||||
ElementType.METHOD,
|
||||
ElementType.TYPE
|
||||
})
|
||||
@@ -20,7 +21,9 @@ import java.lang.annotation.Target;
|
||||
@Inherited
|
||||
public @interface RestResource {
|
||||
|
||||
String path();
|
||||
boolean exported() default true;
|
||||
|
||||
String path() default "";
|
||||
|
||||
String rel() default "";
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.springframework.data.rest.repository.jpa;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.persistence.metamodel.Attribute;
|
||||
@@ -9,6 +10,8 @@ import javax.persistence.metamodel.SingularAttribute;
|
||||
|
||||
import org.springframework.data.repository.support.Repositories;
|
||||
import org.springframework.data.rest.repository.EntityMetadata;
|
||||
import org.springframework.data.rest.repository.annotation.RestResource;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* @author Jon Brisbin <jbrisbin@vmware.com>
|
||||
@@ -30,15 +33,25 @@ public class JpaEntityMetadata implements EntityMetadata<JpaAttributeMetadata> {
|
||||
}
|
||||
|
||||
for (Attribute attr : entityType.getAttributes()) {
|
||||
Class<?> attrType = (attr instanceof PluralAttribute
|
||||
? ((PluralAttribute) attr).getElementType().getJavaType()
|
||||
: attr.getJavaType());
|
||||
if (repositories.hasRepositoryFor(attrType)) {
|
||||
linkedAttributes.put(attr.getName(), new JpaAttributeMetadata(entityType, attr));
|
||||
} else {
|
||||
if (!(attr instanceof SingularAttribute && ((SingularAttribute) attr).isId())
|
||||
&& !(attr instanceof SingularAttribute && ((SingularAttribute) attr).isVersion())) {
|
||||
embeddedAttributes.put(attr.getName(), new JpaAttributeMetadata(entityType, attr));
|
||||
boolean exported = true;
|
||||
Field field = ReflectionUtils.findField(type, attr.getJavaMember().getName());
|
||||
if (null != field) {
|
||||
RestResource fieldResourceAnno = field.getAnnotation(RestResource.class);
|
||||
if (null != fieldResourceAnno) {
|
||||
exported = fieldResourceAnno.exported();
|
||||
}
|
||||
}
|
||||
if (exported) {
|
||||
Class<?> attrType = (attr instanceof PluralAttribute
|
||||
? ((PluralAttribute) attr).getElementType().getJavaType()
|
||||
: attr.getJavaType());
|
||||
if (repositories.hasRepositoryFor(attrType)) {
|
||||
linkedAttributes.put(attr.getName(), new JpaAttributeMetadata(entityType, attr));
|
||||
} else {
|
||||
if (!(attr instanceof SingularAttribute && ((SingularAttribute) attr).isId())
|
||||
&& !(attr instanceof SingularAttribute && ((SingularAttribute) attr).isVersion())) {
|
||||
embeddedAttributes.put(attr.getName(), new JpaAttributeMetadata(entityType, attr));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,11 +52,17 @@ public class JpaRepositoryMetadata implements RepositoryMetadata<JpaEntityMetada
|
||||
for (Method method : repositories.getRepositoryInformationFor(domainType).getQueryMethods()) {
|
||||
String pathSeg = method.getName();
|
||||
RestResource methodResourceAnno = method.getAnnotation(RestResource.class);
|
||||
boolean methodExported = true;
|
||||
if (null != methodResourceAnno) {
|
||||
pathSeg = methodResourceAnno.path();
|
||||
if (StringUtils.hasText(methodResourceAnno.path())) {
|
||||
pathSeg = methodResourceAnno.path();
|
||||
}
|
||||
methodExported = methodResourceAnno.exported();
|
||||
}
|
||||
if (methodExported) {
|
||||
ReflectionUtils.makeAccessible(method);
|
||||
queryMethods.put(pathSeg, new RepositoryQueryMethod(method));
|
||||
}
|
||||
ReflectionUtils.makeAccessible(method);
|
||||
queryMethods.put(pathSeg, new RepositoryQueryMethod(method));
|
||||
}
|
||||
|
||||
Metamodel metamodel = entityManager.getMetamodel();
|
||||
|
||||
@@ -6,6 +6,8 @@ import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToMany;
|
||||
|
||||
import org.springframework.data.rest.repository.annotation.RestResource;
|
||||
|
||||
/**
|
||||
* @author Jon Brisbin <jbrisbin@vmware.com>
|
||||
*/
|
||||
@@ -16,6 +18,7 @@ public class Family {
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
private String surname;
|
||||
@RestResource(exported = false)
|
||||
@OneToMany
|
||||
private List<Person> members;
|
||||
|
||||
|
||||
@@ -299,7 +299,9 @@ public class RepositoryRestController
|
||||
URI path = buildUri(baseUri, repository, "search", entry.getKey());
|
||||
RestResource resourceAnno = entry.getValue().method().getAnnotation(RestResource.class);
|
||||
if (null != resourceAnno) {
|
||||
path = buildUri(baseUri, repository, "search", resourceAnno.path());
|
||||
if (StringUtils.hasText(resourceAnno.path())) {
|
||||
path = buildUri(baseUri, repository, "search", resourceAnno.path());
|
||||
}
|
||||
if (StringUtils.hasText(resourceAnno.rel())) {
|
||||
rel = repoMeta.rel() + "." + resourceAnno.rel();
|
||||
}
|
||||
@@ -1069,10 +1071,7 @@ public class RepositoryRestController
|
||||
}
|
||||
|
||||
for (String attrName : entityMetadata.linkedAttributes().keySet()) {
|
||||
URI uri = UriComponentsBuilder.fromUri(baseUri)
|
||||
.pathSegment(attrName)
|
||||
.build()
|
||||
.toUri();
|
||||
URI uri = buildUri(baseUri, attrName);
|
||||
Link l = new SimpleLink(repoRel + "." + entity.getClass().getSimpleName() + "." + attrName, uri);
|
||||
List<Link> links = (List<Link>) entityDto.get(LINKS);
|
||||
if (null == links) {
|
||||
|
||||
@@ -8,6 +8,8 @@ import javax.persistence.Id;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Version;
|
||||
|
||||
import org.springframework.data.rest.repository.annotation.RestResource;
|
||||
|
||||
/**
|
||||
* @author Jon Brisbin <jbrisbin@vmware.com>
|
||||
*/
|
||||
|
||||
@@ -3,9 +3,11 @@ package org.springframework.data.rest.test.webmvc;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.data.rest.repository.annotation.RestResource;
|
||||
|
||||
/**
|
||||
* @author Jon Brisbin <jbrisbin@vmware.com>
|
||||
*/
|
||||
@RestResource(exported = false)
|
||||
public interface UuidTestRepository extends CrudRepository<UuidTest, UUID> {
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user