diff --git a/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/ResourceMappings.java b/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/ResourceMappings.java index 5a7de21e4..cea4b6a2b 100644 --- a/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/ResourceMappings.java +++ b/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/ResourceMappings.java @@ -25,6 +25,7 @@ import java.util.Map; import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.repository.core.RepositoryInformation; import org.springframework.data.repository.support.Repositories; +import org.springframework.data.rest.core.Path; import org.springframework.data.rest.core.config.RepositoryRestConfiguration; import org.springframework.data.rest.core.support.RepositoriesUtils; import org.springframework.hateoas.RelProvider; @@ -44,6 +45,7 @@ public class ResourceMappings implements Iterable { private final Map, ResourceMetadata> cache = new HashMap, ResourceMetadata>(); private final Map, SearchResourceMappings> searchCache = new HashMap, SearchResourceMappings>(); + private final Map, ResourceMapping> propertyCache = new HashMap, ResourceMapping>(); /** * Creates a new {@link ResourceMappings} using the given {@link RepositoryRestConfiguration} and {@link Repositories} @@ -187,7 +189,19 @@ public class ResourceMappings implements Iterable { * @see org.springframework.data.rest.core.mapping.ResourceMetadataProvider#getMappingFor(org.springframework.data.mapping.PersistentProperty) */ ResourceMapping getMappingFor(PersistentProperty property) { - return getMappingFor(property.getActualType()); + + ResourceMapping propertyMapping = propertyCache.get(property); + + if (propertyMapping != null) { + return propertyMapping; + } + + ResourceMetadata propertyTypeMapping = getMappingFor(property.getActualType()); + propertyMapping = new PersistentPropertyResourceMapping(property, propertyTypeMapping == null ? false + : propertyTypeMapping.isExported()); + propertyCache.put(property, propertyMapping); + + return propertyMapping; } /* @@ -208,4 +222,55 @@ public class ResourceMappings implements Iterable { public Iterator iterator() { return cache.values().iterator(); } + + /** + * Special resource mapping for {@link PersistentProperty} instances. + * + * @author Oliver Gierke + */ + private static class PersistentPropertyResourceMapping implements ResourceMapping { + + private final PersistentProperty property; + private final boolean exported; + + /** + * Creates a new {@link PersistentPropertyResourceMapping}. + * + * @param property must not be {@literal null}. + * @param exported whether the property is exported or not. + */ + public PersistentPropertyResourceMapping(PersistentProperty property, boolean exported) { + + Assert.notNull(property, "PersistentProperty must not be null!"); + this.property = property; + this.exported = exported; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.rest.core.mapping.ResourceMapping#getPath() + */ + @Override + public Path getPath() { + return new Path(property.getName()); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.rest.core.mapping.ResourceMapping#getRel() + */ + @Override + public String getRel() { + return property.getName(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.rest.core.mapping.ResourceMapping#isExported() + */ + @Override + public Boolean isExported() { + return exported; + } + } } diff --git a/spring-data-rest-core/src/test/java/org/springframework/data/rest/core/mapping/ResourceMappingsIntegrationTest.java b/spring-data-rest-core/src/test/java/org/springframework/data/rest/core/mapping/ResourceMappingsIntegrationTest.java index e82c557a0..cafc00179 100644 --- a/spring-data-rest-core/src/test/java/org/springframework/data/rest/core/mapping/ResourceMappingsIntegrationTest.java +++ b/spring-data-rest-core/src/test/java/org/springframework/data/rest/core/mapping/ResourceMappingsIntegrationTest.java @@ -24,13 +24,14 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.mapping.PersistentEntity; +import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.repository.support.Repositories; +import org.springframework.data.rest.core.Path; import org.springframework.data.rest.core.config.RepositoryRestConfiguration; import org.springframework.data.rest.core.domain.jpa.CreditCard; import org.springframework.data.rest.core.domain.jpa.JpaRepositoryConfig; import org.springframework.data.rest.core.domain.jpa.Person; -import org.springframework.data.rest.core.mapping.ResourceMappings; -import org.springframework.data.rest.core.mapping.ResourceMetadata; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.transaction.annotation.Transactional; @@ -78,4 +79,22 @@ public class ResourceMappingsIntegrationTest { assertThat(creditCardMapping.isExported(), is(false)); assertThat(creditCardMapping.getSearchResourceMappings().isExported(), is(false)); } + + /** + * @see DATAREST-112 + */ + @Test + public void usesPropertyNameAsRelForPropertyResourceMapping() { + + Repositories repositories = new Repositories(factory); + PersistentEntity entity = repositories.getPersistentEntity(Person.class); + PersistentProperty property = entity.getPersistentProperty("siblings"); + + ResourceMetadata metadata = mappings.getMappingFor(Person.class); + ResourceMapping mapping = metadata.getMappingFor(property); + + assertThat(mapping.getRel(), is("siblings")); + assertThat(mapping.getPath(), is(new Path("siblings"))); + assertThat(mapping.isExported(), is(true)); + } } diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/json/PersistentEntityJackson2Module.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/json/PersistentEntityJackson2Module.java index c49db8d72..823ad787e 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/json/PersistentEntityJackson2Module.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/json/PersistentEntityJackson2Module.java @@ -27,6 +27,7 @@ import org.springframework.data.mapping.model.BeanWrapper; import org.springframework.data.repository.support.Repositories; import org.springframework.data.rest.core.UriDomainClassConverter; import org.springframework.data.rest.core.config.RepositoryRestConfiguration; +import org.springframework.data.rest.core.mapping.ResourceMapping; import org.springframework.data.rest.core.mapping.ResourceMappings; import org.springframework.data.rest.core.mapping.ResourceMetadata; import org.springframework.data.rest.webmvc.PersistentEntityResource; @@ -72,19 +73,16 @@ public class PersistentEntityJackson2Module extends SimpleModule implements Init PersistentProperty persistentProperty, List links) { Assert.isTrue(persistentProperty.isAssociation(), "PersistentProperty must be an association!"); - ResourceMetadata metadata = mappings.getMappingFor(persistentProperty.getOwner().getType()); + ResourceMetadata ownerMetadata = mappings.getMappingFor(persistentProperty.getOwner().getType()); - if (!metadata.isManagedResource(persistentProperty)) { + if (!ownerMetadata.isManagedResource(persistentProperty)) { return false; } - metadata = mappings.getMappingFor(persistentProperty.getActualType()); - - if (metadata.isExported()) { - - String propertyRel = String.format("%s.%s", metadata.getSingleResourceRel(), persistentProperty.getName()); - links.add(builder.slash(persistentProperty.getName()).withRel(propertyRel)); + ResourceMapping propertyMapping = ownerMetadata.getMappingFor(persistentProperty); + if (propertyMapping.isExported()) { + links.add(builder.slash(propertyMapping.getPath()).withRel(propertyMapping.getRel())); // This is an association. We added a Link. return true; } diff --git a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/PersistentEntitySerializationTests.java b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/PersistentEntitySerializationTests.java index 92b75817e..8627f5a3f 100644 --- a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/PersistentEntitySerializationTests.java +++ b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/PersistentEntitySerializationTests.java @@ -68,10 +68,10 @@ public class PersistentEntitySerializationTests { String s = writer.toString(); - Link fatherLink = linkDiscoverer.findLinkWithRel("person.father", s); + Link fatherLink = linkDiscoverer.findLinkWithRel("father", s); assertThat(fatherLink.getHref(), endsWith(new UriTemplate("/{id}/father").expand(person.getId()).toString())); - Link siblingLink = linkDiscoverer.findLinkWithRel("person.siblings", s); + Link siblingLink = linkDiscoverer.findLinkWithRel("siblings", s); assertThat(siblingLink.getHref(), endsWith(new UriTemplate("/{id}/siblings").expand(person.getId()).toString())); } }