From e7374697f1e02b614c9de60a76fca6905e138f97 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Fri, 28 Aug 2015 18:28:51 +0200 Subject: [PATCH] DATAREST-363 - Fixed Resources setup for embedded values in PersistentEntityResource. We're now creating a dedicated Resources inner class to be able to explicitly ignore the links of the embeds as they would cause the link attribute to be rendered when the unwrapping is applied in the custom JSON serializer. Polished test case. Foxed Javadoc in PersistentEntityResource.Builder. Tweaked the TestDataPopulator to always reinitialize the data set to make sure the test cases see the expected data. --- .../rest/webmvc/PersistentEntityResource.java | 29 ++++++++++-- .../webmvc/DuplicateLinkListingTests.java | 34 +++++++------- .../rest/webmvc/jpa/TestDataPopulator.java | 44 +++++++++++-------- 3 files changed, 68 insertions(+), 39 deletions(-) diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/PersistentEntityResource.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/PersistentEntityResource.java index 06bf69ec7..f7960634d 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/PersistentEntityResource.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/PersistentEntityResource.java @@ -28,6 +28,8 @@ import org.springframework.hateoas.Resources; import org.springframework.hateoas.core.EmbeddedWrapper; import org.springframework.util.Assert; +import com.fasterxml.jackson.annotation.JsonIgnore; + /** * A Spring HATEOAS {@link Resource} subclass that holds a reference to the entity's {@link PersistentEntity} metadata. * @@ -36,7 +38,8 @@ import org.springframework.util.Assert; */ public class PersistentEntityResource extends Resource { - private static final Iterable NO_EMBEDDEDS = Collections.emptyList(); + private static final Iterable NO_EMBEDDEDS = new NoLinksResources( + Collections. emptyList()); private final PersistentEntity entity; private final Iterable embeddeds; @@ -122,7 +125,7 @@ public class PersistentEntityResource extends Resource { private final PersistentEntity entity; private final List links = new ArrayList(); - private Resources embeddeds; + private Iterable embeddeds; /** * Creates a new {@link Builder} instance for the given content and {@link PersistentEntity}. @@ -140,14 +143,15 @@ public class PersistentEntityResource extends Resource { } /** - * Configures the builder to embedd the given E + * Configures the builder to embed the given {@link EmbeddedWrapper} instances. Creates a {@link Resources} instance + * to make sure the {@link EmbeddedWrapper} handling gets applied to the serialization output ignoring the links. * * @param resources can be {@literal null}. * @return the builder */ public Builder withEmbedded(Iterable resources) { - this.embeddeds = resources == null ? null : new Resources(resources); + this.embeddeds = resources == null ? null : new NoLinksResources(resources); return this; } @@ -184,4 +188,21 @@ public class PersistentEntityResource extends Resource { return new PersistentEntityResource(entity, content, links, embeddeds, true); } } + + private static class NoLinksResources extends Resources { + + public NoLinksResources(Iterable content) { + super(content); + } + + /* + * (non-Javadoc) + * @see org.springframework.hateoas.ResourceSupport#getLinks() + */ + @Override + @JsonIgnore + public List getLinks() { + return super.getLinks(); + } + } } diff --git a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/DuplicateLinkListingTests.java b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/DuplicateLinkListingTests.java index 9dd3a563c..8b81a48df 100644 --- a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/DuplicateLinkListingTests.java +++ b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/DuplicateLinkListingTests.java @@ -15,14 +15,13 @@ */ package org.springframework.data.rest.webmvc; -import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; - import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -45,37 +44,35 @@ import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; /** + * Integration tests for DATAREST-363. + * * @author Greg Turnquist + * @author Oliver Gierke */ @RunWith(SpringJUnit4ClassRunner.class) @WebAppConfiguration -@ContextConfiguration(classes = {JpaRepositoryConfig.class, DuplicateLinkListingTests.ClassicConfiguration.class, +@ContextConfiguration(classes = { JpaRepositoryConfig.class, RepositoryRestMvcConfiguration.class, DuplicateLinkListingTests.Config.class }) public class DuplicateLinkListingTests { + private static MediaType MEDIA_TYPE = MediaType.APPLICATION_JSON; + @Autowired WebApplicationContext context; @Autowired LinkDiscoverers discoverers; @Autowired PersonRepository personRepository; - private static MediaType MEDIA_TYPE = MediaType.APPLICATION_JSON; - - protected TestMvcClient testMvcClient; - protected MockMvc mvc; + TestMvcClient testMvcClient; @Configuration - static class Config { + static class Config extends RepositoryRestConfigurerAdapter { @Bean public LinkDiscoverer classicLinkDiscover() { return new JsonPathLinkDiscoverer("$.links[?(@.rel == '%s')].href", MEDIA_TYPE); } - } - - @Configuration - static class ClassicConfiguration extends RepositoryRestMvcConfiguration { @Override - protected void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) { + public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) { config.setDefaultMediaType(MEDIA_TYPE).useHalAsDefaultJsonMediaType(false); } } @@ -83,18 +80,21 @@ public class DuplicateLinkListingTests { @Before public void setUp() { - mvc = MockMvcBuilders.webAppContextSetup(context).// + MockMvc mvc = MockMvcBuilders.webAppContextSetup(context).// defaultRequest(get("/")).build(); testMvcClient = new TestMvcClient(mvc, discoverers); personRepository.save(new Person("Frodo", "Baggins")); } + /** + * @see DATAREST-363 + */ @Test public void testBasics() throws Exception { ResultActions frodoActions = testMvcClient.follow("/people/1"); - frodoActions.andExpect(jsonPath("$.links").value(hasSize(1))); + frodoActions.andExpect(jsonPath("$.links").value(hasSize(4))); } -} \ No newline at end of file +} diff --git a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/jpa/TestDataPopulator.java b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/jpa/TestDataPopulator.java index 39bd404f0..f617922d5 100644 --- a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/jpa/TestDataPopulator.java +++ b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/jpa/TestDataPopulator.java @@ -1,3 +1,18 @@ +/* + * Copyright 2013-2015 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.springframework.data.rest.webmvc.jpa; import java.util.Arrays; @@ -6,16 +21,22 @@ import org.springframework.beans.factory.annotation.Autowired; /** * @author Jon Brisbin + * @author Oliver Gierke */ public class TestDataPopulator { - @Autowired private PersonRepository people; - @Autowired private OrderRepository orders; - @Autowired private AuthorRepository authorRepository; - @Autowired private BookRepository books; + @Autowired PersonRepository people; + @Autowired OrderRepository orders; + @Autowired AuthorRepository authors; + @Autowired BookRepository books; public void populateRepositories() { + books.deleteAll(); + authors.deleteAll(); + orders.deleteAll(); + people.deleteAll(); + populatePeople(); populateOrders(); populateAuthorsAndBooks(); @@ -23,10 +44,6 @@ public class TestDataPopulator { private void populateAuthorsAndBooks() { - if (authorRepository.count() != 0 || books.count() != 0) { - return; - } - Author ollie = new Author("Ollie"); Author mark = new Author("Mark"); Author michael = new Author("Michael"); @@ -34,7 +51,7 @@ public class TestDataPopulator { Author john = new Author("John"); Author thomas = new Author("Thomas"); - Iterable authors = authorRepository.save(Arrays.asList(ollie, mark, michael, david, john, thomas)); + Iterable authors = this.authors.save(Arrays.asList(ollie, mark, michael, david, john, thomas)); books.save(new Book("1449323952", "Spring Data", authors)); books.save(new Book("1449323953", "Spring Data (Second Edition)", authors)); @@ -42,10 +59,6 @@ public class TestDataPopulator { private void populateOrders() { - if (orders.count() != 0) { - return; - } - Person person = people.findAll().iterator().next(); Order order = new Order(person); @@ -55,10 +68,6 @@ public class TestDataPopulator { private void populatePeople() { - if (people.count() != 0) { - return; - } - Person billyBob = people.save(new Person("Billy Bob", "Thornton")); Person john = new Person("John", "Doe"); @@ -70,5 +79,4 @@ public class TestDataPopulator { people.save(Arrays.asList(john, jane)); } - }