diff --git a/spring-data-rest-tests/spring-data-rest-tests-core/src/test/java/org/springframework/data/rest/tests/AbstractWebIntegrationTests.java b/spring-data-rest-tests/spring-data-rest-tests-core/src/test/java/org/springframework/data/rest/tests/AbstractWebIntegrationTests.java index 209a972b1..dc705d3e9 100755 --- a/spring-data-rest-tests/spring-data-rest-tests-core/src/test/java/org/springframework/data/rest/tests/AbstractWebIntegrationTests.java +++ b/spring-data-rest-tests/spring-data-rest-tests-core/src/test/java/org/springframework/data/rest/tests/AbstractWebIntegrationTests.java @@ -28,7 +28,6 @@ import java.util.Optional; import org.junit.Before; import org.junit.runner.RunWith; - import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration; import org.springframework.hateoas.Link; @@ -61,6 +60,7 @@ import com.jayway.jsonpath.JsonPath; * @author Oliver Gierke * @author Greg Turnquist * @author Christoph Strobl + * @author Ľubomír Varga */ @RunWith(SpringRunner.class) @WebAppConfiguration @@ -115,6 +115,17 @@ public abstract class AbstractWebIntegrationTests { return StringUtils.hasText(response.getContentAsString()) ? response : client.request(link); } + protected MockHttpServletResponse putOnlyExpect5XXStatus(Link link, Object payload, MediaType mediaType) + throws Exception { + + String href = link.isTemplated() ? link.expand().getHref() : link.getHref(); + + MockHttpServletResponse response = mvc.perform(put(href).content(payload.toString()).contentType(mediaType))// + .andExpect(status().is5xxServerError()).andReturn().getResponse(); + + return StringUtils.hasText(response.getContentAsString()) ? response : client.request(link); + } + protected MockHttpServletResponse patchAndGet(Link link, Object payload, MediaType mediaType) throws Exception { String href = link.isTemplated() ? link.expand().getHref() : link.getHref(); diff --git a/spring-data-rest-tests/spring-data-rest-tests-jpa/src/test/java/org/springframework/data/rest/webmvc/jpa/JpaWebTests.java b/spring-data-rest-tests/spring-data-rest-tests-jpa/src/test/java/org/springframework/data/rest/webmvc/jpa/JpaWebTests.java index c3bd25f5b..d41a22a3d 100755 --- a/spring-data-rest-tests/spring-data-rest-tests-jpa/src/test/java/org/springframework/data/rest/webmvc/jpa/JpaWebTests.java +++ b/spring-data-rest-tests/spring-data-rest-tests-jpa/src/test/java/org/springframework/data/rest/webmvc/jpa/JpaWebTests.java @@ -61,6 +61,7 @@ import com.jayway.jsonpath.JsonPath; * @author Oliver Gierke * @author Greg Turnquist * @author Mark Paluch + * @author Ľubomír Varga */ @Transactional @ContextConfiguration(classes = JpaRepositoryConfig.class) @@ -321,6 +322,40 @@ public class JpaWebTests extends CommonWebTests { assertSiblingNames(frodoSiblingLink, "Merry", "Pippin"); } + /** + * Test does simulate changing creator association from Order to Person. First it sets Frodo Baggins as creator and + * checks for its first name. Than it sets Pippin Baggins as creator of the Order. Check for first name is done again. + */ + @Test // DATAREST-1356 + public void associateCreatorToOrderWithSinglePut() throws Exception { + + Link firstCreatorLink = preparePersonResource(new Person("Frodo", "Baggins")); + Link secondCreatorLink = preparePersonResource(new Person("Pippin", "Baggins")); + Link orderLinkToItsCreator = prepareOrderResource(new Order()); + + putAndGet(orderLinkToItsCreator, toUriList(firstCreatorLink), TEXT_URI_LIST); + assertCreatorName(orderLinkToItsCreator, "Frodo"); + + putAndGet(orderLinkToItsCreator, toUriList(secondCreatorLink), TEXT_URI_LIST); + assertCreatorName(orderLinkToItsCreator, "Pippin"); + } + + /** + * Negative test scenario, which does try to put two persons at once as the creator of Order. We expect that result + * will contain "send only 1 link" substring. + */ + @Test // DATAREST-1356 + public void associateTwoCreatorsToOrderWithSinglePut() throws Exception { + + Link firstCreatorLink = preparePersonResource(new Person("Frodo", "Baggins")); + Link secondCreatorLink = preparePersonResource(new Person("Pippin", "Baggins")); + Link orderLinkToItsCreator = prepareOrderResource(new Order()); + + MockHttpServletResponse response = putOnlyExpect5XXStatus(orderLinkToItsCreator, + toUriList(firstCreatorLink, secondCreatorLink), TEXT_URI_LIST); + assertThat(response.getContentAsString()).contains("send only 1 link"); + } + @Test // DATAREST-219 public void manipulatePropertyCollectionRestfullyWithDelete() throws Exception { @@ -673,6 +708,28 @@ public class JpaWebTests extends CommonWebTests { return links; } + /** + * @return link to creator of order (associative link for given order instance) + */ + private Link prepareOrderResource(Order order) throws Exception { + Link orderLink = client.discoverUnique(LinkRelation.of("orders")); + + MockHttpServletResponse primaryResponse = postAndGet(orderLink, mapper.writeValueAsString(order), + MediaType.APPLICATION_JSON); + return client.assertHasLinkWithRel("creator", primaryResponse); + } + + /** + * @return link to given person (canonical, self, link) + */ + private Link preparePersonResource(Person person) throws Exception { + Link orderLink = client.discoverUnique(LinkRelation.of("people")); + + MockHttpServletResponse primaryResponse = postAndGet(orderLink, mapper.writeValueAsString(person), + MediaType.APPLICATION_JSON); + return client.assertHasLinkWithRel("self", primaryResponse); + } + /** * Asserts the {@link Person} resource the given link points to contains siblings with the given names. * @@ -689,6 +746,13 @@ public class JpaWebTests extends CommonWebTests { assertThat(persons).contains(siblingNames); } + private void assertCreatorName(Link orderLinkToItsCreator, String creatorName) throws Exception { + String responseBody = client.request(orderLinkToItsCreator).getContentAsString(); + String personFirstName = JsonPath.read(responseBody, "$.firstName"); + + assertThat(personFirstName).isEqualTo(creatorName); + } + private void assertPersonWithNameAndSiblingLink(String name) throws Exception { MockHttpServletResponse response = client.request(client.discoverUnique(LinkRelation.of("people"))); diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryPropertyReferenceController.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryPropertyReferenceController.java index 3ecca5bde..c47041821 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryPropertyReferenceController.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryPropertyReferenceController.java @@ -77,6 +77,7 @@ import org.springframework.web.bind.annotation.RequestMapping; * @author Jon Brisbin * @author Oliver Gierke * @author Greg Turnquist + * @author Ľubomír Varga */ @RepositoryRestController @SuppressWarnings({ "unchecked" }) @@ -318,7 +319,7 @@ class RepositoryPropertyReferenceController extends AbstractRepositoryRestContro "Cannot PATCH a reference to this singular property since the property type is not a List or a Map."); } - if (source.getLinks().hasSingleLink()) { + if (!source.getLinks().hasSingleLink()) { throw new IllegalArgumentException( "Must send only 1 link to update a property reference that isn't a List or a Map."); }