From 554d6cb27b84cebedc651a5a25b10ccfb0cf8265 Mon Sep 17 00:00:00 2001 From: Oliver Drotbohm Date: Fri, 15 Feb 2019 11:05:05 +0100 Subject: [PATCH] DATAREST-1341 - Further API adaption for Spring HATEOAS 1.0. --- .../mapping/CollectionResourceMapping.java | 4 +- .../rest/core/mapping/ParameterMetadata.java | 5 +- .../PersistentPropertyResourceMapping.java | 9 +- .../RepositoryAwareResourceMetadata.java | 5 +- .../RepositoryCollectionResourceMapping.java | 15 +-- .../RepositoryMethodResourceMapping.java | 12 +- .../rest/core/mapping/ResourceMapping.java | 3 +- .../core/mapping/SearchResourceMappings.java | 44 +++---- .../mapping/SimpleResourceDescription.java | 5 +- .../TypeBasedCollectionResourceMapping.java | 7 +- .../mapping/TypedResourceDescription.java | 11 +- .../core/support/RepositoryRelProvider.java | 5 +- .../rest/core/support/SimpleRelProvider.java | 11 +- ...stentPropertyResourceMappingUnitTests.java | 8 +- ...oryCollectionResourceMappingUnitTests.java | 17 +-- ...ositoryMethodResourceMappingUnitTests.java | 5 +- ...itoryResourceMappingsIntegrationTests.java | 5 +- ...sedCollectionResourceMappingUnitTests.java | 9 +- .../tests/AbstractWebIntegrationTests.java | 53 ++++----- .../data/rest/tests/CommonWebTests.java | 53 +++++---- .../data/rest/tests/ResourceTester.java | 5 +- .../data/rest/tests/TestMvcClient.java | 109 ++++++++++-------- .../gemfire/GemfireRepositoryConfig.java | 1 - .../rest/tests/gemfire/GemfireWebTests.java | 7 +- .../rest/webmvc/jpa/CorsIntegrationTests.java | 7 +- .../jpa/JpaDefaultPageableWebTests.java | 6 +- .../data/rest/webmvc/jpa/JpaWebTests.java | 101 ++++++++-------- .../webmvc/jpa/ProfileIntegrationTests.java | 1 - .../PersistentEntitySerializationTests.java | 32 +++-- ...RepositoryEntityLinksIntegrationTests.java | 13 ++- .../rest/tests/mongodb/MongoWebTests.java | 24 ++-- ...tityResourceAssemblerIntegrationTests.java | 10 +- .../data/rest/webmvc/solr/SolrWebTests.java | 19 +-- .../AbstractRepositoryRestController.java | 6 +- .../webmvc/EmbeddedResourcesAssembler.java | 5 +- .../rest/webmvc/PersistentEntityResource.java | 5 +- .../webmvc/RepositoryEntityController.java | 31 +++-- ...RepositoryPropertyReferenceController.java | 12 +- ...eInformationToAlpsDescriptorConverter.java | 26 +++-- .../json/PersistentEntityJackson2Module.java | 2 +- .../LinkCollectingAssociationHandler.java | 6 +- .../rest/webmvc/mapping/LinkCollector.java | 55 +++------ .../webmvc/support/RepositoryEntityLinks.java | 52 ++++----- .../PersistentEntityResourceUnitTests.java | 3 +- 44 files changed, 423 insertions(+), 401 deletions(-) diff --git a/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/CollectionResourceMapping.java b/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/CollectionResourceMapping.java index 00bd9a135..956a7b3e0 100644 --- a/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/CollectionResourceMapping.java +++ b/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/CollectionResourceMapping.java @@ -15,6 +15,8 @@ */ package org.springframework.data.rest.core.mapping; +import org.springframework.hateoas.LinkRelation; + /** * A custom resource mapping for collection resources. * @@ -27,7 +29,7 @@ public interface CollectionResourceMapping extends ResourceMapping { * * @return */ - String getItemResourceRel(); + LinkRelation getItemResourceRel(); /** * Returns the {@link ResourceDescription} for the item resource. diff --git a/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/ParameterMetadata.java b/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/ParameterMetadata.java index 717c1a040..87fd6bb24 100644 --- a/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/ParameterMetadata.java +++ b/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/ParameterMetadata.java @@ -17,6 +17,7 @@ package org.springframework.data.rest.core.mapping; import org.springframework.core.MethodParameter; import org.springframework.data.rest.core.annotation.Description; +import org.springframework.hateoas.LinkRelation; import org.springframework.util.Assert; /** @@ -42,8 +43,8 @@ public final class ParameterMetadata { Assert.hasText(name, "Parameter name must not be null or empty!"); Assert.hasText(baseRel, "Method rel must not be null!"); - ResourceDescription fallback = TypedResourceDescription.defaultFor(baseRel.concat(".").concat(name), - parameter.getParameterType()); + ResourceDescription fallback = TypedResourceDescription + .defaultFor(LinkRelation.of(baseRel.concat(".").concat(name)), parameter.getParameterType()); Description annotation = parameter.getParameterAnnotation(Description.class); this.description = annotation == null ? fallback : new AnnotationBasedResourceDescription(annotation, fallback); diff --git a/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/PersistentPropertyResourceMapping.java b/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/PersistentPropertyResourceMapping.java index 6df9fcb56..d1483458f 100644 --- a/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/PersistentPropertyResourceMapping.java +++ b/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/PersistentPropertyResourceMapping.java @@ -22,6 +22,7 @@ import org.springframework.data.rest.core.Path; import org.springframework.data.rest.core.annotation.Description; import org.springframework.data.rest.core.annotation.RestResource; import org.springframework.data.util.Optionals; +import org.springframework.hateoas.LinkRelation; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -71,11 +72,11 @@ class PersistentPropertyResourceMapping implements PropertyAwareResourceMapping * @see org.springframework.data.rest.core.mapping.ResourceMapping#getRel() */ @Override - public String getRel() { + public LinkRelation getRel() { - return annotation.filter(it -> StringUtils.hasText(it.rel()))// - .map(it -> it.rel())// - .orElseGet(() -> property.getName()); + return LinkRelation.of(annotation.filter(it -> StringUtils.hasText(it.rel())) // + .map(it -> it.rel()) // + .orElseGet(() -> property.getName())); } /* diff --git a/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/RepositoryAwareResourceMetadata.java b/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/RepositoryAwareResourceMetadata.java index db45e8afb..d89922c65 100644 --- a/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/RepositoryAwareResourceMetadata.java +++ b/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/RepositoryAwareResourceMetadata.java @@ -21,6 +21,7 @@ import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.repository.core.RepositoryMetadata; import org.springframework.data.rest.core.Path; +import org.springframework.hateoas.LinkRelation; import org.springframework.util.Assert; /** @@ -129,7 +130,7 @@ class RepositoryAwareResourceMetadata implements ResourceMetadata { * @see org.springframework.data.rest.core.mapping.CollectionResourceMapping#getCollectionRel() */ @Override - public String getRel() { + public LinkRelation getRel() { return mapping.getRel(); } @@ -138,7 +139,7 @@ class RepositoryAwareResourceMetadata implements ResourceMetadata { * @see org.springframework.data.rest.core.mapping.CollectionResourceMapping#getSingleResourceRel() */ @Override - public String getItemResourceRel() { + public LinkRelation getItemResourceRel() { return mapping.getItemResourceRel(); } diff --git a/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/RepositoryCollectionResourceMapping.java b/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/RepositoryCollectionResourceMapping.java index a7abcccb7..5537420fe 100644 --- a/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/RepositoryCollectionResourceMapping.java +++ b/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/RepositoryCollectionResourceMapping.java @@ -22,6 +22,7 @@ import org.springframework.data.repository.core.RepositoryMetadata; import org.springframework.data.rest.core.Path; import org.springframework.data.rest.core.annotation.RepositoryRestResource; import org.springframework.data.rest.core.annotation.RestResource; +import org.springframework.hateoas.LinkRelation; import org.springframework.hateoas.RelProvider; import org.springframework.hateoas.core.EvoInflectorRelProvider; import org.springframework.util.Assert; @@ -111,18 +112,18 @@ class RepositoryCollectionResourceMapping implements CollectionResourceMapping { * @see org.springframework.data.rest.core.mapping.ResourceMapping#getRel() */ @Override - public String getRel() { + public LinkRelation getRel() { - String fallback = domainTypeMapping.getRel(); + LinkRelation fallback = domainTypeMapping.getRel(); if (repositoryAnnotation != null) { String rel = repositoryAnnotation.collectionResourceRel(); - return StringUtils.hasText(rel) ? rel : fallback; + return StringUtils.hasText(rel) ? LinkRelation.of(rel) : fallback; } if (annotation != null) { String rel = annotation.rel(); - return StringUtils.hasText(rel) ? rel : fallback; + return StringUtils.hasText(rel) ? LinkRelation.of(rel) : fallback; } return fallback; @@ -133,13 +134,13 @@ class RepositoryCollectionResourceMapping implements CollectionResourceMapping { * @see org.springframework.data.rest.core.mapping.CollectionResourceMapping#getSingleResourceRel() */ @Override - public String getItemResourceRel() { + public LinkRelation getItemResourceRel() { - String fallback = domainTypeMapping.getItemResourceRel(); + LinkRelation fallback = domainTypeMapping.getItemResourceRel(); if (repositoryAnnotation != null) { String rel = repositoryAnnotation.itemResourceRel(); - return StringUtils.hasText(rel) ? rel : fallback; + return StringUtils.hasText(rel) ? LinkRelation.of(rel) : fallback; } return fallback; diff --git a/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/RepositoryMethodResourceMapping.java b/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/RepositoryMethodResourceMapping.java index 6a9248485..c0f75a0ba 100644 --- a/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/RepositoryMethodResourceMapping.java +++ b/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/RepositoryMethodResourceMapping.java @@ -30,6 +30,7 @@ import org.springframework.data.repository.core.RepositoryMetadata; import org.springframework.data.repository.query.Param; import org.springframework.data.rest.core.Path; import org.springframework.data.rest.core.annotation.RestResource; +import org.springframework.hateoas.LinkRelation; import org.springframework.hateoas.core.AnnotationAttribute; import org.springframework.hateoas.core.MethodParameters; import org.springframework.util.Assert; @@ -46,7 +47,7 @@ class RepositoryMethodResourceMapping implements MethodResourceMapping { private static final AnnotationAttribute PARAM_VALUE = new AnnotationAttribute(Param.class); private final boolean isExported; - private final String rel; + private final LinkRelation rel; private final Path path; private final Method method; private final boolean paging; @@ -70,14 +71,15 @@ class RepositoryMethodResourceMapping implements MethodResourceMapping { Assert.notNull(resourceMapping, "ResourceMapping must not be null!"); RestResource annotation = AnnotationUtils.findAnnotation(method, RestResource.class); - String resourceRel = resourceMapping.getRel(); + LinkRelation resourceRel = resourceMapping.getRel(); this.isExported = annotation != null ? annotation.exported() : exposeMethodsByDefault; - this.rel = annotation == null || !StringUtils.hasText(annotation.rel()) ? method.getName() : annotation.rel(); + this.rel = LinkRelation + .of(annotation == null || !StringUtils.hasText(annotation.rel()) ? method.getName() : annotation.rel()); this.path = annotation == null || !StringUtils.hasText(annotation.path()) ? new Path(method.getName()) : new Path(annotation.path()); this.method = method; - this.parameterMetadata = discoverParameterMetadata(method, resourceRel.concat(".").concat(rel)); + this.parameterMetadata = discoverParameterMetadata(method, resourceRel.value().concat(".").concat(rel.value())); List> parameterTypes = Arrays.asList(method.getParameterTypes()); @@ -114,7 +116,7 @@ class RepositoryMethodResourceMapping implements MethodResourceMapping { * @see org.springframework.data.rest.core.mapping.ResourceMapping#getRel() */ @Override - public String getRel() { + public LinkRelation getRel() { return rel; } diff --git a/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/ResourceMapping.java b/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/ResourceMapping.java index d2240e6e5..4e9622a54 100644 --- a/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/ResourceMapping.java +++ b/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/ResourceMapping.java @@ -16,6 +16,7 @@ package org.springframework.data.rest.core.mapping; import org.springframework.data.rest.core.Path; +import org.springframework.hateoas.LinkRelation; /** * Mapping information for components to be exported as REST resources. @@ -36,7 +37,7 @@ public interface ResourceMapping { * * @return will never be {@literal null}. */ - String getRel(); + LinkRelation getRel(); /** * Returns the path the resource is exposed under. diff --git a/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/SearchResourceMappings.java b/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/SearchResourceMappings.java index 42b910957..0b63d2d11 100644 --- a/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/SearchResourceMappings.java +++ b/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/SearchResourceMappings.java @@ -17,13 +17,14 @@ package org.springframework.data.rest.core.mapping; import java.lang.reflect.Method; import java.util.HashMap; -import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Set; +import java.util.stream.Stream; import org.springframework.data.rest.core.Path; +import org.springframework.hateoas.IanaLinkRelations; +import org.springframework.hateoas.LinkRelation; import org.springframework.util.Assert; /** @@ -37,7 +38,7 @@ public class SearchResourceMappings implements Iterable, + "%s are mapped to %s! Tweak configuration to get to unambiguous paths!"; private static final Path PATH = new Path("/search"); - private static final String REL = "search"; + private static final LinkRelation REL = IanaLinkRelations.SEARCH; private final Map mappings; @@ -57,8 +58,8 @@ public class SearchResourceMappings implements Iterable, MethodResourceMapping existing = this.mappings.get(mapping.getPath()); if (existing != null) { - throw new IllegalStateException(String.format(AMBIGUOUS_MAPPING, existing.getMethod(), mapping.getMethod(), - existing.getPath())); + throw new IllegalStateException( + String.format(AMBIGUOUS_MAPPING, existing.getMethod(), mapping.getMethod(), existing.getPath())); } this.mappings.put(mapping.getPath(), mapping); @@ -85,38 +86,27 @@ public class SearchResourceMappings implements Iterable, * @return * @since 2.3 */ - public Iterable getExportedMappings() { + public Stream getExportedMappings() { - Set result = new HashSet(mappings.values().size()); - - for (MethodResourceMapping mapping : this) { - if (mapping.isExported()) { - result.add(mapping); - } - } - - return result; + return mappings.values().stream() // + .filter(MethodResourceMapping::isExported); } /** * Returns the {@link MappingResourceMetadata} for the given relation name. * - * @param rel must not be {@literal null} or empty. + * @param rel must not be {@literal null}. * @return * @since 2.3 */ - public MethodResourceMapping getExportedMethodMappingForRel(String rel) { + public MethodResourceMapping getExportedMethodMappingForRel(LinkRelation rel) { - Assert.hasText(rel, "Rel must not be null or empty!"); + Assert.notNull(rel, "Rel must not be null!"); - for (MethodResourceMapping mapping : this) { - - if (mapping.isExported() && mapping.getRel().equals(rel)) { - return mapping; - } - } - - return null; + return mappings.values().stream() // + .filter(MethodResourceMapping::isExported) // + .filter(it -> it.getRel().isSameAs(rel)) // + .findFirst().orElse(null); } /** @@ -154,7 +144,7 @@ public class SearchResourceMappings implements Iterable, * @see org.springframework.data.rest.core.mapping.ResourceMapping#getRel() */ @Override - public String getRel() { + public LinkRelation getRel() { return REL; } diff --git a/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/SimpleResourceDescription.java b/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/SimpleResourceDescription.java index e923836ba..f75e9ffa3 100644 --- a/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/SimpleResourceDescription.java +++ b/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/SimpleResourceDescription.java @@ -15,6 +15,7 @@ */ package org.springframework.data.rest.core.mapping; +import org.springframework.hateoas.LinkRelation; import org.springframework.http.MediaType; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -45,8 +46,8 @@ public class SimpleResourceDescription extends ResolvableResourceDescriptionSupp this.mediaType = mediaType; } - public static ResourceDescription defaultFor(String rel) { - return new SimpleResourceDescription(String.format("%s.%s", DEFAULT_KEY_PREFIX, rel), DEFAULT_MEDIA_TYPE); + public static ResourceDescription defaultFor(LinkRelation rel) { + return new SimpleResourceDescription(String.format("%s.%s", DEFAULT_KEY_PREFIX, rel.value()), DEFAULT_MEDIA_TYPE); } /* diff --git a/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/TypeBasedCollectionResourceMapping.java b/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/TypeBasedCollectionResourceMapping.java index 60c5269d9..28fdfb79f 100644 --- a/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/TypeBasedCollectionResourceMapping.java +++ b/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/TypeBasedCollectionResourceMapping.java @@ -21,6 +21,7 @@ import org.springframework.core.annotation.AnnotationUtils; import org.springframework.data.rest.core.Path; import org.springframework.data.rest.core.annotation.Description; import org.springframework.data.rest.core.annotation.RestResource; +import org.springframework.hateoas.LinkRelation; import org.springframework.hateoas.RelProvider; import org.springframework.hateoas.core.EvoInflectorRelProvider; import org.springframework.util.Assert; @@ -91,13 +92,13 @@ class TypeBasedCollectionResourceMapping implements CollectionResourceMapping { * @see org.springframework.data.rest.core.mapping.ResourceMapping#getRel() */ @Override - public String getRel() { + public LinkRelation getRel() { if (annotation == null || !StringUtils.hasText(annotation.rel())) { return relProvider.getCollectionResourceRelFor(type); } - return annotation.rel(); + return LinkRelation.of(annotation.rel()); } /* @@ -105,7 +106,7 @@ class TypeBasedCollectionResourceMapping implements CollectionResourceMapping { * @see org.springframework.data.rest.core.mapping.CollectionResourceMapping#getSingleResourceRel() */ @Override - public String getItemResourceRel() { + public LinkRelation getItemResourceRel() { return relProvider.getItemResourceRelFor(type); } diff --git a/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/TypedResourceDescription.java b/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/TypedResourceDescription.java index e24f05fa5..0033e2774 100644 --- a/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/TypedResourceDescription.java +++ b/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/TypedResourceDescription.java @@ -18,6 +18,7 @@ package org.springframework.data.rest.core.mapping; import java.util.Arrays; import org.springframework.data.mapping.PersistentProperty; +import org.springframework.hateoas.LinkRelation; import org.springframework.http.MediaType; import org.springframework.util.StringUtils; @@ -46,19 +47,19 @@ public class TypedResourceDescription extends SimpleResourceDescription { this.type = type == null ? Object.class : type; } - public static ResourceDescription defaultFor(String rel, PersistentProperty property) { + public static ResourceDescription defaultFor(LinkRelation rel, PersistentProperty property) { return defaultFor(rel, property.getName(), property.getType()); } - public static ResourceDescription defaultFor(String rel, String name, Class type) { + public static ResourceDescription defaultFor(LinkRelation rel, String name, Class type) { - String message = String.format("%s.%s.%s", DEFAULT_KEY_PREFIX, rel, name); + String message = String.format("%s.%s.%s", DEFAULT_KEY_PREFIX, rel.value(), name); return new TypedResourceDescription(message, DEFAULT_MEDIA_TYPE, type); } - public static ResourceDescription defaultFor(String rel, Class type) { + public static ResourceDescription defaultFor(LinkRelation rel, Class type) { - String message = String.format("%s.%s", DEFAULT_KEY_PREFIX, rel); + String message = String.format("%s.%s", DEFAULT_KEY_PREFIX, rel.value()); return new TypedResourceDescription(message, DEFAULT_MEDIA_TYPE, type); } diff --git a/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/support/RepositoryRelProvider.java b/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/support/RepositoryRelProvider.java index 3a14696f7..5129fdc65 100644 --- a/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/support/RepositoryRelProvider.java +++ b/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/support/RepositoryRelProvider.java @@ -19,6 +19,7 @@ import org.springframework.beans.factory.ObjectFactory; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.data.rest.core.mapping.ResourceMappings; +import org.springframework.hateoas.LinkRelation; import org.springframework.hateoas.RelProvider; import org.springframework.util.Assert; @@ -48,7 +49,7 @@ public class RepositoryRelProvider implements RelProvider { * @see org.springframework.hateoas.RelProvider#getCollectionResourceRelFor(java.lang.Class) */ @Override - public String getCollectionResourceRelFor(Class type) { + public LinkRelation getCollectionResourceRelFor(Class type) { return mappings.getObject().getMetadataFor(type).getRel(); } @@ -57,7 +58,7 @@ public class RepositoryRelProvider implements RelProvider { * @see org.springframework.hateoas.RelProvider#getItemResourceRelFor(java.lang.Class) */ @Override - public String getItemResourceRelFor(Class type) { + public LinkRelation getItemResourceRelFor(Class type) { return mappings.getObject().getMetadataFor(type).getItemResourceRel(); } diff --git a/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/support/SimpleRelProvider.java b/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/support/SimpleRelProvider.java index 7931d0e7e..2ecfdeeab 100644 --- a/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/support/SimpleRelProvider.java +++ b/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/support/SimpleRelProvider.java @@ -15,6 +15,7 @@ */ package org.springframework.data.rest.core.support; +import org.springframework.hateoas.LinkRelation; import org.springframework.hateoas.RelProvider; import org.springframework.util.StringUtils; @@ -37,10 +38,10 @@ public class SimpleRelProvider implements RelProvider { * @see org.springframework.hateoas.RelProvider#getItemResourceRelFor(java.lang.Class) */ @Override - public String getItemResourceRelFor(Class type) { + public LinkRelation getItemResourceRelFor(Class type) { - String collectionRel = getCollectionResourceRelFor(type); - return String.format("%s.%s", collectionRel, collectionRel); + LinkRelation collectionRel = getCollectionResourceRelFor(type); + return LinkRelation.of(String.format("%s.%s", collectionRel.value(), collectionRel.value())); } /* @@ -48,7 +49,7 @@ public class SimpleRelProvider implements RelProvider { * @see org.springframework.hateoas.RelProvider#getCollectionResourceRelFor(java.lang.Class) */ @Override - public String getCollectionResourceRelFor(Class type) { - return StringUtils.uncapitalize(type.getSimpleName()); + public LinkRelation getCollectionResourceRelFor(Class type) { + return LinkRelation.of(StringUtils.uncapitalize(type.getSimpleName())); } } diff --git a/spring-data-rest-core/src/test/java/org/springframework/data/rest/core/mapping/PersistentPropertyResourceMappingUnitTests.java b/spring-data-rest-core/src/test/java/org/springframework/data/rest/core/mapping/PersistentPropertyResourceMappingUnitTests.java index 37dcd3bc5..adfa34ac6 100755 --- a/spring-data-rest-core/src/test/java/org/springframework/data/rest/core/mapping/PersistentPropertyResourceMappingUnitTests.java +++ b/spring-data-rest-core/src/test/java/org/springframework/data/rest/core/mapping/PersistentPropertyResourceMappingUnitTests.java @@ -31,6 +31,8 @@ import org.springframework.data.mapping.context.PersistentEntities; import org.springframework.data.rest.core.Path; import org.springframework.data.rest.core.annotation.Description; import org.springframework.data.rest.core.annotation.RestResource; +import org.springframework.hateoas.IanaLinkRelations; +import org.springframework.hateoas.LinkRelation; /** * Unit tests for {@link PersistentPropertyResourceMapping}. @@ -49,7 +51,7 @@ public class PersistentPropertyResourceMappingUnitTests { assertThat(mapping).isNotNull(); assertThat(mapping.getPath()).isEqualTo(new Path("first")); - assertThat(mapping.getRel()).isEqualTo("first"); + assertThat(mapping.getRel()).isEqualTo(IanaLinkRelations.FIRST); assertThat(mapping.isExported()).isFalse(); } @@ -60,7 +62,7 @@ public class PersistentPropertyResourceMappingUnitTests { assertThat(mapping).isNotNull(); assertThat(mapping.getPath()).isEqualTo(new Path("secPath")); - assertThat(mapping.getRel()).isEqualTo("secRel"); + assertThat(mapping.getRel()).isEqualTo(LinkRelation.of("secRel")); assertThat(mapping.isExported()).isFalse(); } @@ -71,7 +73,7 @@ public class PersistentPropertyResourceMappingUnitTests { assertThat(mapping).isNotNull(); assertThat(mapping.getPath()).isEqualTo(new Path("thirdPath")); - assertThat(mapping.getRel()).isEqualTo("thirdRel"); + assertThat(mapping.getRel()).isEqualTo(LinkRelation.of("thirdRel")); assertThat(mapping.isExported()).isFalse(); } diff --git a/spring-data-rest-core/src/test/java/org/springframework/data/rest/core/mapping/RepositoryCollectionResourceMappingUnitTests.java b/spring-data-rest-core/src/test/java/org/springframework/data/rest/core/mapping/RepositoryCollectionResourceMappingUnitTests.java index eae5e4952..bdcf2a6a8 100755 --- a/spring-data-rest-core/src/test/java/org/springframework/data/rest/core/mapping/RepositoryCollectionResourceMappingUnitTests.java +++ b/spring-data-rest-core/src/test/java/org/springframework/data/rest/core/mapping/RepositoryCollectionResourceMappingUnitTests.java @@ -27,6 +27,7 @@ import org.springframework.data.rest.core.Path; import org.springframework.data.rest.core.annotation.RepositoryRestResource; import org.springframework.data.rest.core.annotation.RestResource; import org.springframework.data.rest.core.mapping.RepositoryDetectionStrategy.RepositoryDetectionStrategies; +import org.springframework.hateoas.LinkRelation; /** * Unit tests for {@link RepositoryCollectionResourceMapping}. @@ -41,8 +42,8 @@ public class RepositoryCollectionResourceMappingUnitTests { CollectionResourceMapping mapping = getResourceMappingFor(PersonRepository.class); assertThat(mapping.getPath()).isEqualTo(new Path("persons")); - assertThat(mapping.getRel()).isEqualTo("persons"); - assertThat(mapping.getItemResourceRel()).isEqualTo("person"); + assertThat(mapping.getRel()).isEqualTo(LinkRelation.of("persons")); + assertThat(mapping.getItemResourceRel()).isEqualTo(LinkRelation.of("person")); assertThat(mapping.isExported()).isTrue(); } @@ -52,8 +53,8 @@ public class RepositoryCollectionResourceMappingUnitTests { CollectionResourceMapping mapping = getResourceMappingFor(AnnotatedPersonRepository.class); assertThat(mapping.getPath()).isEqualTo(new Path("bar")); - assertThat(mapping.getRel()).isEqualTo("foo"); - assertThat(mapping.getItemResourceRel()).isEqualTo("annotatedPerson"); + assertThat(mapping.getRel()).isEqualTo(LinkRelation.of("foo")); + assertThat(mapping.getItemResourceRel()).isEqualTo(LinkRelation.of("annotatedPerson")); assertThat(mapping.isExported()).isFalse(); } @@ -63,8 +64,8 @@ public class RepositoryCollectionResourceMappingUnitTests { CollectionResourceMapping mapping = getResourceMappingFor(AnnotatedAnnotatedPersonRepository.class); assertThat(mapping.getPath()).isEqualTo(new Path("/trumpsAll")); - assertThat(mapping.getRel()).isEqualTo("foo"); - assertThat(mapping.getItemResourceRel()).isEqualTo("annotatedPerson"); + assertThat(mapping.getRel()).isEqualTo(LinkRelation.of("foo")); + assertThat(mapping.getItemResourceRel()).isEqualTo(LinkRelation.of("annotatedPerson")); assertThat(mapping.isExported()).isTrue(); } @@ -84,8 +85,8 @@ public class RepositoryCollectionResourceMappingUnitTests { public void discoversCustomizationsUsingRestRepositoryResource() { CollectionResourceMapping mapping = getResourceMappingFor(RepositoryAnnotatedRepository.class); - assertThat(mapping.getRel()).isEqualTo("foo"); - assertThat(mapping.getItemResourceRel()).isEqualTo("bar"); + assertThat(mapping.getRel()).isEqualTo(LinkRelation.of("foo")); + assertThat(mapping.getItemResourceRel()).isEqualTo(LinkRelation.of("bar")); } @Test // DATAREST-445 diff --git a/spring-data-rest-core/src/test/java/org/springframework/data/rest/core/mapping/RepositoryMethodResourceMappingUnitTests.java b/spring-data-rest-core/src/test/java/org/springframework/data/rest/core/mapping/RepositoryMethodResourceMappingUnitTests.java index 5e4db86a3..3901812a8 100755 --- a/spring-data-rest-core/src/test/java/org/springframework/data/rest/core/mapping/RepositoryMethodResourceMappingUnitTests.java +++ b/spring-data-rest-core/src/test/java/org/springframework/data/rest/core/mapping/RepositoryMethodResourceMappingUnitTests.java @@ -30,6 +30,7 @@ import org.springframework.data.repository.query.Param; import org.springframework.data.rest.core.Path; import org.springframework.data.rest.core.annotation.RestResource; import org.springframework.data.rest.core.mapping.RepositoryDetectionStrategy.RepositoryDetectionStrategies; +import org.springframework.hateoas.LinkRelation; /** * Unit tests for {@link RepositoryMethodResourceMapping}. @@ -94,7 +95,7 @@ public class RepositoryMethodResourceMappingUnitTests { Method method = PersonRepository.class.getMethod("findByEmailAddress", String.class, Pageable.class); MethodResourceMapping mapping = getMappingFor(method); - assertThat(mapping.getRel()).isEqualTo("findByEmailAddress"); + assertThat(mapping.getRel()).isEqualTo(LinkRelation.of("findByEmailAddress")); } @Test // DATAREST-384 @@ -118,7 +119,7 @@ public class RepositoryMethodResourceMappingUnitTests { Method method = PersonRepository.class.getMethod("findByLastname", String.class); MethodResourceMapping mapping = getMappingFor(method); - assertThat(mapping.getReturnedDomainType()).isEqualTo((Class) Person.class); + assertThat(mapping.getReturnedDomainType()).isEqualTo(Person.class); } @Test // DATAREST-699 diff --git a/spring-data-rest-core/src/test/java/org/springframework/data/rest/core/mapping/RepositoryResourceMappingsIntegrationTests.java b/spring-data-rest-core/src/test/java/org/springframework/data/rest/core/mapping/RepositoryResourceMappingsIntegrationTests.java index f66950f62..7de307b3b 100755 --- a/spring-data-rest-core/src/test/java/org/springframework/data/rest/core/mapping/RepositoryResourceMappingsIntegrationTests.java +++ b/spring-data-rest-core/src/test/java/org/springframework/data/rest/core/mapping/RepositoryResourceMappingsIntegrationTests.java @@ -42,6 +42,7 @@ import org.springframework.data.rest.core.domain.CreditCard; import org.springframework.data.rest.core.domain.JpaRepositoryConfig; import org.springframework.data.rest.core.domain.Person; import org.springframework.data.rest.core.domain.Profile; +import org.springframework.hateoas.LinkRelation; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @@ -106,7 +107,7 @@ public class RepositoryResourceMappingsIntegrationTests { ResourceMetadata metadata = mappings.getMetadataFor(Person.class); ResourceMapping mapping = metadata.getMappingFor(property); - assertThat(mapping.getRel()).isEqualTo("siblings"); + assertThat(mapping.getRel()).isEqualTo(LinkRelation.of("siblings")); assertThat(mapping.getPath()).isEqualTo(new Path("siblings")); assertThat(mapping.isExported()).isTrue(); } @@ -168,7 +169,7 @@ public class RepositoryResourceMappingsIntegrationTests { PropertyAwareResourceMapping propertyMapping = metadata.getProperty("father-mapped"); - assertThat(propertyMapping.getRel()).isEqualTo("father"); + assertThat(propertyMapping.getRel()).isEqualTo(LinkRelation.of("father")); assertThat(propertyMapping.getPath()).isEqualTo(new Path("father-mapped")); } } diff --git a/spring-data-rest-core/src/test/java/org/springframework/data/rest/core/mapping/TypeBasedCollectionResourceMappingUnitTests.java b/spring-data-rest-core/src/test/java/org/springframework/data/rest/core/mapping/TypeBasedCollectionResourceMappingUnitTests.java index fdfba7761..8fbc5ac6f 100755 --- a/spring-data-rest-core/src/test/java/org/springframework/data/rest/core/mapping/TypeBasedCollectionResourceMappingUnitTests.java +++ b/spring-data-rest-core/src/test/java/org/springframework/data/rest/core/mapping/TypeBasedCollectionResourceMappingUnitTests.java @@ -20,6 +20,7 @@ import static org.assertj.core.api.Assertions.*; import org.junit.Test; import org.springframework.data.rest.core.Path; import org.springframework.data.rest.core.annotation.RestResource; +import org.springframework.hateoas.LinkRelation; /** * Unit tests for {@link TypeBasedCollectionResourceMapping}. @@ -34,8 +35,8 @@ public class TypeBasedCollectionResourceMappingUnitTests { CollectionResourceMapping mapping = new TypeBasedCollectionResourceMapping(Sample.class); assertThat(mapping.getPath()).isEqualTo(new Path("sample")); - assertThat(mapping.getRel()).isEqualTo("samples"); - assertThat(mapping.getItemResourceRel()).isEqualTo("sample"); + assertThat(mapping.getRel()).isEqualTo(LinkRelation.of("samples")); + assertThat(mapping.getItemResourceRel()).isEqualTo(LinkRelation.of("sample")); assertThat(mapping.isExported()).isTrue(); } @@ -45,8 +46,8 @@ public class TypeBasedCollectionResourceMappingUnitTests { CollectionResourceMapping mapping = new TypeBasedCollectionResourceMapping(CustomizedSample.class); assertThat(mapping.getPath()).isEqualTo(new Path("customizedSample")); - assertThat(mapping.getRel()).isEqualTo("myRel"); - assertThat(mapping.getItemResourceRel()).isEqualTo("customizedSample"); + assertThat(mapping.getRel()).isEqualTo(LinkRelation.of("myRel")); + assertThat(mapping.getItemResourceRel()).isEqualTo(LinkRelation.of("customizedSample")); assertThat(mapping.isExported()).isTrue(); } diff --git a/spring-data-rest-tests/spring-data-rest-tests-core/src/test/java/org/springframework/data/rest/tests/AbstractWebIntegrationTests.java b/spring-data-rest-tests/spring-data-rest-tests-core/src/test/java/org/springframework/data/rest/tests/AbstractWebIntegrationTests.java index 9cdc61ca0..f957e968b 100755 --- a/spring-data-rest-tests/spring-data-rest-tests-core/src/test/java/org/springframework/data/rest/tests/AbstractWebIntegrationTests.java +++ b/spring-data-rest-tests/spring-data-rest-tests-core/src/test/java/org/springframework/data/rest/tests/AbstractWebIntegrationTests.java @@ -15,9 +15,8 @@ */ package org.springframework.data.rest.tests; -import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.*; import static org.hamcrest.CoreMatchers.*; -import static org.junit.Assert.fail; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; @@ -25,6 +24,7 @@ import net.minidev.json.JSONArray; import java.util.Collections; import java.util.Map; +import java.util.Optional; import org.junit.Before; import org.junit.runner.RunWith; @@ -32,6 +32,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration; import org.springframework.hateoas.Link; import org.springframework.hateoas.LinkDiscoverers; +import org.springframework.hateoas.LinkRelation; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.mock.web.MockHttpServletResponse; @@ -39,7 +40,6 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.ResultMatcher; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.setup.MockMvcBuilders; @@ -118,10 +118,8 @@ public abstract class AbstractWebIntegrationTests { String href = link.isTemplated() ? link.expand().getHref() : link.getHref(); - MockHttpServletResponse response = mvc - .perform(MockMvcRequestBuilders.request(HttpMethod.PATCH, href).// - content(payload.toString()).contentType(mediaType)) - .andExpect(status().is2xxSuccessful())// + MockHttpServletResponse response = mvc.perform(MockMvcRequestBuilders.request(HttpMethod.PATCH, href).// + content(payload.toString()).contentType(mediaType)).andExpect(status().is2xxSuccessful())// .andReturn().getResponse(); return StringUtils.hasText(response.getContentAsString()) ? response : client.request(href); @@ -140,15 +138,16 @@ public abstract class AbstractWebIntegrationTests { .andExpect(status().isNotFound()); } - protected Link assertHasContentLinkWithRel(String rel, MockHttpServletResponse response) throws Exception { - return assertContentLinkWithRel(rel, response, true); + protected Link assertHasContentLinkWithRel(LinkRelation relation, MockHttpServletResponse response) throws Exception { + return assertContentLinkWithRel(relation, response, true); } - protected void assertDoesNotHaveContentLinkWithRel(String rel, MockHttpServletResponse response) throws Exception { + protected void assertDoesNotHaveContentLinkWithRel(LinkRelation rel, MockHttpServletResponse response) + throws Exception { assertContentLinkWithRel(rel, response, false); } - protected Link assertContentLinkWithRel(String rel, MockHttpServletResponse response, boolean expected) + protected Link assertContentLinkWithRel(LinkRelation rel, MockHttpServletResponse response, boolean expected) throws Exception { String content = response.getContentAsString(); @@ -170,19 +169,19 @@ public abstract class AbstractWebIntegrationTests { } catch (InvalidPathException o_O) { if (expected) { - fail("Didn't find any content in the given response!"); + fail("Didn't find any content in the given response!", o_O); } return null; } } - protected void assertDoesNotHaveLinkWithRel(String rel, MockHttpServletResponse response) throws Exception { + protected void assertDoesNotHaveLinkWithRel(LinkRelation rel, MockHttpServletResponse response) throws Exception { String content = response.getContentAsString(); - Link link = client.getDiscoverer(response).findLinkWithRel(rel, content); + Optional link = client.getDiscoverer(response).findLinkWithRel(rel, content); - assertThat(link).as("Expected not to find link with rel %s but found %s!", rel, link).isNull(); + assertThat(link).as("Expected not to find link with rel %s but found %s!", rel, link).isEmpty(); } @SuppressWarnings("unchecked") @@ -231,28 +230,24 @@ public abstract class AbstractWebIntegrationTests { return jsonString; } - protected ResultMatcher doesNotHaveLinkWithRel(final String rel) { + protected ResultMatcher doesNotHaveLinkWithRel(final LinkRelation relation) { - return new ResultMatcher() { + return result -> { - @Override - public void match(MvcResult result) throws Exception { + MockHttpServletResponse response = result.getResponse(); + String s = response.getContentAsString(); - MockHttpServletResponse response = result.getResponse(); - String s = response.getContentAsString(); - - assertThat(client.getDiscoverer(response).findLinkWithRel(rel, s))// - .as("Expected not to find link with rel %s but found one in %s!", rel, s)// - .isNull(); - } + assertThat(client.getDiscoverer(response).findLinkWithRel(relation, s))// + .as("Expected not to find link with rel %s but found one in %s!", relation, s)// + .isEmpty(); }; } - protected Map getPayloadToPost() throws Exception { + protected Map getPayloadToPost() throws Exception { return Collections.emptyMap(); } - protected MultiValueMap getRootAndLinkedResources() { - return new LinkedMultiValueMap(0); + protected MultiValueMap getRootAndLinkedResources() { + return new LinkedMultiValueMap(0); } } diff --git a/spring-data-rest-tests/spring-data-rest-tests-core/src/test/java/org/springframework/data/rest/tests/CommonWebTests.java b/spring-data-rest-tests/spring-data-rest-tests-core/src/test/java/org/springframework/data/rest/tests/CommonWebTests.java index 8b6d0c810..7b3cdd998 100755 --- a/spring-data-rest-tests/spring-data-rest-tests-core/src/test/java/org/springframework/data/rest/tests/CommonWebTests.java +++ b/spring-data-rest-tests/spring-data-rest-tests-core/src/test/java/org/springframework/data/rest/tests/CommonWebTests.java @@ -29,7 +29,9 @@ import java.util.Map; import org.junit.Test; import org.springframework.data.rest.webmvc.RestMediaTypes; +import org.springframework.hateoas.IanaLinkRelations; import org.springframework.hateoas.Link; +import org.springframework.hateoas.LinkRelation; import org.springframework.hateoas.Links; import org.springframework.hateoas.MediaTypes; import org.springframework.http.HttpStatus; @@ -37,7 +39,6 @@ import org.springframework.http.MediaType; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.test.web.servlet.ResultActions; import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; -import org.springframework.test.web.servlet.result.MockMvcResultHandlers; import com.jayway.jsonpath.JsonPath; @@ -53,7 +54,7 @@ import com.jayway.jsonpath.JsonPath; */ public abstract class CommonWebTests extends AbstractWebIntegrationTests { - protected abstract Iterable expectedRootLinkRels(); + protected abstract Iterable expectedRootLinkRels(); // Root test cases @@ -62,8 +63,8 @@ public abstract class CommonWebTests extends AbstractWebIntegrationTests { ResultActions actions = mvc.perform(get("/").accept(TestMvcClient.DEFAULT_MEDIA_TYPE)).andExpect(status().isOk()); - for (String rel : expectedRootLinkRels()) { - actions.andDo(MockMvcResultHandlers.print()).andExpect(client.hasLinkWithRel(rel)); + for (LinkRelation rel : expectedRootLinkRels()) { + actions.andExpect(client.hasLinkWithRel(rel)); } } @@ -72,14 +73,14 @@ public abstract class CommonWebTests extends AbstractWebIntegrationTests { MockHttpServletResponse response = client.request("/"); - for (String rel : expectedRootLinkRels()) { + for (LinkRelation rel : expectedRootLinkRels()) { Link link = client.assertHasLinkWithRel(rel, response); // Resource client.follow(link).andExpect(status().is2xxSuccessful()); - Link profileLink = client.discoverUnique(link, "profile"); + Link profileLink = client.discoverUnique(link, LinkRelation.of("profile")); // Default metadata client.follow(profileLink).andExpect(status().is2xxSuccessful()); @@ -113,29 +114,37 @@ public abstract class CommonWebTests extends AbstractWebIntegrationTests { MockHttpServletResponse response = client.request("/"); - for (String rel : expectedRootLinkRels()) { + for (LinkRelation rel : expectedRootLinkRels()) { Link link = client.assertHasLinkWithRel(rel, response); String rootResourceRepresentation = client.request(link).getContentAsString(); - Link searchLink = client.getDiscoverer(response).findLinkWithRel("search", rootResourceRepresentation); - if (searchLink != null) { - client.follow(searchLink).// - andExpect(client.hasLinkWithRel("self")).// - andExpect(jsonPath("$.domainType").doesNotExist()); // DATAREST-549 - } + client.getDiscoverer(response) // + .findLinkWithRel("search", rootResourceRepresentation) // + .ifPresent(it -> { + + try { + + client.follow(it).// + andExpect(client.hasLinkWithRel(IanaLinkRelations.SELF)).// + andExpect(jsonPath("$.domainType").doesNotExist()); + + } catch (Exception e) { + throw new RuntimeException(e); + } + }); } } @Test public void nic() throws Exception { - Map payloads = getPayloadToPost(); + Map payloads = getPayloadToPost(); assumeFalse(payloads.isEmpty()); MockHttpServletResponse response = client.request("/"); - for (String rel : expectedRootLinkRels()) { + for (LinkRelation rel : expectedRootLinkRels()) { String payload = payloads.get(rel); @@ -159,7 +168,7 @@ public abstract class CommonWebTests extends AbstractWebIntegrationTests { MockHttpServletResponse rootResource = client.request("/"); - for (Map.Entry> linked : getRootAndLinkedResources().entrySet()) { + for (Map.Entry> linked : getRootAndLinkedResources().entrySet()) { Link resourceLink = client.assertHasLinkWithRel(linked.getKey(), rootResource); MockHttpServletResponse resource = client.request(resourceLink); @@ -186,7 +195,7 @@ public abstract class CommonWebTests extends AbstractWebIntegrationTests { MediaType ALPS_MEDIA_TYPE = MediaType.valueOf("application/alps+json"); MockHttpServletResponse response = client.request("/"); - Link profileLink = client.assertHasLinkWithRel("profile", response); + Link profileLink = client.assertHasLinkWithRel(LinkRelation.of("profile"), response); mvc.perform(// get(profileLink.expand().getHref()).// @@ -206,7 +215,7 @@ public abstract class CommonWebTests extends AbstractWebIntegrationTests { @Test // DATAREST-658 public void collectionResourcesExposeLinksAsHeadersForHeadRequest() throws Exception { - for (String rel : expectedRootLinkRels()) { + for (LinkRelation rel : expectedRootLinkRels()) { Link link = client.discoverUnique(rel); @@ -214,9 +223,9 @@ public abstract class CommonWebTests extends AbstractWebIntegrationTests { .andExpect(status().isNoContent())// .andReturn().getResponse(); - Links links = Links.valueOf(response.getHeader("Link")); + Links links = Links.parse(response.getHeader("Link")); - assertThat(links.hasLink(Link.REL_SELF)).isTrue(); + assertThat(links.hasLink(IanaLinkRelations.SELF)).isTrue(); assertThat(links.hasLink("profile")).isTrue(); } } @@ -224,7 +233,7 @@ public abstract class CommonWebTests extends AbstractWebIntegrationTests { @Test // DATAREST-661 public void patchToNonExistingResourceReturnsNotFound() throws Exception { - String rel = expectedRootLinkRels().iterator().next(); + LinkRelation rel = expectedRootLinkRels().iterator().next(); String uri = client.discoverUnique(rel).expand().getHref().concat("/"); String id = "4711"; Integer status = null; @@ -244,7 +253,7 @@ public abstract class CommonWebTests extends AbstractWebIntegrationTests { @Test // DATAREST-1003 public void rejectsUnsupportedAcceptTypeForResources() throws Exception { - for (String string : expectedRootLinkRels()) { + for (LinkRelation string : expectedRootLinkRels()) { Link link = client.discoverUnique(string); diff --git a/spring-data-rest-tests/spring-data-rest-tests-core/src/test/java/org/springframework/data/rest/tests/ResourceTester.java b/spring-data-rest-tests/spring-data-rest-tests-core/src/test/java/org/springframework/data/rest/tests/ResourceTester.java index 2af3fc50c..d5665b905 100644 --- a/spring-data-rest-tests/spring-data-rest-tests-core/src/test/java/org/springframework/data/rest/tests/ResourceTester.java +++ b/spring-data-rest-tests/spring-data-rest-tests-core/src/test/java/org/springframework/data/rest/tests/ResourceTester.java @@ -15,8 +15,9 @@ */ package org.springframework.data.rest.tests; +import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.CoreMatchers.*; -import static org.junit.Assert.*; +import static org.junit.Assert.assertThat; import org.hamcrest.Matcher; import org.springframework.data.rest.core.Path; @@ -58,7 +59,7 @@ public class ResourceTester { * @param number */ public void assertNumberOfLinks(int number) { - assertThat(resource.getLinks().size(), is(number)); + assertThat(resource.getLinks()).hasSize(number); } /** diff --git a/spring-data-rest-tests/spring-data-rest-tests-core/src/test/java/org/springframework/data/rest/tests/TestMvcClient.java b/spring-data-rest-tests/spring-data-rest-tests-core/src/test/java/org/springframework/data/rest/tests/TestMvcClient.java index fff35936c..3e2b3a681 100644 --- a/spring-data-rest-tests/spring-data-rest-tests-core/src/test/java/org/springframework/data/rest/tests/TestMvcClient.java +++ b/spring-data-rest-tests/spring-data-rest-tests-core/src/test/java/org/springframework/data/rest/tests/TestMvcClient.java @@ -15,18 +15,21 @@ */ package org.springframework.data.rest.tests; +import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.Matchers.*; -import static org.junit.Assert.*; +import static org.junit.Assert.assertThat; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; import java.util.Arrays; import java.util.Iterator; -import java.util.List; +import java.util.Optional; import org.springframework.hateoas.Link; import org.springframework.hateoas.LinkDiscoverer; import org.springframework.hateoas.LinkDiscoverers; +import org.springframework.hateoas.LinkRelation; +import org.springframework.hateoas.Links; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; @@ -34,7 +37,6 @@ import org.springframework.http.MediaType; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.ResultActions; import org.springframework.test.web.servlet.ResultMatcher; import org.springframework.util.Assert; @@ -208,10 +210,14 @@ public class TestMvcClient { * @return * @throws Exception */ - public List discover(String rel) throws Exception { + public Links discover(LinkRelation rel) throws Exception { return discover(new Link("/"), rel); } + public Link discoverUnique(String rel) throws Exception { + return discoverUnique(LinkRelation.of(rel)); + } + /** * Discover single URI associated with a rel, starting at the root node ("/") * @@ -219,11 +225,15 @@ public class TestMvcClient { * @return * @throws Exception */ - public Link discoverUnique(String rel) throws Exception { + public Link discoverUnique(LinkRelation rel) throws Exception { - List discover = discover(rel); - assertThat(discover, hasSize(1)); - return discover.get(0); + Links discover = discover(rel); + assertThat(discover).hasSize(1); + return discover.toList().get(0); + } + + public Link discoverUnique(String... rels) throws Exception { + return discoverUnique(Arrays.stream(rels).map(LinkRelation::of).toArray(LinkRelation[]::new)); } /** @@ -233,15 +243,18 @@ public class TestMvcClient { * @return * @throws Exception */ - public Link discoverUnique(String... rels) throws Exception { + public Link discoverUnique(LinkRelation... rels) throws Exception { - Iterator toTraverse = Arrays.asList(rels).iterator(); + Iterator toTraverse = Arrays.asList(rels).iterator(); Link lastLink = null; while (toTraverse.hasNext()) { - String rel = toTraverse.next(); - lastLink = lastLink == null ? discoverUnique(rel) : discoverUnique(lastLink, rel); + LinkRelation relation = toTraverse.next(); + + lastLink = lastLink == null // + ? discoverUnique(relation) // + : discoverUnique(lastLink, relation); } return lastLink; @@ -251,31 +264,39 @@ public class TestMvcClient { * Given a URI (root), discover the URIs for a given rel. * * @param root - URI to start from - * @param rel - name of the relationship to seek links + * @param relation - name of the relationship to seek links * @return list of {@link org.springframework.hateoas.Link Link} objects associated with the rel * @throws Exception */ - public List discover(Link root, String rel) throws Exception { + public Links discover(Link root, LinkRelation relation) throws Exception { MockHttpServletResponse response = mvc.perform(get(root.expand().getHref()).accept(DEFAULT_MEDIA_TYPE)).// andExpect(status().isOk()).// - andExpect(hasLinkWithRel(rel)).// + andExpect(hasLinkWithRel(relation)).// andReturn().getResponse(); - String s = response.getContentAsString(); - return getDiscoverer(response).findLinksWithRel(rel, s); + String content = response.getContentAsString(); + return getDiscoverer(response).findLinksWithRel(relation, content); + } + + public Link discoverUnique(Link root, String relation) throws Exception { + return discoverUnique(root, LinkRelation.of(relation)); } /** * Given a URI (root), discover the unique URI for a given rel. NOTE: Assumes there is only one URI * * @param root - * @param rel + * @param relation * @return {@link org.springframework.hateoas.Link Link} tied to a given rel * @throws Exception */ - public Link discoverUnique(Link root, String rel) throws Exception { - return discoverUnique(root, rel, DEFAULT_MEDIA_TYPE); + public Link discoverUnique(Link root, LinkRelation relation) throws Exception { + return discoverUnique(root, relation, DEFAULT_MEDIA_TYPE); + } + + public Link discoverUnique(Link root, String rel, MediaType mediaType) throws Exception { + return discoverUnique(root, LinkRelation.of(rel), mediaType); } /** @@ -287,35 +308,39 @@ public class TestMvcClient { * @return {@link org.springframework.hateoas.Link Link} tied to a given rel * @throws Exception */ - public Link discoverUnique(Link root, String rel, MediaType mediaType) throws Exception { + public Link discoverUnique(Link root, LinkRelation rel, MediaType mediaType) throws Exception { - MockHttpServletResponse response = mvc - .perform(get(root.expand().getHref())// - .accept(mediaType)) - .andExpect(status().isOk())// + MockHttpServletResponse response = mvc.perform(get(root.expand().getHref())// + .accept(mediaType)).andExpect(status().isOk())// .andExpect(hasLinkWithRel(rel))// .andReturn().getResponse(); return assertHasLinkWithRel(rel, response); } + public Link assertHasLinkWithRel(String relation, MockHttpServletResponse response) throws Exception { + return assertHasLinkWithRel(LinkRelation.of(relation), response); + } + /** * For a given servlet response, verify that the provided rel exists in its hypermedia. If so, return the URI link. * - * @param rel + * @param relation * @param response * @return {@link org.springframework.hateoas.Link} of the rel found in the response * @throws Exception */ - public Link assertHasLinkWithRel(String rel, MockHttpServletResponse response) throws Exception { + public Link assertHasLinkWithRel(LinkRelation relation, MockHttpServletResponse response) throws Exception { String content = response.getContentAsString(); - Link link = getDiscoverer(response).findLinkWithRel(rel, content); + Optional link = getDiscoverer(response).findLinkWithRel(relation, content); - assertThat("Expected to find link with rel " + rel + " but found none in " + content + "!", link, - is(notNullValue())); + return link.orElseThrow(() -> new IllegalStateException( + "Expected to find link with rel " + relation + " but found none in " + content + "!")); + } - return link; + public ResultMatcher hasLinkWithRel(String rel) { + return hasLinkWithRel(LinkRelation.of(rel)); } /** @@ -324,19 +349,15 @@ public class TestMvcClient { * @param rel * @return */ - public ResultMatcher hasLinkWithRel(final String rel) { + public ResultMatcher hasLinkWithRel(LinkRelation rel) { - return new ResultMatcher() { + return result -> { - @Override - public void match(MvcResult result) throws Exception { + MockHttpServletResponse response = result.getResponse(); + String s = response.getContentAsString(); - MockHttpServletResponse response = result.getResponse(); - String s = response.getContentAsString(); - - assertThat("Expected to find link with rel " + rel + " but found none in " + s, // - getDiscoverer(response).findLinkWithRel(rel, s), notNullValue()); - } + assertThat("Expected to find link with rel " + rel + " but found none in " + s, // + getDiscoverer(response).findLinkWithRel(rel, s), notNullValue()); }; } @@ -349,11 +370,7 @@ public class TestMvcClient { public LinkDiscoverer getDiscoverer(MockHttpServletResponse response) { String contentType = response.getContentType(); - LinkDiscoverer linkDiscovererFor = discoverers.getLinkDiscovererFor(contentType); - assertThat("Did not find a LinkDiscoverer for returned media type " + contentType + "!", linkDiscovererFor, - is(notNullValue())); - - return linkDiscovererFor; + return discoverers.getRequiredLinkDiscovererFor(contentType); } } diff --git a/spring-data-rest-tests/spring-data-rest-tests-gemfire/src/test/java/org/springframework/data/rest/tests/gemfire/GemfireRepositoryConfig.java b/spring-data-rest-tests/spring-data-rest-tests-gemfire/src/test/java/org/springframework/data/rest/tests/gemfire/GemfireRepositoryConfig.java index 800f21b48..168ed506b 100644 --- a/spring-data-rest-tests/spring-data-rest-tests-gemfire/src/test/java/org/springframework/data/rest/tests/gemfire/GemfireRepositoryConfig.java +++ b/spring-data-rest-tests/spring-data-rest-tests-gemfire/src/test/java/org/springframework/data/rest/tests/gemfire/GemfireRepositoryConfig.java @@ -38,7 +38,6 @@ public class GemfireRepositoryConfig { * TODO: Remove, once Spring Data Gemfire exposes a mapping context. */ @Bean - @SuppressWarnings("unchecked") public GemfireMappingContext gemfireMappingContext() { AnnotatedTypeScanner scanner = new AnnotatedTypeScanner(Region.class); diff --git a/spring-data-rest-tests/spring-data-rest-tests-gemfire/src/test/java/org/springframework/data/rest/tests/gemfire/GemfireWebTests.java b/spring-data-rest-tests/spring-data-rest-tests-gemfire/src/test/java/org/springframework/data/rest/tests/gemfire/GemfireWebTests.java index fa70097a7..1b87c50ed 100755 --- a/spring-data-rest-tests/spring-data-rest-tests-gemfire/src/test/java/org/springframework/data/rest/tests/gemfire/GemfireWebTests.java +++ b/spring-data-rest-tests/spring-data-rest-tests-gemfire/src/test/java/org/springframework/data/rest/tests/gemfire/GemfireWebTests.java @@ -15,9 +15,8 @@ */ package org.springframework.data.rest.tests.gemfire; -import java.util.Arrays; - import org.springframework.data.rest.tests.CommonWebTests; +import org.springframework.hateoas.LinkRelation; import org.springframework.test.context.ContextConfiguration; /** @@ -31,7 +30,7 @@ public class GemfireWebTests extends CommonWebTests { * @see org.springframework.data.rest.webmvc.AbstractWebIntegrationTests#expectedRootLinkRels() */ @Override - protected Iterable expectedRootLinkRels() { - return Arrays.asList("products"); + protected Iterable expectedRootLinkRels() { + return LinkRelation.manyOf("products"); } } diff --git a/spring-data-rest-tests/spring-data-rest-tests-jpa/src/test/java/org/springframework/data/rest/webmvc/jpa/CorsIntegrationTests.java b/spring-data-rest-tests/spring-data-rest-tests-jpa/src/test/java/org/springframework/data/rest/webmvc/jpa/CorsIntegrationTests.java index f805fd468..96e01d616 100755 --- a/spring-data-rest-tests/spring-data-rest-tests-jpa/src/test/java/org/springframework/data/rest/webmvc/jpa/CorsIntegrationTests.java +++ b/spring-data-rest-tests/spring-data-rest-tests-jpa/src/test/java/org/springframework/data/rest/webmvc/jpa/CorsIntegrationTests.java @@ -26,6 +26,7 @@ import org.springframework.data.rest.webmvc.BasePathAwareController; import org.springframework.data.rest.webmvc.RepositoryRestController; import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurer; import org.springframework.hateoas.Link; +import org.springframework.hateoas.LinkRelation; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.test.context.ContextConfiguration; @@ -61,7 +62,7 @@ public class CorsIntegrationTests extends AbstractWebIntegrationTests { @Test // DATAREST-573 public void appliesSelectiveDefaultCorsConfiguration() throws Exception { - Link findItems = client.discoverUnique("items"); + Link findItems = client.discoverUnique(LinkRelation.of("items")); // Preflight request mvc.perform(options(findItems.expand().getHref()).header(HttpHeaders.ORIGIN, "http://far.far.away") @@ -74,7 +75,7 @@ public class CorsIntegrationTests extends AbstractWebIntegrationTests { @Test // DATAREST-573 public void appliesGlobalCorsConfiguration() throws Exception { - Link findBooks = client.discoverUnique("books"); + Link findBooks = client.discoverUnique(LinkRelation.of("books")); // Preflight request mvc.perform(options(findBooks.expand().getHref()).header(HttpHeaders.ORIGIN, "http://far.far.away") @@ -132,7 +133,7 @@ public class CorsIntegrationTests extends AbstractWebIntegrationTests { @Test // DATAREST-573 public void appliesCorsConfigurationOnRepository() throws Exception { - Link authorsLink = client.discoverUnique("authors"); + Link authorsLink = client.discoverUnique(LinkRelation.of("authors")); // Preflight request mvc.perform(options(authorsLink.expand().getHref()).header(HttpHeaders.ORIGIN, "http://not.so.far.away") 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 index 7d1ed0732..ba690e1e2 100755 --- 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 @@ -37,7 +37,9 @@ import org.springframework.data.rest.tests.AbstractWebIntegrationTests; import org.springframework.data.rest.webmvc.RepositoryRestController; import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurer; import org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration; +import org.springframework.hateoas.IanaLinkRelations; import org.springframework.hateoas.Link; +import org.springframework.hateoas.LinkRelation; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; @@ -83,6 +85,7 @@ public class JpaDefaultPageableWebTests extends AbstractWebIntegrationTests { @Autowired TestDataPopulator loader; @Autowired ApplicationContext context; + @Override @Before public void setUp() { loader.populateRepositories(); @@ -92,7 +95,8 @@ public class JpaDefaultPageableWebTests extends AbstractWebIntegrationTests { @Test // DATAREST-906 public void executesSearchThatTakesAMappedSortProperty() throws Exception { - Link findBySortedLink = client.discoverUnique("books", "search", "find-spring-books-sorted"); + Link findBySortedLink = client.discoverUnique(LinkRelation.of("books"), IanaLinkRelations.SEARCH, + LinkRelation.of("find-spring-books-sorted")); // Assert sort options advertised assertThat(findBySortedLink.isTemplated()).isTrue(); diff --git a/spring-data-rest-tests/spring-data-rest-tests-jpa/src/test/java/org/springframework/data/rest/webmvc/jpa/JpaWebTests.java b/spring-data-rest-tests/spring-data-rest-tests-jpa/src/test/java/org/springframework/data/rest/webmvc/jpa/JpaWebTests.java index c870a043e..b6d3a687e 100755 --- a/spring-data-rest-tests/spring-data-rest-tests-jpa/src/test/java/org/springframework/data/rest/webmvc/jpa/JpaWebTests.java +++ b/spring-data-rest-tests/spring-data-rest-tests-jpa/src/test/java/org/springframework/data/rest/webmvc/jpa/JpaWebTests.java @@ -28,7 +28,6 @@ import net.minidev.json.JSONArray; import java.math.BigDecimal; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; @@ -38,7 +37,9 @@ import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.rest.core.mapping.ResourceMappings; import org.springframework.data.rest.tests.CommonWebTests; +import org.springframework.hateoas.IanaLinkRelations; import org.springframework.hateoas.Link; +import org.springframework.hateoas.LinkRelation; import org.springframework.hateoas.Links; import org.springframework.hateoas.RelProvider; import org.springframework.http.MediaType; @@ -90,8 +91,8 @@ public class JpaWebTests extends CommonWebTests { * @see org.springframework.data.rest.webmvc.AbstractWebIntegrationTests#expectedRootLinkRels() */ @Override - protected Iterable expectedRootLinkRels() { - return Arrays.asList("people", "authors", "books"); + protected Iterable expectedRootLinkRels() { + return LinkRelation.manyOf("people", "authors", "books"); } /* @@ -99,8 +100,8 @@ public class JpaWebTests extends CommonWebTests { * @see org.springframework.data.rest.webmvc.AbstractWebIntegrationTests#getPayloadToPost() */ @Override - protected Map getPayloadToPost() throws Exception { - return Collections.singletonMap("people", readFileFromClasspath("person.json")); + protected Map getPayloadToPost() throws Exception { + return Collections.singletonMap(LinkRelation.of("people"), readFileFromClasspath("person.json")); } /* @@ -108,11 +109,11 @@ public class JpaWebTests extends CommonWebTests { * @see org.springframework.data.rest.webmvc.AbstractWebIntegrationTests#getRootAndLinkedResources() */ @Override - protected MultiValueMap getRootAndLinkedResources() { + protected MultiValueMap getRootAndLinkedResources() { - MultiValueMap map = new LinkedMultiValueMap(); - map.add("authors", "books"); - map.add("books", "authors"); + MultiValueMap map = new LinkedMultiValueMap<>(); + map.add(LinkRelation.of("authors"), "books"); + map.add(LinkRelation.of("books"), "authors"); return map; } @@ -130,26 +131,26 @@ public class JpaWebTests extends CommonWebTests { MockHttpServletResponse response = client.request("/people?page=0&size=1"); - Link nextLink = client.assertHasLinkWithRel(Link.REL_NEXT, response); - assertDoesNotHaveLinkWithRel(Link.REL_PREVIOUS, response); + Link nextLink = client.assertHasLinkWithRel(IanaLinkRelations.NEXT, response); + assertDoesNotHaveLinkWithRel(IanaLinkRelations.PREV, response); response = client.request(nextLink); - client.assertHasLinkWithRel(Link.REL_PREVIOUS, response); - nextLink = client.assertHasLinkWithRel(Link.REL_NEXT, response); + client.assertHasLinkWithRel(IanaLinkRelations.PREV, response); + nextLink = client.assertHasLinkWithRel(IanaLinkRelations.NEXT, response); response = client.request(nextLink); - client.assertHasLinkWithRel(Link.REL_PREVIOUS, response); - assertDoesNotHaveLinkWithRel(Link.REL_NEXT, response); + client.assertHasLinkWithRel(IanaLinkRelations.PREV, response); + assertDoesNotHaveLinkWithRel(IanaLinkRelations.NEXT, response); } @Test // DATAREST-169 public void exposesLinkForRelatedResource() throws Exception { MockHttpServletResponse response = client.request("/"); - Link ordersLink = client.assertHasLinkWithRel("orders", response); + Link ordersLink = client.assertHasLinkWithRel(LinkRelation.of("orders"), response); MockHttpServletResponse orders = client.request(ordersLink); - Link creatorLink = assertHasContentLinkWithRel("creator", orders); + Link creatorLink = assertHasContentLinkWithRel(LinkRelation.of("creator"), orders); assertThat(client.request(creatorLink)).isNotNull(); } @@ -158,7 +159,7 @@ public class JpaWebTests extends CommonWebTests { public void exposesInlinedEntities() throws Exception { MockHttpServletResponse response = client.request("/"); - Link ordersLink = client.assertHasLinkWithRel("orders", response); + Link ordersLink = client.assertHasLinkWithRel(LinkRelation.of("orders"), response); MockHttpServletResponse orders = client.request(ordersLink); assertHasJsonPathValue("$..lineItems", orders); @@ -176,7 +177,7 @@ public class JpaWebTests extends CommonWebTests { @Test // DATAREST-117 public void createPersonThenVerifyIgnoredAttributesDontExist() throws Exception { - Link peopleLink = client.discoverUnique("people"); + Link peopleLink = client.discoverUnique(LinkRelation.of("people")); ObjectMapper mapper = new ObjectMapper(); Person frodo = new Person("Frodo", "Baggins"); frodo.setAge(77); @@ -196,12 +197,12 @@ public class JpaWebTests extends CommonWebTests { @Test // DATAREST-95 public void createThenPatch() throws Exception { - Link peopleLink = client.discoverUnique("people"); + Link peopleLink = client.discoverUnique(LinkRelation.of("people")); MockHttpServletResponse bilbo = postAndGet(peopleLink, "{ \"firstName\" : \"Bilbo\", \"lastName\" : \"Baggins\" }", MediaType.APPLICATION_JSON); - Link bilboLink = client.assertHasLinkWithRel("self", bilbo); + Link bilboLink = client.assertHasLinkWithRel(IanaLinkRelations.SELF, bilbo); assertThat((String) JsonPath.read(bilbo.getContentAsString(), "$.firstName")).isEqualTo("Bilbo"); assertThat((String) JsonPath.read(bilbo.getContentAsString(), "$.lastName")).isEqualTo("Baggins"); @@ -220,13 +221,13 @@ public class JpaWebTests extends CommonWebTests { @Test // DATAREST-150 public void createThenPut() throws Exception { - Link peopleLink = client.discoverUnique("people"); + Link peopleLink = client.discoverUnique(LinkRelation.of("people")); MockHttpServletResponse bilbo = postAndGet(peopleLink, // "{ \"firstName\" : \"Bilbo\", \"lastName\" : \"Baggins\" }", // MediaType.APPLICATION_JSON); - Link bilboLink = client.assertHasLinkWithRel("self", bilbo); + Link bilboLink = client.assertHasLinkWithRel(IanaLinkRelations.SELF, bilbo); assertThat((String) JsonPath.read(bilbo.getContentAsString(), "$.firstName"), equalTo("Bilbo")); assertThat((String) JsonPath.read(bilbo.getContentAsString(), "$.lastName"), equalTo("Baggins")); @@ -343,7 +344,7 @@ public class JpaWebTests extends CommonWebTests { @Test // DATAREST-50 public void propertiesCanHaveNulls() throws Exception { - Link peopleLink = client.discoverUnique("people"); + Link peopleLink = client.discoverUnique(LinkRelation.of("people")); Person frodo = new Person(); frodo.setFirstName("Frodo"); @@ -360,14 +361,14 @@ public class JpaWebTests extends CommonWebTests { @Test // DATAREST-238 public void putShouldWorkDespiteExistingLinks() throws Exception { - Link peopleLink = client.discoverUnique("people"); + Link peopleLink = client.discoverUnique(LinkRelation.of("people")); Person frodo = new Person("Frodo", "Baggins"); String frodoString = mapper.writeValueAsString(frodo); MockHttpServletResponse createdPerson = postAndGet(peopleLink, frodoString, MediaType.APPLICATION_JSON); - Link frodoLink = client.assertHasLinkWithRel("self", createdPerson); + Link frodoLink = client.assertHasLinkWithRel(IanaLinkRelations.SELF, createdPerson); assertJsonPathEquals("$.firstName", "Frodo", createdPerson); String bilboWithFrodosLinks = createdPerson.getContentAsString().replace("Frodo", "Bilbo"); @@ -375,14 +376,14 @@ public class JpaWebTests extends CommonWebTests { MockHttpServletResponse overwrittenResponse = putAndGet(frodoLink, bilboWithFrodosLinks, MediaType.APPLICATION_JSON); - client.assertHasLinkWithRel("self", overwrittenResponse); + client.assertHasLinkWithRel(IanaLinkRelations.SELF, overwrittenResponse); assertJsonPathEquals("$.firstName", "Bilbo", overwrittenResponse); } @Test // DATAREST-217 public void doesNotAllowGetToCollectionResourceIfFindAllIsNotExported() throws Exception { - Link link = client.discoverUnique("addresses"); + Link link = client.discoverUnique(LinkRelation.of("addresses")); mvc.perform(get(link.getHref())).// andExpect(status().isMethodNotAllowed()); @@ -391,7 +392,7 @@ public class JpaWebTests extends CommonWebTests { @Test // DATAREST-217 public void doesNotAllowPostToCollectionResourceIfSaveIsNotExported() throws Exception { - Link link = client.discoverUnique("addresses"); + Link link = client.discoverUnique(LinkRelation.of("addresses")); mvc.perform(post(link.getHref()).content("{}").contentType(MediaType.APPLICATION_JSON)).// andExpect(status().isMethodNotAllowed()); @@ -405,10 +406,10 @@ public class JpaWebTests extends CommonWebTests { @Test // DATAREST-221 public void returnsProjectionIfRequested() throws Exception { - Link orders = client.discoverUnique("orders"); + Link orders = client.discoverUnique(LinkRelation.of("orders")); MockHttpServletResponse response = client.request(orders); - Link orderLink = assertContentLinkWithRel("self", response, true).expand(); + Link orderLink = assertContentLinkWithRel(IanaLinkRelations.SELF, response, true).expand(); UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(orderLink.getHref()); String uri = builder.queryParam("projection", "summary").build().toUriString(); @@ -423,18 +424,18 @@ public class JpaWebTests extends CommonWebTests { @Test // DATAREST-261 public void relProviderDetectsCustomizedMapping() { - assertThat(relProvider.getCollectionResourceRelFor(Person.class)).isEqualTo("people"); + assertThat(relProvider.getCollectionResourceRelFor(Person.class)).isEqualTo(LinkRelation.of("people")); } @Test // DATAREST-311 public void onlyLinksShouldAppearWhenExecuteSearchCompact() throws Exception { - Link peopleLink = client.discoverUnique("people"); + Link peopleLink = client.discoverUnique(LinkRelation.of("people")); Person daenerys = new Person("Daenerys", "Targaryen"); String daenerysString = mapper.writeValueAsString(daenerys); MockHttpServletResponse createdPerson = postAndGet(peopleLink, daenerysString, MediaType.APPLICATION_JSON); - Link daenerysLink = client.assertHasLinkWithRel("self", createdPerson); + Link daenerysLink = client.assertHasLinkWithRel(IanaLinkRelations.SELF, createdPerson); assertJsonPathEquals("$.firstName", "Daenerys", createdPerson); Link searchLink = client.discoverUnique(peopleLink, "search"); @@ -448,7 +449,7 @@ public class JpaWebTests extends CommonWebTests { JSONArray personLinks = JsonPath. read(responseBody, "$.links[?(@.rel=='person')].href"); assertThat(personLinks).hasSize(1); - assertThat(personLinks.get(0)).isEqualTo((Object) daenerysLink.getHref()); + assertThat(personLinks.get(0)).isEqualTo(daenerysLink.getHref()); assertThat(JsonPath. read(responseBody, "$.content")).hasSize(0); } @@ -499,12 +500,12 @@ public class JpaWebTests extends CommonWebTests { client.follow(findBySortedLink.expand("title,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")); + andExpect(client.hasLinkWithRel(IanaLinkRelations.SELF)); client.follow(findBySortedLink.expand("title,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")); + andExpect(client.hasLinkWithRel(IanaLinkRelations.SELF)); } @Test // DATAREST-160 @@ -519,7 +520,7 @@ public class JpaWebTests extends CommonWebTests { String stringReceipt = mapper.writeValueAsString(receipt); MockHttpServletResponse createdReceipt = postAndGet(receiptLink, stringReceipt, MediaType.APPLICATION_JSON); - Link tacosLink = client.assertHasLinkWithRel("self", createdReceipt); + Link tacosLink = client.assertHasLinkWithRel(IanaLinkRelations.SELF, createdReceipt); assertJsonPathEquals("$.saleItem", "Springy Tacos", createdReceipt); UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(tacosLink.getHref()); @@ -569,15 +570,15 @@ public class JpaWebTests extends CommonWebTests { @Test // DATAREST-658 public void returnsLinkHeadersForHeadRequestToItemResource() throws Exception { - MockHttpServletResponse response = client.request(client.discoverUnique("people")); + MockHttpServletResponse response = client.request(client.discoverUnique(LinkRelation.of("people"))); String personHref = JsonPath.read(response.getContentAsString(), "$._embedded.people[0]._links.self.href"); response = mvc.perform(head(personHref))// .andExpect(status().isNoContent())// .andReturn().getResponse(); - Links links = Links.valueOf(response.getHeader("Link")); - assertThat(links.hasLink("self")).isTrue(); + Links links = Links.parse(response.getHeader("Link")); + assertThat(links.hasLink(IanaLinkRelations.SELF)).isTrue(); assertThat(links.hasLink("person")).isTrue(); } @@ -594,12 +595,12 @@ public class JpaWebTests extends CommonWebTests { 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")); + andExpect(client.hasLinkWithRel(IanaLinkRelations.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")); + andExpect(client.hasLinkWithRel(IanaLinkRelations.SELF)); } @Test // DATAREST-883 @@ -614,12 +615,12 @@ public class JpaWebTests extends CommonWebTests { 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")); + andExpect(client.hasLinkWithRel(IanaLinkRelations.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")); + andExpect(client.hasLinkWithRel(IanaLinkRelations.SELF)); } @Test // DATAREST-910 @@ -644,17 +645,17 @@ public class JpaWebTests extends CommonWebTests { client.follow(findBySortedLink.expand("offer.price,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")); + andExpect(client.hasLinkWithRel(IanaLinkRelations.SELF)); client.follow(findBySortedLink.expand("offer.price,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")); + andExpect(client.hasLinkWithRel(IanaLinkRelations.SELF)); } private List preparePersonResources(Person primary, Person... persons) throws Exception { - Link peopleLink = client.discoverUnique("people"); + Link peopleLink = client.discoverUnique(LinkRelation.of("people")); List links = new ArrayList(); MockHttpServletResponse primaryResponse = postAndGet(peopleLink, mapper.writeValueAsString(primary), @@ -666,7 +667,7 @@ public class JpaWebTests extends CommonWebTests { String payload = mapper.writeValueAsString(person); MockHttpServletResponse response = postAndGet(peopleLink, payload, MediaType.APPLICATION_JSON); - links.add(client.assertHasLinkWithRel(Link.REL_SELF, response)); + links.add(client.assertHasLinkWithRel(IanaLinkRelations.SELF, response)); } return links; @@ -690,7 +691,7 @@ public class JpaWebTests extends CommonWebTests { private void assertPersonWithNameAndSiblingLink(String name) throws Exception { - MockHttpServletResponse response = client.request(client.discoverUnique("people")); + MockHttpServletResponse response = client.request(client.discoverUnique(LinkRelation.of("people"))); String jsonPath = String.format("$._embedded.people[?(@.firstName == '%s')]", name); diff --git a/spring-data-rest-tests/spring-data-rest-tests-jpa/src/test/java/org/springframework/data/rest/webmvc/jpa/ProfileIntegrationTests.java b/spring-data-rest-tests/spring-data-rest-tests-jpa/src/test/java/org/springframework/data/rest/webmvc/jpa/ProfileIntegrationTests.java index 44b96d158..3ba43a828 100755 --- a/spring-data-rest-tests/spring-data-rest-tests-jpa/src/test/java/org/springframework/data/rest/webmvc/jpa/ProfileIntegrationTests.java +++ b/spring-data-rest-tests/spring-data-rest-tests-jpa/src/test/java/org/springframework/data/rest/webmvc/jpa/ProfileIntegrationTests.java @@ -108,5 +108,4 @@ public class ProfileIntegrationTests extends AbstractControllerIntegrationTests client.follow(profileLink, RestMediaTypes.SCHEMA_JSON).andExpect(status().is2xxSuccessful()) .andExpect(content().contentTypeCompatibleWith(RestMediaTypes.SCHEMA_JSON)); } - } diff --git a/spring-data-rest-tests/spring-data-rest-tests-jpa/src/test/java/org/springframework/data/rest/webmvc/json/PersistentEntitySerializationTests.java b/spring-data-rest-tests/spring-data-rest-tests-jpa/src/test/java/org/springframework/data/rest/webmvc/json/PersistentEntitySerializationTests.java index 1bc4518fb..1e1af6a47 100755 --- a/spring-data-rest-tests/spring-data-rest-tests-jpa/src/test/java/org/springframework/data/rest/webmvc/json/PersistentEntitySerializationTests.java +++ b/spring-data-rest-tests/spring-data-rest-tests-jpa/src/test/java/org/springframework/data/rest/webmvc/json/PersistentEntitySerializationTests.java @@ -38,21 +38,11 @@ import org.springframework.data.projection.ProjectionFactory; import org.springframework.data.projection.SpelAwareProxyProjectionFactory; import org.springframework.data.repository.support.Repositories; import org.springframework.data.rest.webmvc.PersistentEntityResource; -import org.springframework.data.rest.webmvc.jpa.CreditCard; -import org.springframework.data.rest.webmvc.jpa.Dinner; -import org.springframework.data.rest.webmvc.jpa.Guest; -import org.springframework.data.rest.webmvc.jpa.JpaRepositoryConfig; -import org.springframework.data.rest.webmvc.jpa.LineItem; -import org.springframework.data.rest.webmvc.jpa.Order; -import org.springframework.data.rest.webmvc.jpa.OrderRepository; -import org.springframework.data.rest.webmvc.jpa.Person; -import org.springframework.data.rest.webmvc.jpa.PersonRepository; -import org.springframework.data.rest.webmvc.jpa.PersonSummary; -import org.springframework.data.rest.webmvc.jpa.Suite; -import org.springframework.data.rest.webmvc.jpa.UserExcerpt; +import org.springframework.data.rest.webmvc.jpa.*; import org.springframework.data.rest.webmvc.util.TestUtils; import org.springframework.hateoas.Link; import org.springframework.hateoas.LinkDiscoverer; +import org.springframework.hateoas.LinkRelation; import org.springframework.hateoas.PagedResources; import org.springframework.hateoas.PagedResources.PageMetadata; import org.springframework.hateoas.Resource; @@ -105,7 +95,7 @@ public class PersistentEntitySerializationTests { } } - LinkDiscoverer linkDiscoverer; + LinkDiscoverer discoverer; ProjectionFactory projectionFactory; @Before @@ -113,7 +103,7 @@ public class PersistentEntitySerializationTests { RequestContextHolder.setRequestAttributes(new ServletWebRequest(new MockHttpServletRequest())); - this.linkDiscoverer = new HalLinkDiscoverer(); + this.discoverer = new HalLinkDiscoverer(); this.projectionFactory = new SpelAwareProxyProjectionFactory(); } @@ -156,11 +146,15 @@ public class PersistentEntitySerializationTests { String s = writer.toString(); - Link fatherLink = linkDiscoverer.findLinkWithRel("father", s); - assertThat(fatherLink.getHref(), endsWith(new UriTemplate("/{id}/father").expand(person.getId()).toString())); + assertThat(discoverer.findLinkWithRel("father", s)) // + .map(Link::getHref) // + .hasValueSatisfying( + it -> assertThat(it).endsWith(new UriTemplate("/{id}/father").expand(person.getId()).toString())); - Link siblingLink = linkDiscoverer.findLinkWithRel("siblings", s); - assertThat(siblingLink.getHref(), endsWith(new UriTemplate("/{id}/siblings").expand(person.getId()).toString())); + assertThat(discoverer.findLinkWithRel("siblings", s)) // + .map(Link::getHref) // + .hasValueSatisfying( + it -> assertThat(it).endsWith(new UriTemplate("/{id}/siblings").expand(person.getId()).toString())); } @Test // DATAREST-248 @@ -229,7 +223,7 @@ public class PersistentEntitySerializationTests { oliver.setFather(dave); UserExcerpt daveExcerpt = projectionFactory.createProjection(UserExcerpt.class, dave); - EmbeddedWrapper wrapper = new EmbeddedWrappers(false).wrap(daveExcerpt, "father"); + EmbeddedWrapper wrapper = new EmbeddedWrappers(false).wrap(daveExcerpt, LinkRelation.of("father")); PersistentEntityResource resource = PersistentEntityResource.// build(oliver, repositories.getPersistentEntity(Person.class)).// diff --git a/spring-data-rest-tests/spring-data-rest-tests-jpa/src/test/java/org/springframework/data/rest/webmvc/support/RepositoryEntityLinksIntegrationTests.java b/spring-data-rest-tests/spring-data-rest-tests-jpa/src/test/java/org/springframework/data/rest/webmvc/support/RepositoryEntityLinksIntegrationTests.java index a76043ae7..bd9937be5 100755 --- a/spring-data-rest-tests/spring-data-rest-tests-jpa/src/test/java/org/springframework/data/rest/webmvc/support/RepositoryEntityLinksIntegrationTests.java +++ b/spring-data-rest-tests/spring-data-rest-tests-jpa/src/test/java/org/springframework/data/rest/webmvc/support/RepositoryEntityLinksIntegrationTests.java @@ -31,6 +31,7 @@ import org.springframework.data.rest.webmvc.jpa.JpaRepositoryConfig; import org.springframework.data.rest.webmvc.jpa.Order; import org.springframework.data.rest.webmvc.jpa.Person; import org.springframework.hateoas.Link; +import org.springframework.hateoas.LinkRelation; import org.springframework.hateoas.Links; import org.springframework.test.context.ContextConfiguration; import org.springframework.web.util.UriComponents; @@ -53,7 +54,7 @@ public class RepositoryEntityLinksIntegrationTests extends AbstractControllerInt Link link = entityLinks.linkToSingleResource(Person.class, 1); assertThat(link.getHref(), endsWith("/people/1{?projection}")); - assertThat(link.getRel()).isEqualTo("person"); + assertThat(link.getRel()).isEqualTo(LinkRelation.of("person")); } @Test @@ -63,7 +64,7 @@ public class RepositoryEntityLinksIntegrationTests extends AbstractControllerInt assertThat(link.isTemplated()).isTrue(); assertThat(link.getVariableNames()).contains("page", "size", "sort"); - assertThat(link.getRel()).isEqualTo("people"); + assertThat(link.getRel()).isEqualTo(LinkRelation.of("people")); } @Test // DATAREST-221 @@ -107,7 +108,7 @@ public class RepositoryEntityLinksIntegrationTests extends AbstractControllerInt @Test // DATAREST-467 public void returnsLinkToSearchResource() { - Link link = entityLinks.linkToSearchResource(Person.class, "firstname"); + Link link = entityLinks.linkToSearchResource(Person.class, LinkRelation.of("firstname")); assertThat(link).isNotNull(); assertThat(link.isTemplated()).isTrue(); @@ -117,7 +118,7 @@ public class RepositoryEntityLinksIntegrationTests extends AbstractControllerInt @Test // DATAREST-467, DATAREST-519 public void prepopulatesPaginationInformationForSearchResourceLink() { - Link link = entityLinks.linkToSearchResource(Person.class, "firstname", PageRequest.of(0, 10)); + Link link = entityLinks.linkToSearchResource(Person.class, LinkRelation.of("firstname"), PageRequest.of(0, 10)); assertThat(link).isNotNull(); assertThat(link.isTemplated()).isTrue(); @@ -131,7 +132,7 @@ public class RepositoryEntityLinksIntegrationTests extends AbstractControllerInt @Test // DATAREST-467 public void returnsTemplatedLinkForSortedSearchResource() { - Link link = entityLinks.linkToSearchResource(Person.class, "lastname"); + Link link = entityLinks.linkToSearchResource(Person.class, LinkRelation.of("lastname")); assertThat(link.isTemplated()).isTrue(); assertThat(link.getVariableNames()).contains("lastname", "sort"); @@ -140,7 +141,7 @@ public class RepositoryEntityLinksIntegrationTests extends AbstractControllerInt @Test // DATAREST-467, DATAREST-519 public void prepopulatesSortInformationForSearchResourceLink() { - Link link = entityLinks.linkToSearchResource(Person.class, "lastname", Sort.by("firstname")); + Link link = entityLinks.linkToSearchResource(Person.class, LinkRelation.of("lastname"), Sort.by("firstname")); assertThat(link).isNotNull(); assertThat(link.isTemplated()).isTrue(); diff --git a/spring-data-rest-tests/spring-data-rest-tests-mongodb/src/test/java/org/springframework/data/rest/tests/mongodb/MongoWebTests.java b/spring-data-rest-tests/spring-data-rest-tests-mongodb/src/test/java/org/springframework/data/rest/tests/mongodb/MongoWebTests.java index f5c8a8b56..5a20dbab0 100755 --- a/spring-data-rest-tests/spring-data-rest-tests-mongodb/src/test/java/org/springframework/data/rest/tests/mongodb/MongoWebTests.java +++ b/spring-data-rest-tests/spring-data-rest-tests-mongodb/src/test/java/org/springframework/data/rest/tests/mongodb/MongoWebTests.java @@ -33,7 +33,9 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.rest.tests.CommonWebTests; import org.springframework.data.rest.webmvc.RestMediaTypes; import org.springframework.data.rest.webmvc.support.RepositoryEntityLinks; +import org.springframework.hateoas.IanaLinkRelations; import org.springframework.hateoas.Link; +import org.springframework.hateoas.LinkRelation; import org.springframework.http.MediaType; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.test.context.ContextConfiguration; @@ -106,8 +108,8 @@ public class MongoWebTests extends CommonWebTests { * @see org.springframework.data.rest.webmvc.AbstractWebIntegrationTests#expectedRootLinkRels() */ @Override - protected Iterable expectedRootLinkRels() { - return Arrays.asList("profiles", "users"); + protected Iterable expectedRootLinkRels() { + return LinkRelation.manyOf("profiles", "users"); } @Test @@ -122,7 +124,7 @@ public class MongoWebTests extends CommonWebTests { public void rendersEmbeddedDocuments() throws Exception { Link usersLink = client.discoverUnique("users"); - Link userLink = assertHasContentLinkWithRel("self", client.request(usersLink)); + Link userLink = assertHasContentLinkWithRel(IanaLinkRelations.SELF, client.request(usersLink)); client.follow(userLink).// andExpect(jsonPath("$.address.zipCode").value(is(notNullValue()))); } @@ -145,7 +147,7 @@ public class MongoWebTests extends CommonWebTests { public void testname() throws Exception { Link usersLink = client.discoverUnique("users"); - Link userLink = assertHasContentLinkWithRel("self", client.request(usersLink)); + Link userLink = assertHasContentLinkWithRel(IanaLinkRelations.SELF, client.request(usersLink)); MockHttpServletResponse response = patchAndGet(userLink, "{\"lastname\" : null, \"address\" : { \"zipCode\" : \"ZIP\"}}", @@ -159,7 +161,7 @@ public class MongoWebTests extends CommonWebTests { public void testname2() throws Exception { Link usersLink = client.discoverUnique("users"); - Link userLink = assertHasContentLinkWithRel("self", client.request(usersLink)); + Link userLink = assertHasContentLinkWithRel(IanaLinkRelations.SELF, client.request(usersLink)); MockHttpServletResponse response = patchAndGet(userLink, "[{ \"op\": \"replace\", \"path\": \"/address/zipCode\", \"value\": \"ZIP\" }," @@ -183,7 +185,7 @@ public class MongoWebTests extends CommonWebTests { String stringReceipt = mapper.writeValueAsString(receipt); MockHttpServletResponse createdReceipt = postAndGet(receiptLink, stringReceipt, MediaType.APPLICATION_JSON); - Link tacosLink = client.assertHasLinkWithRel("self", createdReceipt); + Link tacosLink = client.assertHasLinkWithRel(IanaLinkRelations.SELF, createdReceipt); assertJsonPathEquals("$.saleItem", "Springy Tacos", createdReceipt); UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(tacosLink.getHref()); @@ -213,7 +215,7 @@ public class MongoWebTests extends CommonWebTests { public void putDoesNotRemoveAssociations() throws Exception { Link usersLink = client.discoverUnique("users"); - Link userLink = assertHasContentLinkWithRel("self", client.request(usersLink)); + Link userLink = assertHasContentLinkWithRel(IanaLinkRelations.SELF, client.request(usersLink)); Link colleaguesLink = client.assertHasLinkWithRel("colleagues", client.request(userLink)); // Expect a user returned as colleague @@ -236,7 +238,7 @@ public class MongoWebTests extends CommonWebTests { public void emptiesAssociationForEmptyUriList() throws Exception { Link usersLink = client.discoverUnique("users"); - Link userLink = assertHasContentLinkWithRel("self", client.request(usersLink)); + Link userLink = assertHasContentLinkWithRel(IanaLinkRelations.SELF, client.request(usersLink)); Link colleaguesLink = client.assertHasLinkWithRel("colleagues", client.request(userLink)); putAndGet(colleaguesLink, "", MediaType.parseMediaType("text/uri-list")); @@ -250,7 +252,7 @@ public class MongoWebTests extends CommonWebTests { public void updatesMapPropertyCorrectly() throws Exception { Link profilesLink = client.discoverUnique("profiles"); - Link profileLink = assertHasContentLinkWithRel("self", client.request(profilesLink)); + Link profileLink = assertHasContentLinkWithRel(IanaLinkRelations.SELF, client.request(profilesLink)); Profile profile = new Profile(); profile.setMetadata(Collections.singletonMap("Key", "Value")); @@ -272,7 +274,9 @@ public class MongoWebTests extends CommonWebTests { MockHttpServletResponse response = postAndGet(receiptsLink, mapper.writeValueAsString(receipt), MediaType.APPLICATION_JSON); - Link receiptLink = client.getDiscoverer(response).findLinkWithRel("self", response.getContentAsString()); + Link receiptLink = client.getDiscoverer(response) // + .findLinkWithRel(IanaLinkRelations.SELF, response.getContentAsString()) // + .orElseThrow(() -> new IllegalStateException("Did not find self link!")); mvc.perform(get(receiptLink.getHref()).header(IF_MODIFIED_SINCE, response.getHeader(LAST_MODIFIED))).// andExpect(status().isNotModified()).// diff --git a/spring-data-rest-tests/spring-data-rest-tests-mongodb/src/test/java/org/springframework/data/rest/webmvc/PersistentEntityResourceAssemblerIntegrationTests.java b/spring-data-rest-tests/spring-data-rest-tests-mongodb/src/test/java/org/springframework/data/rest/webmvc/PersistentEntityResourceAssemblerIntegrationTests.java index fa8c77633..5b6b34adb 100755 --- a/spring-data-rest-tests/spring-data-rest-tests-mongodb/src/test/java/org/springframework/data/rest/webmvc/PersistentEntityResourceAssemblerIntegrationTests.java +++ b/spring-data-rest-tests/spring-data-rest-tests-mongodb/src/test/java/org/springframework/data/rest/webmvc/PersistentEntityResourceAssemblerIntegrationTests.java @@ -27,7 +27,6 @@ import org.mockito.internal.stubbing.answers.ReturnsArgumentAt; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.mapping.context.PersistentEntities; import org.springframework.data.rest.core.support.DefaultSelfLinkProvider; -import org.springframework.data.rest.core.support.EntityLookup; import org.springframework.data.rest.tests.AbstractControllerIntegrationTests; import org.springframework.data.rest.tests.AbstractControllerIntegrationTests.TestConfiguration; import org.springframework.data.rest.tests.mongodb.MongoDbRepositoryConfig; @@ -35,6 +34,7 @@ import org.springframework.data.rest.tests.mongodb.User; import org.springframework.data.rest.webmvc.mapping.Associations; import org.springframework.data.rest.webmvc.support.Projector; import org.springframework.hateoas.EntityLinks; +import org.springframework.hateoas.IanaLinkRelations; import org.springframework.hateoas.Links; import org.springframework.test.context.ContextConfiguration; @@ -58,17 +58,17 @@ public class PersistentEntityResourceAssemblerIntegrationTests extends AbstractC when(projector.projectExcerpt(any())).thenAnswer(new ReturnsArgumentAt(0)); PersistentEntityResourceAssembler assembler = new PersistentEntityResourceAssembler(entities, projector, - associations, new DefaultSelfLinkProvider(entities, entityLinks, Collections.> emptyList())); + associations, new DefaultSelfLinkProvider(entities, entityLinks, Collections.emptyList())); User user = new User(); user.id = BigInteger.valueOf(4711); PersistentEntityResource resource = assembler.toResource(user); - Links links = new Links(resource.getLinks()); + Links links = resource.getLinks(); assertThat(links).hasSize(2); - assertThat(links.getLink("self").orElseThrow(() -> new RuntimeException("Unable to find 'self' link")).getVariables()).isEmpty(); - assertThat(links.getLink("user").orElseThrow(() -> new RuntimeException("Unable to find 'user' link")).getVariableNames()).contains("projection"); + assertThat(links.getRequiredLink(IanaLinkRelations.SELF).getVariables()).isEmpty(); + assertThat(links.getRequiredLink("user").getVariableNames()).contains("projection"); } } diff --git a/spring-data-rest-tests/spring-data-rest-tests-solr/src/test/java/org/springframework/data/rest/webmvc/solr/SolrWebTests.java b/spring-data-rest-tests/spring-data-rest-tests-solr/src/test/java/org/springframework/data/rest/webmvc/solr/SolrWebTests.java index d8efd16b6..6a29b348e 100755 --- a/spring-data-rest-tests/spring-data-rest-tests-solr/src/test/java/org/springframework/data/rest/webmvc/solr/SolrWebTests.java +++ b/spring-data-rest-tests/spring-data-rest-tests-solr/src/test/java/org/springframework/data/rest/webmvc/solr/SolrWebTests.java @@ -31,7 +31,9 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.data.rest.tests.CommonWebTests; import org.springframework.data.solr.repository.config.EnableSolrRepositories; +import org.springframework.hateoas.IanaLinkRelations; import org.springframework.hateoas.Link; +import org.springframework.hateoas.LinkRelation; import org.springframework.http.MediaType; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.test.context.ContextConfiguration; @@ -65,6 +67,7 @@ public class SolrWebTests extends CommonWebTests { @Autowired ProductRepository repo; + @Override @Before public void setUp() { @@ -82,16 +85,16 @@ public class SolrWebTests extends CommonWebTests { MockHttpServletResponse response = client.request("/products?page=0&size=1"); - Link nextLink = client.assertHasLinkWithRel(Link.REL_NEXT, response); - assertDoesNotHaveLinkWithRel(Link.REL_PREVIOUS, response); + Link nextLink = client.assertHasLinkWithRel(IanaLinkRelations.NEXT, response); + assertDoesNotHaveLinkWithRel(IanaLinkRelations.PREV, response); response = client.request(nextLink); - client.assertHasLinkWithRel(Link.REL_PREVIOUS, response); - nextLink = client.assertHasLinkWithRel(Link.REL_NEXT, response); + client.assertHasLinkWithRel(IanaLinkRelations.PREV, response); + nextLink = client.assertHasLinkWithRel(IanaLinkRelations.NEXT, response); response = client.request(nextLink); - client.assertHasLinkWithRel(Link.REL_PREVIOUS, response); - assertDoesNotHaveLinkWithRel(Link.REL_NEXT, response); + client.assertHasLinkWithRel(IanaLinkRelations.PREV, response); + assertDoesNotHaveLinkWithRel(IanaLinkRelations.NEXT, response); } @Test // DATAREST-387 @@ -121,8 +124,8 @@ public class SolrWebTests extends CommonWebTests { * @see org.springframework.data.rest.webmvc.AbstractWebIntegrationTests#expectedRootLinkRels() */ @Override - protected Iterable expectedRootLinkRels() { - return Arrays.asList("products"); + protected Iterable expectedRootLinkRels() { + return LinkRelation.manyOf("products"); } private void assertJsonDocumentMatches(Product reference) throws Exception { diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/AbstractRepositoryRestController.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/AbstractRepositoryRestController.java index 0e7924ec8..8ec52f64f 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/AbstractRepositoryRestController.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/AbstractRepositoryRestController.java @@ -26,7 +26,9 @@ import org.springframework.data.auditing.AuditableBeanWrapperFactory; import org.springframework.data.domain.Page; import org.springframework.data.rest.core.mapping.ResourceMetadata; import org.springframework.data.web.PagedResourcesAssembler; +import org.springframework.hateoas.IanaLinkRelations; import org.springframework.hateoas.Link; +import org.springframework.hateoas.LinkRelation; import org.springframework.hateoas.PagedResources; import org.springframework.hateoas.Resource; import org.springframework.hateoas.Resources; @@ -63,8 +65,8 @@ class AbstractRepositoryRestController { ResourceMetadata repoMapping = resourceLink.getResourceMetadata(); - Link selfLink = resource.getRequiredLink(Link.REL_SELF); - String rel = repoMapping.getItemResourceRel(); + Link selfLink = resource.getRequiredLink(IanaLinkRelations.SELF); + LinkRelation rel = repoMapping.getItemResourceRel(); return new Link(selfLink.getHref(), rel); } diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/EmbeddedResourcesAssembler.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/EmbeddedResourcesAssembler.java index 44e529568..c6b35088f 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/EmbeddedResourcesAssembler.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/EmbeddedResourcesAssembler.java @@ -30,6 +30,7 @@ import org.springframework.data.mapping.context.PersistentEntities; import org.springframework.data.rest.core.mapping.ResourceMetadata; import org.springframework.data.rest.webmvc.mapping.Associations; import org.springframework.data.rest.webmvc.support.ExcerptProjector; +import org.springframework.hateoas.LinkRelation; import org.springframework.hateoas.core.EmbeddedWrapper; import org.springframework.hateoas.core.EmbeddedWrappers; import org.springframework.util.Assert; @@ -59,7 +60,7 @@ public class EmbeddedResourcesAssembler { PersistentEntity entity = entities.getRequiredPersistentEntity(instance.getClass()); final List associationProjections = new ArrayList(); - final PersistentPropertyAccessor accessor = entity.getPropertyAccessor(instance); + final PersistentPropertyAccessor accessor = entity.getPropertyAccessor(instance); final ResourceMetadata metadata = associations.getMetadataFor(entity.getType()); entity.doWithAssociations((SimpleAssociationHandler) association -> { @@ -80,7 +81,7 @@ public class EmbeddedResourcesAssembler { return; } - String rel = metadata.getMappingFor(property).getRel(); + LinkRelation rel = metadata.getMappingFor(property).getRel(); if (value instanceof Collection) { diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/PersistentEntityResource.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/PersistentEntityResource.java index 1c1c0e2bf..1cb1046d6 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/PersistentEntityResource.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/PersistentEntityResource.java @@ -25,6 +25,7 @@ import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.mapping.PersistentPropertyAccessor; import org.springframework.hateoas.Link; +import org.springframework.hateoas.Links; import org.springframework.hateoas.Resource; import org.springframework.hateoas.Resources; import org.springframework.hateoas.core.EmbeddedWrapper; @@ -91,7 +92,7 @@ public class PersistentEntityResource extends Resource { * * @return */ - public PersistentPropertyAccessor getPropertyAccessor() { + public PersistentPropertyAccessor getPropertyAccessor() { return entity.getPropertyAccessor(getContent()); } @@ -214,7 +215,7 @@ public class PersistentEntityResource extends Resource { */ @Override @JsonIgnore - public List getLinks() { + public Links getLinks() { return super.getLinks(); } } diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryEntityController.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryEntityController.java index e2893de61..0a68d4d2b 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryEntityController.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryEntityController.java @@ -18,7 +18,6 @@ package org.springframework.data.rest.webmvc; import static org.springframework.http.HttpMethod.*; import java.io.Serializable; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -165,11 +164,11 @@ class RepositoryEntityController extends AbstractRepositoryRestController implem throw new ResourceNotFoundException(); } - List links = getCollectionResourceLinks(resourceInformation, pageable); - links.add(0, getDefaultSelfLink()); + Links links = Links.of(getDefaultSelfLink()) // + .and(getCollectionResourceLinks(resourceInformation, pageable)); HttpHeaders headers = new HttpHeaders(); - headers.add(LINK_HEADER, new Links(links).toString()); + headers.add(LINK_HEADER, links.toString()); return new ResponseEntity(headers, HttpStatus.NO_CONTENT); } @@ -211,21 +210,18 @@ class RepositoryEntityController extends AbstractRepositoryRestController implem return result; } - private List getCollectionResourceLinks(RootResourceInformation resourceInformation, - DefaultedPageable pageable) { + private Links getCollectionResourceLinks(RootResourceInformation resourceInformation, DefaultedPageable pageable) { ResourceMetadata metadata = resourceInformation.getResourceMetadata(); SearchResourceMappings searchMappings = metadata.getSearchResourceMappings(); - List links = new ArrayList(); - links.add(new Link(ProfileController.getPath(this.config, metadata), ProfileResourceProcessor.PROFILE_REL)); + Links links = Links + .of(new Link(ProfileController.getPath(this.config, metadata), ProfileResourceProcessor.PROFILE_REL)); - if (searchMappings.isExported()) { - links.add(entityLinks.linkFor(metadata.getDomainType()).slash(searchMappings.getPath()) - .withRel(searchMappings.getRel())); - } - - return links; + return searchMappings.isExported() // + ? links.and(entityLinks.linkFor(metadata.getDomainType()).slash(searchMappings.getPath()) + .withRel(searchMappings.getRel())) + : links; } @ResponseBody @@ -237,12 +233,13 @@ class RepositoryEntityController extends AbstractRepositoryRestController implem throws ResourceNotFoundException, HttpRequestMethodNotSupportedException { Resources resources = getCollectionResource(resourceinformation, pageable, sort, assembler); - List links = new ArrayList(resources.getLinks()); + Links links = resources.getLinks(); for (Resource resource : ((Resources>) resources).getContent()) { PersistentEntityResource persistentEntityResource = (PersistentEntityResource) resource; - links.add(resourceLink(resourceinformation, persistentEntityResource)); + links = links.and(resourceLink(resourceinformation, persistentEntityResource)); } + if (resources instanceof PagedResources) { return new PagedResources(Collections.emptyList(), ((PagedResources) resources).getMetadata(), links); } else { @@ -307,7 +304,7 @@ class RepositoryEntityController extends AbstractRepositoryRestController implem return getItemResource(resourceInformation, id).map(it -> { - Links links = new Links(assembler.toResource(it).getLinks()); + Links links = assembler.toResource(it).getLinks(); HttpHeaders headers = headersPreparer.prepareHeaders(resourceInformation.getPersistentEntity(), it); headers.add(LINK_HEADER, links.toString()); diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryPropertyReferenceController.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryPropertyReferenceController.java index f7bd9b9ed..86298a787 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryPropertyReferenceController.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryPropertyReferenceController.java @@ -57,6 +57,7 @@ import org.springframework.data.rest.core.mapping.ResourceMetadata; import org.springframework.data.rest.webmvc.support.BackendId; import org.springframework.data.web.PagedResourcesAssembler; import org.springframework.hateoas.Link; +import org.springframework.hateoas.LinkRelation; import org.springframework.hateoas.Resource; import org.springframework.hateoas.ResourceSupport; import org.springframework.hateoas.Resources; @@ -294,9 +295,9 @@ class RepositoryPropertyReferenceController extends AbstractRepositoryRestContro } else if (prop.property.isMap()) { - Map map = AUGMENTING_METHODS.contains(requestMethod) // - ? (Map) prop.propertyValue // - : CollectionFactory. createMap(propertyType, 0); + Map map = AUGMENTING_METHODS.contains(requestMethod) // + ? (Map) prop.propertyValue // + : CollectionFactory. createMap(propertyType, 0); // Add to the existing collection for (Link l2 : source.getLinks()) { @@ -314,12 +315,13 @@ class RepositoryPropertyReferenceController extends AbstractRepositoryRestContro "Cannot PATCH a reference to this singular property since the property type is not a List or a Map."); } - if (source.getLinks().size() != 1) { + if (source.getLinks().hasSingleLink()) { throw new IllegalArgumentException( "Must send only 1 link to update a property reference that isn't a List or a Map."); } - prop.accessor.setProperty(prop.property, loadPropertyValue(prop.propertyType, source.getLinks().get(0))); + prop.accessor.setProperty(prop.property, + loadPropertyValue(prop.propertyType, source.getLinks().toList().get(0))); } publisher.publishEvent(new BeforeLinkSaveEvent(prop.accessor.getBean(), prop.propertyValue)); diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/alps/RootResourceInformationToAlpsDescriptorConverter.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/alps/RootResourceInformationToAlpsDescriptorConverter.java index caebcc3fe..07d22d545 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/alps/RootResourceInformationToAlpsDescriptorConverter.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/alps/RootResourceInformationToAlpsDescriptorConverter.java @@ -57,6 +57,7 @@ import org.springframework.data.rest.webmvc.json.JacksonMetadata; import org.springframework.data.rest.webmvc.mapping.Associations; import org.springframework.hateoas.EntityLinks; import org.springframework.hateoas.Link; +import org.springframework.hateoas.LinkRelation; import org.springframework.hateoas.TemplateVariable; import org.springframework.hateoas.alps.Alps; import org.springframework.hateoas.alps.Descriptor; @@ -150,8 +151,8 @@ public class RootResourceInformationToAlpsDescriptorConverter { Type descriptorType = getType(method); return descriptor().// - id(prefix(method).concat(metadata.getRel())).// - name(metadata.getRel()).// + id(prefix(method).concat(metadata.getRel().value())).// + name(metadata.getRel().value()).// type(descriptorType).// doc(getDocFor(metadata.getDescription())).// rt("#" + representationDescriptor.getId()).// @@ -176,7 +177,7 @@ public class RootResourceInformationToAlpsDescriptorConverter { Class type = projection.getValue(); String key = String.format("%s.%s.%s", metadata.getRel(), projectionParameterName, projection.getKey()); - ResourceDescription fallback = SimpleResourceDescription.defaultFor(key); + ResourceDescription fallback = SimpleResourceDescription.defaultFor(LinkRelation.of(key)); AnnotationBasedResourceDescription projectionDescription = new AnnotationBasedResourceDescription(type, fallback); projectionDescriptors.add(// @@ -191,7 +192,7 @@ public class RootResourceInformationToAlpsDescriptorConverter { return descriptor().// type(Type.SEMANTIC).// name(projectionParameterName).// - doc(getDocFor(SimpleResourceDescription.defaultFor(projectionParameterName))).// + doc(getDocFor(SimpleResourceDescription.defaultFor(LinkRelation.of(projectionParameterName)))).// descriptor(projectionDescriptors).build(); } @@ -204,7 +205,7 @@ public class RootResourceInformationToAlpsDescriptorConverter { AnnotatedMethod getter = definition.getGetter(); Description description = getter.getAnnotation(Description.class); ResourceDescription fallback = SimpleResourceDescription - .defaultFor(String.format("%s.%s", name, definition.getName())); + .defaultFor(LinkRelation.of(String.format("%s.%s", name, definition.getName()))); ResourceDescription resourceDescription = description == null ? null : new AnnotationBasedResourceDescription(description, fallback); @@ -226,8 +227,8 @@ public class RootResourceInformationToAlpsDescriptorConverter { ResourceMetadata metadata = associations.getMetadataFor(entity.getType()); return descriptor().// - id(prefix(method).concat(metadata.getItemResourceRel())).// - name(metadata.getItemResourceRel()).// + id(prefix(method).concat(metadata.getItemResourceRel().value())).// + name(metadata.getItemResourceRel().value()).// type(getType(method)).// doc(getDocFor(metadata.getItemResourceDescription())).// rt("#".concat(representationDescriptor.getId())). // @@ -275,7 +276,8 @@ public class RootResourceInformationToAlpsDescriptorConverter { continue; } - ResourceDescription description = SimpleResourceDescription.defaultFor(variable.getDescription()); + ResourceDescription description = SimpleResourceDescription + .defaultFor(LinkRelation.of(variable.getDescription())); descriptors.add(// descriptor().// @@ -288,7 +290,7 @@ public class RootResourceInformationToAlpsDescriptorConverter { return descriptors; } - private List buildPropertyDescriptors(final Class type, String baseRel) { + private List buildPropertyDescriptors(final Class type, LinkRelation baseRel) { final PersistentEntity entity = persistentEntities.getRequiredPersistentEntity(type); final List propertyDescriptors = new ArrayList(); @@ -333,7 +335,7 @@ public class RootResourceInformationToAlpsDescriptorConverter { ResourceMapping mapping = metadata.getMappingFor(property); DescriptorBuilder builder = descriptor().// - name(mapping.getRel()).doc(getDocFor(mapping.getDescription())); + name(mapping.getRel().value()).doc(getDocFor(mapping.getDescription())); ResourceMetadata targetTypeMetadata = associations.getMetadataFor(property.getActualType()); @@ -374,7 +376,7 @@ public class RootResourceInformationToAlpsDescriptorConverter { descriptors.add(descriptor().// type(Type.SAFE).// - name(methodMapping.getRel()).// + name(methodMapping.getRel().value()).// descriptor(parameterDescriptors).// build()); } @@ -421,7 +423,7 @@ public class RootResourceInformationToAlpsDescriptorConverter { } private static String getRepresentationDescriptorId(ResourceMetadata metadata) { - return metadata.getItemResourceRel().concat("-representation"); + return metadata.getItemResourceRel().value().concat("-representation"); } private static String prefix(HttpMethod method) { 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 bd5c4bf8e..1ec94c040 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 @@ -613,7 +613,7 @@ public class PersistentEntityJackson2Module extends SimpleModule { Object target = value.getTarget(); ResourceMetadata metadata = associations.getMetadataFor(value.getTargetClass()); - Links links = metadata.isExported() ? collector.getLinksFor(target) : new Links(); + Links links = metadata.isExported() ? collector.getLinksFor(target) : Links.NONE; Resource resource = invoker.invokeProcessorsFor(new Resource(value, links)); diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/mapping/LinkCollectingAssociationHandler.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/mapping/LinkCollectingAssociationHandler.java index 43eb2173a..a90dfe2d4 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/mapping/LinkCollectingAssociationHandler.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/mapping/LinkCollectingAssociationHandler.java @@ -81,8 +81,8 @@ public class LinkCollectingAssociationHandler implements SimpleAssociationHandle * * @return the links */ - public List getLinks() { - return links; + public Links getLinks() { + return Links.of(links); } /* @@ -96,7 +96,7 @@ public class LinkCollectingAssociationHandler implements SimpleAssociationHandle if (associations.isLinkableAssociation(property)) { - Links existingLinks = new Links(links); + Links existingLinks = Links.of(links); for (Link link : associations.getLinksFor(association, basePath)) { if (existingLinks.hasLink(link.getRel())) { diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/mapping/LinkCollector.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/mapping/LinkCollector.java index a1dfc82c4..c1abbd340 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/mapping/LinkCollector.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/mapping/LinkCollector.java @@ -35,6 +35,7 @@ import org.springframework.data.rest.core.Path; import org.springframework.data.rest.core.mapping.ResourceMapping; import org.springframework.data.rest.core.mapping.ResourceMetadata; import org.springframework.data.rest.core.support.SelfLinkProvider; +import org.springframework.hateoas.IanaLinkRelations; import org.springframework.hateoas.Link; import org.springframework.hateoas.Links; import org.springframework.util.Assert; @@ -75,7 +76,7 @@ public class LinkCollector { * @return */ public Links getLinksFor(Object object) { - return getLinksFor(object, Collections. emptyList()); + return getLinksFor(object, Links.NONE); } /** @@ -85,16 +86,15 @@ public class LinkCollector { * @param existingLinks must not be {@literal null}. * @return */ - public Links getLinksFor(Object object, List existingLinks) { + public Links getLinksFor(Object object, Links existingLinks) { Assert.notNull(object, "Object must not be null!"); Assert.notNull(existingLinks, "Existing links must not be null!"); - Links links = new Links(existingLinks); - Link selfLink = createSelfLink(object, links); + Link selfLink = createSelfLink(object, existingLinks); if (selfLink == null) { - return links; + return existingLinks; } Path path = new Path(selfLink.expand().getHref()); @@ -102,13 +102,10 @@ public class LinkCollector { LinkCollectingAssociationHandler handler = new LinkCollectingAssociationHandler(entities, path, associationLinks); entities.getRequiredPersistentEntity(object.getClass()).doWithAssociations(handler); - List result = new ArrayList(existingLinks); - result.addAll(handler.getLinks()); - - return addSelfLinkIfNecessary(object, result); + return addSelfLinkIfNecessary(object, existingLinks.and(handler.getLinks())); } - public Links getLinksForNested(Object object, List existing) { + public Links getLinksForNested(Object object, Links existing) { PersistentEntity entity = entities.getRequiredPersistentEntity(object.getClass()); @@ -116,35 +113,21 @@ public class LinkCollector { entity.getPropertyAccessor(object), associationLinks); entity.doWithAssociations(handler); - List links = new ArrayList(); - links.addAll(existing); - links.addAll(handler.getLinks()); - - return new Links(links); + return existing.and(handler.getLinks()); } - private Links addSelfLinkIfNecessary(Object object, List existing) { + private Links addSelfLinkIfNecessary(Object object, Links existing) { - Links result = new Links(existing); - - if (result.hasLink(Link.REL_SELF)) { - return result; - } - - List list = new ArrayList(); - list.add(createSelfLink(object, result)); - list.addAll(existing); - - return new Links(list); + return existing.hasLink(IanaLinkRelations.SELF) // + ? existing // + : Links.of(createSelfLink(object, existing)) // + .and(existing); } private Link createSelfLink(Object object, Links existing) { - if (existing.hasLink(Link.REL_SELF)) { - return existing.getLink(Link.REL_SELF).get(); - } - - return links.createSelfLinkFor(object).withSelfRel(); + return existing.getLink(IanaLinkRelations.SELF) // + .orElseGet(() -> links.createSelfLinkFor(object).withSelfRel()); } /** @@ -168,8 +151,8 @@ public class LinkCollector { * * @return the links */ - public List getLinks() { - return links; + public Links getLinks() { + return Links.of(links); } /* @@ -182,7 +165,7 @@ public class LinkCollector { if (associationLinks.isLinkableAssociation(association)) { PersistentProperty property = association.getInverse(); - Links existingLinks = new Links(links); + Links existingLinks = Links.of(links); for (Link link : associationLinks.getLinksFor(association, basePath)) { if (existingLinks.hasLink(link.getRel())) { @@ -199,7 +182,7 @@ public class LinkCollector { private static class NestedLinkCollectingAssociationHandler implements SimpleAssociationHandler { private final SelfLinkProvider selfLinks; - private final PersistentPropertyAccessor accessor; + private final PersistentPropertyAccessor accessor; private final Associations associations; private final @Getter List links = new ArrayList(); diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/support/RepositoryEntityLinks.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/support/RepositoryEntityLinks.java index 54afbb575..05fa6cc48 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/support/RepositoryEntityLinks.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/support/RepositoryEntityLinks.java @@ -41,6 +41,7 @@ import org.springframework.data.rest.webmvc.spi.BackendIdConverter.DefaultIdConv import org.springframework.hateoas.EntityLinks; import org.springframework.hateoas.Link; import org.springframework.hateoas.LinkBuilder; +import org.springframework.hateoas.LinkRelation; import org.springframework.hateoas.Links; import org.springframework.hateoas.TemplateVariable; import org.springframework.hateoas.TemplateVariable.VariableType; @@ -181,43 +182,43 @@ public class RepositoryEntityLinks extends AbstractEntityLinks { } /** - * Creates the link to the search resource with the given rel for a given type. + * Creates the link to the search resource with the given {@link LinkRelation} for a given type. * * @param domainType must not be {@literal null}. - * @param rel must not be {@literal null} or empty. + * @param relation must not be {@literal null}. * @return * @since 2.3 */ - public Link linkToSearchResource(Class domainType, String rel) { - return getSearchResourceLinkFor(domainType, rel, null, null); + public Link linkToSearchResource(Class domainType, LinkRelation relation) { + return getSearchResourceLinkFor(domainType, relation, null, null); } /** - * Creates the link to the search resource with the given rel for a given type. Uses the given {@link Pageable} to - * pre-expand potentially available template variables. + * Creates the link to the search resource with the given {@link LinkRelation} for a given type. Uses the given + * {@link Pageable} to pre-expand potentially available template variables. * * @param domainType must not be {@literal null}. - * @param rel must not be {@literal null} or empty. + * @param relation must not be {@literal null}. * @param pageable can be {@literal null}. * @return * @since 2.3 */ - public Link linkToSearchResource(Class domainType, String rel, Pageable pageable) { - return getSearchResourceLinkFor(domainType, rel, pageable, null); + public Link linkToSearchResource(Class domainType, LinkRelation relation, Pageable pageable) { + return getSearchResourceLinkFor(domainType, relation, pageable, null); } /** - * Creates the link to the search resource with the given rel for a given type. Uses the given {@link Sort} to - * pre-expand potentially available template variables. + * Creates the link to the search resource with the given {@link LinkRelation} for a given type. Uses the given + * {@link Sort} to pre-expand potentially available template variables. * * @param domainType must not be {@literal null}. - * @param rel must not be {@literal null} or empty. + * @param relation must not be {@literal null}. * @param sort can be {@literal null}. * @return * @since 2.3 */ - public Link linkToSearchResource(Class domainType, String rel, Sort sort) { - return getSearchResourceLinkFor(domainType, rel, null, sort); + public Link linkToSearchResource(Class domainType, LinkRelation relation, Sort sort) { + return getSearchResourceLinkFor(domainType, relation, null, sort); } /** @@ -231,31 +232,26 @@ public class RepositoryEntityLinks extends AbstractEntityLinks { */ private Links linksToSearchResources(Class type, Pageable pageable, Sort sort) { - List links = new ArrayList(); - - SearchResourceMappings searchMappings = mappings.getSearchResourceMappings(type); - - for (MethodResourceMapping mapping : searchMappings.getExportedMappings()) { - links.add(getSearchResourceLinkFor(type, mapping.getRel(), pageable, sort)); - } - - return new Links(links); + return mappings.getSearchResourceMappings(type).getExportedMappings() // + .map(MethodResourceMapping::getRel) // + .map(it -> getSearchResourceLinkFor(type, it, pageable, sort)) // + .collect(Links.collector()); } /** - * Returns the link pointing to the search resource with the given rel of the given type and pre-expands the - * calculated URi tempalte with the given {@link Pageable} and {@link Sort}. + * Returns the link pointing to the search resource with the given {@link LinkRelation} of the given type and + * pre-expands the calculated URi template with the given {@link Pageable} and {@link Sort}. * * @param type must not be {@literal null}. - * @param rel must not be {@literal null} or empty. + * @param rel must not be {@literal null}. * @param pageable can be {@literal null}. * @param sort can be {@literal null}. * @return */ - private Link getSearchResourceLinkFor(Class type, String rel, Pageable pageable, Sort sort) { + private Link getSearchResourceLinkFor(Class type, LinkRelation rel, Pageable pageable, Sort sort) { Assert.notNull(type, "Domain type must not be null!"); - Assert.hasText(rel, "Relation name must not be null or empty!"); + Assert.notNull(rel, "Relation name must not be null!"); SearchResourceMappings searchMappings = mappings.getSearchResourceMappings(type); MethodResourceMapping mapping = searchMappings.getExportedMethodMappingForRel(rel); diff --git a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/PersistentEntityResourceUnitTests.java b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/PersistentEntityResourceUnitTests.java index ce3e5349a..4c2c49c4c 100755 --- a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/PersistentEntityResourceUnitTests.java +++ b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/PersistentEntityResourceUnitTests.java @@ -26,6 +26,7 @@ import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import org.springframework.data.mapping.PersistentEntity; import org.springframework.hateoas.Link; +import org.springframework.hateoas.LinkRelation; import org.springframework.hateoas.Resources; import org.springframework.hateoas.core.EmbeddedWrapper; import org.springframework.hateoas.core.EmbeddedWrappers; @@ -48,7 +49,7 @@ public class PersistentEntityResourceUnitTests { public void setUp() { EmbeddedWrappers wrappers = new EmbeddedWrappers(false); - EmbeddedWrapper wrapper = wrappers.wrap("Embedded", "foo"); + EmbeddedWrapper wrapper = wrappers.wrap("Embedded", LinkRelation.of("foo")); this.resources = new Resources(Collections.singleton(wrapper)); }