Added test coverage, updated the README to reflect a sample configuration.
This commit is contained in:
66
README.md
66
README.md
@@ -11,9 +11,69 @@ managing associations.
|
||||
### Installation
|
||||
|
||||
To use the Spring Data Rest exporter, first package your domain classes and repositories into a JAR
|
||||
file. Include some Spring XML configuration files in the `META-INF/spring-data-rest` directory in
|
||||
that JAR file (including an applicable EntityManager and DataSource).
|
||||
file. Include some Spring XML configuration files in the `META-INF/spring-data-rest` directory (the
|
||||
file name should end with "-export.xml" to be picked up by the scanner) in that JAR file that include
|
||||
an applicable EntityManager and DataSource and the Repository configuration (using the special JPA
|
||||
Repository namespace).
|
||||
|
||||
You can either deploy this JAR file into your Servlet container in a "shared" configuration, or you
|
||||
can add this JAR file (and any other application dependencies to the exporter WAR file's `WEB-INF/lib`
|
||||
can add this JAR file (and any other application dependencies) to the exporter WAR file's `WEB-INF/lib`
|
||||
directory.
|
||||
|
||||
Somewhere in the Spring configuration files you need to define a bean called "baseUri" that is a
|
||||
`java.net.URI` and is the fully-qualified URI in which the exporter servlet has been deployed. In the
|
||||
case of the sample below, the servlet is deployed to a context path of `/data`. Using the default
|
||||
host and port settings, this yields a `baseUri` of `http://localhost:8080/data`. You'll want to change
|
||||
this to reflect your deployment configuration.
|
||||
|
||||
### Sample Configuration
|
||||
|
||||
The configuration used in testing looks like this:
|
||||
|
||||
##### META-INF/spring-data-rest/shared.xml
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd">
|
||||
|
||||
<bean id="baseUri" class="java.net.URI">
|
||||
<constructor-arg value="http://localhost:8080/data"/>
|
||||
</bean>
|
||||
|
||||
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
|
||||
<property name="dataSource" ref="dataSource"/>
|
||||
<property name="jpaVendorAdapter">
|
||||
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
|
||||
<property name="generateDdl" value="true"/>
|
||||
<property name="database" value="HSQL"/>
|
||||
</bean>
|
||||
</property>
|
||||
<property name="persistenceUnitName" value="jpa.sample"/>
|
||||
</bean>
|
||||
|
||||
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
|
||||
<property name="entityManagerFactory" ref="entityManagerFactory"/>
|
||||
</bean>
|
||||
|
||||
<jdbc:embedded-database id="dataSource" type="HSQL"/>
|
||||
|
||||
</beans>
|
||||
|
||||
##### META-INF/spring-data-rest/repositories-export.xml
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
|
||||
|
||||
<import resource="shared.xml"/>
|
||||
|
||||
<jpa:repositories base-package="org.springframework.data.rest.test.mvc"/>
|
||||
|
||||
</beans>
|
||||
|
||||
|
||||
@@ -204,10 +204,6 @@ public class RepositoryRestController implements InitializingBean {
|
||||
|
||||
URI relativeUri = baseUri.relativize(request.getURI());
|
||||
final Stack<URI> uris = UriUtils.explode(baseUri, relativeUri);
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("uris: " + uris);
|
||||
}
|
||||
|
||||
final int uriCnt = uris.size();
|
||||
if (uris.size() > 0) {
|
||||
final String repoName = uris.get(0).getPath();
|
||||
@@ -448,6 +444,11 @@ public class RepositoryRestController implements InitializingBean {
|
||||
repo.findOne(serId) :
|
||||
entityMetadata.targetType().newInstance();
|
||||
|
||||
if (null == entity) {
|
||||
model.addAttribute(STATUS, HttpStatus.NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
entityMetadata.doWithEmbedded(new Handler<Attribute, Void>() {
|
||||
@Override public Void handle(Attribute attribute) {
|
||||
String name = attribute.getName();
|
||||
|
||||
@@ -14,6 +14,7 @@ import org.springframework.mock.web.MockHttpServletRequest
|
||||
import org.springframework.test.context.ContextConfiguration
|
||||
import org.springframework.transaction.annotation.Transactional
|
||||
import org.springframework.ui.ExtendedModelMap
|
||||
import org.springframework.ui.Model
|
||||
import spock.lang.Shared
|
||||
import spock.lang.Specification
|
||||
|
||||
@@ -30,21 +31,47 @@ class RepositoryRestControllerSpec extends Specification {
|
||||
@Autowired
|
||||
RepositoryRestController controller
|
||||
|
||||
ServletServerHttpRequest createRequest(String method, String path) {
|
||||
return new ServletServerHttpRequest(new MockHttpServletRequest(
|
||||
MockHttpServletRequest createRequest(String method, String path) {
|
||||
return new MockHttpServletRequest(
|
||||
serverPort: 8080,
|
||||
requestURI: "/data/$path",
|
||||
method: method
|
||||
))
|
||||
)
|
||||
}
|
||||
|
||||
Map GET(String path) {
|
||||
Model GET(String path) {
|
||||
def request = createRequest("GET", path)
|
||||
def model = new ExtendedModelMap()
|
||||
controller.get(request, model)
|
||||
controller.get(new ServletServerHttpRequest(request), model)
|
||||
return model
|
||||
}
|
||||
|
||||
Model POST(String path, m) {
|
||||
def request = createRequest("POST", path)
|
||||
request.contentType = "application/json"
|
||||
request.setContent(mapper.writeValueAsBytes(m))
|
||||
def model = new ExtendedModelMap()
|
||||
controller.createOrUpdate(new ServletServerHttpRequest(request), model)
|
||||
return model
|
||||
}
|
||||
|
||||
Model PUT(String path, m) {
|
||||
def request = createRequest("PUT", path)
|
||||
request.contentType = "application/json"
|
||||
request.setContent(mapper.writeValueAsBytes(m))
|
||||
def model = new ExtendedModelMap()
|
||||
controller.createOrUpdate(new ServletServerHttpRequest(request), model)
|
||||
return model
|
||||
}
|
||||
|
||||
Model DELETE(String path) {
|
||||
def request = createRequest("DELETE", path)
|
||||
def model = new ExtendedModelMap()
|
||||
controller.delete(new ServletServerHttpRequest(request), model)
|
||||
return model
|
||||
|
||||
}
|
||||
|
||||
def setupSpec() {
|
||||
def customSerializerFactory = new CustomSerializerFactory()
|
||||
customSerializerFactory.addSpecificMapping(SimpleLink, new FluentBeanSerializer(SimpleLink))
|
||||
@@ -74,15 +101,86 @@ class RepositoryRestControllerSpec extends Specification {
|
||||
def person = GET("person/1")
|
||||
|
||||
then:
|
||||
person?.resource.name == "John Doe"
|
||||
person?.resource?.name == "John Doe"
|
||||
|
||||
when:
|
||||
def profiles = GET("person/1/profiles")
|
||||
def profilesLinks = profiles?.resource.profiles
|
||||
def profilesLinks = profiles.resource?.profiles
|
||||
|
||||
then:
|
||||
profilesLinks.size() == 2
|
||||
|
||||
}
|
||||
|
||||
@Transactional
|
||||
def "responds to POST with ID"() {
|
||||
|
||||
when:
|
||||
def created = POST("person/3", [name: "James Doe"])
|
||||
|
||||
then:
|
||||
created.status == HttpStatus.CREATED
|
||||
|
||||
}
|
||||
|
||||
@Transactional
|
||||
def "responds to PUT"() {
|
||||
|
||||
given:
|
||||
POST("person/3", [name: "James Doe"])
|
||||
|
||||
when:
|
||||
def updated = PUT("person/3", [name: "James Doe Jr."])
|
||||
def getUpdated = GET("person/3")
|
||||
|
||||
then:
|
||||
updated.status == HttpStatus.NO_CONTENT
|
||||
getUpdated.status == HttpStatus.OK
|
||||
getUpdated.resource?.name == "James Doe Jr."
|
||||
|
||||
}
|
||||
|
||||
@Transactional
|
||||
def "updates links"() {
|
||||
|
||||
given:
|
||||
POST("person/3", [name: "James Doe"])
|
||||
|
||||
when:
|
||||
def link = POST("person/3/addresses", [[href: "$baseUri/address/1".toString()]])
|
||||
def getUpdated = GET("person/3/addresses")
|
||||
|
||||
then:
|
||||
link.status == HttpStatus.CREATED
|
||||
getUpdated.status == HttpStatus.OK
|
||||
getUpdated.resource?.size() == 1
|
||||
|
||||
}
|
||||
|
||||
@Transactional
|
||||
def "responds to DELETE"() {
|
||||
|
||||
given:
|
||||
POST("person/3", [name: "James Doe"])
|
||||
POST("person/3/addresses", [[href: "$baseUri/address/1".toString()]])
|
||||
|
||||
when:
|
||||
def deleted = DELETE("person/3/addresses/1")
|
||||
def getUpdated = GET("person/3/addresses")
|
||||
|
||||
then:
|
||||
deleted.status == HttpStatus.NO_CONTENT
|
||||
getUpdated.status == HttpStatus.OK
|
||||
getUpdated.resource?._links?.size() == 0
|
||||
|
||||
when:
|
||||
def delEntity = DELETE("person/3")
|
||||
def getUpdEntity = GET("person/3")
|
||||
|
||||
then:
|
||||
delEntity.status == HttpStatus.NO_CONTENT
|
||||
getUpdEntity.status == HttpStatus.NOT_FOUND
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user