From 6cf4e50e98138e7b72c6fc9969d5425cf154bc48 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Tue, 27 Sep 2016 09:12:05 +0200 Subject: [PATCH] DATAREST-909 - Revert Jackson-aware Sort and Pageable translation. Revert changes introduced by DATAREST-883 - Jackson-aware field translation in Sort and DATAREST-906 - Consider default pageable if Sort is null. The way how Sort translation was implemented breaks Sort and Pageable argument resolution for custom controllers as a domain type is always required. Argument resolution fails if the related domain type cannot be resolved. Related pull requests: #231, #222. --- .../jpa/JpaDefaultPageableWebTests.java | 137 ------------------ .../RepositoryRestMvcConfiguration.java | 19 +-- .../rest/webmvc/json/DomainObjectReader.java | 74 +++++++++- .../JacksonMappingAwareSortTranslator.java | 136 ----------------- .../rest/webmvc/json/MappedProperties.java | 111 -------------- ...wareDefaultedPageableArgumentResolver.java | 92 ------------ .../MappingAwarePageableArgumentResolver.java | 89 ------------ .../MappingAwareSortArgumentResolver.java | 81 ----------- .../webmvc/support/DomainClassResolver.java | 104 ------------- .../data/rest/webmvc/jpa/Book.java | 9 +- .../data/rest/webmvc/jpa/BookRepository.java | 7 - .../jpa/JpaDefaultPageableWebTests.java | 137 ------------------ .../data/rest/webmvc/jpa/JpaWebTests.java | 50 +------ .../rest/webmvc/jpa/TestDataPopulator.java | 5 +- ...warePageableArgumentResolverUnitTests.java | 105 -------------- .../webmvc/json/SortTranslatorUnitTests.java | 113 --------------- 16 files changed, 76 insertions(+), 1193 deletions(-) delete mode 100644 spring-data-rest-tests/spring-data-rest-tests-jpa/src/test/java/org/springframework/data/rest/webmvc/jpa/JpaDefaultPageableWebTests.java delete mode 100644 spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/json/JacksonMappingAwareSortTranslator.java delete mode 100644 spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/json/MappedProperties.java delete mode 100644 spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/json/MappingAwareDefaultedPageableArgumentResolver.java delete mode 100644 spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/json/MappingAwarePageableArgumentResolver.java delete mode 100644 spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/json/MappingAwareSortArgumentResolver.java delete mode 100644 spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/support/DomainClassResolver.java delete mode 100644 spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/jpa/JpaDefaultPageableWebTests.java delete mode 100644 spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/MappingAwarePageableArgumentResolverUnitTests.java delete mode 100644 spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/SortTranslatorUnitTests.java diff --git a/spring-data-rest-tests/spring-data-rest-tests-jpa/src/test/java/org/springframework/data/rest/webmvc/jpa/JpaDefaultPageableWebTests.java b/spring-data-rest-tests/spring-data-rest-tests-jpa/src/test/java/org/springframework/data/rest/webmvc/jpa/JpaDefaultPageableWebTests.java deleted file mode 100644 index f9e8bf023..000000000 --- a/spring-data-rest-tests/spring-data-rest-tests-jpa/src/test/java/org/springframework/data/rest/webmvc/jpa/JpaDefaultPageableWebTests.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright 2016 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 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.MockMvcResultHandlers.*; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; - -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.ApplicationContext; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageImpl; -import org.springframework.data.domain.Pageable; -import org.springframework.data.jpa.repository.config.EnableJpaRepositories; -import org.springframework.data.rest.core.config.RepositoryRestConfiguration; -import org.springframework.data.rest.tests.AbstractWebIntegrationTests; -import org.springframework.data.rest.webmvc.RepositoryRestController; -import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurerAdapter; -import org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration; -import org.springframework.hateoas.Link; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.context.web.WebAppConfiguration; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.ResponseBody; - -/** - * Web integration tests specific to default {@link Pageable} handling. - * - * @author Mark Paluch - */ -@RunWith(SpringJUnit4ClassRunner.class) -@WebAppConfiguration -@ContextConfiguration(classes = JpaDefaultPageableWebTests.Config.class) -public class JpaDefaultPageableWebTests extends AbstractWebIntegrationTests { - - @Configuration - @Import({ RepositoryRestMvcConfiguration.class, JpaRepositoryConfig.class }) - @EnableJpaRepositories(considerNestedRepositories = true) - static class Config extends RepositoryRestConfigurerAdapter { - - public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) { - config.setDefaultPageSize(1); - } - } - - @RepositoryRestController - public static class MyRestController { - - @RequestMapping(method = RequestMethod.GET, path = "books/default-pageable") - @ResponseBody - Page getDefaultPageable(Pageable pageable) { - - if (pageable != null) { - return new PageImpl(Collections.singletonList(new Book()), pageable, 1); - } - - return new PageImpl(Collections.emptyList(), pageable, 0); - } - } - - @Autowired TestDataPopulator loader; - @Autowired ApplicationContext context; - - @Before - public void setUp() { - loader.populateRepositories(); - super.setUp(); - } - - /** - * @see DATAREST-906 - */ - @Test - public void executesSearchThatTakesAMappedSortProperty() throws Exception { - - Link findBySortedLink = client.discoverUnique("books", "search", "find-spring-books-sorted"); - - // Assert sort options advertised - assertThat(findBySortedLink.isTemplated(), is(true)); - assertThat(findBySortedLink.getVariableNames(), hasItems("sort", "projection")); - - // Assert results returned as specified - client.follow(findBySortedLink.expand()).// - andExpect(jsonPath("$._embedded.books[0].title").exists()).// - andExpect(jsonPath("$._embedded.books[1].title").doesNotExist()); - - client.follow(findBySortedLink.expand("sales,desc")).// - andExpect(jsonPath("$._embedded.books[0].title").exists()).// - andExpect(jsonPath("$._embedded.books[1].title").doesNotExist()); - } - - /** - * @see DATAREST-906 - */ - @Test - public void shouldApplyDefaultPageable() throws Exception { - - mvc.perform(get("/books/default-pageable")).andDo(print()) // - .andExpect(jsonPath("$.content[0].sales").value(0)) // - .andExpect(jsonPath("$.size").value(1)); - } - - /** - * @see DATAREST-906 - */ - @Test - public void shouldOverrideDefaultPageable() throws Exception { - - mvc.perform(get("/books/default-pageable?size=10")).andDo(print()) // - .andExpect(jsonPath("$.content[0].sales").value(0)) // - .andExpect(jsonPath("$.size").value(10)); - } -} diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/config/RepositoryRestMvcConfiguration.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/config/RepositoryRestMvcConfiguration.java index 0492666af..4297137cc 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/config/RepositoryRestMvcConfiguration.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/config/RepositoryRestMvcConfiguration.java @@ -86,11 +86,7 @@ import org.springframework.data.rest.webmvc.convert.UriListHttpMessageConverter; import org.springframework.data.rest.webmvc.json.DomainObjectReader; import org.springframework.data.rest.webmvc.json.EnumTranslator; import org.springframework.data.rest.webmvc.json.Jackson2DatatypeHelper; -import org.springframework.data.rest.webmvc.json.JacksonMappingAwareSortTranslator; import org.springframework.data.rest.webmvc.json.JacksonSerializers; -import org.springframework.data.rest.webmvc.json.MappingAwareDefaultedPageableArgumentResolver; -import org.springframework.data.rest.webmvc.json.MappingAwarePageableArgumentResolver; -import org.springframework.data.rest.webmvc.json.MappingAwareSortArgumentResolver; import org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module; import org.springframework.data.rest.webmvc.json.PersistentEntityToJsonSchemaConverter; import org.springframework.data.rest.webmvc.spi.BackendIdConverter; @@ -98,7 +94,6 @@ import org.springframework.data.rest.webmvc.spi.BackendIdConverter.DefaultIdConv import org.springframework.data.rest.webmvc.support.BackendIdHandlerMethodArgumentResolver; import org.springframework.data.rest.webmvc.support.DefaultedPageableHandlerMethodArgumentResolver; import org.springframework.data.rest.webmvc.support.DelegatingHandlerMapping; -import org.springframework.data.rest.webmvc.support.DomainClassResolver; import org.springframework.data.rest.webmvc.support.ETagArgumentResolver; import org.springframework.data.rest.webmvc.support.HttpMethodHandlerMethodArgumentResolver; import org.springframework.data.rest.webmvc.support.JpaHelper; @@ -151,12 +146,11 @@ import com.fasterxml.jackson.databind.SerializationFeature; * @author Oliver Gierke * @author Jon Brisbin * @author Greg Turnquist - * @author Mark Paluch */ @Configuration @EnableHypermediaSupport(type = HypermediaType.HAL) @ComponentScan(basePackageClasses = RepositoryRestController.class, - includeFilters = @Filter(BasePathAwareController.class), useDefaultFilters = false) + includeFilters = @Filter(BasePathAwareController.class) , useDefaultFilters = false) @ImportResource("classpath*:META-INF/spring-data-rest/**/*.xml") @Import({ SpringDataJacksonConfiguration.class, EnableSpringDataWebSupport.QuerydslActivator.class }) public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebConfiguration implements InitializingBean { @@ -719,17 +713,10 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon resourceMappings()); HateoasPageableHandlerMethodArgumentResolver pageableResolver = pageableResolver(); - - JacksonMappingAwareSortTranslator sortTranslator = new JacksonMappingAwareSortTranslator(objectMapper(), - repositories(), DomainClassResolver.of(repositories(), resourceMappings(), baseUri())); - - HandlerMethodArgumentResolver sortResolver = new MappingAwareSortArgumentResolver(sortTranslator, sortResolver()); - HandlerMethodArgumentResolver jacksonPageableResolver = new MappingAwarePageableArgumentResolver(sortTranslator, + HandlerMethodArgumentResolver defaultedPageableResolver = new DefaultedPageableHandlerMethodArgumentResolver( pageableResolver); - HandlerMethodArgumentResolver defaultedPageableResolver = new MappingAwareDefaultedPageableArgumentResolver( - sortTranslator, pageableResolver); - return Arrays.asList(defaultedPageableResolver, jacksonPageableResolver, sortResolver, + return Arrays.asList(defaultedPageableResolver, pageableResolver, sortResolver(), serverHttpRequestMethodArgumentResolver(), repoRequestArgumentResolver(), persistentEntityArgumentResolver(), resourceMetadataHandlerMethodArgumentResolver(), HttpMethodHandlerMethodArgumentResolver.INSTANCE, peraResolver, backendIdHandlerMethodArgumentResolver(), eTagArgumentResolver()); diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/json/DomainObjectReader.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/json/DomainObjectReader.java index cdf3a1993..25b40d6d4 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/json/DomainObjectReader.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/json/DomainObjectReader.java @@ -16,6 +16,7 @@ package org.springframework.data.rest.webmvc.json; import java.io.InputStream; +import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; @@ -30,8 +31,12 @@ import org.springframework.data.rest.webmvc.mapping.AssociationLinks; import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.util.Assert; +import com.fasterxml.jackson.databind.BeanDescription; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.introspect.BasicClassIntrospector; +import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition; +import com.fasterxml.jackson.databind.introspect.ClassIntrospector; import com.fasterxml.jackson.databind.node.ObjectNode; /** @@ -40,13 +45,13 @@ import com.fasterxml.jackson.databind.node.ObjectNode; * detect nested objects, lookup the original value and apply the merge recursively. * * @author Oliver Gierke - * @author Mark Paluch * @since 2.2 */ public class DomainObjectReader { private final PersistentEntities entities; private final AssociationLinks associationLinks; + private final ClassIntrospector introspector; /** * Creates a new {@link DomainObjectReader} using the given {@link PersistentEntities} and {@link ResourceMappings}. @@ -61,12 +66,13 @@ public class DomainObjectReader { this.entities = entities; this.associationLinks = new AssociationLinks(mappings); + this.introspector = new BasicClassIntrospector(); } /** * Reads the given input stream into an {@link ObjectNode} and applies that to the given existing instance. * - * @param source must not be {@literal null}. + * @param request must not be {@literal null}. * @param target must not be {@literal null}. * @param mapper must not be {@literal null}. * @return @@ -104,7 +110,7 @@ public class DomainObjectReader { Assert.notNull(entity, "No PersistentEntity found for ".concat(type.getName()).concat("!")); - final MappedProperties properties = MappedProperties.fromJacksonProperties(entity, mapper); + final MappedProperties properties = getJacksonProperties(entity, mapper); entity.doWithProperties(new SimplePropertyHandler() { @@ -151,7 +157,6 @@ public class DomainObjectReader { * @return * @throws Exception */ - @SuppressWarnings("unchecked") private T doMerge(ObjectNode root, T target, ObjectMapper mapper) throws Exception { Assert.notNull(root, "Root ObjectNode must not be null!"); @@ -164,7 +169,7 @@ public class DomainObjectReader { return mapper.readerForUpdating(target).readValue(root); } - MappedProperties mappedProperties = MappedProperties.fromJacksonProperties(entity, mapper); + MappedProperties mappedProperties = getJacksonProperties(entity, mapper); for (Iterator> i = root.fields(); i.hasNext();) { @@ -249,4 +254,63 @@ public class DomainObjectReader { } } } + + /** + * Returns the {@link MappedProperties} for the given {@link PersistentEntity}. + * + * @param entity must not be {@literal null}. + * @param mapper must not be {@literal null}. + * @return + */ + private MappedProperties getJacksonProperties(PersistentEntity entity, ObjectMapper mapper) { + + BeanDescription description = introspector.forDeserialization(mapper.getDeserializationConfig(), + mapper.constructType(entity.getType()), mapper.getDeserializationConfig()); + + return new MappedProperties(entity, description); + } + + /** + * Simple value object to capture a mapping of Jackson mapped field names and {@link PersistentProperty} instances. + * + * @author Oliver Gierke + */ + private static class MappedProperties { + + private final Map, String> propertyToFieldName; + private final Map> fieldNameToProperty; + + /** + * Creates a new {@link MappedProperties} instance for the given {@link PersistentEntity} and + * {@link BeanDescription}. + * + * @param entity must not be {@literal null}. + * @param description must not be {@literal null}. + */ + public MappedProperties(PersistentEntity entity, BeanDescription description) { + + this.propertyToFieldName = new HashMap, String>(); + this.fieldNameToProperty = new HashMap>(); + + for (BeanPropertyDefinition property : description.findProperties()) { + + PersistentProperty persistentProperty = entity.getPersistentProperty(property.getInternalName()); + + propertyToFieldName.put(persistentProperty, property.getName()); + fieldNameToProperty.put(property.getName(), persistentProperty); + } + } + + public String getMappedName(PersistentProperty property) { + return propertyToFieldName.get(property); + } + + public boolean hasPersistentPropertyForField(String fieldName) { + return fieldNameToProperty.containsKey(fieldName); + } + + public PersistentProperty getPersistentProperty(String fieldName) { + return fieldNameToProperty.get(fieldName); + } + } } diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/json/JacksonMappingAwareSortTranslator.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/json/JacksonMappingAwareSortTranslator.java deleted file mode 100644 index eb8fba93a..000000000 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/json/JacksonMappingAwareSortTranslator.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright 2016 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 java.util.ArrayList; -import java.util.List; - -import org.springframework.core.MethodParameter; -import org.springframework.data.domain.Sort; -import org.springframework.data.domain.Sort.Order; -import org.springframework.data.mapping.PersistentEntity; -import org.springframework.data.mapping.PersistentProperty; -import org.springframework.data.repository.support.Repositories; -import org.springframework.data.rest.webmvc.support.DomainClassResolver; -import org.springframework.util.Assert; -import org.springframework.web.context.request.NativeWebRequest; - -import com.fasterxml.jackson.databind.ObjectMapper; - -/** - * Translator for {@link Sort} arguments that is aware of Jackson-Mapping on domain classes. Jackson field names are - * translated to {@link PersistentProperty} names. Domain class are looked up by resolving request URLs to mapped - * repositories. - * - * @author Mark Paluch - * @since 2.6, 2.5.3, 2.4.5 - */ -public class JacksonMappingAwareSortTranslator { - - private final ObjectMapper objectMapper; - private final Repositories repositories; - private final DomainClassResolver domainClassResolver; - - /** - * Creates a new {@link JacksonMappingAwareSortTranslator} for the given {@link ObjectMapper}, {@link Repositories} - * and {@link DomainClassResolver}. - * - * @param objectMapper must not be {@literal null}. - * @param repositories must not be {@literal null}. - * @param domainClassResolver must not be {@literal null}. - */ - public JacksonMappingAwareSortTranslator(ObjectMapper objectMapper, Repositories repositories, - DomainClassResolver domainClassResolver) { - - Assert.notNull(objectMapper, "ObjectMapper must not be null!"); - Assert.notNull(repositories, "Repositories must not be null!"); - Assert.notNull(domainClassResolver, "DomainClassResolver must not be null!"); - - this.objectMapper = objectMapper; - this.repositories = repositories; - this.domainClassResolver = domainClassResolver; - } - - /** - * Translates Jackson field names within a {@link Sort} to {@link PersistentProperty} property names. - * - * @param input must not be {@literal null}. - * @param parameter must not be {@literal null}. - * @param webRequest must not be {@literal null}. - * @return a {@link Sort} containing translated property names or {@literal null} the resulting {@link Sort} contains - * no properties. - */ - protected Sort translateSort(Sort input, MethodParameter parameter, NativeWebRequest webRequest) { - - Assert.notNull(input, "Sort must not be null!"); - Assert.notNull(parameter, "MethodParameter must not be null!"); - Assert.notNull(webRequest, "NativeWebRequest must not be null!"); - - Class domainClass = domainClassResolver.resolve(parameter.getMethod(), webRequest); - PersistentEntity persistentEntity = repositories.getPersistentEntity(domainClass); - MappedProperties mappedProperties = MappedProperties.fromJacksonProperties(persistentEntity, objectMapper); - - return new SortTranslator(mappedProperties).translateSort(input); - } - - /** - * Translates {@link Sort} orders from Jackson-mapped field names to {@link PersistentProperty} names. - * - * @author Mark Paluch - * @author Oliver Gierke - * @since 2.6, 2.5.3, 2.4.5 - */ - static class SortTranslator { - - private final MappedProperties mappedProperties; - - /** - * Creates a new {@link SortTranslator}. - * - * @param mappedProperties must not be {@literal null}. - */ - public SortTranslator(MappedProperties mappedProperties) { - - Assert.notNull(mappedProperties, "MappedProperties must not be null!"); - - this.mappedProperties = mappedProperties; - } - - /** - * Translates {@link Sort} orders from Jackson-mapped field names to {@link PersistentProperty} names. Properties - * that cannot be resolved are dropped. - * - * @param input must not be {@literal null}. - * @return {@link Sort} with translated field names or {@literal null} if translation dropped all sort fields. - */ - Sort translateSort(Sort input) { - - List filteredOrders = new ArrayList(); - - for (Order order : input) { - - if (mappedProperties.hasPersistentPropertyForField(order.getProperty())) { - - PersistentProperty persistentProperty = mappedProperties.getPersistentProperty(order.getProperty()); - Order mappedOrder = new Order(order.getDirection(), persistentProperty.getName(), order.getNullHandling()); - filteredOrders.add(order.isIgnoreCase() ? mappedOrder.ignoreCase() : mappedOrder); - } - } - - return filteredOrders.isEmpty() ? null : new Sort(filteredOrders); - } - } -} diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/json/MappedProperties.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/json/MappedProperties.java deleted file mode 100644 index 886796866..000000000 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/json/MappedProperties.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright 2016 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 java.util.HashMap; -import java.util.Map; - -import org.springframework.data.mapping.PersistentEntity; -import org.springframework.data.mapping.PersistentProperty; -import org.springframework.util.Assert; - -import com.fasterxml.jackson.databind.BeanDescription; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.introspect.BasicClassIntrospector; -import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition; -import com.fasterxml.jackson.databind.introspect.ClassIntrospector; - -/** - * Simple value object to capture a mapping of Jackson mapped field names and {@link PersistentProperty} instances. - * - * @author Oliver Gierke - * @author Mark Paluch - */ -class MappedProperties { - - private static final ClassIntrospector INTROSPECTOR = new BasicClassIntrospector(); - - private final Map, String> propertyToFieldName; - private final Map> fieldNameToProperty; - - /** - * Creates a new {@link MappedProperties} instance for the given {@link PersistentEntity} and {@link BeanDescription}. - * - * @param entity must not be {@literal null}. - * @param description must not be {@literal null}. - */ - private MappedProperties(PersistentEntity entity, BeanDescription description) { - - this.propertyToFieldName = new HashMap, String>(); - this.fieldNameToProperty = new HashMap>(); - - for (BeanPropertyDefinition property : description.findProperties()) { - - PersistentProperty persistentProperty = entity.getPersistentProperty(property.getInternalName()); - - propertyToFieldName.put(persistentProperty, property.getName()); - fieldNameToProperty.put(property.getName(), persistentProperty); - } - } - - /** - * Creates {@link MappedProperties} for the given {@link PersistentEntity}. - * - * @param entity must not be {@literal null}. - * @param mapper must not be {@literal null}. - * @return - */ - public static MappedProperties fromJacksonProperties(PersistentEntity entity, ObjectMapper mapper) { - - BeanDescription description = INTROSPECTOR.forDeserialization(mapper.getDeserializationConfig(), - mapper.constructType(entity.getType()), mapper.getDeserializationConfig()); - - return new MappedProperties(entity, description); - } - - /** - * @param property must not be {@literal null} - * @return the mapped name for the {@link PersistentProperty} - */ - public String getMappedName(PersistentProperty property) { - - Assert.notNull(property, "PersistentProperty must not be null!"); - - return propertyToFieldName.get(property); - } - - /** - * @param fieldName must not be empty or {@literal null}. - * @return {@literal true} if the field name resolves to a {@literal PersistentProperty}. - */ - public boolean hasPersistentPropertyForField(String fieldName) { - - Assert.hasText(fieldName, "Field name must not be null or empty!"); - - return fieldNameToProperty.containsKey(fieldName); - } - - /** - * @param fieldName must not be empty or {@literal null}. - * @return - */ - public PersistentProperty getPersistentProperty(String fieldName) { - - Assert.hasText(fieldName, "Field name must not be null or empty!"); - - return fieldNameToProperty.get(fieldName); - } -} diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/json/MappingAwareDefaultedPageableArgumentResolver.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/json/MappingAwareDefaultedPageableArgumentResolver.java deleted file mode 100644 index bc690eb87..000000000 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/json/MappingAwareDefaultedPageableArgumentResolver.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2016 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 org.springframework.core.MethodParameter; -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Sort; -import org.springframework.data.rest.webmvc.support.DefaultedPageable; -import org.springframework.data.web.PageableHandlerMethodArgumentResolver; -import org.springframework.util.Assert; -import org.springframework.web.bind.support.WebDataBinderFactory; -import org.springframework.web.context.request.NativeWebRequest; -import org.springframework.web.method.support.HandlerMethodArgumentResolver; -import org.springframework.web.method.support.ModelAndViewContainer; - -/** - * {@link HandlerMethodArgumentResolver} to resolve {@link DefaultedPageable} from a - * {@link PageableHandlerMethodArgumentResolver} applying field to property mapping. - *

