DATAREST-514 - Fixed resource exposure for customized associations.
We no correctly handle the customized association path if @RestResource is used on an association. Took the chance to refactor the resource mapping subsystem quite significantly to improve the handling of property mappings. Those had been externalized before.
This commit is contained in:
@@ -124,7 +124,7 @@ public class PersistentEntityResourceAssembler implements ResourceAssembler<Obje
|
||||
final List<EmbeddedWrapper> associationProjections = new ArrayList<EmbeddedWrapper>();
|
||||
final PersistentPropertyAccessor accessor = entity.getPropertyAccessor(instance);
|
||||
final AssociationLinks associationLinks = new AssociationLinks(mappings);
|
||||
final ResourceMetadata metadata = mappings.getMappingFor(entity.getType());
|
||||
final ResourceMetadata metadata = mappings.getMetadataFor(entity.getType());
|
||||
|
||||
entity.doWithAssociations(new SimpleAssociationHandler() {
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@ public class RepositoryController extends AbstractRepositoryRestController {
|
||||
|
||||
for (Class<?> domainType : repositories) {
|
||||
|
||||
ResourceMetadata metadata = mappings.getMappingFor(domainType);
|
||||
ResourceMetadata metadata = mappings.getMetadataFor(domainType);
|
||||
if (metadata.isExported()) {
|
||||
resource.add(entityLinks.linkToCollectionResource(domainType));
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ import org.springframework.data.rest.core.event.AfterLinkDeleteEvent;
|
||||
import org.springframework.data.rest.core.event.AfterLinkSaveEvent;
|
||||
import org.springframework.data.rest.core.event.BeforeLinkDeleteEvent;
|
||||
import org.springframework.data.rest.core.event.BeforeLinkSaveEvent;
|
||||
import org.springframework.data.rest.core.mapping.PropertyAwareResourceMapping;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMapping;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMetadata;
|
||||
import org.springframework.data.rest.core.mapping.ResourceType;
|
||||
@@ -445,32 +446,31 @@ class RepositoryPropertyReferenceController extends AbstractRepositoryRestContro
|
||||
return conversionService.convert(id, type);
|
||||
}
|
||||
|
||||
private ResourceSupport doWithReferencedProperty(RootResourceInformation repoRequest, Serializable id,
|
||||
private ResourceSupport doWithReferencedProperty(RootResourceInformation resourceInformation, Serializable id,
|
||||
String propertyPath, Function<ReferencedProperty, ResourceSupport> handler, HttpMethod method) throws Exception {
|
||||
|
||||
RepositoryInvoker invoker = repoRequest.getInvoker();
|
||||
RepositoryInvoker invoker = resourceInformation.getInvoker();
|
||||
|
||||
if (!repoRequest.getSupportedMethods().supports(method, ResourceType.ITEM)) {
|
||||
if (!resourceInformation.getSupportedMethods().supports(method, ResourceType.ITEM)) {
|
||||
throw new HttpRequestMethodNotSupportedException(method.name());
|
||||
}
|
||||
|
||||
ResourceMetadata metadata = resourceInformation.getResourceMetadata();
|
||||
PropertyAwareResourceMapping mapping = metadata.getProperty(propertyPath);
|
||||
|
||||
if (mapping == null || !mapping.isExported()) {
|
||||
throw new ResourceNotFoundException();
|
||||
}
|
||||
|
||||
Object domainObj = invoker.invokeFindOne(id);
|
||||
|
||||
if (null == domainObj) {
|
||||
throw new ResourceNotFoundException();
|
||||
}
|
||||
|
||||
PersistentEntity<?, ?> persistentEntity = repoRequest.getPersistentEntity();
|
||||
PersistentProperty<?> prop = persistentEntity.getPersistentProperty(propertyPath);
|
||||
|
||||
if (null == prop) {
|
||||
throw new ResourceNotFoundException();
|
||||
}
|
||||
|
||||
PersistentPropertyAccessor accessor = persistentEntity.getPropertyAccessor(domainObj);
|
||||
Object propVal = accessor.getProperty(prop);
|
||||
|
||||
return handler.apply(new ReferencedProperty(prop, propVal, accessor));
|
||||
PersistentProperty<?> property = mapping.getProperty();
|
||||
PersistentPropertyAccessor accessor = property.getOwner().getPropertyAccessor(domainObj);
|
||||
return handler.apply(new ReferencedProperty(property, accessor.getProperty(property), accessor));
|
||||
}
|
||||
|
||||
private class ReferencedProperty {
|
||||
@@ -490,4 +490,5 @@ class RepositoryPropertyReferenceController extends AbstractRepositoryRestContro
|
||||
this.entity = repositories.getPersistentEntity(propertyType);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -302,7 +302,7 @@ class RepositorySearchController extends AbstractRepositoryRestController {
|
||||
continue;
|
||||
}
|
||||
|
||||
ResourceMetadata metadata = mappings.getMappingFor(parameter.getParameterType());
|
||||
ResourceMetadata metadata = mappings.getMetadataFor(parameter.getParameterType());
|
||||
|
||||
if (metadata != null && metadata.isExported()) {
|
||||
result.put(parameter.getParameterName(), prepareUris(entry.getValue()));
|
||||
|
||||
@@ -108,7 +108,7 @@ public class AlpsController {
|
||||
|
||||
for (Class<?> domainType : repositories) {
|
||||
|
||||
ResourceMetadata mapping = mappings.getMappingFor(domainType);
|
||||
ResourceMetadata mapping = mappings.getMetadataFor(domainType);
|
||||
|
||||
if (mapping.isExported()) {
|
||||
|
||||
|
||||
@@ -51,7 +51,6 @@ import org.springframework.data.rest.core.mapping.SupportedHttpMethods;
|
||||
import org.springframework.data.rest.webmvc.RootResourceInformation;
|
||||
import org.springframework.data.rest.webmvc.json.JacksonMetadata;
|
||||
import org.springframework.data.rest.webmvc.mapping.AssociationLinks;
|
||||
import org.springframework.data.rest.webmvc.mapping.PropertyMappings;
|
||||
import org.springframework.hateoas.EntityLinks;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.hateoas.TemplateVariable;
|
||||
@@ -146,7 +145,7 @@ public class RootResourceInformationToAlpsDescriptorConverter {
|
||||
|
||||
private Descriptor buildRepresentationDescriptor(Class<?> type) {
|
||||
|
||||
ResourceMetadata metadata = mappings.getMappingFor(type);
|
||||
ResourceMetadata metadata = mappings.getMetadataFor(type);
|
||||
|
||||
return descriptor().//
|
||||
id(metadata.getItemResourceRel().concat("-representation")).//
|
||||
@@ -159,7 +158,7 @@ public class RootResourceInformationToAlpsDescriptorConverter {
|
||||
private Descriptor buildCollectionResourceDescriptor(Class<?> type, RootResourceInformation resourceInformation,
|
||||
Descriptor representationDescriptor, HttpMethod method) {
|
||||
|
||||
ResourceMetadata metadata = mappings.getMappingFor(type);
|
||||
ResourceMetadata metadata = mappings.getMetadataFor(type);
|
||||
|
||||
List<Descriptor> nestedDescriptors = new ArrayList<Descriptor>();
|
||||
nestedDescriptors.addAll(getPaginationDescriptors(type, method));
|
||||
@@ -241,7 +240,7 @@ public class RootResourceInformationToAlpsDescriptorConverter {
|
||||
Descriptor representationDescriptor, HttpMethod method) {
|
||||
|
||||
PersistentEntity<?, ?> entity = resourceInformation.getPersistentEntity();
|
||||
ResourceMetadata metadata = mappings.getMappingFor(entity.getType());
|
||||
ResourceMetadata metadata = mappings.getMetadataFor(entity.getType());
|
||||
|
||||
return descriptor().//
|
||||
id(prefix(method).concat(metadata.getItemResourceRel())).//
|
||||
@@ -262,7 +261,7 @@ public class RootResourceInformationToAlpsDescriptorConverter {
|
||||
ProjectionDefinitionConfiguration projectionConfiguration = configuration.projectionConfiguration();
|
||||
|
||||
return projectionConfiguration.hasProjectionFor(type) ? Arrays.asList(buildProjectionDescriptor(mappings
|
||||
.getMappingFor(type))) : Collections.<Descriptor> emptyList();
|
||||
.getMetadataFor(type))) : Collections.<Descriptor> emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -310,8 +309,8 @@ public class RootResourceInformationToAlpsDescriptorConverter {
|
||||
final PersistentEntity<?, ?> entity = persistentEntities.getPersistentEntity(type);
|
||||
final List<Descriptor> propertyDescriptors = new ArrayList<Descriptor>();
|
||||
final JacksonMetadata jackson = new JacksonMetadata(mapper, type);
|
||||
final PropertyMappings propertyMappings = new PropertyMappings(mappings);
|
||||
final AssociationLinks associationLinks = new AssociationLinks(mappings);
|
||||
final ResourceMetadata metadata = mappings.getMetadataFor(entity.getType());
|
||||
|
||||
entity.doWithProperties(new SimplePropertyHandler() {
|
||||
|
||||
@@ -319,7 +318,7 @@ public class RootResourceInformationToAlpsDescriptorConverter {
|
||||
public void doWithPersistentProperty(PersistentProperty<?> property) {
|
||||
|
||||
BeanPropertyDefinition propertyDefinition = jackson.getDefinitionFor(property);
|
||||
ResourceMapping propertyMapping = propertyMappings.getMappingFor(property);
|
||||
ResourceMapping propertyMapping = metadata.getMappingFor(property);
|
||||
|
||||
if (propertyDefinition != null) {
|
||||
propertyDescriptors.add(//
|
||||
@@ -343,12 +342,12 @@ public class RootResourceInformationToAlpsDescriptorConverter {
|
||||
return;
|
||||
}
|
||||
|
||||
ResourceMapping mapping = propertyMappings.getMappingFor(property);
|
||||
ResourceMapping mapping = metadata.getMappingFor(property);
|
||||
|
||||
DescriptorBuilder builder = descriptor().//
|
||||
name(mapping.getRel()).doc(getDocFor(mapping.getDescription()));
|
||||
|
||||
ResourceMetadata targetTypeMapping = mappings.getMappingFor(property.getActualType());
|
||||
ResourceMetadata targetTypeMapping = mappings.getMetadataFor(property.getActualType());
|
||||
String localPath = targetTypeMapping.getRel().concat("#").concat(targetTypeMapping.getItemResourceRel());
|
||||
Link link = ControllerLinkBuilder.linkTo(AlpsController.class).slash(localPath).withSelfRel();
|
||||
|
||||
@@ -365,7 +364,7 @@ public class RootResourceInformationToAlpsDescriptorConverter {
|
||||
|
||||
private Collection<Descriptor> buildSearchResourceDescriptors(PersistentEntity<?, ?> entity) {
|
||||
|
||||
ResourceMetadata metadata = mappings.getMappingFor(entity.getType());
|
||||
ResourceMetadata metadata = mappings.getMetadataFor(entity.getType());
|
||||
List<Descriptor> descriptors = new ArrayList<Descriptor>();
|
||||
|
||||
for (MethodResourceMapping methodMapping : metadata.getSearchResourceMappings()) {
|
||||
|
||||
@@ -525,11 +525,7 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon
|
||||
|
||||
@Bean
|
||||
public ResourceMappings resourceMappings() {
|
||||
|
||||
Repositories repositories = repositories();
|
||||
RepositoryRestConfiguration config = config();
|
||||
|
||||
return new RepositoryResourceMappings(config, repositories);
|
||||
return new RepositoryResourceMappings(repositories(), persistentEntities());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -88,7 +88,7 @@ public class ResourceMetadataHandlerMethodArgumentResolver implements HandlerMet
|
||||
}
|
||||
|
||||
for (Class<?> domainType : repositories) {
|
||||
ResourceMetadata mapping = mappings.getMappingFor(domainType);
|
||||
ResourceMetadata mapping = mappings.getMetadataFor(domainType);
|
||||
if (mapping.getPath().matches(repositoryKey) && mapping.isExported()) {
|
||||
return mapping;
|
||||
}
|
||||
|
||||
@@ -33,7 +33,6 @@ import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.context.PersistentEntities;
|
||||
import org.springframework.data.rest.core.config.JsonSchemaFormat;
|
||||
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
|
||||
import org.springframework.data.rest.core.mapping.MappingResourceMetadata;
|
||||
import org.springframework.data.rest.core.mapping.ResourceDescription;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMapping;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMappings;
|
||||
@@ -137,7 +136,7 @@ public class PersistentEntityToJsonSchemaConverter implements ConditionalGeneric
|
||||
public JsonSchema convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
|
||||
final PersistentEntity<?, ?> persistentEntity = entities.getPersistentEntity((Class<?>) source);
|
||||
final ResourceMetadata metadata = mappings.getMappingFor(persistentEntity.getType());
|
||||
final ResourceMetadata metadata = mappings.getMetadataFor(persistentEntity.getType());
|
||||
|
||||
Descriptors descriptors = new Descriptors();
|
||||
List<JsonSchemaProperty> propertiesFor = getPropertiesFor(persistentEntity.getType(), metadata, descriptors);
|
||||
@@ -228,11 +227,7 @@ public class PersistentEntityToJsonSchemaConverter implements ConditionalGeneric
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
Class<?> actualType = property.getActualType();
|
||||
PersistentEntity<?, ?> propertyEntity = entities.getPersistentEntity(actualType);
|
||||
MappingResourceMetadata propertyMetadata = new MappingResourceMetadata(propertyEntity);
|
||||
|
||||
return getPropertiesFor(actualType, propertyMetadata, descriptors);
|
||||
return getPropertiesFor(property.getActualType(), mappings.getMetadataFor(property.getActualType()), descriptors);
|
||||
}
|
||||
|
||||
private Property getSchemaProperty(BeanPropertyDefinition definition, TypeInformation<?> type,
|
||||
|
||||
@@ -37,7 +37,6 @@ import org.springframework.util.Assert;
|
||||
public class AssociationLinks {
|
||||
|
||||
private final ResourceMappings mappings;
|
||||
private final PropertyMappings propertyMappings;
|
||||
|
||||
/**
|
||||
* Creates a new {@link AssociationLinks} using the given {@link ResourceMappings}.
|
||||
@@ -48,7 +47,6 @@ public class AssociationLinks {
|
||||
|
||||
Assert.notNull(mappings, "ResourceMappings must not be null!");
|
||||
|
||||
this.propertyMappings = new PropertyMappings(mappings);
|
||||
this.mappings = mappings;
|
||||
}
|
||||
|
||||
@@ -68,7 +66,8 @@ public class AssociationLinks {
|
||||
|
||||
if (isLinkableAssociation(property)) {
|
||||
|
||||
ResourceMapping propertyMapping = propertyMappings.getMappingFor(property);
|
||||
ResourceMetadata metadata = mappings.getMetadataFor(property.getOwner().getType());
|
||||
ResourceMapping propertyMapping = metadata.getMappingFor(property);
|
||||
|
||||
String href = path.slash(propertyMapping.getPath()).toString();
|
||||
String rel = propertyMapping.getRel();
|
||||
@@ -91,13 +90,13 @@ public class AssociationLinks {
|
||||
return false;
|
||||
}
|
||||
|
||||
ResourceMetadata metadata = mappings.getMappingFor(property.getOwner().getType());
|
||||
ResourceMetadata metadata = mappings.getMetadataFor(property.getOwner().getType());
|
||||
|
||||
if (metadata != null && !metadata.isExported(property)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
metadata = mappings.getMappingFor(property.getActualType());
|
||||
metadata = mappings.getMetadataFor(property.getActualType());
|
||||
return metadata == null ? false : metadata.isExported();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 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.mapping;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.rest.core.mapping.MappingResourceMetadata;
|
||||
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.util.Assert;
|
||||
|
||||
/**
|
||||
* Value object for {@link ResourceMapping}s for {@link PersistentProperty} instances.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @see 2.1
|
||||
*/
|
||||
public class PropertyMappings {
|
||||
|
||||
private final ResourceMappings resourceMappings;
|
||||
private final Map<PersistentProperty<?>, ResourceMetadata> resourceMetadata;
|
||||
|
||||
/**
|
||||
* Creates a new {@link PropertyMappings} instance for the given {@link ResourceMappings}.
|
||||
*
|
||||
* @param resourceMappings
|
||||
*/
|
||||
public PropertyMappings(ResourceMappings resourceMappings) {
|
||||
|
||||
Assert.notNull(resourceMappings, "ResourceMappings must not be null!");
|
||||
|
||||
this.resourceMappings = resourceMappings;
|
||||
this.resourceMetadata = new HashMap<PersistentProperty<?>, ResourceMetadata>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link ResourceMapping} for the given {@link PersistentProperty}.
|
||||
*
|
||||
* @param property can be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public ResourceMapping getMappingFor(PersistentProperty<?> property) {
|
||||
|
||||
Assert.notNull(property, "PersistentProperty must not be null!");
|
||||
|
||||
ResourceMetadata metadata = resourceMetadata.get(property);
|
||||
|
||||
if (metadata != null) {
|
||||
return metadata.getMappingFor(property);
|
||||
}
|
||||
|
||||
metadata = resourceMappings.getMappingFor(property.getOwner().getType());
|
||||
|
||||
if (metadata != null) {
|
||||
return cacheAndReturn(metadata, property);
|
||||
}
|
||||
|
||||
return cacheAndReturn(new MappingResourceMetadata(property.getOwner()), property);
|
||||
}
|
||||
|
||||
private ResourceMapping cacheAndReturn(ResourceMetadata metadata, PersistentProperty<?> property) {
|
||||
|
||||
resourceMetadata.put(property, metadata);
|
||||
return metadata.getMappingFor(property);
|
||||
}
|
||||
}
|
||||
@@ -79,7 +79,7 @@ public class PersistentEntityProjector implements Projector {
|
||||
|
||||
Assert.notNull(source, "Projection source must not be null!");
|
||||
|
||||
ResourceMetadata metadata = mappings.getMappingFor(source.getClass());
|
||||
ResourceMetadata metadata = mappings.getMetadataFor(source.getClass());
|
||||
Class<?> projection = metadata == null ? null : metadata.getExcerptProjection();
|
||||
|
||||
if (projection == null) {
|
||||
@@ -96,7 +96,7 @@ public class PersistentEntityProjector implements Projector {
|
||||
@Override
|
||||
public boolean hasExcerptProjection(Class<?> type) {
|
||||
|
||||
ResourceMetadata metadata = mappings.getMappingFor(type);
|
||||
ResourceMetadata metadata = mappings.getMetadataFor(type);
|
||||
return metadata == null ? false : metadata.getExcerptProjection() != null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ public class RepositoryEntityLinks extends AbstractEntityLinks {
|
||||
@Override
|
||||
public LinkBuilder linkFor(Class<?> type) {
|
||||
|
||||
ResourceMetadata metadata = mappings.getMappingFor(type);
|
||||
ResourceMetadata metadata = mappings.getMetadataFor(type);
|
||||
return new RepositoryLinkBuilder(metadata, new BaseUri(config.getBaseUri()));
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ public class RepositoryEntityLinks extends AbstractEntityLinks {
|
||||
*/
|
||||
public Link linkToPagedResource(Class<?> type, Pageable pageable) {
|
||||
|
||||
ResourceMetadata metadata = mappings.getMappingFor(type);
|
||||
ResourceMetadata metadata = mappings.getMetadataFor(type);
|
||||
String href = linkFor(type).toString();
|
||||
UriComponents components = prepareUri(href, metadata, pageable);
|
||||
|
||||
@@ -158,7 +158,7 @@ public class RepositoryEntityLinks extends AbstractEntityLinks {
|
||||
|
||||
Assert.isInstanceOf(Serializable.class, id, "Id must be assignable to Serializable!");
|
||||
|
||||
ResourceMetadata metadata = mappings.getMappingFor(type);
|
||||
ResourceMetadata metadata = mappings.getMetadataFor(type);
|
||||
String mappedId = idConverters.getPluginFor(type, DefaultIdConverter.INSTANCE).toRequestId((Serializable) id, type);
|
||||
|
||||
Link link = linkFor(type).slash(mappedId).withRel(metadata.getItemResourceRel());
|
||||
|
||||
@@ -74,14 +74,7 @@ public class RepositoryLinkBuilder extends LinkBuilderSupport<RepositoryLinkBuil
|
||||
}
|
||||
|
||||
public RepositoryLinkBuilder slash(PersistentProperty<?> property) {
|
||||
|
||||
String propName = property.getName();
|
||||
|
||||
if (metadata.isManagedResource(property)) {
|
||||
return slash(metadata.getMappingFor(property).getPath());
|
||||
} else {
|
||||
return slash(propName);
|
||||
}
|
||||
return slash(metadata.getMappingFor(property).getPath());
|
||||
}
|
||||
|
||||
public Link withResourceRel() {
|
||||
|
||||
@@ -79,7 +79,7 @@ public abstract class AbstractControllerIntegrationTests {
|
||||
|
||||
PersistentEntity<?, ?> entity = repositories.getPersistentEntity(domainType);
|
||||
|
||||
return new RootResourceInformation(mappings.getMappingFor(domainType), entity,
|
||||
return new RootResourceInformation(mappings.getMetadataFor(domainType), entity,
|
||||
invokerFactory.getInvokerFor(domainType));
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ public abstract class AbstractControllerIntegrationTests {
|
||||
}
|
||||
|
||||
protected ResourceMetadata getMetadata(Class<?> domainType) {
|
||||
return mappings.getMappingFor(domainType);
|
||||
return mappings.getMetadataFor(domainType);
|
||||
}
|
||||
|
||||
private static enum StubProjector implements Projector {
|
||||
|
||||
@@ -17,23 +17,23 @@ package org.springframework.data.rest.webmvc;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
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.data.annotation.Reference;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.context.PersistentEntities;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||
import org.springframework.data.rest.core.Path;
|
||||
import org.springframework.data.rest.core.annotation.RestResource;
|
||||
import org.springframework.data.rest.core.mapping.MappingResourceMetadata;
|
||||
import org.springframework.data.rest.core.mapping.PersistentEntitiesResourceMappings;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMappings;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMetadata;
|
||||
import org.springframework.data.rest.webmvc.mapping.AssociationLinks;
|
||||
@@ -47,7 +47,7 @@ public class AssociationLinksUnitTests {
|
||||
|
||||
AssociationLinks links;
|
||||
|
||||
@Mock ResourceMappings mappings;
|
||||
ResourceMappings mappings;
|
||||
|
||||
MongoMappingContext mappingContext;
|
||||
MongoPersistentEntity<?> entity;
|
||||
@@ -56,13 +56,10 @@ public class AssociationLinksUnitTests {
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
this.links = new AssociationLinks(mappings);
|
||||
|
||||
this.mappingContext = new MongoMappingContext();
|
||||
this.entity = mappingContext.getPersistentEntity(Sample.class);
|
||||
this.sampleResourceMetadata = new MappingResourceMetadata(entity);
|
||||
|
||||
when(mappings.getMappingFor(Sample.class)).thenReturn(sampleResourceMetadata);
|
||||
this.mappings = new PersistentEntitiesResourceMappings(new PersistentEntities(Arrays.asList(mappingContext)));
|
||||
this.links = new AssociationLinks(mappings);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -81,20 +78,12 @@ public class AssociationLinksUnitTests {
|
||||
assertThat(links.isLinkableAssociation(null), is(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-262
|
||||
*/
|
||||
@Test
|
||||
public void consideredExportedPropertyLinkable() {
|
||||
assertThat(links.isLinkableAssociation(exposeProperty("property")), is(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-262
|
||||
*/
|
||||
@Test
|
||||
public void consideredHiddenPropertyUnlinkable() {
|
||||
assertThat(links.isLinkableAssociation(exposeProperty("hiddenProperty")), is(false));
|
||||
assertThat(links.isLinkableAssociation(entity.getPersistentProperty("hiddenProperty")), is(false));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -113,7 +102,7 @@ public class AssociationLinksUnitTests {
|
||||
@Test
|
||||
public void createsLinkToAssociationProperty() {
|
||||
|
||||
PersistentProperty<?> property = exposeProperty("property");
|
||||
PersistentProperty<?> property = entity.getPersistentProperty("property");
|
||||
List<Link> associationLinks = links.getLinksFor(property.getAssociation(), new Path("/base"));
|
||||
|
||||
assertThat(associationLinks, hasSize(1));
|
||||
@@ -126,42 +115,17 @@ public class AssociationLinksUnitTests {
|
||||
@Test
|
||||
public void doesNotCreateLinksForHiddenProperty() {
|
||||
|
||||
PersistentProperty<?> property = exposeProperty("hiddenProperty");
|
||||
PersistentProperty<?> property = entity.getPersistentProperty("hiddenProperty");
|
||||
assertThat(links.getLinksFor(property.getAssociation(), new Path("/sample")), hasSize(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-262
|
||||
*/
|
||||
@Test
|
||||
public void doesNotCreateLinksForUnexportedProperty() {
|
||||
|
||||
PersistentProperty<?> property = entity.getPersistentProperty("unexportedProperty");
|
||||
assertThat(links.getLinksFor(property.getAssociation(), new Path("/sample")), hasSize(0));
|
||||
}
|
||||
|
||||
private PersistentProperty<?> exposeProperty(String name) {
|
||||
|
||||
MongoPersistentProperty property = entity.getPersistentProperty(name);
|
||||
ResourceMetadata metadata = new MappingResourceMetadata(mappingContext.getPersistentEntity(property));
|
||||
|
||||
when(mappings.getMappingFor(property.getActualType())).thenReturn(metadata);
|
||||
|
||||
return property;
|
||||
}
|
||||
|
||||
public static class Sample {
|
||||
|
||||
@Reference Property property;
|
||||
@RestResource(exported = false) @Reference Property hiddenProperty;
|
||||
@Reference UnexportedProperty unexportedProperty;
|
||||
}
|
||||
|
||||
public static class Property {
|
||||
|
||||
}
|
||||
|
||||
public static class UnexportedProperty {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.rest.webmvc;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.rest.webmvc.jpa.Book;
|
||||
import org.springframework.data.rest.webmvc.jpa.JpaRepositoryConfig;
|
||||
import org.springframework.data.rest.webmvc.jpa.TestDataPopulator;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@ContextConfiguration(classes = JpaRepositoryConfig.class)
|
||||
@Transactional
|
||||
public class RepositoryPropertyReferenceControllerIntegrationTests extends AbstractControllerIntegrationTests {
|
||||
|
||||
@Autowired RepositoryPropertyReferenceController controller;
|
||||
@Autowired TestDataPopulator populator;
|
||||
|
||||
PersistentEntityResourceAssembler assembler;
|
||||
RootResourceInformation information;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
this.assembler = mock(PersistentEntityResourceAssembler.class);
|
||||
this.information = getResourceInformation(Book.class);
|
||||
this.populator.populateRepositories();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exposesResourceForCustomizedPropertyResourcePath() throws Exception {
|
||||
assertThat(controller.followPropertyReference(information, 1L, "creators", assembler).getStatusCode(),
|
||||
is(HttpStatus.OK));
|
||||
}
|
||||
|
||||
@Test(expected = ResourceNotFoundException.class)
|
||||
public void doesNotExposeOriginalPathIfPropertyResourcePathIsCustomized() throws Exception {
|
||||
controller.followPropertyReference(information, 1L, "authors", assembler);
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,8 @@ import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToMany;
|
||||
|
||||
import org.springframework.data.rest.core.annotation.RestResource;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@@ -34,7 +36,7 @@ public class Book {
|
||||
public String isbn;
|
||||
|
||||
@ManyToMany(cascade = { CascadeType.MERGE })//
|
||||
public Set<Author> authors;
|
||||
@RestResource(path = "creators") public Set<Author> authors;
|
||||
|
||||
public String title;
|
||||
|
||||
|
||||
@@ -120,7 +120,7 @@ public class JpaWebTests extends CommonWebTests {
|
||||
|
||||
mvc.perform(get("/")). //
|
||||
andExpect(status().isOk()). //
|
||||
andExpect(doesNotHaveLinkWithRel(mappings.getMappingFor(CreditCard.class).getRel()));
|
||||
andExpect(doesNotHaveLinkWithRel(mappings.getMetadataFor(CreditCard.class).getRel()));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -94,7 +94,7 @@ public class RepositoryTestsConfig {
|
||||
|
||||
@Bean
|
||||
public Module persistentEntityModule() {
|
||||
return new PersistentEntityJackson2Module(new RepositoryResourceMappings(config(), repositories()),
|
||||
return new PersistentEntityJackson2Module(new RepositoryResourceMappings(repositories(), persistentEntities()),
|
||||
persistentEntities(), config(), new UriToEntityConverter(persistentEntities(), defaultConversionService()));
|
||||
}
|
||||
|
||||
|
||||
@@ -18,11 +18,13 @@ package org.springframework.data.rest.webmvc.support;
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.mapping.context.PersistentEntities;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
||||
import org.springframework.data.rest.core.mapping.MappingResourceMetadata;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMetadata;
|
||||
import org.springframework.data.rest.core.mapping.PersistentEntitiesResourceMappings;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMappings;
|
||||
import org.springframework.data.rest.webmvc.BaseUri;
|
||||
import org.springframework.data.rest.webmvc.TestMvcClient;
|
||||
import org.springframework.data.rest.webmvc.mongodb.Profile;
|
||||
@@ -58,10 +60,11 @@ public class RepositoryLinkBuildUnitTests {
|
||||
|
||||
private void assertRootUriFor(String baseUri, String expectedUri) {
|
||||
|
||||
MongoPersistentEntity<?> entity = context.getPersistentEntity(Profile.class);
|
||||
ResourceMetadata metadata = new MappingResourceMetadata(entity);
|
||||
context.getPersistentEntity(Profile.class);
|
||||
ResourceMappings mappings = new PersistentEntitiesResourceMappings(new PersistentEntities(Arrays.asList(context)));
|
||||
|
||||
RepositoryLinkBuilder builder = new RepositoryLinkBuilder(metadata, new BaseUri(baseUri));
|
||||
RepositoryLinkBuilder builder = new RepositoryLinkBuilder(mappings.getMetadataFor(Profile.class), new BaseUri(
|
||||
baseUri));
|
||||
Link link = builder.withSelfRel();
|
||||
|
||||
assertThat(link.getHref(), is(expectedUri));
|
||||
|
||||
Reference in New Issue
Block a user