GET for linked entities.
This commit is contained in:
@@ -17,18 +17,12 @@ Installation is as simple as downloading a WAR file. To expose your Repositories
|
||||
|
||||
<import resource="shared.xml"/>
|
||||
|
||||
<bean id="baseUri" class="java.net.URI">
|
||||
<constructor-arg value="http://localhost:8080/data"/>
|
||||
</bean>
|
||||
|
||||
<jpa:repositories base-package="com.mycompany.domain.repositories"/>
|
||||
|
||||
</beans>
|
||||
|
||||
The file `shared.xml` contains a JDBC DataSource configuration, an EntityManagerFactoryBean, and a JpaTransactionManager.
|
||||
|
||||
Of note in this configuration is the bean named `baseUri`. This is the fully-qualified URI at which the exporter is deployed. This tells the exporter what base URI to use when generating links to your entities.
|
||||
|
||||
### Including your domain artifacts
|
||||
|
||||
To expose your domain objects (your JPA entities, Repositories) and Spring configuration using the web exporter, you need to copy those resources to the web exporter's `WEB-INF/lib` or `WEB-INF/classes` directory. There are potentially other ways to deploy these artifacts without modifying the web exporter's WAR file, but those methods are considerably more complicated and prone to classpath problems. The easiest and most reliable way to deploy your user artifacts are by deploying them alongside the web exporter's artifacts.
|
||||
@@ -37,7 +31,7 @@ To expose your domain objects (your JPA entities, Repositories) and Spring confi
|
||||
|
||||
By default, any repositories found are exported using the bean name of the repository in the Spring configuration (minus the word "Repository", if it appears in the bean name).
|
||||
|
||||
If you have a JPA entity in your domain model that looks like this:
|
||||
If you have a JPA entity in your domain model that looks like...
|
||||
|
||||
@Entity
|
||||
public class Person {
|
||||
@@ -52,12 +46,12 @@ If you have a JPA entity in your domain model that looks like this:
|
||||
private Map<String, Profile> profiles;
|
||||
}
|
||||
|
||||
An appropriate CrudRepository interface defined like this:
|
||||
...and an appropriate CrudRepository interface defined like...
|
||||
|
||||
public interface PersonRepository extends CrudRepository<Person, Long> {
|
||||
}
|
||||
|
||||
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 will be `http://localhost:8080/data/person`.
|
||||
...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`.
|
||||
|
||||
### Discoverability
|
||||
|
||||
@@ -78,7 +72,7 @@ You'll get back a chunk of JSON that points your user agent to the locations of
|
||||
|
||||
The "rel" of the link will match the exposed name of the repository. Your application should keep track of this rel value as the key to this repository.
|
||||
|
||||
Similarly, if you issue a GET to `http://localhost:8080/data/person`, you should get back a list of entities exposed at this resource (as returned by the CrudRepository.findAll method).
|
||||
Similarly, if you issue a GET to `http://localhost:8080/data/person`, you should get back a list of entities exposed at this resource (as returned by the CrudRepository.findAll method). At the moment, there is no paging, sorting, or querying capability.
|
||||
|
||||
curl -v http://localhost:8080/data/person
|
||||
|
||||
@@ -117,7 +111,7 @@ This entity has a simple String value called "name", and two relationships to ot
|
||||
|
||||
The "self" link will always point to the resource for this entity. Use the "self" link to access the entity itself if you wish to update or delete the entity.
|
||||
|
||||
Following the links for the "profiles" property, gives us a list of links to the actual entities that are referenced by this relationship:
|
||||
Following the links for the "profiles" property gives us a list of links to the actual entities that are referenced by this relationship:
|
||||
|
||||
curl -v http://localhost:8080/data/person/1/profiles
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package org.springframework.data.rest.webmvc;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@@ -25,8 +24,6 @@ import org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcesso
|
||||
@ImportResource("classpath*:META-INF/spring-data-rest/**/*-export.xml")
|
||||
public class RepositoryRestConfiguration {
|
||||
|
||||
@Autowired(required = false)
|
||||
URI baseUri;
|
||||
@Autowired
|
||||
EntityManagerFactory entityManagerFactory;
|
||||
@Autowired(required = false)
|
||||
@@ -37,13 +34,6 @@ public class RepositoryRestConfiguration {
|
||||
@Autowired(required = false)
|
||||
List<HttpMessageConverter<?>> httpMessageConverters = new ArrayList<HttpMessageConverter<?>>();
|
||||
|
||||
@Bean URI baseUri() {
|
||||
if (null == baseUri) {
|
||||
baseUri = URI.create("");
|
||||
}
|
||||
return baseUri;
|
||||
}
|
||||
|
||||
@Bean ConversionService conversionService() {
|
||||
if (null != customConversionService) {
|
||||
return customConversionService;
|
||||
|
||||
@@ -495,13 +495,13 @@ public class RepositoryRestController implements InitializingBean {
|
||||
if (child instanceof Collection) {
|
||||
for (Object o : (Collection) child) {
|
||||
String childId = childTypeMeta.entityInfo.getId(o).toString();
|
||||
URI uri = buildUri(baseUri, repositoryMetadata.repositoryNameFor(childRepo), childId);
|
||||
URI uri = buildUri(baseUri, repository, id, property, childId);
|
||||
links.add(new SimpleLink(childType.getSimpleName(), uri));
|
||||
}
|
||||
} else if (child instanceof Map) {
|
||||
for (Map.Entry<Object, Object> entry : ((Map<Object, Object>) child).entrySet()) {
|
||||
String childId = childTypeMeta.entityInfo.getId(entry.getValue()).toString();
|
||||
URI uri = buildUri(baseUri, repositoryMetadata.repositoryNameFor(childRepo), childId);
|
||||
URI uri = buildUri(baseUri, repository, id, property, childId);
|
||||
Object oKey = entry.getKey();
|
||||
String sKey;
|
||||
if (ClassUtils.isAssignable(oKey.getClass(), String.class)) {
|
||||
@@ -684,6 +684,63 @@ public class RepositoryRestController implements InitializingBean {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
@RequestMapping(
|
||||
value = "/{repository}/{id}/{property}/{childId}",
|
||||
method = {
|
||||
RequestMethod.GET
|
||||
},
|
||||
produces = {
|
||||
"application/json"
|
||||
}
|
||||
)
|
||||
public void childEntity(UriComponentsBuilder uriBuilder,
|
||||
@PathVariable String repository,
|
||||
@PathVariable String id,
|
||||
@PathVariable String property,
|
||||
@PathVariable String childId,
|
||||
Model model) {
|
||||
URI baseUri = uriBuilder.build().toUri();
|
||||
|
||||
CrudRepository repo = repositoryMetadata.repositoryFor(repository);
|
||||
if (null == repo) {
|
||||
model.addAttribute(STATUS, HttpStatus.NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
final TypeMetaCacheEntry typeMeta = typeMetaEntry(repo);
|
||||
|
||||
Serializable serId = stringToSerializable(id, typeMeta.idType);
|
||||
final Object entity = repo.findOne(serId);
|
||||
if (null != entity) {
|
||||
final Attribute attr = typeMeta.entityMetadata.linkedAttributes().get(property);
|
||||
if (null != attr) {
|
||||
// Find child entity
|
||||
CrudRepository childRepo = repositoryFromAttribute(attr);
|
||||
if (null != childRepo) {
|
||||
TypeMetaCacheEntry childTypeMeta = typeMetaEntry(childRepo);
|
||||
Serializable sChildId = stringToSerializable(childId, childTypeMeta.idType);
|
||||
Object childEntity = childRepo.findOne(sChildId);
|
||||
if (null != childEntity) {
|
||||
Map<String, Object> entityDto = extractPropertiesLinkAware(childEntity,
|
||||
childTypeMeta.entityMetadata,
|
||||
baseUri);
|
||||
URI selfUri = addSelfLink(baseUri, entityDto, repository, id);
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.add("Content-Location", selfUri.toString());
|
||||
model.addAttribute(HEADERS, headers);
|
||||
model.addAttribute(STATUS, HttpStatus.OK);
|
||||
model.addAttribute(RESOURCE, entityDto);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
model.addAttribute(STATUS, HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
@RequestMapping(
|
||||
value = "/{repository}/{id}/{property}/{childId}",
|
||||
@@ -712,8 +769,7 @@ public class RepositoryRestController implements InitializingBean {
|
||||
final Attribute attr = typeMeta.entityMetadata.linkedAttributes().get(property);
|
||||
if (null != attr) {
|
||||
// Find child entity
|
||||
Class<?> childType = attr.getJavaType();
|
||||
CrudRepository childRepo = repositoryMetadata.repositoryFor(childType);
|
||||
CrudRepository childRepo = repositoryFromAttribute(attr);
|
||||
if (null != childRepo) {
|
||||
TypeMetaCacheEntry childTypeMeta = typeMetaEntry(childRepo);
|
||||
Serializable sChildId = stringToSerializable(childId, childTypeMeta.idType);
|
||||
@@ -780,7 +836,18 @@ public class RepositoryRestController implements InitializingBean {
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
private void addSelfLink(URI baseUri, Map<String, Object> model, String... pathComponents) {
|
||||
private CrudRepository repositoryFromAttribute(Attribute attr) {
|
||||
CrudRepository repo = null;
|
||||
if (attr instanceof PluralAttribute) {
|
||||
repo = repositoryMetadata.repositoryFor(((PluralAttribute) attr).getElementType().getJavaType());
|
||||
} else {
|
||||
repo = repositoryMetadata.repositoryFor(attr.getJavaType());
|
||||
}
|
||||
return repo;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
private URI addSelfLink(URI baseUri, Map<String, Object> model, String... pathComponents) {
|
||||
List<Link> links = (List<Link>) model.get(LINKS);
|
||||
if (null == links) {
|
||||
links = new ArrayList<Link>();
|
||||
@@ -788,6 +855,7 @@ public class RepositoryRestController implements InitializingBean {
|
||||
}
|
||||
URI selfUri = buildUri(baseUri, pathComponents);
|
||||
links.add(new SimpleLink(SELF, selfUri));
|
||||
return selfUri;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
|
||||
Reference in New Issue
Block a user