- * A resolved {@link DefaultedPageable} is post-processed by applying Jackson field-to-property mapping if it contains a - * {@link Sort} instance. Customized fields are resolved to their property names. Unknown properties are removed from - * {@link Sort}. - * - * @author Mark Paluch - * @author Oliver Gierke - * @since 2.6, 2.5.3, 2.4.5 - */ -public class MappingAwareDefaultedPageableArgumentResolver implements HandlerMethodArgumentResolver { - - private final PageableHandlerMethodArgumentResolver delegate; - private final JacksonMappingAwareSortTranslator translator; - - /** - * Creates a new {@link MappingAwareDefaultedPageableArgumentResolver} for the given - * {@link JacksonMappingAwareSortTranslator} and {@link PageableHandlerMethodArgumentResolver}. - * - * @param translator must not be {@literal null}. - * @param delegate must not be {@literal null}. - */ - public MappingAwareDefaultedPageableArgumentResolver(JacksonMappingAwareSortTranslator translator, - PageableHandlerMethodArgumentResolver delegate) { - - Assert.notNull(translator, "JacksonMappingSortTranslator must not be null!"); - Assert.notNull(delegate, "PageableHandlerMethodArgumentResolver must not be null!"); - - this.translator = translator; - this.delegate = delegate; - } - - /* - * (non-Javadoc) - * @see org.springframework.web.method.support.HandlerMethodArgumentResolver#supportsParameter(org.springframework.core.MethodParameter) - */ - @Override - public boolean supportsParameter(MethodParameter parameter) { - return DefaultedPageable.class.isAssignableFrom(parameter.getParameterType()); - } - - /* - * (non-Javadoc) - * @see org.springframework.web.method.support.HandlerMethodArgumentResolver#resolveArgument(org.springframework.core.MethodParameter, org.springframework.web.method.support.ModelAndViewContainer, org.springframework.web.context.request.NativeWebRequest, org.springframework.web.bind.support.WebDataBinderFactory) - */ - @Override - public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, - NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { - - Pageable pageable = delegate.resolveArgument(parameter, mavContainer, webRequest, binderFactory); - - if (pageable == null || pageable.getSort() == null) { - return new DefaultedPageable(pageable, delegate.isFallbackPageable(pageable)); - } - - Sort translated = translator.translateSort(pageable.getSort(), parameter, webRequest); - pageable = new PageRequest(pageable.getPageNumber(), pageable.getPageSize(), translated); - - return new DefaultedPageable(pageable, delegate.isFallbackPageable(pageable)); - } -} diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/json/MappingAwarePageableArgumentResolver.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/json/MappingAwarePageableArgumentResolver.java deleted file mode 100644 index e50c9ef06..000000000 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/json/MappingAwarePageableArgumentResolver.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2016 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 org.springframework.core.MethodParameter; -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Sort; -import org.springframework.data.web.PageableHandlerMethodArgumentResolver; -import org.springframework.util.Assert; -import org.springframework.web.bind.support.WebDataBinderFactory; -import org.springframework.web.context.request.NativeWebRequest; -import org.springframework.web.method.support.HandlerMethodArgumentResolver; -import org.springframework.web.method.support.ModelAndViewContainer; - -/** - * {@link HandlerMethodArgumentResolver} to resolve {@link Pageable} from a - * {@link PageableHandlerMethodArgumentResolver} applying field to property mapping. - *

- * A resolved {@link Pageable} is post-processed by applying Jackson field-to-property mapping if it contains a - * {@link Sort} instance. Customized fields are resolved to their property names. Unknown properties are removed from - * {@link Sort}. - * - * @author Mark Paluch - * @author Oliver Gierke - * @since 2.6, 2.5.3, 2.4.5 - */ -public class MappingAwarePageableArgumentResolver implements HandlerMethodArgumentResolver { - - private final JacksonMappingAwareSortTranslator translator; - private final PageableHandlerMethodArgumentResolver delegate; - - /** - * Creates a new {@link MappingAwarePageableArgumentResolver} for the given {@link JacksonMappingAwareSortTranslator} - * and {@link PageableHandlerMethodArgumentResolver}. - * - * @param translator must not be {@literal null}. - * @param delegate must not be {@literal null}. - */ - public MappingAwarePageableArgumentResolver(JacksonMappingAwareSortTranslator translator, - PageableHandlerMethodArgumentResolver delegate) { - - Assert.notNull(translator, "JacksonMappingSortTranslator must not be null!"); - Assert.notNull(delegate, "PageableHandlerMethodArgumentResolver must not be null!"); - - this.translator = translator; - this.delegate = delegate; - } - - /* - * (non-Javadoc) - * @see org.springframework.web.method.support.HandlerMethodArgumentResolver#supportsParameter(org.springframework.core.MethodParameter) - */ - @Override - public boolean supportsParameter(MethodParameter parameter) { - return delegate.supportsParameter(parameter); - } - - /* - * (non-Javadoc) - * @see org.springframework.web.method.support.HandlerMethodArgumentResolver#resolveArgument(org.springframework.core.MethodParameter, org.springframework.web.method.support.ModelAndViewContainer, org.springframework.web.context.request.NativeWebRequest, org.springframework.web.bind.support.WebDataBinderFactory) - */ - @Override - public Pageable resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, - NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { - - Pageable pageable = delegate.resolveArgument(parameter, mavContainer, webRequest, binderFactory); - - if (pageable == null || pageable.getSort() == null) { - return pageable; - } - - Sort translated = translator.translateSort(pageable.getSort(), parameter, webRequest); - return new PageRequest(pageable.getPageNumber(), pageable.getPageSize(), translated); - } -} diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/json/MappingAwareSortArgumentResolver.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/json/MappingAwareSortArgumentResolver.java deleted file mode 100644 index 3227c0424..000000000 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/json/MappingAwareSortArgumentResolver.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2016 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 org.springframework.core.MethodParameter; -import org.springframework.data.domain.Sort; -import org.springframework.data.web.SortHandlerMethodArgumentResolver; -import org.springframework.util.Assert; -import org.springframework.web.bind.support.WebDataBinderFactory; -import org.springframework.web.context.request.NativeWebRequest; -import org.springframework.web.method.support.HandlerMethodArgumentResolver; -import org.springframework.web.method.support.ModelAndViewContainer; - -/** - * {@link HandlerMethodArgumentResolver} to resolve {@link Sort} from a {@link SortHandlerMethodArgumentResolver} - * applying field to property mapping. - *

- * A resolved {@link Sort} is post-processed by applying Jackson field-to-property mapping. Customized fields are - * resolved to their property names. Unknown properties are removed from {@link Sort}. - * - * @author Mark Paluch - * @author Oliver Gierke - * @since 2.6, 2.5.3, 2.4.5 - */ -public class MappingAwareSortArgumentResolver implements HandlerMethodArgumentResolver { - - private final JacksonMappingAwareSortTranslator translator; - private final SortHandlerMethodArgumentResolver delegate; - - /** - * Creates a new {@link MappingAwareSortArgumentResolver} for the given {@link JacksonMappingAwareSortTranslator} and - * {@link SortHandlerMethodArgumentResolver}. - * - * @param translator must not be {@literal null}. - * @param delegate must not be {@literal null}. - */ - public MappingAwareSortArgumentResolver(JacksonMappingAwareSortTranslator translator, - SortHandlerMethodArgumentResolver delegate) { - - Assert.notNull(translator, "JacksonMappingSortTranslator must not be null!"); - Assert.notNull(delegate, "PageableHandlerMethodArgumentResolver must not be null!"); - - this.translator = translator; - this.delegate = delegate; - } - - /* - * (non-Javadoc) - * @see org.springframework.web.method.support.HandlerMethodArgumentResolver#supportsParameter(org.springframework.core.MethodParameter) - */ - @Override - public boolean supportsParameter(MethodParameter parameter) { - return delegate.supportsParameter(parameter); - } - - /* - * (non-Javadoc) - * @see org.springframework.web.method.support.HandlerMethodArgumentResolver#resolveArgument(org.springframework.core.MethodParameter, org.springframework.web.method.support.ModelAndViewContainer, org.springframework.web.context.request.NativeWebRequest, org.springframework.web.bind.support.WebDataBinderFactory) - */ - @Override - public Sort resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, - NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { - - Sort sort = delegate.resolveArgument(parameter, mavContainer, webRequest, binderFactory); - - return sort == null ? null : translator.translateSort(sort, parameter, webRequest); - } -} diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/support/DomainClassResolver.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/support/DomainClassResolver.java deleted file mode 100644 index 094dd1c7f..000000000 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/support/DomainClassResolver.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2016 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.support; - -import java.lang.reflect.Method; - -import org.springframework.data.repository.support.Repositories; -import org.springframework.data.rest.core.mapping.ResourceMappings; -import org.springframework.data.rest.core.mapping.ResourceMetadata; -import org.springframework.data.rest.webmvc.BaseUri; -import org.springframework.data.rest.webmvc.util.UriUtils; -import org.springframework.util.Assert; -import org.springframework.util.StringUtils; -import org.springframework.web.context.request.NativeWebRequest; - -/** - * Resolves a domain class from a web request. Domain class resolution is only available for {@link NativeWebRequest web - * requests} related to mapped and exported {@link Repositories}. - * - * @author Mark Paluch - * @author Oliver Gierke - * @since 2.6, 2.5.3, 2.4.5 - */ -public class DomainClassResolver { - - private final Repositories repositories; - private final ResourceMappings mappings; - private final BaseUri baseUri; - - /** - * Creates a new {@link DomainClassResolver} for the given {@link Repositories} and {@link ResourceMappings}. - * - * @param repositories must not be {@literal null}. - * @param mappings must not be {@literal null}. - * @param baseUri must not be {@literal null}. - */ - private DomainClassResolver(Repositories repositories, ResourceMappings mappings, BaseUri baseUri) { - - Assert.notNull(repositories, "Repositories must not be null!"); - Assert.notNull(mappings, "ResourceMappings must not be null!"); - Assert.notNull(baseUri, "BaseUri must not be null!"); - - this.repositories = repositories; - this.mappings = mappings; - this.baseUri = baseUri; - } - - /** - * Creates a new {@link DomainClassResolver} for the given {@link Repositories} and {@link ResourceMappings}. - * - * @param repositories must not be {@literal null}. - * @param mappings must not be {@literal null}. - * @param baseUri must not be {@literal null}. - */ - public static DomainClassResolver of(Repositories repositories, ResourceMappings mappings, BaseUri baseUri) { - return new DomainClassResolver(repositories, mappings, baseUri); - } - - /** - * Resolves a domain class that is associated with the {@link NativeWebRequest} - * - * @param method must not be {@literal null}. - * @param webRequest must not be {@literal null}. - * @return domain type that is associated with this request. - * @throws IllegalArgumentException if there's no repository key associated or no domain type can be resolved. - */ - public Class resolve(Method method, NativeWebRequest webRequest) { - - Assert.notNull(method, "Method must not be null!"); - Assert.notNull(webRequest, "NativeWebRequest must not be null!"); - - String lookupPath = baseUri.getRepositoryLookupPath(webRequest); - String repositoryKey = UriUtils.findMappingVariable("repository", method, lookupPath); - - if (!StringUtils.hasText(repositoryKey)) { - throw new IllegalArgumentException(String.format("Could not determine a repository key from %s.", lookupPath)); - } - - for (Class domainType : repositories) { - - ResourceMetadata mapping = mappings.getMetadataFor(domainType); - - if (mapping.getPath().matches(repositoryKey) && mapping.isExported()) { - return domainType; - } - } - - throw new IllegalArgumentException( - String.format("Could not resolve an exported domain type for %s.", repositoryKey)); - } -} diff --git a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/jpa/Book.java b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/jpa/Book.java index f136be7ba..86bf1680b 100644 --- a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/jpa/Book.java +++ b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/jpa/Book.java @@ -26,11 +26,8 @@ import javax.persistence.ManyToMany; import org.springframework.data.rest.core.annotation.RestResource; -import com.fasterxml.jackson.annotation.JsonProperty; - /** * @author Oliver Gierke - * @author Mark Paluch */ @Entity public class Book { @@ -41,18 +38,14 @@ public class Book { @ManyToMany(cascade = { CascadeType.MERGE })// @RestResource(path = "creators") public Set authors; - @JsonProperty("sales") - public long soldUnits; - public String title; protected Book() {} - public Book(String isbn, String title, long soldUnits, Iterable authors) { + public Book(String isbn, String title, Iterable authors) { this.isbn = isbn; this.title = title; - this.soldUnits = soldUnits; this.authors = new HashSet(); diff --git a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/jpa/BookRepository.java b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/jpa/BookRepository.java index eb419f787..43d277a80 100644 --- a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/jpa/BookRepository.java +++ b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/jpa/BookRepository.java @@ -17,8 +17,6 @@ package org.springframework.data.rest.webmvc.jpa; import java.util.List; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; @@ -28,7 +26,6 @@ import org.springframework.data.rest.core.annotation.RestResource; /** * @author Oliver Gierke - * @author Mark Paluch */ @RepositoryRestResource(excerptProjection = BookExcerpt.class) public interface BookRepository extends CrudRepository { @@ -38,8 +35,4 @@ public interface BookRepository extends CrudRepository { @Query("select b from Book b where :author member of b.authors") List findByAuthorsContains(@Param("author") Author author); - - @RestResource(rel = "find-spring-books-sorted") - @Query("select b from Book b where b.title like 'Spring%'") - Page findByTitleIsLike(Pageable pageable); } diff --git a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/jpa/JpaDefaultPageableWebTests.java b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/jpa/JpaDefaultPageableWebTests.java deleted file mode 100644 index eb567c29a..000000000 --- a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/jpa/JpaDefaultPageableWebTests.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright 2016 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 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.MockMvcResultHandlers.*; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; - -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.ApplicationContext; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageImpl; -import org.springframework.data.domain.Pageable; -import org.springframework.data.jpa.repository.config.EnableJpaRepositories; -import org.springframework.data.rest.core.config.RepositoryRestConfiguration; -import org.springframework.data.rest.webmvc.AbstractWebIntegrationTests; -import org.springframework.data.rest.webmvc.RepositoryRestController; -import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurerAdapter; -import org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration; -import org.springframework.hateoas.Link; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.context.web.WebAppConfiguration; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.ResponseBody; - -/** - * Web integration tests specific to default {@link Pageable} handling. - * - * @author Mark Paluch - */ -@RunWith(SpringJUnit4ClassRunner.class) -@WebAppConfiguration -@ContextConfiguration(classes = JpaDefaultPageableWebTests.Config.class) -public class JpaDefaultPageableWebTests extends AbstractWebIntegrationTests { - - @Configuration - @Import({ RepositoryRestMvcConfiguration.class, JpaRepositoryConfig.class }) - @EnableJpaRepositories(considerNestedRepositories = true) - static class Config extends RepositoryRestConfigurerAdapter { - - public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) { - config.setDefaultPageSize(1); - } - } - - @RepositoryRestController - public static class MyRestController { - - @RequestMapping(method = RequestMethod.GET, value = "books/default-pageable") - @ResponseBody - Page getDefaultPageable(Pageable pageable) { - - if (pageable != null) { - return new PageImpl(Collections.singletonList(new Book()), pageable, 1); - } - - return new PageImpl(Collections.emptyList(), pageable, 0); - } - } - - @Autowired TestDataPopulator loader; - @Autowired ApplicationContext context; - - @Before - public void setUp() { - loader.populateRepositories(); - super.setUp(); - } - - /** - * @see DATAREST-906 - */ - @Test - public void executesSearchThatTakesAMappedSortProperty() throws Exception { - - Link findBySortedLink = client.discoverUnique("books", "search", "find-spring-books-sorted"); - - // Assert sort options advertised - assertThat(findBySortedLink.isTemplated(), is(true)); - assertThat(findBySortedLink.getVariableNames(), hasItems("sort", "projection")); - - // Assert results returned as specified - client.follow(findBySortedLink.expand()).// - andExpect(jsonPath("$._embedded.books[0].title").exists()).// - andExpect(jsonPath("$._embedded.books[1].title").doesNotExist()); - - client.follow(findBySortedLink.expand("sales,desc")).// - andExpect(jsonPath("$._embedded.books[0].title").exists()).// - andExpect(jsonPath("$._embedded.books[1].title").doesNotExist()); - } - - /** - * @see DATAREST-906 - */ - @Test - public void shouldApplyDefaultPageable() throws Exception { - - mvc.perform(get("/books/default-pageable")).andDo(print()) // - .andExpect(jsonPath("$.content[0].sales").value(0)) // - .andExpect(jsonPath("$.size").value(1)); - } - - /** - * @see DATAREST-906 - */ - @Test - public void shouldOverrideDefaultPageable() throws Exception { - - mvc.perform(get("/books/default-pageable?size=10")).andDo(print()) // - .andExpect(jsonPath("$.content[0].sales").value(0)) // - .andExpect(jsonPath("$.size").value(10)); - } -} diff --git a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/jpa/JpaWebTests.java b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/jpa/JpaWebTests.java index 47107060d..35ca5ce37 100644 --- a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/jpa/JpaWebTests.java +++ b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/jpa/JpaWebTests.java @@ -57,7 +57,6 @@ import com.jayway.jsonpath.JsonPath; * * @author Oliver Gierke * @author Greg Turnquist - * @author Mark Paluch */ @Transactional @ContextConfiguration(classes = JpaRepositoryConfig.class) @@ -547,7 +546,7 @@ public class JpaWebTests extends CommonWebTests { * @see DATAREST-384 */ @Test - public void exectuesSearchThatTakesASort() throws Exception { + public void execturesSearchThatTakesASort() throws Exception { Link booksLink = client.discoverUnique("books"); Link searchLink = client.discoverUnique(booksLink, "search"); @@ -655,53 +654,6 @@ public class JpaWebTests extends CommonWebTests { assertThat(links.hasLink("person"), is(true)); } - /** - * @see DATAREST-883 - */ - @Test - public void exectuesSearchThatTakesAMappedSortProperty() throws Exception { - - Link findBySortedLink = client.discoverUnique("books", "search", "find-by-sorted"); - - // Assert sort options advertised - assertThat(findBySortedLink.isTemplated(), is(true)); - assertThat(findBySortedLink.getVariableNames(), hasItems("sort", "projection")); - - // Assert results returned as specified - client.follow(findBySortedLink.expand("sales,desc")).// - andExpect(jsonPath("$._embedded.books[0].title").value("Spring Data (Second Edition)")).// - andExpect(jsonPath("$._embedded.books[1].title").value("Spring Data")).// - andExpect(client.hasLinkWithRel("self")); - - client.follow(findBySortedLink.expand("sales,asc")).// - andExpect(jsonPath("$._embedded.books[0].title").value("Spring Data")).// - andExpect(jsonPath("$._embedded.books[1].title").value("Spring Data (Second Edition)")).// - andExpect(client.hasLinkWithRel("self")); - } - - /** - * @see DATAREST-883 - */ - @Test - public void exectuesCustomQuerySearchThatTakesAMappedSortProperty() throws Exception { - - Link findByLink = client.discoverUnique("books", "search", "find-spring-books-sorted"); - - // Assert sort options advertised - assertThat(findByLink.isTemplated(), is(true)); - - // Assert results returned as specified - client.follow(findByLink.expand("0", "10", "sales,desc")).// - andExpect(jsonPath("$._embedded.books[0].title").value("Spring Data (Second Edition)")).// - andExpect(jsonPath("$._embedded.books[1].title").value("Spring Data")).// - andExpect(client.hasLinkWithRel("self")); - - client.follow(findByLink.expand("0", "10", "unknown,asc,sales,asc")).// - andExpect(jsonPath("$._embedded.books[0].title").value("Spring Data")).// - andExpect(jsonPath("$._embedded.books[1].title").value("Spring Data (Second Edition)")).// - andExpect(client.hasLinkWithRel("self")); - } - private List preparePersonResources(Person primary, Person... persons) throws Exception { Link peopleLink = client.discoverUnique("people"); 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 95f9dcc40..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 @@ -22,7 +22,6 @@ import org.springframework.beans.factory.annotation.Autowired; /** * @author Jon Brisbin * @author Oliver Gierke - * @author Mark Paluch */ public class TestDataPopulator { @@ -54,8 +53,8 @@ public class TestDataPopulator { Iterable authors = this.authors.save(Arrays.asList(ollie, mark, michael, david, john, thomas)); - books.save(new Book("1449323952", "Spring Data", 1000, authors)); - books.save(new Book("1449323953", "Spring Data (Second Edition)", 2000, authors)); + books.save(new Book("1449323952", "Spring Data", authors)); + books.save(new Book("1449323953", "Spring Data (Second Edition)", authors)); } private void populateOrders() { diff --git a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/MappingAwarePageableArgumentResolverUnitTests.java b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/MappingAwarePageableArgumentResolverUnitTests.java deleted file mode 100644 index ddcca137b..000000000 --- a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/MappingAwarePageableArgumentResolverUnitTests.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2016 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.hamcrest.MatcherAssert.*; -import static org.hamcrest.Matchers.*; -import static org.mockito.Mockito.*; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; -import org.springframework.core.MethodParameter; -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Sort; -import org.springframework.data.domain.Sort.Direction; -import org.springframework.data.web.PageableHandlerMethodArgumentResolver; -import org.springframework.web.bind.support.WebDataBinderFactory; -import org.springframework.web.context.request.NativeWebRequest; -import org.springframework.web.method.support.ModelAndViewContainer; - -/** - * Unit tests for {@link MappingAwarePageableArgumentResolver}. - * - * @author Mark Paluch - */ -@RunWith(MockitoJUnitRunner.class) -public class MappingAwarePageableArgumentResolverUnitTests { - - @Mock JacksonMappingAwareSortTranslator translator; - @Mock PageableHandlerMethodArgumentResolver delegate; - @Mock MethodParameter parameter; - @Mock NativeWebRequest webRequest; - @Mock ModelAndViewContainer modelAndViewContainer; - @Mock WebDataBinderFactory binderFactory; - - MappingAwarePageableArgumentResolver resolver; - - @Before - public void setUp() { - resolver = new MappingAwarePageableArgumentResolver(translator, delegate); - } - - /** - * @see DATAREST-906 - */ - @Test - public void resolveArgumentShouldReturnTranslatedPageable() throws Exception { - - Sort translated = new Sort("world"); - Pageable pageable = new PageRequest(0, 1, Direction.ASC, "hello"); - - when(delegate.resolveArgument(parameter, modelAndViewContainer, webRequest, binderFactory)).thenReturn(pageable); - when(translator.translateSort(pageable.getSort(), parameter, webRequest)).thenReturn(translated); - - Pageable result = resolver.resolveArgument(parameter, modelAndViewContainer, webRequest, binderFactory); - - assertThat(result.getPageSize(), is(1)); - assertThat(result.getPageNumber(), is(0)); - assertThat(result.getSort(), is(equalTo(translated))); - } - - /** - * @see DATAREST-906 - */ - @Test - public void resolveArgumentShouldReturnPageableWithoutSort() throws Exception { - - Pageable pageable = new PageRequest(0, 1); - - when(delegate.resolveArgument(parameter, modelAndViewContainer, webRequest, binderFactory)).thenReturn(pageable); - - Pageable result = resolver.resolveArgument(parameter, modelAndViewContainer, webRequest, binderFactory); - - assertThat(result.getPageSize(), is(1)); - assertThat(result.getPageNumber(), is(0)); - assertThat(result.getSort(), is(nullValue())); - } - - /** - * @see DATAREST-906 - */ - @Test - public void resolveArgumentShouldReturnNoPageable() throws Exception { - - Pageable result = resolver.resolveArgument(parameter, modelAndViewContainer, webRequest, binderFactory); - - assertThat(result, is(nullValue())); - } -} diff --git a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/SortTranslatorUnitTests.java b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/SortTranslatorUnitTests.java deleted file mode 100644 index 6ee98d18e..000000000 --- a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/SortTranslatorUnitTests.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2016 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.hamcrest.Matchers.*; -import static org.junit.Assert.*; - -import org.junit.Before; -import org.junit.Test; -import org.springframework.data.domain.Sort; -import org.springframework.data.mongodb.core.mapping.MongoMappingContext; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.ObjectMapper; - -/** - * Unit tests for {@link JacksonMappingAwareSortTranslator.SortTranslator}. - * - * @author Mark Paluch - * @author Oliver Gierke - * @soundtrack dkn - Out Of This World (original version) - */ -public class SortTranslatorUnitTests { - - private MongoMappingContext mappingContext; - - @Before - public void setUp() { - - mappingContext = new MongoMappingContext(); - mappingContext.getPersistentEntity(Plain.class); - mappingContext.getPersistentEntity(WithJsonProperty.class); - } - - /** - * @see DATAREST-883 - */ - @Test - public void shouldMapKnownProperties() { - - MappedProperties mappedProperties = MappedProperties - .fromJacksonProperties(mappingContext.getPersistentEntity(Plain.class), new ObjectMapper()); - Sort translatedSort = new JacksonMappingAwareSortTranslator.SortTranslator(mappedProperties) - .translateSort(new Sort("hello", "name")); - - assertThat(translatedSort.getOrderFor("hello"), is(nullValue())); - assertThat(translatedSort.getOrderFor("name"), is(notNullValue())); - } - - /** - * @see DATAREST-883 - */ - @Test - public void returnsNullSortIfNoPropertiesMatch() { - - MappedProperties mappedProperties = MappedProperties - .fromJacksonProperties(mappingContext.getPersistentEntity(Plain.class), new ObjectMapper()); - Sort translatedSort = new JacksonMappingAwareSortTranslator.SortTranslator(mappedProperties) - .translateSort(new Sort("hello", "world")); - - assertThat(translatedSort, is(nullValue())); - } - - /** - * @see DATAREST-883 - */ - @Test - public void shouldMapKnownPropertiesWithJsonProperty() { - - MappedProperties mappedProperties = MappedProperties - .fromJacksonProperties(mappingContext.getPersistentEntity(WithJsonProperty.class), new ObjectMapper()); - Sort translatedSort = new JacksonMappingAwareSortTranslator.SortTranslator(mappedProperties) - .translateSort(new Sort("hello", "foo")); - - assertThat(translatedSort.getOrderFor("hello"), is(nullValue())); - assertThat(translatedSort.getOrderFor("name"), is(notNullValue())); - } - - /** - * @see DATAREST-883 - */ - @Test - public void shouldJacksonFieldNameForMapping() { - - MappedProperties mappedProperties = MappedProperties - .fromJacksonProperties(mappingContext.getPersistentEntity(WithJsonProperty.class), new ObjectMapper()); - Sort translatedSort = new JacksonMappingAwareSortTranslator.SortTranslator(mappedProperties) - .translateSort(new Sort("name")); - - assertThat(translatedSort, is(nullValue())); - } - - static class Plain { - public String name; - } - - static class WithJsonProperty { - public @JsonProperty("foo") String name; - } -}