/*
* Copyright 2012-2017 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.json;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import java.io.IOException;
import java.io.StringWriter;
import java.util.Arrays;
import java.util.Collections;
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;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.context.support.StaticMessageSource;
import org.springframework.data.jpa.mapping.JpaMetamodelMappingContext;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
import org.springframework.data.repository.support.Repositories;
import org.springframework.data.rest.webmvc.PersistentEntityResource;
import org.springframework.data.rest.webmvc.jpa.CreditCard;
import org.springframework.data.rest.webmvc.jpa.Dinner;
import org.springframework.data.rest.webmvc.jpa.Guest;
import org.springframework.data.rest.webmvc.jpa.JpaRepositoryConfig;
import org.springframework.data.rest.webmvc.jpa.LineItem;
import org.springframework.data.rest.webmvc.jpa.Order;
import org.springframework.data.rest.webmvc.jpa.OrderRepository;
import org.springframework.data.rest.webmvc.jpa.Person;
import org.springframework.data.rest.webmvc.jpa.PersonRepository;
import org.springframework.data.rest.webmvc.jpa.PersonSummary;
import org.springframework.data.rest.webmvc.jpa.Suite;
import org.springframework.data.rest.webmvc.jpa.UserExcerpt;
import org.springframework.data.rest.webmvc.util.TestUtils;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.LinkDiscoverer;
import org.springframework.hateoas.PagedResources;
import org.springframework.hateoas.PagedResources.PageMetadata;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.core.EmbeddedWrapper;
import org.springframework.hateoas.core.EmbeddedWrappers;
import org.springframework.hateoas.hal.HalLinkDiscoverer;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.util.UriTemplate;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jayway.jsonpath.JsonPath;
/**
* Integration tests for entity (de)serialization.
*
* @author Jon Brisbin
* @author Greg Turnquist
* @author Oliver Gierke
* @author Alex Leigh
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { JpaRepositoryConfig.class, PersistentEntitySerializationTests.TestConfig.class })
@Transactional
public class PersistentEntitySerializationTests {
private static final String PERSON_JSON_IN = "{\"firstName\": \"John\",\"lastName\": \"Doe\"}";
@Autowired ObjectMapper mapper;
@Autowired Repositories repositories;
@Autowired PersonRepository people;
@Autowired OrderRepository orders;
@Autowired JpaMetamodelMappingContext context;
@Configuration
static class TestConfig extends RepositoryTestsConfig {
@Bean
@Override
public ObjectMapper objectMapper() {
ObjectMapper objectMapper = super.objectMapper();
objectMapper.registerModule(
new JacksonSerializers(new EnumTranslator(new MessageSourceAccessor(new StaticMessageSource()))));
return objectMapper;
}
}
LinkDiscoverer linkDiscoverer;
ProjectionFactory projectionFactory;
@Before
public void setUp() {
RequestContextHolder.setRequestAttributes(new ServletWebRequest(new MockHttpServletRequest()));
this.linkDiscoverer = new HalLinkDiscoverer();
this.projectionFactory = new SpelAwareProxyProjectionFactory();
}
@Test
public void deserializesPersonEntity() throws IOException {
Person p = mapper.readValue(PERSON_JSON_IN, Person.class);
assertThat(p.getFirstName()).isEqualTo("John");
assertThat(p.getLastName()).isEqualTo("Doe");
assertThat(p.getSiblings()).isEqualTo(Collections.EMPTY_LIST);
}
@Test // DATAREST-238
public void deserializePersonWithLinks() throws IOException {
String bilbo = "{\n" + " \"_links\" : {\n" + " \"self\" : {\n"
+ " \"href\" : \"http://localhost/people/4\"\n" + " },\n" + " \"siblings\" : {\n"
+ " \"href\" : \"http://localhost/people/4/siblings\"\n" + " },\n" + " \"father\" : {\n"
+ " \"href\" : \"http://localhost/people/4/father\"\n" + " }\n" + " },\n"
+ " \"firstName\" : \"Bilbo\",\n" + " \"lastName\" : \"Baggins\",\n"
+ " \"created\" : \"2014-01-31T21:07:45.574+0000\"\n" + "}\n";
Person p = mapper.readValue(bilbo, Person.class);
assertThat(p.getFirstName(), equalTo("Bilbo"));
assertThat(p.getLastName(), equalTo("Baggins"));
}
@Test // DATAREST-238
public void serializesPersonEntity() throws IOException, InterruptedException {
PersistentEntity<?, ?> persistentEntity = repositories.getPersistentEntity(Person.class);
Person person = people.save(new Person("John", "Doe"));
PersistentEntityResource resource = PersistentEntityResource.build(person, persistentEntity).//
withLink(new Link("/person/" + person.getId())).build();
StringWriter writer = new StringWriter();
mapper.writeValue(writer, resource);
String s = writer.toString();
Link fatherLink = linkDiscoverer.findLinkWithRel("father", s);
assertThat(fatherLink.getHref(), endsWith(new UriTemplate("/{id}/father").expand(person.getId()).toString()));
Link siblingLink = linkDiscoverer.findLinkWithRel("siblings", s);
assertThat(siblingLink.getHref(), endsWith(new UriTemplate("/{id}/siblings").expand(person.getId()).toString()));
}
@Test // DATAREST-248
public void deserializesPersonWithLinkToOtherPersonCorrectly() throws Exception {
Person father = people.save(new Person("John", "Doe"));
String child = String.format("{ \"firstName\" : \"Bilbo\", \"father\" : \"/persons/%s\"}", father.getId());
Person result = mapper.readValue(child, Person.class);
assertThat(result.getFather()).isEqualTo(father);
}
@Test // DATAREST-248
public void deserializesPersonWithLinkToOtherPersonsCorrectly() throws Exception {
Person firstSibling = people.save(new Person("John", "Doe"));
Person secondSibling = people.save(new Person("Dave", "Doe"));
String child = String.format("{ \"firstName\" : \"Bilbo\", \"siblings\" : [\"/persons/%s\", \"/persons/%s\"]}",
firstSibling.getId(), secondSibling.getId());
Person result = mapper.readValue(child, Person.class);
assertThat(result.getSiblings()).contains(firstSibling, secondSibling);
}
@Test // DATAREST-248
public void deserializesEmbeddedAssociationsCorrectly() throws Exception {
String content = TestUtils.readFileFromClasspath("order.json");
Order order = mapper.readValue(content, Order.class);
assertThat(order.getLineItems()).hasSize(2);
}
@Test // DATAREST-250
public void serializesReferencesWithinPagedResourceCorrectly() throws Exception {
Person creator = new Person("Dave", "Matthews");
Order order = new Order(creator);
order.add(new LineItem("first"));
order.add(new LineItem("second"));
PersistentEntityResource orderResource = PersistentEntityResource.//
build(order, repositories.getPersistentEntity(Order.class)).//
withLink(new Link("/orders/1")).//
build();
PagedResources<PersistentEntityResource> persistentEntityResource = new PagedResources<PersistentEntityResource>(
Arrays.asList(orderResource), new PageMetadata(1, 0, 10));
String result = mapper.writeValueAsString(persistentEntityResource);
assertThat(JsonPath.<Object> read(result, "$._embedded.orders[*].lineItems")).isNotNull();
}
@Test // DATAREST-521
public void serializesLinksForExcerpts() throws Exception {
Person dave = new Person("Dave", "Matthews");
dave.setId(1L);
Person oliver = new Person("Oliver August", "Matthews");
oliver.setId(2L);
oliver.setFather(dave);
UserExcerpt daveExcerpt = projectionFactory.createProjection(UserExcerpt.class, dave);
EmbeddedWrapper wrapper = new EmbeddedWrappers(false).wrap(daveExcerpt, "father");
PersistentEntityResource resource = PersistentEntityResource.//
build(oliver, repositories.getPersistentEntity(Person.class)).//
withEmbedded(Arrays.asList(wrapper)).//
build();
String result = mapper.writeValueAsString(resource);
assertThat(JsonPath.<Object> read(result, "$._embedded.father[*]._links.self")).isNotNull();
}
@Test // DATAREST-521
public void rendersAdditionalLinksRegisteredWithResource() throws Exception {
Person dave = new Person("Dave", "Matthews");
PersistentEntityResource resource = PersistentEntityResource.//
build(dave, repositories.getPersistentEntity(Person.class)).//
withLink(new Link("/people/1")).//
withLink(new Link("/aditional", "processed")).//
build();
String result = mapper.writeValueAsString(resource);
assertThat(JsonPath.<Object> read(result, "$._links.processed")).isNotNull();
}
@Test // DATAREST-697
public void rendersProjectionWithinSimpleResourceCorrectly() throws Exception {
Person person = new Person("Dave", "Matthews");
person.setId(1L);
ProjectionFactory factory = new SpelAwareProxyProjectionFactory();
PersonSummary projection = factory.createProjection(PersonSummary.class, person);
String result = mapper.writeValueAsString(new Resource<PersonSummary>(projection));
assertThat(JsonPath.<Object> read(result, "$._links.self")).isNotNull();
}
@Test // DATAREST-880
public void unwrapsNestedTypeCorrectly() throws Exception {
CreditCard creditCard = new CreditCard(new CreditCard.CCN("1234123412341234"));
assertThat(JsonPath.<Object> read(mapper.writeValueAsString(creditCard), "$.ccn")).isEqualTo("1234123412341234");
}
@Test // DATAREST-872
public void serializesInheritance() throws Exception {
Suite suite = new Suite();
suite.setSuiteCode("Suite 42");
Dinner dinner = new Dinner();
dinner.setDinnerCode("STD_DINNER");
Guest guest = new Guest();
guest.setRoom(suite);
guest.addMeal(dinner);
PersistentEntityResource resource = PersistentEntityResource//
.build(guest, context.getRequiredPersistentEntity(Guest.class))//
.withLink(new Link("/guests/1")).build();
String result = mapper.writeValueAsString(resource);
assertThat(JsonPath.<Object> read(result, "$.room.type")).isEqualTo("suite");
assertThat(JsonPath.<Object> read(result, "$.meals[0].type")).isEqualTo("dinner");
}
}