DATAREST-976 - Embedded properties are now considered in sort property paths.

We now allow sorting by properties of embedded objects. An embedded object is not linkable to a root object but embedded in the resource itself. If any part of the sort property path points to a linkable association, the whole sort property path is discarded silently and not used for sorting any further.

Original pull request: #251.
This commit is contained in:
Mark Paluch
2017-01-10 14:19:02 +01:00
committed by Oliver Gierke
parent 629ca4e33d
commit ffe96e4079
7 changed files with 63 additions and 16 deletions

View File

@@ -804,7 +804,8 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon
PageableHandlerMethodArgumentResolver pageableResolver = pageableResolver();
JacksonMappingAwareSortTranslator sortTranslator = new JacksonMappingAwareSortTranslator(objectMapper(),
repositories(), DomainClassResolver.of(repositories(), resourceMappings(), baseUri()), persistentEntities());
repositories(), DomainClassResolver.of(repositories(), resourceMappings(), baseUri()), persistentEntities(),
associationLinks());
HandlerMethodArgumentResolver sortResolver = new MappingAwareSortArgumentResolver(sortTranslator, sortResolver());
HandlerMethodArgumentResolver jacksonPageableResolver = new MappingAwarePageableArgumentResolver(sortTranslator,

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016 the original author or authors.
* Copyright 2016-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.
@@ -31,6 +31,7 @@ import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.PersistentProperty;
import org.springframework.data.mapping.context.PersistentEntities;
import org.springframework.data.repository.support.Repositories;
import org.springframework.data.rest.webmvc.mapping.Associations;
import org.springframework.data.rest.webmvc.support.DomainClassResolver;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -62,16 +63,18 @@ public class JacksonMappingAwareSortTranslator {
* @param repositories must not be {@literal null}.
* @param domainClassResolver must not be {@literal null}.
* @param persistentEntities must not be {@literal null}.
* @param associations must not be {@literal null}.
*/
public JacksonMappingAwareSortTranslator(ObjectMapper objectMapper, Repositories repositories,
DomainClassResolver domainClassResolver, PersistentEntities persistentEntities) {
DomainClassResolver domainClassResolver, PersistentEntities persistentEntities, Associations associations) {
Assert.notNull(repositories, "Repositories must not be null!");
Assert.notNull(domainClassResolver, "DomainClassResolver must not be null!");
Assert.notNull(associations, "Associations must not be null!");
this.repositories = repositories;
this.domainClassResolver = domainClassResolver;
this.sortTranslator = new SortTranslator(persistentEntities, objectMapper);
this.sortTranslator = new SortTranslator(persistentEntities, objectMapper, associations);
}
/**
@@ -117,6 +120,7 @@ public class JacksonMappingAwareSortTranslator {
private final @NonNull PersistentEntities persistentEntities;
private final @NonNull ObjectMapper objectMapper;
private final @NonNull Associations associations;
/**
* Translates {@link Sort} orders from Jackson-mapped field names to {@link PersistentProperty} names. Properties
@@ -181,7 +185,7 @@ public class JacksonMappingAwareSortTranslator {
for (PersistentProperty<?> persistentProperty : persistentProperties) {
if (persistentProperty.isAssociation()) {
if (associations.isLinkableAssociation(persistentProperty)) {
return Collections.emptyList();
}

View File

@@ -17,6 +17,7 @@ package org.springframework.data.rest.webmvc.json;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import java.util.Collections;
import java.util.List;
@@ -27,7 +28,11 @@ import org.springframework.data.annotation.Reference;
import org.springframework.data.domain.Sort;
import org.springframework.data.keyvalue.core.mapping.context.KeyValueMappingContext;
import org.springframework.data.mapping.context.PersistentEntities;
import org.springframework.data.rest.core.annotation.RestResource;
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
import org.springframework.data.rest.core.mapping.PersistentEntitiesResourceMappings;
import org.springframework.data.rest.webmvc.json.JacksonMappingAwareSortTranslator.SortTranslator;
import org.springframework.data.rest.webmvc.mapping.Associations;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonUnwrapped;
@@ -57,7 +62,9 @@ public class SortTranslatorUnitTests {
mappingContext.getPersistentEntity(MultiUnwrapped.class);
persistentEntities = new PersistentEntities(Collections.singleton(mappingContext));
sortTranslator = new SortTranslator(persistentEntities, objectMapper);
sortTranslator = new SortTranslator(persistentEntities, objectMapper, new Associations(
new PersistentEntitiesResourceMappings(persistentEntities), mock(RepositoryRestConfiguration.class)));
}
@Test // DATAREST-883
@@ -119,13 +126,22 @@ public class SortTranslatorUnitTests {
assertThat(translatedSort, is(nullValue()));
}
@Test // DATAREST-910
@Test // DATAREST-910, DATAREST-976
public void shouldSkipKnownAssociationProperties() {
Sort translatedSort = sortTranslator.translateSort(new Sort("association.name"),
mappingContext.getPersistentEntity(Plain.class));
assertThat(translatedSort, is(nullValue()));
}
@Test // DATAREST-976
public void shouldMapEmbeddableAssociationProperties() {
Sort translatedSort = sortTranslator.translateSort(new Sort("refEmbedded.name"),
mappingContext.getPersistentEntity(Plain.class));
assertThat(translatedSort, is(nullValue()));
assertThat(translatedSort.getOrderFor("refEmbedded.name"), is(notNullValue()));
}
@Test // DATAREST-910
@@ -161,6 +177,7 @@ public class SortTranslatorUnitTests {
public String name;
public Embedded embedded;
@Reference public Embedded refEmbedded;
@Reference public AnotherRootEntity association;
}
static class UnwrapEmbedded {
@@ -192,4 +209,9 @@ public class SortTranslatorUnitTests {
}
static interface SomeInterface {}
@RestResource
static class AnotherRootEntity {
public String name;
}
}