DATAREST-219 - Polishing.

Generally polished implementation and test cases for Greg's contribution.
Re-ordered parameters in ControllerUtils' helper methods for consistency.
Use Spring's CollectionFactory to create a suitable collection for the handled properties in the first place to avoid unnecessary conversion later on.

Removed duplication in test cases. Polished JavaDoc in UriListHttpMessageConverter and moved to a Scanner based implementation to read the request body. 

Adapted to latest changes in Spring HATEOAS. Reactivated ResourceStringUtilsTests.

Related pull requests: #128, #86.
This commit is contained in:
Oliver Gierke
2014-01-24 15:16:21 +01:00
parent 1f0b9bd664
commit bd8d3afa65
11 changed files with 208 additions and 215 deletions

View File

@@ -15,8 +15,11 @@
*/
package org.springframework.data.rest.core.mapping;
import org.springframework.context.MessageSourceResolvable;
/**
*
* Adapter class for the {@link MessageSourceResolvable} part of a {@link ResourceDescription}.
*
* @author Oliver Gierke
*/
public abstract class ResolvableResourceDescriptionSupport implements ResourceDescription {
@@ -29,7 +32,7 @@ public abstract class ResolvableResourceDescriptionSupport implements ResourceDe
public String[] getCodes() {
return new String[] { getMessage() };
}
/*
* (non-Javadoc)
* @see org.springframework.context.MessageSourceResolvable#getArguments()
@@ -38,7 +41,7 @@ public abstract class ResolvableResourceDescriptionSupport implements ResourceDe
public Object[] getArguments() {
return new Object[0];
}
/*
* (non-Javadoc)
* @see org.springframework.context.MessageSourceResolvable#getDefaultMessage()

View File

@@ -106,7 +106,7 @@ class TypeBasedCollectionResourceMapping implements CollectionResourceMapping {
*/
@Override
public String getItemResourceRel() {
return relProvider.getSingleResourceRelFor(type);
return relProvider.getItemResourceRelFor(type);
}
/*

View File

@@ -50,10 +50,10 @@ public class RepositoryRelProvider implements RelProvider {
/*
* (non-Javadoc)
* @see org.springframework.hateoas.RelProvider#getSingleResourceRelFor(java.lang.Class)
* @see org.springframework.hateoas.RelProvider#getItemResourceRelFor(java.lang.Class)
*/
@Override
public String getSingleResourceRelFor(Class<?> type) {
public String getItemResourceRelFor(Class<?> type) {
return mappings.getMappingFor(type).getItemResourceRel();
}

View File

@@ -32,11 +32,13 @@ public class SimpleRelProvider implements RelProvider {
return true;
}
/* (non-Javadoc)
* @see org.springframework.hateoas.RelProvider#getSingleResourceRelFor(java.lang.Class)
/*
* (non-Javadoc)
* @see org.springframework.hateoas.RelProvider#getItemResourceRelFor(java.lang.Class)
*/
@Override
public String getSingleResourceRelFor(Class<?> type) {
public String getItemResourceRelFor(Class<?> type) {
String collectionRel = getCollectionResourceRelFor(type);
return String.format("%s.%s", collectionRel, collectionRel);
}

View File

@@ -33,13 +33,13 @@ import static org.junit.runners.Parameterized.Parameters;
* @author Florent Biville
*/
@RunWith(Parameterized.class)
public class ResourceStringUtilsTest {
public class ResourceStringUtilsTests {
final String actual;
final String expected;
final boolean hasText;
public ResourceStringUtilsTest(String testDescription, String actual, String expected, boolean hasText) {
public ResourceStringUtilsTests(String testDescription, String actual, String expected, boolean hasText) {
this.actual = actual;
this.expected = expected;

View File

@@ -38,14 +38,15 @@ public class ControllerUtils {
/**
* Wrap a resource as a {@link ResourceEntity} and attach given headers and status.
*
* @param status
* @param headers
* @param resource
* @param status
* @param <R>
* @return
*/
public static <R extends ResourceSupport> ResponseEntity<ResourceSupport> toResponseEntity(HttpHeaders headers,
R resource, HttpStatus status) {
public static <R extends ResourceSupport> ResponseEntity<ResourceSupport> toResponseEntity(HttpStatus status,
HttpHeaders headers, R resource) {
HttpHeaders hdrs = new HttpHeaders();
if (null != headers) {
@@ -57,20 +58,22 @@ public class ControllerUtils {
/**
* Return an empty response that is only comprised of a status
*
* @param status
* @return
*/
public static ResponseEntity<ResourceSupport> toEmptyResponse(HttpStatus status) {
return toResponseEntity(null, EMPTY_RESOURCES, status);
return toResponseEntity(status, null, EMPTY_RESOURCES);
}
/**
* Return an empty response that is only comprised of headers and a status
* @param headers
*
* @param status
* @param headers
* @return
*/
public static ResponseEntity<ResourceSupport> toEmptyResponse(HttpHeaders headers, HttpStatus status) {
return toResponseEntity(headers, EMPTY_RESOURCES, status);
public static ResponseEntity<ResourceSupport> toEmptyResponse(HttpStatus status, HttpHeaders headers) {
return toResponseEntity(status, headers, EMPTY_RESOURCES);
}
}

View File

@@ -176,7 +176,7 @@ class RepositoryEntityController extends AbstractRepositoryRestController implem
headers.setLocation(URI.create(selfLink.getHref()));
PersistentEntityResource<Object> resource = config.isReturnBodyOnCreate() ? perAssembler.toResource(obj) : null;
return ControllerUtils.toResponseEntity(headers, resource, HttpStatus.CREATED);
return ControllerUtils.toResponseEntity(HttpStatus.CREATED, headers, resource);
}
/**
@@ -238,9 +238,9 @@ class RepositoryEntityController extends AbstractRepositoryRestController implem
publisher.publishEvent(new AfterSaveEvent(obj));
if (config.isReturnBodyOnUpdate()) {
return ControllerUtils.toResponseEntity(null, perAssembler.toResource(obj), HttpStatus.OK);
return ControllerUtils.toResponseEntity(HttpStatus.OK, null, perAssembler.toResource(obj));
} else {
return ControllerUtils.toResponseEntity(null, null, HttpStatus.NO_CONTENT);
return ControllerUtils.toResponseEntity(HttpStatus.NO_CONTENT, null, null);
}
}

View File

@@ -18,7 +18,6 @@ package org.springframework.data.rest.webmvc;
import static org.springframework.data.rest.webmvc.ControllerUtils.*;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.*;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
@@ -30,6 +29,7 @@ import java.util.Map.Entry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.core.CollectionFactory;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.PersistentProperty;
@@ -60,7 +60,7 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.util.UriComponentsBuilder;
/**
* @author Jon Brisbin
@@ -145,7 +145,7 @@ public class RepositoryPropertyReferenceController extends AbstractRepositoryRes
};
ResourceSupport responseResource = doWithReferencedProperty(repoRequest, id, property, handler);
return ControllerUtils.toResponseEntity(headers, responseResource, HttpStatus.OK);
return ControllerUtils.toResponseEntity(HttpStatus.OK, headers, responseResource);
}
@RequestMapping(value = BASE_MAPPING, method = RequestMethod.DELETE)
@@ -244,7 +244,7 @@ public class RepositoryPropertyReferenceController extends AbstractRepositoryRes
};
ResourceSupport responseResource = doWithReferencedProperty(repoRequest, id, property, handler);
return ControllerUtils.toResponseEntity(headers, responseResource, HttpStatus.OK);
return ControllerUtils.toResponseEntity(HttpStatus.OK, headers, responseResource);
}
@RequestMapping(value = BASE_MAPPING, method = RequestMethod.GET, produces = {
@@ -292,7 +292,7 @@ public class RepositoryPropertyReferenceController extends AbstractRepositoryRes
links.add(linkBuilder.withRel(propertyMapping.getRel()));
}
return ControllerUtils.toResponseEntity(null, new Resource<Object>(EMPTY_RESOURCE_LIST, links), HttpStatus.OK);
return ControllerUtils.toResponseEntity(HttpStatus.OK, null, new Resource<Object>(EMPTY_RESOURCE_LIST, links));
}
@RequestMapping(value = BASE_MAPPING, //
@@ -301,28 +301,28 @@ public class RepositoryPropertyReferenceController extends AbstractRepositoryRes
@ResponseBody
public ResponseEntity<? extends ResourceSupport> createPropertyReference(final RepositoryRestRequest repoRequest,
final @RequestBody Resources<Object> incoming, @PathVariable String id, @PathVariable String property,
final HttpServletRequest request)
throws NoSuchMethodException {
final UriComponentsBuilder builder) throws NoSuchMethodException {
final RepositoryInvoker invoker = repoRequest.getRepositoryInvoker();
if (!invoker.exposesSave()) {
return new ResponseEntity<Resource<?>>(HttpStatus.METHOD_NOT_ALLOWED);
}
Function<ReferencedProperty, ResourceSupport> handler = new Function<ReferencedProperty, ResourceSupport>() {
@Override
public ResourceSupport apply(ReferencedProperty prop) {
Class<?> propertyType = prop.property.getType();
if (prop.property.isCollectionLike()) {
Collection<Object> coll;
Collection<Object> coll = CollectionFactory.createCollection(propertyType, 0);
// Either load the exist collection to add to it (POST)
if (HttpMethod.POST.equals(repoRequest.getRequestMethod())) {
coll = (Collection<Object>) prop.propertyValue;
} else { // Or start from an empty collection to replace it (PUT)
coll = new ArrayList<Object>();
}
// Add to the existing collection
@@ -335,13 +335,11 @@ public class RepositoryPropertyReferenceController extends AbstractRepositoryRes
} else if (prop.property.isMap()) {
Map<String, Object> m;
Map<String, Object> m = CollectionFactory.createMap(propertyType, 0);
// Either load the exist collection to add to it (POST)
if (HttpMethod.POST.equals(repoRequest.getRequestMethod())) {
m = (Map<String, Object>) prop.propertyValue;
} else { // Or start from an empty collection to replace it (PUT)
m = new HashMap<String, Object>();
}
// Add to the existing collection
@@ -378,10 +376,10 @@ public class RepositoryPropertyReferenceController extends AbstractRepositoryRes
doWithReferencedProperty(repoRequest, id, property, handler);
final HttpHeaders headers = new HttpHeaders();
headers.set("Location", String.valueOf(request.getRequestURL()));
HttpHeaders headers = new HttpHeaders();
headers.set("Location", builder.build().toUriString());
return ControllerUtils.toEmptyResponse(headers, HttpStatus.CREATED);
return ControllerUtils.toEmptyResponse(HttpStatus.CREATED, headers);
}
@RequestMapping(value = BASE_MAPPING + "/{propertyId}", method = RequestMethod.DELETE)

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014 the original author or authors.
* Copyright 2012-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,15 +15,15 @@
*/
package org.springframework.data.rest.webmvc.convert;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Scanner;
import org.springframework.core.convert.converter.Converter;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.hateoas.Resources;
@@ -33,10 +33,15 @@ import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.util.StringUtils;
/**
* {@link Converter} to render all {@link Link}s contained in a {@link ResourceSupport} as {@code text/uri-list} and
* parse a request of that media type back into a {@link ResourceSupport} instance.
*
* @author Jon Brisbin
* @author Greg Turnquist
* @author Oliver Gierke
*/
public class UriListHttpMessageConverter implements HttpMessageConverter<ResourceSupport> {
@@ -46,6 +51,10 @@ public class UriListHttpMessageConverter implements HttpMessageConverter<Resourc
MEDIA_TYPES.add(MediaType.parseMediaType("text/uri-list"));
}
/*
* (non-Javadoc)
* @see org.springframework.http.converter.HttpMessageConverter#canRead(java.lang.Class, org.springframework.http.MediaType)
*/
@Override
public boolean canRead(Class<?> clazz, MediaType mediaType) {
if (null == mediaType) {
@@ -54,37 +63,68 @@ public class UriListHttpMessageConverter implements HttpMessageConverter<Resourc
return ResourceSupport.class.isAssignableFrom(clazz) && mediaType.getSubtype().contains("uri-list");
}
/*
* (non-Javadoc)
* @see org.springframework.http.converter.HttpMessageConverter#canWrite(java.lang.Class, org.springframework.http.MediaType)
*/
@Override
public boolean canWrite(Class<?> clazz, MediaType mediaType) {
return canRead(clazz, mediaType);
}
/*
* (non-Javadoc)
* @see org.springframework.http.converter.HttpMessageConverter#getSupportedMediaTypes()
*/
@Override
public List<MediaType> getSupportedMediaTypes() {
return MEDIA_TYPES;
}
/*
* (non-Javadoc)
* @see org.springframework.http.converter.HttpMessageConverter#read(java.lang.Class, org.springframework.http.HttpInputMessage)
*/
@Override
public ResourceSupport read(Class<? extends ResourceSupport> clazz, HttpInputMessage inputMessage) throws IOException,
HttpMessageNotReadableException {
public ResourceSupport read(Class<? extends ResourceSupport> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {
List<Link> links = new ArrayList<Link>();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputMessage.getBody()));
String line;
while (null != (line = reader.readLine())) {
links.add(new Link(line));
Scanner scanner = new Scanner(inputMessage.getBody());
try {
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
if (StringUtils.hasText(line)) {
links.add(new Link(line));
}
}
} finally {
scanner.close();
}
return new Resources<Object>(Collections.emptyList(), links);
}
/*
* (non-Javadoc)
* @see org.springframework.http.converter.HttpMessageConverter#write(java.lang.Object, org.springframework.http.MediaType, org.springframework.http.HttpOutputMessage)
*/
@Override
public void write(ResourceSupport resource, MediaType contentType, HttpOutputMessage outputMessage) throws IOException,
HttpMessageNotWritableException {
public void write(ResourceSupport resource, MediaType contentType, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputMessage.getBody()));
for (Link link : resource.getLinks()) {
writer.write(link.getHref());
writer.newLine();
}
writer.flush();
}
}

View File

@@ -138,12 +138,7 @@ public abstract class AbstractWebIntegrationTests {
protected MockHttpServletResponse postAndGet(Link link, Object payload, MediaType mediaType) throws Exception {
String href;
if (link.isTemplated()) {
href = link.expand().getHref();
} else {
href = link.getHref();
}
String href = link.isTemplated() ? link.expand().getHref() : link.getHref();
MockHttpServletResponse response = mvc.perform(post(href).content(payload.toString()).contentType(mediaType)).//
andExpect(status().isCreated()).//
@@ -161,12 +156,7 @@ public abstract class AbstractWebIntegrationTests {
protected MockHttpServletResponse putAndGet(Link link, Object payload, MediaType mediaType) throws Exception {
String href;
if (link.isTemplated()) {
href = link.expand().getHref();
} else {
href = link.getHref();
}
String href = link.isTemplated() ? link.expand().getHref() : link.getHref();
MockHttpServletResponse response = mvc.perform(put(href).content(payload.toString()).contentType(mediaType)).//
andExpect(status().isCreated()).//
@@ -184,12 +174,7 @@ public abstract class AbstractWebIntegrationTests {
protected MockHttpServletResponse deleteAndGet(Link link, MediaType mediaType) throws Exception {
String href;
if (link.isTemplated()) {
href = link.expand().getHref();
} else {
href = link.getHref();
}
String href = link.isTemplated() ? link.expand().getHref() : link.getHref();
MockHttpServletResponse response = mvc.perform(delete(href).contentType(mediaType)).//
andExpect(status().isNoContent()).//

View File

@@ -15,7 +15,7 @@
*/
package org.springframework.data.rest.webmvc.jpa;
import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@@ -23,11 +23,10 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import net.minidev.json.JSONArray;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
@@ -41,12 +40,11 @@ import org.springframework.test.context.ContextConfiguration;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.util.UriTemplate;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jayway.jsonpath.JsonPath;
import org.springframework.util.StringUtils;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriTemplate;
/**
* Web integration tests specific to JPA.
@@ -194,40 +192,24 @@ public class JpaWebTests extends AbstractWebIntegrationTests {
mvc.perform(get(href)).andExpect(status().isOk());
}
/**
* @see DATAREST-219
*/
@Test
public void manipulatePropertyCollectionRestfullyWithMultiplePosts() throws Exception {
ObjectMapper mapper = new ObjectMapper();
List<Link> links = preparePersonResources(new Person("Frodo", "Baggins"), //
new Person("Bilbo", "Baggins"), //
new Person("Merry", "Baggins"), //
new Person("Pippin", "Baggins"));
String bilbo = mapper.writeValueAsString(new Person("Bilbo", "Baggins"));
String frodo = mapper.writeValueAsString(new Person("Frodo", "Baggins"));
String merry = mapper.writeValueAsString(new Person("Merry", "Baggins"));
String pippin = mapper.writeValueAsString(new Person("Pippin", "Baggins"));
Link frodosSiblingLink = links.get(0);
Link peopleLink = discoverUnique("people");
postAndGet(frodosSiblingLink, links.get(1).getHref(), TEXT_URI_LIST);
postAndGet(frodosSiblingLink, links.get(2).getHref(), TEXT_URI_LIST);
postAndGet(frodosSiblingLink, links.get(3).getHref(), TEXT_URI_LIST);
MockHttpServletResponse bilboResponse = postAndGet(peopleLink, bilbo, MediaType.APPLICATION_JSON);
MockHttpServletResponse frodoResponse = postAndGet(peopleLink, frodo, MediaType.APPLICATION_JSON);
MockHttpServletResponse merryResponse = postAndGet(peopleLink, merry, MediaType.APPLICATION_JSON);
MockHttpServletResponse pippinResponse = postAndGet(peopleLink, pippin, MediaType.APPLICATION_JSON);
Link bilboSelfLink = assertHasLinkWithRel(Link.REL_SELF, bilboResponse);
Link merrySelfLink = assertHasLinkWithRel(Link.REL_SELF, merryResponse);
Link pippinSelfLink = assertHasLinkWithRel(Link.REL_SELF, pippinResponse);
Link frodosSiblingsLink = assertHasLinkWithRel("siblings", frodoResponse);
postAndGet(frodosSiblingsLink, bilboSelfLink.getHref(), TEXT_URI_LIST);
postAndGet(frodosSiblingsLink, merrySelfLink.getHref(), TEXT_URI_LIST);
postAndGet(frodosSiblingsLink, pippinSelfLink.getHref(), TEXT_URI_LIST);
MockHttpServletResponse frodosLatestSiblings = request(frodosSiblingsLink);
String[] persons = ((JSONArray) JsonPath.read(frodosLatestSiblings.getContentAsString(), "$._embedded.persons[*].firstName")).toArray(new String[]{});
assertThat(persons.length, equalTo(3));
assertThat(Arrays.asList(persons), hasItems("Bilbo", "Merry", "Pippin"));
assertSiblingNames(frodosSiblingLink, "Bilbo", "Merry", "Pippin");
}
/**
@@ -236,34 +218,16 @@ public class JpaWebTests extends AbstractWebIntegrationTests {
@Test
public void manipulatePropertyCollectionRestfullyWithSinglePost() throws Exception {
ObjectMapper mapper = new ObjectMapper();
List<Link> links = preparePersonResources(new Person("Frodo", "Baggins"), //
new Person("Bilbo", "Baggins"), //
new Person("Merry", "Baggins"), //
new Person("Pippin", "Baggins"));
String bilbo = mapper.writeValueAsString(new Person("Bilbo", "Baggins"));
String frodo = mapper.writeValueAsString(new Person("Frodo", "Baggins"));
String merry = mapper.writeValueAsString(new Person("Merry", "Baggins"));
String pippin = mapper.writeValueAsString(new Person("Pippin", "Baggins"));
Link frodosSiblingLink = links.get(0);
Link peopleLink = discoverUnique("people");
postAndGet(frodosSiblingLink, toUriList(links.get(1), links.get(2), links.get(3)), TEXT_URI_LIST);
MockHttpServletResponse bilboResponse = postAndGet(peopleLink, bilbo, MediaType.APPLICATION_JSON);
MockHttpServletResponse frodoResponse = postAndGet(peopleLink, frodo, MediaType.APPLICATION_JSON);
MockHttpServletResponse merryResponse = postAndGet(peopleLink, merry, MediaType.APPLICATION_JSON);
MockHttpServletResponse pippinResponse = postAndGet(peopleLink, pippin, MediaType.APPLICATION_JSON);
final Link bilboSelfLink = assertHasLinkWithRel(Link.REL_SELF, bilboResponse);
final Link merrySelfLink = assertHasLinkWithRel(Link.REL_SELF, merryResponse);
final Link pippinSelfLink = assertHasLinkWithRel(Link.REL_SELF, pippinResponse);
Link frodosSiblingsLink = assertHasLinkWithRel("siblings", frodoResponse);
postAndGet(frodosSiblingsLink,
StringUtils.arrayToDelimitedString(new Object[]{bilboSelfLink.getHref(),
merrySelfLink.getHref(), pippinSelfLink.getHref()}, "\n"),
TEXT_URI_LIST);
MockHttpServletResponse frodosLatestSiblings = request(frodosSiblingsLink);
String[] persons = ((JSONArray) JsonPath.read(frodosLatestSiblings.getContentAsString(), "$._embedded.persons[*].firstName")).toArray(new String[]{});
assertThat(persons.length, equalTo(3));
assertThat(Arrays.asList(persons), hasItems("Bilbo", "Merry", "Pippin"));
assertSiblingNames(frodosSiblingLink, "Bilbo", "Merry", "Pippin");
}
/**
@@ -272,40 +236,20 @@ public class JpaWebTests extends AbstractWebIntegrationTests {
@Test
public void manipulatePropertyCollectionRestfullyWithMultiplePuts() throws Exception {
ObjectMapper mapper = new ObjectMapper();
List<Link> links = preparePersonResources(new Person("Frodo", "Baggins"), //
new Person("Bilbo", "Baggins"), //
new Person("Merry", "Baggins"), //
new Person("Pippin", "Baggins"));
String bilbo = mapper.writeValueAsString(new Person("Bilbo", "Baggins"));
String frodo = mapper.writeValueAsString(new Person("Frodo", "Baggins"));
String merry = mapper.writeValueAsString(new Person("Merry", "Baggins"));
String pippin = mapper.writeValueAsString(new Person("Pippin", "Baggins"));
Link frodosSiblingsLink = links.get(0);
Link peopleLink = discoverUnique("people");
putAndGet(frodosSiblingsLink, links.get(1).getHref(), TEXT_URI_LIST);
putAndGet(frodosSiblingsLink, links.get(2).getHref(), TEXT_URI_LIST);
putAndGet(frodosSiblingsLink, links.get(3).getHref(), TEXT_URI_LIST);
assertSiblingNames(frodosSiblingsLink, "Pippin");
MockHttpServletResponse bilboResponse = postAndGet(peopleLink, bilbo, MediaType.APPLICATION_JSON);
MockHttpServletResponse frodoResponse = postAndGet(peopleLink, frodo, MediaType.APPLICATION_JSON);
MockHttpServletResponse merryResponse = postAndGet(peopleLink, merry, MediaType.APPLICATION_JSON);
MockHttpServletResponse pippinResponse = postAndGet(peopleLink, pippin, MediaType.APPLICATION_JSON);
Link bilboSelfLink = assertHasLinkWithRel(Link.REL_SELF, bilboResponse);
Link merrySelfLink = assertHasLinkWithRel(Link.REL_SELF, merryResponse);
Link pippinSelfLink = assertHasLinkWithRel(Link.REL_SELF, pippinResponse);
Link frodosSiblingsLink = assertHasLinkWithRel("siblings", frodoResponse);
putAndGet(frodosSiblingsLink, bilboSelfLink.getHref(), TEXT_URI_LIST);
putAndGet(frodosSiblingsLink, merrySelfLink.getHref(), TEXT_URI_LIST);
putAndGet(frodosSiblingsLink, pippinSelfLink.getHref(), TEXT_URI_LIST);
MockHttpServletResponse frodosLatestSiblings = request(frodosSiblingsLink);
String firstName = JsonPath.read(frodosLatestSiblings.getContentAsString(), "$._embedded.person.firstName");
assertThat(firstName, equalTo("Pippin"));
postAndGet(frodosSiblingsLink, merrySelfLink.getHref(), TEXT_URI_LIST);
frodosLatestSiblings = request(frodosSiblingsLink);
String[] persons = ((JSONArray) JsonPath.read(frodosLatestSiblings.getContentAsString(),
"$._embedded.persons[*].firstName")).toArray(new String[]{});
assertThat(persons.length, equalTo(2));
assertThat(Arrays.asList(persons), hasItems("Merry", "Pippin"));
postAndGet(frodosSiblingsLink, links.get(2).getHref(), TEXT_URI_LIST);
assertSiblingNames(frodosSiblingsLink, "Merry", "Pippin");
}
/**
@@ -314,42 +258,21 @@ public class JpaWebTests extends AbstractWebIntegrationTests {
@Test
public void manipulatePropertyCollectionRestfullyWithSinglePut() throws Exception {
ObjectMapper mapper = new ObjectMapper();
List<Link> links = preparePersonResources(new Person("Frodo", "Baggins"), //
new Person("Bilbo", "Baggins"), //
new Person("Merry", "Baggins"), //
new Person("Pippin", "Baggins"));
String bilbo = mapper.writeValueAsString(new Person("Bilbo", "Baggins"));
String frodo = mapper.writeValueAsString(new Person("Frodo", "Baggins"));
String merry = mapper.writeValueAsString(new Person("Merry", "Baggins"));
String pippin = mapper.writeValueAsString(new Person("Pippin", "Baggins"));
Link frodoSiblingLink = links.get(0);
Link peopleLink = discoverUnique("people");
putAndGet(frodoSiblingLink, toUriList(links.get(1), links.get(2), (links.get(3))), TEXT_URI_LIST);
assertSiblingNames(frodoSiblingLink, "Bilbo", "Merry", "Pippin");
MockHttpServletResponse bilboResponse = postAndGet(peopleLink, bilbo, MediaType.APPLICATION_JSON);
MockHttpServletResponse frodoResponse = postAndGet(peopleLink, frodo, MediaType.APPLICATION_JSON);
MockHttpServletResponse merryResponse = postAndGet(peopleLink, merry, MediaType.APPLICATION_JSON);
MockHttpServletResponse pippinResponse = postAndGet(peopleLink, pippin, MediaType.APPLICATION_JSON);
putAndGet(frodoSiblingLink, toUriList(links.get(3)), TEXT_URI_LIST);
assertSiblingNames(frodoSiblingLink, "Pippin");
Link bilboSelfLink = assertHasLinkWithRel(Link.REL_SELF, bilboResponse);
Link merrySelfLink = assertHasLinkWithRel(Link.REL_SELF, merryResponse);
Link pippinSelfLink = assertHasLinkWithRel(Link.REL_SELF, pippinResponse);
Link frodosSiblingsLink = assertHasLinkWithRel("siblings", frodoResponse);
putAndGet(frodosSiblingsLink,
StringUtils.arrayToDelimitedString(new Object[]{bilboSelfLink.getHref(),
merrySelfLink.getHref()}, "\n"),
TEXT_URI_LIST);
putAndGet(frodosSiblingsLink, pippinSelfLink.getHref(), TEXT_URI_LIST);
MockHttpServletResponse frodosLatestSiblings = request(frodosSiblingsLink);
String firstName = JsonPath.read(frodosLatestSiblings.getContentAsString(), "$._embedded.person.firstName");
assertThat(firstName, equalTo("Pippin"));
postAndGet(frodosSiblingsLink, merrySelfLink.getHref(), TEXT_URI_LIST);
frodosLatestSiblings = request(frodosSiblingsLink);
String[] persons = ((JSONArray) JsonPath.read(frodosLatestSiblings.getContentAsString(),
"$._embedded.persons[*].firstName")).toArray(new String[]{});
assertThat(persons.length, equalTo(2));
assertThat(Arrays.asList(persons), hasItems("Merry", "Pippin"));
postAndGet(frodoSiblingLink, toUriList(links.get(2)), TEXT_URI_LIST);
assertSiblingNames(frodoSiblingLink, "Merry", "Pippin");
}
/**
@@ -358,49 +281,88 @@ public class JpaWebTests extends AbstractWebIntegrationTests {
@Test
public void manipulatePropertyCollectionRestfullyWithDelete() throws Exception {
ObjectMapper mapper = new ObjectMapper();
List<Link> links = preparePersonResources(new Person("Frodo", "Baggins"), //
new Person("Bilbo", "Baggins"), //
new Person("Merry", "Baggins"), //
new Person("Pippin", "Baggins"));
String bilbo = mapper.writeValueAsString(new Person("Bilbo", "Baggins"));
String frodo = mapper.writeValueAsString(new Person("Frodo", "Baggins"));
String merry = mapper.writeValueAsString(new Person("Merry", "Baggins"));
String pippin = mapper.writeValueAsString(new Person("Pippin", "Baggins"));
Link frodosSiblingsLink = links.get(0);
Link peopleLink = discoverUnique("people");
postAndGet(frodosSiblingsLink, links.get(1).getHref(), TEXT_URI_LIST);
postAndGet(frodosSiblingsLink, links.get(2).getHref(), TEXT_URI_LIST);
postAndGet(frodosSiblingsLink, links.get(3).getHref(), TEXT_URI_LIST);
MockHttpServletResponse bilboResponse = postAndGet(peopleLink, bilbo, MediaType.APPLICATION_JSON);
MockHttpServletResponse frodoResponse = postAndGet(peopleLink, frodo, MediaType.APPLICATION_JSON);
MockHttpServletResponse merryResponse = postAndGet(peopleLink, merry, MediaType.APPLICATION_JSON);
MockHttpServletResponse pippinResponse = postAndGet(peopleLink, pippin, MediaType.APPLICATION_JSON);
Link bilboSelfLink = assertHasLinkWithRel(Link.REL_SELF, bilboResponse);
Link merrySelfLink = assertHasLinkWithRel(Link.REL_SELF, merryResponse);
Link pippinSelfLink = assertHasLinkWithRel(Link.REL_SELF, pippinResponse);
Link frodosSiblingsLink = assertHasLinkWithRel("siblings", frodoResponse);
postAndGet(frodosSiblingsLink, bilboSelfLink.getHref(), TEXT_URI_LIST);
postAndGet(frodosSiblingsLink, merrySelfLink.getHref(), TEXT_URI_LIST);
postAndGet(frodosSiblingsLink, pippinSelfLink.getHref(), TEXT_URI_LIST);
String pippinId = new UriTemplate("/people/{id}").match(pippinSelfLink.getHref()).get("id");
String pippinId = new UriTemplate("/people/{id}").match(links.get(3).getHref()).get("id");
deleteAndGet(new Link(frodosSiblingsLink.getHref() + "/" + pippinId), TEXT_URI_LIST);
MockHttpServletResponse frodosLatestSiblings = request(frodosSiblingsLink);
String[] persons = ((JSONArray) JsonPath.read(frodosLatestSiblings.getContentAsString(), "$._embedded.persons[*].firstName")).toArray(new String[]{});
assertThat(persons.length, equalTo(2));
assertThat(Arrays.asList(persons), hasItems("Bilbo", "Merry"));
assertSiblingNames(frodosSiblingsLink, "Bilbo", "Merry");
}
private List<Link> preparePersonResources(Person primary, Person... persons) throws Exception {
private String readFile(String name) throws Exception {
Link peopleLink = discoverUnique("people");
ObjectMapper mapper = new ObjectMapper();
List<Link> links = new ArrayList<Link>();
ClassPathResource file = new ClassPathResource(name, getClass());
MockHttpServletResponse primaryResponse = postAndGet(peopleLink, mapper.writeValueAsString(primary),
MediaType.APPLICATION_JSON);
links.add(assertHasLinkWithRel("siblings", primaryResponse));
for (Person person : persons) {
String payload = mapper.writeValueAsString(person);
MockHttpServletResponse response = postAndGet(peopleLink, payload, MediaType.APPLICATION_JSON);
links.add(assertHasLinkWithRel(Link.REL_SELF, response));
}
return links;
}
/**
* Asserts the {@link Person} resource the given link points to contains siblings with the given names.
*
* @param link
* @param siblingNames
* @throws Exception
*/
private void assertSiblingNames(Link link, String... siblingNames) throws Exception {
String responseBody = request(link).getContentAsString();
List<String> persons = JsonPath.read(responseBody, "$._embedded.persons[*].firstName");
assertThat(persons, hasSize(siblingNames.length));
assertThat(persons, hasItems(siblingNames));
}
private static String readFile(String name) throws Exception {
ClassPathResource file = new ClassPathResource(name, JpaWebTests.class);
StringBuilder builder = new StringBuilder();
Scanner scanner = new Scanner(file.getFile(), "UTF-8");
while (scanner.hasNextLine()) {
builder.append(scanner.nextLine());
try {
while (scanner.hasNextLine()) {
builder.append(scanner.nextLine());
}
} finally {
scanner.close();
}
return builder.toString();
}
private static String toUriList(Link... links) {
List<String> uris = new ArrayList<String>(links.length);
for (Link link : links) {
uris.add(link.expand().getHref());
}
return StringUtils.collectionToDelimitedString(uris, "\n");
}
}