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.
This commit is contained in:
Oliver Gierke
2015-08-28 18:28:51 +02:00
parent 22bbc6d305
commit e7374697f1
3 changed files with 68 additions and 39 deletions

View File

@@ -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<Object> {
private static final Iterable<EmbeddedWrapper> NO_EMBEDDEDS = Collections.emptyList();
private static final Iterable<EmbeddedWrapper> NO_EMBEDDEDS = new NoLinksResources<EmbeddedWrapper>(
Collections.<EmbeddedWrapper> emptyList());
private final PersistentEntity<?, ?> entity;
private final Iterable<EmbeddedWrapper> embeddeds;
@@ -122,7 +125,7 @@ public class PersistentEntityResource extends Resource<Object> {
private final PersistentEntity<?, ?> entity;
private final List<Link> links = new ArrayList<Link>();
private Resources<EmbeddedWrapper> embeddeds;
private Iterable<EmbeddedWrapper> embeddeds;
/**
* Creates a new {@link Builder} instance for the given content and {@link PersistentEntity}.
@@ -140,14 +143,15 @@ public class PersistentEntityResource extends Resource<Object> {
}
/**
* 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<EmbeddedWrapper> resources) {
this.embeddeds = resources == null ? null : new Resources<EmbeddedWrapper>(resources);
this.embeddeds = resources == null ? null : new NoLinksResources<EmbeddedWrapper>(resources);
return this;
}
@@ -184,4 +188,21 @@ public class PersistentEntityResource extends Resource<Object> {
return new PersistentEntityResource(entity, content, links, embeddeds, true);
}
}
private static class NoLinksResources<T> extends Resources<T> {
public NoLinksResources(Iterable<T> content) {
super(content);
}
/*
* (non-Javadoc)
* @see org.springframework.hateoas.ResourceSupport#getLinks()
*/
@Override
@JsonIgnore
public List<Link> getLinks() {
return super.getLinks();
}
}
}

View File

@@ -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)));
}
}
}

View File

@@ -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<Author> authors = authorRepository.save(Arrays.asList(ollie, mark, michael, david, john, thomas));
Iterable<Author> 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));
}
}