#833 - Changed ResourceSupport class name hierarchy.

This commit is contained in:
Oliver Drotbohm
2019-02-27 20:04:15 +01:00
parent 57f36a58db
commit a89e57eed7
93 changed files with 1606 additions and 1476 deletions

View File

@@ -38,6 +38,7 @@ FILES=`find . -name "$FILES_PATTERN"`
EXPRESSION="s/Link\.REL_SELF/IanaLinkRelations.SELF/g;\
s/Link\.REL_PREV/IanaLinkRelations.PREV/g;\
s/Link\.REL_NEXT/IanaLinkRelations.NEXT/g;\
\
s/hateoas\.EntityLinks/hateoas.server.EntityLinks/g;\
s/hateoas\.JsonPathLinkDiscoverer/hateoas.client.JsonPathLinkDiscoverer/g;\
s/hateoas\.LinkBuilder/hateoas.server.LinkBuilder/g;\
@@ -47,7 +48,11 @@ s/hateoas\.MethodLinkBuilderFactory/hateoas.server.MethodLinkBuilderFactory/g;\
s/hateoas\.RelProvider/hateoas.server.RelProvider/g;\
s/hateoas\.ResourceAssembler/hateoas.server.ResourceAssembler/g;\
s/hateoas\.ResourceProcessor/hateoas.server.ResourceProcessor/g;\
s/hateoas\.VndErrors/hateoas.mediatype.vnderror.VndErrors/g;\
s/hateoas\.VndErrors.VndError/hateoas.mediatype.vnderror.VndErrors.VndError/g;\
\
s/hateoas\.alps/hateoas.mediatype.alps/g;\
\
s/hateoas\.core\.AbstractEntityLinks/hateoas.server.core.AbstractEntityLinks/g;\
s/hateoas\.core\.AnnotationAttribute/hateoas.server.core.AnnotationAttribute/g;\
s/hateoas\.core\.AnnotationMappingDiscoverer/hateoas.server.core.AnnotationMappingDiscoverer/g;\
@@ -57,7 +62,9 @@ s/hateoas\.core\.EvoInflectorRelProvider/hateoas.server.core.EvoInflectorRelProv
s/hateoas\.core\.JsonPathLinkDiscoverer/hateoas.client.JsonPathLinkDiscoverer/g;\
s/hateoas\.core\.LinkBuilderSupport/hateoas.server.core.LinkBuilderSupport/g;\
s/hateoas\.core\.MethodParameters/hateoas.server.core.MethodParameters/g;\
\
s/hateoas\.hal/hateoas.mediatype.hal/g;\
\
s/hateoas\.mvc\.ControllerLinkBuilder/hateoas.server.mvc.WebMvcLinkBuilder/g;\
s/hateoas\.mvc\.ControllerLinkBuilderFactory/hateoas.server.mvc.WebMvcLinkBuilderFactory/g;\
s/hateoas\.mvc\.HeaderLinksResponseEntity/hateoas.server.core.HeaderLinksResponseEntity/g;\
@@ -66,12 +73,35 @@ s/hateoas\.mvc\.ResourceProcessorInvokingHandlerAdapter/hateoas.server.mvc.Resou
s/hateoas\.mvc\.TypeConstrainedMappingJackson2HttpMessageConverter/hateoas.server.mvc.TypeConstrainedMappingJackson2HttpMessageConverter/g;\
s/hateoas\.mvc\.UriComponentsContributor/hateoas.server.mvc.UriComponentsContributor/g;\
s/ControllerLinkBuilderFactory/WebMvcLinkBuilderFactory/g;\
s/ControllerLinkBuilder/WebMvcLinkBuilder/g;"
s/ControllerLinkBuilder/WebMvcLinkBuilder/g;\
\
s/\([^a-z]\)ResourceProcessorInvokingHandlerAdapter\([ ><,#();\.]\)/\1RepresentationModelProcessorInvokingHandlerAdapter\2/g;\
s/\([^a-z]\)ResourceProcessorInvoker\([ ><,#();\.]\)/\1RepresentationModelProcessorInvoker\2/g;\
s/\([^a-z]\)ResourceProcessor\([ ><,#();\.]\)/\1RepresentationModelProcessor\2/g;\
\
s/ ResourceAssembler / RepresentationModelAssembler /g;\
s/\.ResourceAssembler;/.RepresentationModelAssembler;/g;\
s/ResourceAssembler\([<#]\)/RepresentationModelAssembler\1/g;\
s/IdentifiableResourceAssemblerSupport/IdentifiableRepresentationModelAssemblerSupport/g;\
s/toResource(/toModel(/g;\
s/toResources(/toCollectionModel(/g;\
\
s/\([^a-z]\)ResourceSupport\([ ><,#();\.]\)/\1RepresentationModel\2/g;\
s/\([^a-z]\)PagedResources\([ ><,#();\.]\)/\1PagedModel\2/g;\
s/\([^a-z]\)Resources\([ ><,#();\.]\)/\1CollectionModel\2/g;\
s/\([^a-z]\)Resource\([ ><,#();\.]\)/\1EntityModel\2/g;\
\
s/linkForSingleResource/linkForItemResource/g;\
s/linkToSingleResource/linkToItemResource/g;\
"
#EXPRESSION="s/[\s\.]PagedResources\([;<]\)/.PagedRepresentationModel\1/g;"
for FILE in $FILES
do
echo "Adapting $FILE"
sed -i "" $EXPRESSION $FILE
# echo $EXPRESSION
sed -i "" -e "$EXPRESSION" $FILE
done
echo
@@ -81,4 +111,7 @@ echo 'If you have used link relation constants defined in Link (like Link.REL_SE
echo 'codebase, you will have to trigger an organize imports in your IDE to make sure the'
echo 'now referenced IanaLinkRelations gets imported.'
echo
echo "Also, if you were referring to core Spring's Resource type you might see invalid migrations"
echo "as there's no way for us to differentiate that from Spring HATEOAS Resource type."
echo
echo 'After that, review your changes, commit and code on! \ö/'

View File

@@ -563,7 +563,6 @@
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>${jsonpath.version}</version>
<optional>true</optional>
</dependency>
<dependency>

View File

@@ -10,13 +10,29 @@ There had been an incredible amount of feedback on it and the major version bump
The biggest changes in package structure were driven by the introduction of a hypermedia type registration API to support additional media types in Spring HATEOAS.
This lead to the clear separation of client and server APIs (packages named respectively) as well as media type implementations in the package `mediatype`.
The easiest way to get your codebase upgraded to the new API is by using the <<migrate-to-1.0.script, migration script>>.
Before we jump to that, here are the changes at a quick glance:
The easiest way to get your code base upgraded to the new API is by using the <<migrate-to-1.0.script, migration script>>.
Before we jump to that, here are the changes at a quick glance.
* `ResourceSupport` now exposes a `Links` instance (over a `List<Link>`) as that exposes additional API to concatenate and merge different `Links` instances using various strategies.
=== Representation models
The `ResourceSupport`/`Resource`/`Resources`/`PagedResources` group of classes never really felt appropriately named.
After all, these types do not actually manifest resources but rather representation models that can be enriched with hypermedia information and affordances.
Here's how new names map to the old ones:
* `ResourceSupport` is now `RepresentationModel`
* `Resource` is now `EntityModel`
* `Resources` is now `CollectionModel`
* `PagedResources` is now `PagedModel`
Consequently, `ResourceAssembler` has been renamed to `RepresentationModelAssembler` and its methods `toResource(…)` and `toResources(…)` have been renamed to `toModel(…)` and `toCollectionModel(…)` respectively.
Also the name changes have been reflected in the classes contained in `TypeReferences`.
* `RepresentationModel.getLinks()` now exposes a `Links` instance (over a `List<Link>`) as that exposes additional API to concatenate and merge different `Links` instances using various strategies.
Also it has been turned into a self-bound generic type to allow the methods that add links to the instance return the instance itself.
* The `LinkDiscoverer` API has been moved to the `client` package.
* The `LinkBuilder` API has been moved to the `server` package.
* The `LinkBuilder` and `EntityLinks` APIs have been moved to the `server` package.
* `ControllerLinkBuilder` has been moved into `server.mvc` and deprecated to be replaced by `WebMvcLinkBuilder`.
* `VndError` has been moved to the `mediatype.vnderror` package.
[migrate-to-1.0.script]
== The migration script

View File

@@ -31,34 +31,34 @@ import com.fasterxml.jackson.annotation.JsonProperty;
* @author Oliver Gierke
* @author Greg Turnquist
*/
public class Resources<T> extends ResourceSupport implements Iterable<T> {
public class CollectionModel<T> extends RepresentationModel<CollectionModel<T>> implements Iterable<T> {
private final Collection<T> content;
/**
* Creates an empty {@link Resources} instance.
* Creates an empty {@link CollectionModel} instance.
*/
protected Resources() {
protected CollectionModel() {
this(new ArrayList<>());
}
/**
* Creates a {@link Resources} instance with the given content and {@link Link}s (optional).
* Creates a {@link CollectionModel} instance with the given content and {@link Link}s (optional).
*
* @param content must not be {@literal null}.
* @param links the links to be added to the {@link Resources}.
* @param links the links to be added to the {@link CollectionModel}.
*/
public Resources(Iterable<T> content, Link... links) {
public CollectionModel(Iterable<T> content, Link... links) {
this(content, Arrays.asList(links));
}
/**
* Creates a {@link Resources} instance with the given content and {@link Link}s.
* Creates a {@link CollectionModel} instance with the given content and {@link Link}s.
*
* @param content must not be {@literal null}.
* @param links the links to be added to the {@link Resources}.
* @param links the links to be added to the {@link CollectionModel}.
*/
public Resources(Iterable<T> content, Iterable<Link> links) {
public CollectionModel(Iterable<T> content, Iterable<Link> links) {
Assert.notNull(content, "Content must not be null!");
@@ -71,23 +71,24 @@ public class Resources<T> extends ResourceSupport implements Iterable<T> {
}
/**
* Creates a new {@link Resources} instance by wrapping the given domain class instances into a {@link Resource}.
* Creates a new {@link CollectionModel} instance by wrapping the given domain class instances into a
* {@link EntityModel}.
*
* @param content must not be {@literal null}.
* @return
*/
@SuppressWarnings("unchecked")
public static <T extends Resource<S>, S> Resources<T> wrap(Iterable<S> content) {
public static <T extends EntityModel<S>, S> CollectionModel<T> wrap(Iterable<S> content) {
Assert.notNull(content, "Content must not be null!");
ArrayList<T> resources = new ArrayList<>();
for (S element : content) {
resources.add((T) new Resource<>(element));
resources.add((T) new EntityModel<>(element));
}
return new Resources<>(resources);
return new CollectionModel<>(resources);
}
/**
@@ -133,7 +134,7 @@ public class Resources<T> extends ResourceSupport implements Iterable<T> {
return false;
}
Resources<?> that = (Resources<?>) obj;
CollectionModel<?> that = (CollectionModel<?>) obj;
boolean contentEqual = this.content == null ? that.content == null : this.content.equals(that.content);
return contentEqual && super.equals(obj);

View File

@@ -23,39 +23,39 @@ import org.springframework.util.Assert;
import com.fasterxml.jackson.annotation.JsonUnwrapped;
/**
* A simple {@link Resource} wrapping a domain object and adding links to it.
*
* A simple {@link EntityModel} wrapping a domain object and adding links to it.
*
* @author Oliver Gierke
* @author Greg Turnquist
*/
public class Resource<T> extends ResourceSupport {
public class EntityModel<T> extends RepresentationModel<EntityModel<T>> {
private final T content;
/**
* Creates an empty {@link Resource}.
* Creates an empty {@link EntityModel}.
*/
protected Resource() {
protected EntityModel() {
this.content = null;
}
/**
* Creates a new {@link Resource} with the given content and {@link Link}s (optional).
*
* Creates a new {@link EntityModel} with the given content and {@link Link}s (optional).
*
* @param content must not be {@literal null}.
* @param links the links to add to the {@link Resource}.
* @param links the links to add to the {@link EntityModel}.
*/
public Resource(T content, Link... links) {
public EntityModel(T content, Link... links) {
this(content, Arrays.asList(links));
}
/**
* Creates a new {@link Resource} with the given content and {@link Link}s.
*
* Creates a new {@link EntityModel} with the given content and {@link Link}s.
*
* @param content must not be {@literal null}.
* @param links the links to add to the {@link Resource}.
* @param links the links to add to the {@link EntityModel}.
*/
public Resource(T content, Iterable<Link> links) {
public EntityModel(T content, Iterable<Link> links) {
Assert.notNull(content, "Content must not be null!");
Assert.isTrue(!(content instanceof Collection), "Content must not be a collection! Use Resources instead!");
@@ -65,7 +65,7 @@ public class Resource<T> extends ResourceSupport {
/**
* Returns the underlying entity.
*
*
* @return the content
*/
@JsonUnwrapped
@@ -73,7 +73,7 @@ public class Resource<T> extends ResourceSupport {
return content;
}
/*
/*
* (non-Javadoc)
* @see org.springframework.hateoas.ResourceSupport#toString()
*/
@@ -82,7 +82,7 @@ public class Resource<T> extends ResourceSupport {
return String.format("Resource { content: %s, %s }", getContent(), super.toString());
}
/*
/*
* (non-Javadoc)
* @see org.springframework.hateoas.ResourceSupport#equals(java.lang.Object)
*/
@@ -97,13 +97,13 @@ public class Resource<T> extends ResourceSupport {
return false;
}
Resource<?> that = (Resource<?>) obj;
EntityModel<?> that = (EntityModel<?>) obj;
boolean contentEqual = this.content == null ? that.content == null : this.content.equals(that.content);
return contentEqual && super.equals(obj);
}
/*
/*
* (non-Javadoc)
* @see org.springframework.hateoas.ResourceSupport#hashCode()
*/

View File

@@ -31,39 +31,41 @@ import com.fasterxml.jackson.annotation.JsonProperty;
* @author Oliver Gierke
* @author Greg Turnquist
*/
public class PagedResources<T> extends Resources<T> {
public class PagedModel<T> extends CollectionModel<T> {
public static PagedResources<?> NO_PAGE = new PagedResources<>();
public static PagedModel<?> NO_PAGE = new PagedModel<>();
private PageMetadata metadata;
/**
* Default constructor to allow instantiation by reflection.
*/
protected PagedResources() {
protected PagedModel() {
this(new ArrayList<>(), null);
}
/**
* Creates a new {@link PagedResources} from the given content, {@link PageMetadata} and {@link Link}s (optional).
* Creates a new {@link PagedModel} from the given content, {@link PageMetadata} and {@link Link}s (optional).
*
* @param content must not be {@literal null}.
* @param metadata
* @param links
*/
public PagedResources(Collection<T> content, PageMetadata metadata, Link... links) {
public PagedModel(Collection<T> content, PageMetadata metadata, Link... links) {
this(content, metadata, Arrays.asList(links));
}
/**
* Creates a new {@link PagedResources} from the given content {@link PageMetadata} and {@link Link}s.
* Creates a new {@link PagedModel} from the given content {@link PageMetadata} and {@link Link}s.
*
* @param content must not be {@literal null}.
* @param metadata
* @param links
*/
public PagedResources(Collection<T> content, PageMetadata metadata, Iterable<Link> links) {
public PagedModel(Collection<T> content, PageMetadata metadata, Iterable<Link> links) {
super(content, links);
this.metadata = metadata;
}
@@ -78,23 +80,23 @@ public class PagedResources<T> extends Resources<T> {
}
/**
* Factory method to easily create a {@link PagedResources} instance from a set of entities and pagination metadata.
* Factory method to easily create a {@link PagedModel} instance from a set of entities and pagination metadata.
*
* @param content must not be {@literal null}.
* @param metadata
* @return
*/
@SuppressWarnings("unchecked")
public static <T extends Resource<S>, S> PagedResources<T> wrap(Iterable<S> content, PageMetadata metadata) {
public static <T extends EntityModel<S>, S> PagedModel<T> wrap(Iterable<S> content, PageMetadata metadata) {
Assert.notNull(content, "Content must not be null!");
ArrayList<T> resources = new ArrayList<>();
for (S element : content) {
resources.add((T) new Resource<>(element));
resources.add((T) new EntityModel<>(element));
}
return new PagedResources<>(resources, metadata);
return new PagedModel<>(resources, metadata);
}
/**
@@ -141,7 +143,7 @@ public class PagedResources<T> extends Resources<T> {
return false;
}
PagedResources<?> that = (PagedResources<?>) obj;
PagedModel<?> that = (PagedModel<?>) obj;
boolean metadataEquals = this.metadata == null ? that.metadata == null : this.metadata.equals(that.metadata);
return metadataEquals && super.equals(obj);

View File

@@ -33,15 +33,15 @@ import com.fasterxml.jackson.annotation.JsonProperty;
* @author Johhny Lim
* @author Greg Turnquist
*/
public class ResourceSupport implements Identifiable<Link> {
public class RepresentationModel<T extends RepresentationModel<? extends T>> implements Identifiable<Link> {
private final List<Link> links;
public ResourceSupport() {
public RepresentationModel() {
this.links = new ArrayList<>();
}
public ResourceSupport(Link initialLink) {
public RepresentationModel(Link initialLink) {
Assert.notNull(initialLink, "initialLink must not be null!");
@@ -49,7 +49,7 @@ public class ResourceSupport implements Identifiable<Link> {
this.links.add(initialLink);
}
public ResourceSupport(List<Link> initialLinks) {
public RepresentationModel(List<Link> initialLinks) {
Assert.notNull(initialLinks, "initialLinks must not be null!");
@@ -70,11 +70,14 @@ public class ResourceSupport implements Identifiable<Link> {
*
* @param link
*/
public void add(Link link) {
@SuppressWarnings("unchecked")
public T add(Link link) {
Assert.notNull(link, "Link must not be null!");
this.links.add(link);
return (T) this;
}
/**
@@ -82,11 +85,14 @@ public class ResourceSupport implements Identifiable<Link> {
*
* @param links
*/
public void add(Iterable<Link> links) {
@SuppressWarnings("unchecked")
public T add(Iterable<Link> links) {
Assert.notNull(links, "Given links must not be null!");
links.forEach(this::add);
return (T) this;
}
/**
@@ -94,11 +100,14 @@ public class ResourceSupport implements Identifiable<Link> {
*
* @param links must not be {@literal null}.
*/
public void add(Link... links) {
@SuppressWarnings("unchecked")
public T add(Link... links) {
Assert.notNull(links, "Given links must not be null!");
add(Arrays.asList(links));
return (T) this;
}
/**
@@ -137,58 +146,90 @@ public class ResourceSupport implements Identifiable<Link> {
/**
* Removes all {@link Link}s added to the resource so far.
*/
public void removeLinks() {
@SuppressWarnings("unchecked")
public T removeLinks() {
this.links.clear();
return (T) this;
}
/**
* Returns the link with the given rel.
* Returns the link with the given relation.
*
* @param rel
* @return the link with the given rel or {@link Optional#empty()} if none found.
* @param relation must not be {@literal null} or empty.
* @return the link with the given relation or {@link Optional#empty()} if none found.
*/
public Optional<Link> getLink(String rel) {
return getLink(LinkRelation.of(rel));
public Optional<Link> getLink(String relation) {
return getLink(LinkRelation.of(relation));
}
public Optional<Link> getLink(LinkRelation rel) {
/**
* Returns the link with the given {@link LinkRelation}.
*
* @param relation
* @return
*/
public Optional<Link> getLink(LinkRelation relation) {
return links.stream() //
.filter(it -> it.hasRel(rel)) //
.filter(it -> it.hasRel(relation)) //
.findFirst();
}
/**
* Returns the link with the given rel.
* Returns the link with the given relation.
*
* @param rel
* @return the link with the given rel.
* @throws IllegalArgumentException in case no link with the given rel can be found.
* @param relation must not be {@literal null} or empty.
* @return the link with the given relation.
* @throws IllegalArgumentException in case no link with the given relation can be found.
*/
public Link getRequiredLink(String rel) {
public Link getRequiredLink(String relation) {
return getLink(rel) //
.orElseThrow(() -> new IllegalArgumentException(String.format("No link with rel %s found!", rel)));
}
public Link getRequiredLink(LinkRelation rel) {
return getRequiredLink(rel.value());
return getLink(relation) //
.orElseThrow(() -> new IllegalArgumentException(String.format("No link with rel %s found!", relation)));
}
/**
* Returns all {@link Link}s with the given relation type.
* Returns the link with the given relation.
*
* @param relation must not be {@literal null}.
* @return the link with the given relation.
* @throws IllegalArgumentException in case no link with the given relation can be found.
*/
public Link getRequiredLink(LinkRelation relation) {
Assert.notNull(relation, "Link relation must not be null!");
return getRequiredLink(relation.value());
}
/**
* Returns all {@link Link}s with the given relation.
*
* @param relation must not be {@literal null}.
* @return the links in a {@link List}
*/
public List<Link> getLinks(String rel) {
public List<Link> getLinks(String relation) {
Assert.hasText(relation, "Link relation must not be null or empty!");
return links.stream() //
.filter(link -> link.hasRel(rel)) //
.filter(link -> link.hasRel(relation)) //
.collect(Collectors.toList());
}
public List<Link> getLinks(LinkRelation rel) {
return getLinks(rel.value());
/**
* Returns all {@link Link}s with the given relation.
*
* @param relation must not be {@literal null}.
* @return the links in a {@link List}
*/
public List<Link> getLinks(LinkRelation relation) {
Assert.notNull(relation, "Link relation must not be null!");
return getLinks(relation.value());
}
/*
@@ -205,6 +246,7 @@ public class ResourceSupport implements Identifiable<Link> {
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
@SuppressWarnings("unchecked")
public boolean equals(Object obj) {
if (this == obj) {
@@ -215,9 +257,9 @@ public class ResourceSupport implements Identifiable<Link> {
return false;
}
ResourceSupport that = (ResourceSupport) obj;
T that = (T) obj;
return this.links.equals(that.links);
return getLinks().equals(that.getLinks());
}
/*

View File

@@ -26,7 +26,7 @@ import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.hateoas.server.mvc.TypeConstrainedMappingJackson2HttpMessageConverter;
import org.springframework.hateoas.server.mvc.UriComponentsContributor;
import org.springframework.hateoas.server.mvc.WebMvcLinkBuilderFactory;
@@ -84,7 +84,7 @@ class WebMvcHateoasConfiguration {
this.hypermediaTypes.forEach(hypermedia -> {
converters.add(0, new TypeConstrainedMappingJackson2HttpMessageConverter(ResourceSupport.class,
converters.add(0, new TypeConstrainedMappingJackson2HttpMessageConverter(RepresentationModel.class,
hypermedia.getMediaTypes(), hypermedia.configureObjectMapper(mapper.copy())));
});
}

View File

@@ -15,8 +15,8 @@
*/
package org.springframework.hateoas.mediatype;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.Resources;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.CollectionModel;
import com.fasterxml.jackson.databind.JavaType;
@@ -49,8 +49,8 @@ public final class JacksonHelper {
public static boolean isResourcesOfResource(JavaType type) {
return
Resources.class.isAssignableFrom(type.getRawClass())
CollectionModel.class.isAssignableFrom(type.getRawClass())
&&
Resource.class.isAssignableFrom(type.containedType(0).getRawClass());
EntityModel.class.isAssignableFrom(type.containedType(0).getRawClass());
}
}

View File

@@ -35,7 +35,7 @@ import reactor.core.publisher.Mono;
import org.springframework.beans.BeanUtils;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.support.WebStack;
import org.springframework.util.ReflectionUtils;
@@ -56,8 +56,8 @@ public class PropertyUtils {
public static Map<String, Object> findProperties(Object object) {
if (object.getClass().equals(Resource.class)) {
return findProperties(((Resource<?>) object).getContent());
if (object.getClass().equals(EntityModel.class)) {
return findProperties(((EntityModel<?>) object).getContent());
}
return getPropertyDescriptors(object.getClass())
@@ -83,7 +83,7 @@ public class PropertyUtils {
}
}
if (resolvableType.getRawClass().equals(Resource.class)) {
if (resolvableType.getRawClass().equals(EntityModel.class)) {
return findPropertyNames(resolvableType.resolveGeneric(0));
} else {
return findPropertyNames(resolvableType.getRawClass());

View File

@@ -17,7 +17,7 @@ package org.springframework.hateoas.mediatype.collectionjson;
import static org.springframework.hateoas.mediatype.collectionjson.Jackson2CollectionJsonModule.*;
import org.springframework.hateoas.Resources;
import org.springframework.hateoas.CollectionModel;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
@@ -27,6 +27,6 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
* @author Greg Turnquist
*/
@JsonDeserialize(using = CollectionJsonResourcesDeserializer.class)
abstract class ResourcesMixin<T> extends Resources<T> {
abstract class CollectionRepresentationModelMixin<T> extends CollectionModel<T> {
}

View File

@@ -17,7 +17,7 @@ package org.springframework.hateoas.mediatype.collectionjson;
import static org.springframework.hateoas.mediatype.collectionjson.Jackson2CollectionJsonModule.*;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.EntityModel;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
@@ -27,6 +27,6 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
* @author Greg Turnquist
*/
@JsonDeserialize(using = CollectionJsonResourceDeserializer.class)
abstract class ResourceMixin<T> extends Resource<T> {
abstract class EntityRepresentationModelMixin<T> extends EntityModel<T> {
}

View File

@@ -26,17 +26,17 @@ import java.util.function.Function;
import java.util.stream.Collectors;
import org.springframework.hateoas.Affordance;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.IanaLinkRelations;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.Links;
import org.springframework.hateoas.Links.MergeMode;
import org.springframework.hateoas.MediaTypes;
import org.springframework.hateoas.PagedModel;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.hateoas.mediatype.JacksonHelper;
import org.springframework.hateoas.mediatype.PropertyUtils;
import org.springframework.hateoas.MediaTypes;
import org.springframework.hateoas.PagedResources;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.hateoas.Resources;
import org.springframework.http.HttpMethod;
import com.fasterxml.jackson.core.JsonGenerator;
@@ -59,8 +59,8 @@ import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import com.fasterxml.jackson.databind.type.TypeFactory;
/**
* Jackson 2 module implementation to render {@link Resources}, {@link Resource}, and {@link ResourceSupport} instances
* in Collection+JSON compatible JSON.
* Jackson 2 module implementation to render {@link CollectionModel}, {@link EntityModel}, and
* {@link RepresentationModel} instances in Collection+JSON compatible JSON.
*
* @author Greg Turnquist
* @author Oliver Drotbohm
@@ -73,10 +73,10 @@ class Jackson2CollectionJsonModule extends SimpleModule {
super("collection-json-module", new Version(1, 0, 0, null, "org.springframework.hateoas", "spring-hateoas"));
setMixInAnnotation(ResourceSupport.class, ResourceSupportMixin.class);
setMixInAnnotation(Resource.class, ResourceMixin.class);
setMixInAnnotation(Resources.class, ResourcesMixin.class);
setMixInAnnotation(PagedResources.class, PagedResourcesMixin.class);
setMixInAnnotation(RepresentationModel.class, RepresentationModelMixin.class);
setMixInAnnotation(EntityModel.class, EntityRepresentationModelMixin.class);
setMixInAnnotation(CollectionModel.class, CollectionRepresentationModelMixin.class);
setMixInAnnotation(PagedModel.class, PagedResourcesMixin.class);
addSerializer(new CollectionJsonPagedResourcesSerializer());
addSerializer(new CollectionJsonResourcesSerializer());
@@ -160,7 +160,7 @@ class Jackson2CollectionJsonModule extends SimpleModule {
}
}
static class CollectionJsonResourceSupportSerializer extends ContainerSerializer<ResourceSupport>
static class CollectionJsonResourceSupportSerializer extends ContainerSerializer<RepresentationModel<?>>
implements ContextualSerializer {
private static final long serialVersionUID = 6127711241993352699L;
@@ -173,12 +173,13 @@ class Jackson2CollectionJsonModule extends SimpleModule {
CollectionJsonResourceSupportSerializer(BeanProperty property) {
super(ResourceSupport.class, false);
super(RepresentationModel.class, false);
this.property = property;
}
@Override
public void serialize(ResourceSupport value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
public void serialize(RepresentationModel<?> value, JsonGenerator jgen, SerializerProvider provider)
throws IOException {
String href = value.getRequiredLink(IanaLinkRelations.SELF.value()).getHref();
@@ -220,7 +221,7 @@ class Jackson2CollectionJsonModule extends SimpleModule {
}
@Override
public boolean hasSingleElement(ResourceSupport value) {
public boolean hasSingleElement(RepresentationModel<?> value) {
return true;
}
@@ -230,7 +231,7 @@ class Jackson2CollectionJsonModule extends SimpleModule {
}
}
static class CollectionJsonResourceSerializer extends ContainerSerializer<Resource<?>>
static class CollectionJsonResourceSerializer extends ContainerSerializer<EntityModel<?>>
implements ContextualSerializer {
private static final long serialVersionUID = 2212535956767860364L;
@@ -243,12 +244,12 @@ class Jackson2CollectionJsonModule extends SimpleModule {
CollectionJsonResourceSerializer(BeanProperty property) {
super(Resource.class, false);
super(EntityModel.class, false);
this.property = property;
}
@Override
public void serialize(Resource<?> value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
public void serialize(EntityModel<?> value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
String href = value.getRequiredLink(IanaLinkRelations.SELF).getHref();
Links withoutSelfLink = value.getLinks().without(IanaLinkRelations.SELF);
@@ -287,7 +288,7 @@ class Jackson2CollectionJsonModule extends SimpleModule {
}
@Override
public boolean hasSingleElement(Resource<?> value) {
public boolean hasSingleElement(EntityModel<?> value) {
return true;
}
@@ -297,12 +298,12 @@ class Jackson2CollectionJsonModule extends SimpleModule {
}
}
static class CollectionJsonResourcesSerializer extends ContainerSerializer<Resources<?>> {
static class CollectionJsonResourcesSerializer extends ContainerSerializer<CollectionModel<?>> {
private static final long serialVersionUID = -278986431091914402L;
CollectionJsonResourcesSerializer() {
super(Resources.class, false);
super(CollectionModel.class, false);
}
/*
@@ -310,7 +311,8 @@ class Jackson2CollectionJsonModule extends SimpleModule {
* @see com.fasterxml.jackson.databind.ser.std.StdSerializer#serialize(java.lang.Object, com.fasterxml.jackson.core.JsonGenerator, com.fasterxml.jackson.databind.SerializerProvider)
*/
@Override
public void serialize(Resources<?> value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
public void serialize(CollectionModel<?> value, JsonGenerator jgen, SerializerProvider provider)
throws IOException {
CollectionJson<Object> collectionJson = new CollectionJson<>() //
.withVersion("1.0") //
@@ -349,7 +351,7 @@ class Jackson2CollectionJsonModule extends SimpleModule {
* @see com.fasterxml.jackson.databind.JsonSerializer#isEmpty(com.fasterxml.jackson.databind.SerializerProvider, java.lang.Object)
*/
@Override
public boolean isEmpty(SerializerProvider provider, Resources<?> value) {
public boolean isEmpty(SerializerProvider provider, CollectionModel<?> value) {
return value.getContent().isEmpty();
}
@@ -358,7 +360,7 @@ class Jackson2CollectionJsonModule extends SimpleModule {
* @see com.fasterxml.jackson.databind.ser.ContainerSerializer#hasSingleElement(java.lang.Object)
*/
@Override
public boolean hasSingleElement(Resources<?> value) {
public boolean hasSingleElement(CollectionModel<?> value) {
return value.getContent().size() == 1;
}
@@ -372,7 +374,7 @@ class Jackson2CollectionJsonModule extends SimpleModule {
}
}
static class CollectionJsonPagedResourcesSerializer extends ContainerSerializer<PagedResources<?>>
static class CollectionJsonPagedResourcesSerializer extends ContainerSerializer<PagedModel<?>>
implements ContextualSerializer {
private static final long serialVersionUID = -6703190072925382402L;
@@ -385,12 +387,12 @@ class Jackson2CollectionJsonModule extends SimpleModule {
CollectionJsonPagedResourcesSerializer(BeanProperty property) {
super(Resources.class, false);
super(CollectionModel.class, false);
this.property = property;
}
@Override
public void serialize(PagedResources<?> value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
public void serialize(PagedModel<?> value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
CollectionJson<?> collectionJson = new CollectionJson<>() //
.withVersion("1.0") //
@@ -422,12 +424,12 @@ class Jackson2CollectionJsonModule extends SimpleModule {
}
@Override
public boolean isEmpty(PagedResources<?> value) {
public boolean isEmpty(PagedModel<?> value) {
return value.getContent().size() == 0;
}
@Override
public boolean hasSingleElement(PagedResources<?> value) {
public boolean hasSingleElement(PagedModel<?> value) {
return value.getContent().size() == 1;
}
@@ -476,7 +478,7 @@ class Jackson2CollectionJsonModule extends SimpleModule {
}
}
static class CollectionJsonResourceSupportDeserializer extends ContainerDeserializerBase<ResourceSupport>
static class CollectionJsonResourceSupportDeserializer extends ContainerDeserializerBase<RepresentationModel<?>>
implements ContextualDeserializer {
private static final long serialVersionUID = 502737712634617739L;
@@ -484,7 +486,7 @@ class Jackson2CollectionJsonModule extends SimpleModule {
private final JavaType contentType;
CollectionJsonResourceSupportDeserializer() {
this(TypeFactory.defaultInstance().constructType(ResourceSupport.class));
this(TypeFactory.defaultInstance().constructType(RepresentationModel.class));
}
CollectionJsonResourceSupportDeserializer(JavaType contentType) {
@@ -516,7 +518,7 @@ class Jackson2CollectionJsonModule extends SimpleModule {
* @see com.fasterxml.jackson.databind.JsonDeserializer#deserialize(com.fasterxml.jackson.core.JsonParser, com.fasterxml.jackson.databind.DeserializationContext)
*/
@Override
public ResourceSupport deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
public RepresentationModel<?> deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
TypeFactory typeFactory = ctxt.getTypeFactory();
@@ -541,10 +543,9 @@ class Jackson2CollectionJsonModule extends SimpleModule {
CollectionJsonItem<?> firstItem = items.get(0).withOwnSelfLink();
ResourceSupport resource = (ResourceSupport) firstItem.toRawData(this.contentType);
resource.add(firstItem.getLinks().merge(merged));
RepresentationModel<?> resource = (RepresentationModel<?>) firstItem.toRawData(this.contentType);
return resource.add(firstItem.getLinks().merge(merged));
return resource;
}
if (withOwnSelfLink.getTemplate() != null) {
@@ -552,19 +553,14 @@ class Jackson2CollectionJsonModule extends SimpleModule {
Map<String, Object> properties = withOwnSelfLink.getTemplate().getData().stream()
.collect(Collectors.toMap(CollectionJsonData::getName, CollectionJsonData::getValue));
ResourceSupport resourceSupport = (ResourceSupport) PropertyUtils
RepresentationModel<?> resourceSupport = (RepresentationModel<?>) PropertyUtils
.createObjectFromProperties(this.contentType.getRawClass(), properties);
resourceSupport.add(withOwnSelfLink.getLinks());
return resourceSupport;
return resourceSupport.add(withOwnSelfLink.getLinks());
} else {
ResourceSupport resource = new ResourceSupport();
resource.add(withOwnSelfLink.getLinks());
return resource;
return new RepresentationModel<>().add(withOwnSelfLink.getLinks());
}
}
@@ -580,7 +576,7 @@ class Jackson2CollectionJsonModule extends SimpleModule {
}
}
static class CollectionJsonResourceDeserializer extends ContainerDeserializerBase<Resource<?>>
static class CollectionJsonResourceDeserializer extends ContainerDeserializerBase<EntityModel<?>>
implements ContextualDeserializer {
private static final long serialVersionUID = -5911687423054932523L;
@@ -608,7 +604,7 @@ class Jackson2CollectionJsonModule extends SimpleModule {
}
@Override
public Resource<?> deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
public EntityModel<?> deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
JavaType rootType = JacksonHelper.findRootType(this.contentType);
JavaType wrappedType = ctxt.getTypeFactory().constructParametricType(CollectionJsonDocument.class, rootType);
@@ -626,7 +622,7 @@ class Jackson2CollectionJsonModule extends SimpleModule {
Object obj = PropertyUtils.createObjectFromProperties(rootType.getRawClass(), properties);
return new Resource<>(obj, links);
return new EntityModel<>(obj, links);
} else {
Links merged = items.stream() //
@@ -637,7 +633,7 @@ class Jackson2CollectionJsonModule extends SimpleModule {
CollectionJsonItem<?> firstItem = items.get(0).withOwnSelfLink();
return new Resource<>(firstItem.toRawData(rootType),
return new EntityModel<>(firstItem.toRawData(rootType),
merged.merge(MergeMode.REPLACE_BY_REL, firstItem.getLinks()));
}
}
@@ -655,8 +651,8 @@ class Jackson2CollectionJsonModule extends SimpleModule {
}
}
static abstract class CollectionJsonDeserializerBase<T extends Resources<?>> extends ContainerDeserializerBase<T>
implements ContextualDeserializer {
static abstract class CollectionJsonDeserializerBase<T extends CollectionModel<?>>
extends ContainerDeserializerBase<T> implements ContextualDeserializer {
private static final long serialVersionUID = 1007769482339850545L;
@@ -731,22 +727,22 @@ class Jackson2CollectionJsonModule extends SimpleModule {
return finalizer.apply(Collections.emptyList(), links);
}
boolean isResource = contentType.hasGenericTypes() && contentType.containedType(0).hasRawClass(Resource.class);
boolean isResource = contentType.hasGenericTypes() && contentType.containedType(0).hasRawClass(EntityModel.class);
return collection.getItems().stream() //
.map(CollectionJsonItem::withOwnSelfLink) //
.<Object> map(it -> isResource //
? new Resource<>(it.toRawData(rootType), it.getLinks()) //
? new EntityModel<>(it.toRawData(rootType), it.getLinks()) //
: it.toRawData(rootType)) //
.collect(Collectors.collectingAndThen(Collectors.toList(), it -> finalizer.apply(it, links)));
}
}
static class CollectionJsonResourcesDeserializer extends CollectionJsonDeserializerBase<Resources<?>> {
static class CollectionJsonResourcesDeserializer extends CollectionJsonDeserializerBase<CollectionModel<?>> {
private static final long serialVersionUID = 6406522912020578141L;
private static final BiFunction<List<Object>, Links, Resources<?>> FINISHER = Resources::new;
private static final Function<JavaType, CollectionJsonDeserializerBase<Resources<?>>> CONTEXTUAL_CREATOR = CollectionJsonResourcesDeserializer::new;
private static final BiFunction<List<Object>, Links, CollectionModel<?>> FINISHER = CollectionModel::new;
private static final Function<JavaType, CollectionJsonDeserializerBase<CollectionModel<?>>> CONTEXTUAL_CREATOR = CollectionJsonResourcesDeserializer::new;
CollectionJsonResourcesDeserializer() {
super(FINISHER, CONTEXTUAL_CREATOR);
@@ -757,12 +753,12 @@ class Jackson2CollectionJsonModule extends SimpleModule {
}
}
static class CollectionJsonPagedResourcesDeserializer extends CollectionJsonDeserializerBase<PagedResources<?>> {
static class CollectionJsonPagedResourcesDeserializer extends CollectionJsonDeserializerBase<PagedModel<?>> {
private static final long serialVersionUID = -7465448422501330790L;
private static final BiFunction<List<Object>, Links, PagedResources<?>> FINISHER = (content,
links) -> new PagedResources<>(content, null, links);
private static final Function<JavaType, CollectionJsonDeserializerBase<PagedResources<?>>> CONTEXTUAL_CREATOR = CollectionJsonPagedResourcesDeserializer::new;
private static final BiFunction<List<Object>, Links, PagedModel<?>> FINISHER = (content,
links) -> new PagedModel<>(content, null, links);
private static final Function<JavaType, CollectionJsonDeserializerBase<PagedModel<?>>> CONTEXTUAL_CREATOR = CollectionJsonPagedResourcesDeserializer::new;
CollectionJsonPagedResourcesDeserializer() {
super(FINISHER, CONTEXTUAL_CREATOR);
@@ -773,15 +769,15 @@ class Jackson2CollectionJsonModule extends SimpleModule {
}
}
private static List<CollectionJsonItem<Object>> resourcesToCollectionJsonItems(Resources<?> resources) {
private static List<CollectionJsonItem<Object>> resourcesToCollectionJsonItems(CollectionModel<?> resources) {
return resources.getContent().stream().map(content -> {
if (!Resource.class.isInstance(content)) {
if (!EntityModel.class.isInstance(content)) {
return new CollectionJsonItem<>().withRawData(content);
}
Resource<?> resource = (Resource<?>) content;
EntityModel<?> resource = (EntityModel<?>) content;
return new CollectionJsonItem<>() //
.withHref(resource.getRequiredLink(IanaLinkRelations.SELF).getHref())
@@ -797,7 +793,7 @@ class Jackson2CollectionJsonModule extends SimpleModule {
* @param resource
* @return
*/
private static List<CollectionJsonQuery> findQueries(ResourceSupport resource) {
private static List<CollectionJsonQuery> findQueries(RepresentationModel<?> resource) {
if (!resource.hasLink(IanaLinkRelations.SELF)) {
return Collections.emptyList();
@@ -823,7 +819,7 @@ class Jackson2CollectionJsonModule extends SimpleModule {
* @param resource
* @return
*/
private static CollectionJsonTemplate findTemplate(ResourceSupport resource) {
private static CollectionJsonTemplate findTemplate(RepresentationModel<?> resource) {
if (!resource.hasLink(IanaLinkRelations.SELF)) {
return null;

View File

@@ -17,16 +17,16 @@ package org.springframework.hateoas.mediatype.collectionjson;
import static org.springframework.hateoas.mediatype.collectionjson.Jackson2CollectionJsonModule.*;
import org.springframework.hateoas.PagedResources;
import org.springframework.hateoas.PagedModel;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
/**
* Jackson 2 mixin to handle {@link PagedResources}.
* Jackson 2 mixin to handle {@link PagedModel}.
*
* @author Greg Turnquist
*/
@JsonDeserialize(using = CollectionJsonPagedResourcesDeserializer.class)
abstract class PagedResourcesMixin<T> extends PagedResources<T> {
abstract class PagedResourcesMixin<T> extends PagedModel<T> {
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015-2018 the original author or authors.
* Copyright 2015-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@
package org.springframework.hateoas.mediatype.collectionjson;
import org.springframework.hateoas.Links;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.hateoas.mediatype.collectionjson.Jackson2CollectionJsonModule.CollectionJsonLinksDeserializer;
import org.springframework.hateoas.mediatype.collectionjson.Jackson2CollectionJsonModule.CollectionJsonLinksSerializer;
import org.springframework.hateoas.mediatype.collectionjson.Jackson2CollectionJsonModule.CollectionJsonResourceSupportDeserializer;
@@ -33,7 +33,7 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize;
* @author Jens Schauder
*/
@JsonDeserialize(using = CollectionJsonResourceSupportDeserializer.class)
abstract class ResourceSupportMixin extends ResourceSupport {
abstract class RepresentationModelMixin extends RepresentationModel<RepresentationModelMixin> {
@Override
@JsonProperty("collection")

View File

@@ -17,7 +17,7 @@ package org.springframework.hateoas.mediatype.hal;
import java.util.Collection;
import org.springframework.hateoas.Resources;
import org.springframework.hateoas.CollectionModel;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
@@ -34,7 +34,7 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize;
* @author Greg Turnquist
*/
@JsonPropertyOrder({ "content", "links" })
abstract class ResourcesMixin<T> extends Resources<T> {
abstract class CollectionModelMixin<T> extends CollectionModel<T> {
@Override
@JsonProperty("_embedded")

View File

@@ -23,7 +23,7 @@ import java.util.List;
import java.util.Map;
import org.springframework.hateoas.LinkRelation;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.server.RelProvider;
import org.springframework.hateoas.server.core.EmbeddedWrapper;
import org.springframework.hateoas.server.core.EmbeddedWrappers;
@@ -63,7 +63,7 @@ class HalEmbeddedBuilder {
/**
* Adds the given value to the embeddeds. Will skip doing so if the value is {@literal null} or the content of a
* {@link Resource} is {@literal null}.
* {@link EntityModel} is {@literal null}.
*
* @param source can be {@literal null}.
*/

View File

@@ -15,18 +15,17 @@
*/
package org.springframework.hateoas.mediatype.hal;
import lombok.RequiredArgsConstructor;
import java.util.List;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.hateoas.client.LinkDiscoverer;
import org.springframework.hateoas.config.EnableHypermediaSupport.HypermediaType;
import org.springframework.hateoas.server.RelProvider;
import org.springframework.hateoas.config.HypermediaMappingInformation;
import org.springframework.hateoas.server.RelProvider;
import org.springframework.http.MediaType;
import com.fasterxml.jackson.databind.DeserializationFeature;
@@ -39,7 +38,6 @@ import com.fasterxml.jackson.databind.ObjectMapper;
* @author Oliver Drotbohm
*/
@Configuration
@RequiredArgsConstructor
public class HalMediaTypeConfiguration implements HypermediaMappingInformation {
private final RelProvider relProvider;
@@ -47,6 +45,22 @@ public class HalMediaTypeConfiguration implements HypermediaMappingInformation {
private final ObjectProvider<HalConfiguration> halConfiguration;
private final MessageSourceAccessor messageSourceAccessor;
/**
* @param relProvider
* @param curieProvider
* @param halConfiguration
* @param messageSourceAccessor
*/
public HalMediaTypeConfiguration(RelProvider relProvider, ObjectProvider<CurieProvider> curieProvider,
ObjectProvider<HalConfiguration> halConfiguration,
@Qualifier("linkRelationMessageSource") MessageSourceAccessor messageSourceAccessor) {
this.relProvider = relProvider;
this.curieProvider = curieProvider;
this.halConfiguration = halConfiguration;
this.messageSourceAccessor = messageSourceAccessor;
}
@Bean
LinkDiscoverer halLinkDisocoverer() {
return new HalLinkDiscoverer();

View File

@@ -29,12 +29,12 @@ import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.NoSuchMessageException;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.LinkRelation;
import org.springframework.hateoas.Links;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.hateoas.Resources;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.hateoas.mediatype.hal.HalConfiguration.RenderSingleLinks;
import org.springframework.hateoas.server.RelProvider;
import org.springframework.util.Assert;
@@ -65,7 +65,8 @@ import com.fasterxml.jackson.databind.ser.std.StdScalarSerializer;
import com.fasterxml.jackson.databind.type.TypeFactory;
/**
* Jackson 2 module implementation to render {@link Link} and {@link ResourceSupport} instances in HAL compatible JSON.
* Jackson 2 module implementation to render {@link Link} and {@link RepresentationModel} instances in HAL compatible
* JSON.
*
* @author Alexander Baetz
* @author Oliver Gierke
@@ -81,8 +82,8 @@ public class Jackson2HalModule extends SimpleModule {
super("json-hal-module", new Version(1, 0, 0, null, "org.springframework.hateoas", "spring-hateoas"));
setMixInAnnotation(Link.class, LinkMixin.class);
setMixInAnnotation(ResourceSupport.class, ResourceSupportMixin.class);
setMixInAnnotation(Resources.class, ResourcesMixin.class);
setMixInAnnotation(RepresentationModel.class, RepresentationModelMixin.class);
setMixInAnnotation(CollectionModel.class, CollectionModelMixin.class);
}
/**
@@ -154,8 +155,8 @@ public class Jackson2HalModule extends SimpleModule {
Object currentValue = jgen.getCurrentValue();
if (currentValue instanceof Resources) {
if (mapper.hasCuriedEmbed((Resources<?>) currentValue)) {
if (currentValue instanceof CollectionModel) {
if (mapper.hasCuriedEmbed((CollectionModel<?>) currentValue)) {
curiedLinkPresent = true;
}
}
@@ -287,7 +288,8 @@ public class Jackson2HalModule extends SimpleModule {
}
/**
* Custom {@link JsonSerializer} to render {@link Resource}-Lists in HAL compatible JSON. Renders the list as a Map.
* Custom {@link JsonSerializer} to render {@link EntityModel}-Lists in HAL compatible JSON. Renders the
* list as a Map.
*
* @author Alexander Baetz
* @author Oliver Gierke
@@ -325,10 +327,10 @@ public class Jackson2HalModule extends SimpleModule {
Object currentValue = jgen.getCurrentValue();
if (currentValue instanceof ResourceSupport) {
if (currentValue instanceof RepresentationModel) {
if (embeddedMapper.hasCuriedEmbed(value)) {
((ResourceSupport) currentValue).add(CURIES_REQUIRED_DUE_TO_EMBEDS);
((RepresentationModel<?>) currentValue).add(CURIES_REQUIRED_DUE_TO_EMBEDS);
}
}

View File

@@ -17,7 +17,7 @@ package org.springframework.hateoas.mediatype.hal;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.Links;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.hateoas.RepresentationModel;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
@@ -32,7 +32,7 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize;
* @author Oliver Gierke
* @author Greg Turnquist
*/
public abstract class ResourceSupportMixin extends ResourceSupport {
public abstract class RepresentationModelMixin extends RepresentationModel<RepresentationModelMixin> {
@Override
@JsonProperty("_links")

View File

@@ -28,7 +28,7 @@ import java.util.Map;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.Links;
import org.springframework.hateoas.PagedResources;
import org.springframework.hateoas.PagedModel;
import org.springframework.hateoas.mediatype.hal.HalLinkRelation;
import org.springframework.hateoas.mediatype.hal.Jackson2HalModule.HalLinkListSerializer;
import org.springframework.hateoas.mediatype.hal.forms.Jackson2HalFormsModule.HalFormsLinksDeserializer;
@@ -71,7 +71,7 @@ public class HalFormsDocument<T> {
@JsonProperty("page") //
@JsonInclude(Include.NON_NULL) //
private PagedResources.PageMetadata pageMetadata;
private PagedModel.PageMetadata pageMetadata;
@Singular //
@JsonProperty("_links") //

View File

@@ -22,13 +22,13 @@ import java.util.List;
import java.util.Map;
import org.springframework.hateoas.Affordance;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.IanaLinkRelations;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.MediaTypes;
import org.springframework.hateoas.PagedResources;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.hateoas.Resources;
import org.springframework.hateoas.PagedModel;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.hateoas.mediatype.hal.HalLinkRelation;
import org.springframework.hateoas.mediatype.hal.Jackson2HalModule;
import org.springframework.http.HttpMethod;
@@ -51,9 +51,10 @@ import com.fasterxml.jackson.databind.ser.ContextualSerializer;
class HalFormsSerializers {
/**
* Serializer for {@link Resources}.
* Serializer for {@link CollectionModel}.
*/
static class HalFormsResourceSerializer extends ContainerSerializer<Resource<?>> implements ContextualSerializer {
static class HalFormsResourceSerializer extends ContainerSerializer<EntityModel<?>>
implements ContextualSerializer {
private static final long serialVersionUID = -7912243216469101379L;
@@ -61,7 +62,7 @@ class HalFormsSerializers {
HalFormsResourceSerializer(BeanProperty property) {
super(Resource.class, false);
super(EntityModel.class, false);
this.property = property;
}
@@ -70,7 +71,8 @@ class HalFormsSerializers {
}
@Override
public void serialize(Resource<?> value, JsonGenerator gen, SerializerProvider provider) throws IOException {
public void serialize(EntityModel<?> value, JsonGenerator gen, SerializerProvider provider)
throws IOException {
HalFormsDocument<?> doc = HalFormsDocument.forResource(value.getContent()) //
.withLinks(value.getLinks()) //
@@ -90,7 +92,7 @@ class HalFormsSerializers {
}
@Override
public boolean hasSingleElement(Resource<?> resource) {
public boolean hasSingleElement(EntityModel<?> resource) {
return false;
}
@@ -107,9 +109,10 @@ class HalFormsSerializers {
}
/**
* Serializer for {@link Resources}
* Serializer for {@link CollectionModel}
*/
static class HalFormsResourcesSerializer extends ContainerSerializer<Resources<?>> implements ContextualSerializer {
static class HalFormsResourcesSerializer extends ContainerSerializer<CollectionModel<?>>
implements ContextualSerializer {
private static final long serialVersionUID = -3601146866067500734L;
@@ -118,7 +121,7 @@ class HalFormsSerializers {
HalFormsResourcesSerializer(BeanProperty property, Jackson2HalModule.EmbeddedMapper embeddedMapper) {
super(Resources.class, false);
super(CollectionModel.class, false);
this.property = property;
this.embeddedMapper = embeddedMapper;
@@ -129,17 +132,18 @@ class HalFormsSerializers {
}
@Override
public void serialize(Resources<?> value, JsonGenerator gen, SerializerProvider provider) throws IOException {
public void serialize(CollectionModel<?> value, JsonGenerator gen, SerializerProvider provider)
throws IOException {
Map<HalLinkRelation, Object> embeddeds = embeddedMapper.map(value);
HalFormsDocument<?> doc;
if (value instanceof PagedResources) {
if (value instanceof PagedModel) {
doc = HalFormsDocument.empty() //
.withEmbedded(embeddeds) //
.withPageMetadata(((PagedResources<?>) value).getMetadata()) //
.withPageMetadata(((PagedModel<?>) value).getMetadata()) //
.withLinks(value.getLinks()) //
.withTemplates(findTemplates(value));
@@ -165,7 +169,7 @@ class HalFormsSerializers {
}
@Override
public boolean hasSingleElement(Resources<?> resources) {
public boolean hasSingleElement(CollectionModel<?> resources) {
return resources.getContent().size() == 1;
}
@@ -182,12 +186,12 @@ class HalFormsSerializers {
}
/**
* Extract template details from a {@link ResourceSupport}'s {@link Affordance}s.
* Extract template details from a {@link RepresentationModel}'s {@link Affordance}s.
*
* @param resource
* @return
*/
private static Map<String, HalFormsTemplate> findTemplates(ResourceSupport resource) {
private static Map<String, HalFormsTemplate> findTemplates(RepresentationModel<?> resource) {
if (!resource.hasLink(IanaLinkRelations.SELF)) {
return Collections.emptyMap();
@@ -222,7 +226,7 @@ class HalFormsSerializers {
* @param resource
* @param model
*/
private static void validate(ResourceSupport resource, HalFormsAffordanceModel model) {
private static void validate(RepresentationModel<?> resource, HalFormsAffordanceModel model) {
String affordanceUri = model.getURI();
String selfLinkUri = resource.getRequiredLink(IanaLinkRelations.SELF.value()).expand().getHref();

View File

@@ -22,18 +22,18 @@ import java.util.Map;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.Links;
import org.springframework.hateoas.PagedResources;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.hateoas.Resources;
import org.springframework.hateoas.PagedModel;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.hateoas.mediatype.hal.CurieProvider;
import org.springframework.hateoas.mediatype.hal.LinkMixin;
import org.springframework.hateoas.mediatype.hal.ResourceSupportMixin;
import org.springframework.hateoas.mediatype.hal.Jackson2HalModule.EmbeddedMapper;
import org.springframework.hateoas.mediatype.hal.Jackson2HalModule.HalHandlerInstantiator;
import org.springframework.hateoas.mediatype.hal.Jackson2HalModule.HalLinkListDeserializer;
import org.springframework.hateoas.mediatype.hal.Jackson2HalModule.HalLinkListSerializer;
import org.springframework.hateoas.mediatype.hal.LinkMixin;
import org.springframework.hateoas.mediatype.hal.RepresentationModelMixin;
import org.springframework.hateoas.mediatype.hal.forms.HalFormsDeserializers.HalFormsResourcesDeserializer;
import org.springframework.hateoas.mediatype.hal.forms.HalFormsSerializers.HalFormsResourceSerializer;
import org.springframework.hateoas.mediatype.hal.forms.HalFormsSerializers.HalFormsResourcesSerializer;
@@ -80,19 +80,16 @@ class Jackson2HalFormsModule extends SimpleModule {
super("hal-forms-module", new Version(1, 0, 0, null, "org.springframework.hateoas", "spring-hateoas"));
setMixInAnnotation(Link.class, LinkMixin.class);
setMixInAnnotation(ResourceSupport.class, ResourceSupportMixin.class);
setMixInAnnotation(Resources.class, ResourcesMixin.class);
setMixInAnnotation(PagedResources.class, PagedResourcesMixin.class);
setMixInAnnotation(RepresentationModel.class, RepresentationModelMixin.class);
setMixInAnnotation(CollectionModel.class, CollectionModelMixin.class);
setMixInAnnotation(PagedModel.class, PagedModelMixin.class);
setMixInAnnotation(MediaType.class, MediaTypeMixin.class);
addSerializer(new HalFormsResourceSerializer());
}
@JsonSerialize(using = HalFormsResourceSerializer.class)
interface ResourceMixin {}
@JsonSerialize(using = HalFormsResourcesSerializer.class)
abstract class ResourcesMixin<T> extends Resources<T> {
abstract class CollectionModelMixin<T> extends CollectionModel<T> {
@Override
@JsonProperty("_embedded")
@@ -101,7 +98,7 @@ class Jackson2HalFormsModule extends SimpleModule {
public abstract Collection<T> getContent();
}
abstract class PagedResourcesMixin<T> extends PagedResources<T> {
abstract class PagedModelMixin<T> extends PagedModel<T> {
@Override
@JsonProperty("page")

View File

@@ -26,15 +26,15 @@ import java.util.Map;
import java.util.stream.Collectors;
import org.jetbrains.annotations.NotNull;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.Links;
import org.springframework.hateoas.PagedResources;
import org.springframework.hateoas.PagedResources.PageMetadata;
import org.springframework.hateoas.PagedModel;
import org.springframework.hateoas.PagedModel.PageMetadata;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.hateoas.mediatype.JacksonHelper;
import org.springframework.hateoas.mediatype.PropertyUtils;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.hateoas.Resources;
import org.springframework.util.StringUtils;
import com.fasterxml.jackson.core.JsonGenerator;
@@ -72,74 +72,75 @@ public class Jackson2UberModule extends SimpleModule {
super("uber-module", new Version(1, 0, 0, null, "org.springframework.hateoas", "spring-hateoas"));
addSerializer(new UberPagedResourcesSerializer());
addSerializer(new UberResourcesSerializer());
addSerializer(new UberResourceSerializer());
addSerializer(new UberResourceSupportSerializer());
addSerializer(new UberPagedModelSerializer());
addSerializer(new UberCollectionModelSerializer());
addSerializer(new UberEntityModelSerializer());
addSerializer(new UberRepresentationModelSerializer());
setMixInAnnotation(ResourceSupport.class, ResourceSupportMixin.class);
setMixInAnnotation(Resource.class, ResourceMixin.class);
setMixInAnnotation(Resources.class, ResourcesMixin.class);
setMixInAnnotation(PagedResources.class, PagedResourcesMixin.class);
setMixInAnnotation(RepresentationModel.class, RepresentationModelMixin.class);
setMixInAnnotation(EntityModel.class, EntityModelMixin.class);
setMixInAnnotation(CollectionModel.class, CollectionModelMixin.class);
setMixInAnnotation(PagedModel.class, PagedModelMixin.class);
}
/**
* Jackson 2 mixin to handle {@link ResourceSupport} for {@literal UBER+JSON}.
* Jackson 2 mixin to handle {@link RepresentationModel} for {@literal UBER+JSON}.
*
* @author Greg Turnquist
* @since 1.0
*/
@JsonDeserialize(using = UberResourceSupportDeserializer.class)
abstract class ResourceSupportMixin extends ResourceSupport {}
@JsonDeserialize(using = UberRepresentationModelDeserializer.class)
abstract class RepresentationModelMixin extends RepresentationModel<RepresentationModelMixin> {}
/**
* Jackson 2 mixin to handle {@link Resource} for {@literal UBER+JSON}.
* Jackson 2 mixin to handle {@link EntityModel} for {@literal UBER+JSON}.
*
* @author Greg Turnquist
* @since 1.0
*/
@JsonDeserialize(using = UberResourceDeserializer.class)
abstract class ResourceMixin<T> extends Resource<T> {}
@JsonDeserialize(using = UberEntityModelDeserializer.class)
abstract class EntityModelMixin<T> extends EntityModel<T> {}
/**
* Jackson 2 mixin to handle {@link Resources} for {@literal UBER+JSON}.
* Jackson 2 mixin to handle {@link CollectionModel} for {@literal UBER+JSON}.
*
* @author Greg Turnquist
* @since 1.0
*/
@JsonDeserialize(using = UberResourcesDeserializer.class)
abstract class ResourcesMixin<T> extends Resources<T> {}
@JsonDeserialize(using = UberCollectionModelDeserializer.class)
abstract class CollectionModelMixin<T> extends CollectionModel<T> {}
/**
* Jackson 2 mixin to handle {@link PagedResources} for {@literal UBER+JSON}.
* Jackson 2 mixin to handle {@link PagedModel} for {@literal UBER+JSON}.
*
* @author Greg Turnquist
* @since 1.0
*/
@JsonDeserialize(using = UberPagedResourcesDeserializer.class)
abstract class PagedResourcesMixin<T> extends PagedResources<T> {}
@JsonDeserialize(using = UberPagedModelDeserializer.class)
abstract class PagedModelMixin<T> extends PagedModel<T> {}
/**
* Custom {@link JsonSerializer} to render {@link ResourceSupport} into {@literal UBER+JSON}.
* Custom {@link JsonSerializer} to render {@link RepresentationModel} into {@literal UBER+JSON}.
*/
static class UberResourceSupportSerializer extends ContainerSerializer<ResourceSupport>
static class UberRepresentationModelSerializer extends ContainerSerializer<RepresentationModel<?>>
implements ContextualSerializer {
private static final long serialVersionUID = -572866287910993300L;
private final BeanProperty property;
UberResourceSupportSerializer(BeanProperty property) {
UberRepresentationModelSerializer(BeanProperty property) {
super(ResourceSupport.class, false);
super(RepresentationModel.class, false);
this.property = property;
}
UberResourceSupportSerializer() {
UberRepresentationModelSerializer() {
this(null);
}
@Override
public void serialize(ResourceSupport value, JsonGenerator gen, SerializerProvider provider) throws IOException {
public void serialize(RepresentationModel<?> value, JsonGenerator gen, SerializerProvider provider)
throws IOException {
UberDocument doc = new UberDocument() //
.withUber(new Uber() //
@@ -162,7 +163,7 @@ public class Jackson2UberModule extends SimpleModule {
}
@Override
public boolean hasSingleElement(ResourceSupport value) {
public boolean hasSingleElement(RepresentationModel<?> value) {
return false;
}
@@ -174,31 +175,33 @@ public class Jackson2UberModule extends SimpleModule {
@Override
public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property)
throws JsonMappingException {
return new UberResourceSupportSerializer(property);
return new UberRepresentationModelSerializer(property);
}
}
/**
* Custom {@link JsonSerializer} to render {@link Resource} into {@literal UBER+JSON}.
* Custom {@link JsonSerializer} to render {@link EntityModel} into {@literal UBER+JSON}.
*/
static class UberResourceSerializer extends ContainerSerializer<Resource<?>> implements ContextualSerializer {
static class UberEntityModelSerializer extends ContainerSerializer<EntityModel<?>>
implements ContextualSerializer {
private static final long serialVersionUID = -5538560800604582741L;
private final BeanProperty property;
UberResourceSerializer(BeanProperty property) {
UberEntityModelSerializer(BeanProperty property) {
super(Resource.class, false);
super(EntityModel.class, false);
this.property = property;
}
UberResourceSerializer() {
UberEntityModelSerializer() {
this(null);
}
@Override
public void serialize(Resource<?> value, JsonGenerator gen, SerializerProvider provider) throws IOException {
public void serialize(EntityModel<?> value, JsonGenerator gen, SerializerProvider provider)
throws IOException {
UberDocument doc = new UberDocument().withUber(new Uber() //
.withVersion("1.0") //
@@ -220,7 +223,7 @@ public class Jackson2UberModule extends SimpleModule {
}
@Override
public boolean hasSingleElement(Resource<?> value) {
public boolean hasSingleElement(EntityModel<?> value) {
return false;
}
@@ -232,26 +235,27 @@ public class Jackson2UberModule extends SimpleModule {
@Override
public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property)
throws JsonMappingException {
return new UberResourceSerializer(property);
return new UberEntityModelSerializer(property);
}
}
/**
* Custom {@link JsonSerializer} to render {@link Resources} into {@literal UBER+JSON}.
* Custom {@link JsonSerializer} to render {@link CollectionModel} into {@literal UBER+JSON}.
*/
static class UberResourcesSerializer extends ContainerSerializer<Resources<?>> implements ContextualSerializer {
static class UberCollectionModelSerializer extends ContainerSerializer<CollectionModel<?>>
implements ContextualSerializer {
private static final long serialVersionUID = 3422019794262694127L;
private BeanProperty property;
UberResourcesSerializer(BeanProperty property) {
UberCollectionModelSerializer(BeanProperty property) {
super(Resources.class, false);
super(CollectionModel.class, false);
this.property = property;
}
UberResourcesSerializer() {
UberCollectionModelSerializer() {
this(null);
}
@@ -260,7 +264,8 @@ public class Jackson2UberModule extends SimpleModule {
* @see com.fasterxml.jackson.databind.ser.std.StdSerializer#serialize(java.lang.Object, com.fasterxml.jackson.core.JsonGenerator, com.fasterxml.jackson.databind.SerializerProvider)
*/
@Override
public void serialize(Resources<?> value, JsonGenerator gen, SerializerProvider provider) throws IOException {
public void serialize(CollectionModel<?> value, JsonGenerator gen, SerializerProvider provider)
throws IOException {
UberDocument doc = new UberDocument() //
.withUber(new Uber() //
@@ -283,7 +288,7 @@ public class Jackson2UberModule extends SimpleModule {
}
@Override
public boolean hasSingleElement(Resources<?> value) {
public boolean hasSingleElement(CollectionModel<?> value) {
return value.getContent().size() == 1;
}
@@ -295,27 +300,27 @@ public class Jackson2UberModule extends SimpleModule {
@Override
public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property)
throws JsonMappingException {
return new UberResourcesSerializer(property);
return new UberCollectionModelSerializer(property);
}
}
/**
* Custom {@link JsonSerializer} to render {@link PagedResources} into {@literal UBER+JSON}.
* Custom {@link JsonSerializer} to render {@link PagedModel} into {@literal UBER+JSON}.
*/
static class UberPagedResourcesSerializer extends ContainerSerializer<PagedResources<?>>
static class UberPagedModelSerializer extends ContainerSerializer<PagedModel<?>>
implements ContextualSerializer {
private static final long serialVersionUID = -7892297813593085984L;
private BeanProperty property;
UberPagedResourcesSerializer(BeanProperty property) {
UberPagedModelSerializer(BeanProperty property) {
super(PagedResources.class, false);
super(PagedModel.class, false);
this.property = property;
}
UberPagedResourcesSerializer() {
UberPagedModelSerializer() {
this(null);
}
@@ -324,7 +329,8 @@ public class Jackson2UberModule extends SimpleModule {
* @see com.fasterxml.jackson.databind.ser.std.StdSerializer#serialize(java.lang.Object, com.fasterxml.jackson.core.JsonGenerator, com.fasterxml.jackson.databind.SerializerProvider)
*/
@Override
public void serialize(PagedResources<?> value, JsonGenerator gen, SerializerProvider provider) throws IOException {
public void serialize(PagedModel<?> value, JsonGenerator gen, SerializerProvider provider)
throws IOException {
UberDocument doc = new UberDocument() //
.withUber(new Uber() //
@@ -359,7 +365,7 @@ public class Jackson2UberModule extends SimpleModule {
* @see com.fasterxml.jackson.databind.ser.ContainerSerializer#hasSingleElement(java.lang.Object)
*/
@Override
public boolean hasSingleElement(PagedResources<?> value) {
public boolean hasSingleElement(PagedModel<?> value) {
return value.getContent().size() == 1;
}
@@ -379,24 +385,24 @@ public class Jackson2UberModule extends SimpleModule {
@Override
public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property)
throws JsonMappingException {
return new UberPagedResourcesSerializer(property);
return new UberPagedModelSerializer(property);
}
}
/**
* Custom {@link StdDeserializer} to deserialize {@link ResourceSupport}.
* Custom {@link StdDeserializer} to deserialize {@link RepresentationModel}.
*/
static class UberResourceSupportDeserializer extends ContainerDeserializerBase<ResourceSupport>
static class UberRepresentationModelDeserializer extends ContainerDeserializerBase<RepresentationModel<?>>
implements ContextualDeserializer {
private static final long serialVersionUID = -8738539821441549016L;
private final JavaType contentType;
UberResourceSupportDeserializer() {
this(TypeFactory.defaultInstance().constructType(ResourceSupport.class));
UberRepresentationModelDeserializer() {
this(TypeFactory.defaultInstance().constructType(RepresentationModel.class));
}
private UberResourceSupportDeserializer(JavaType contentType) {
private UberRepresentationModelDeserializer(JavaType contentType) {
super(contentType);
this.contentType = contentType;
@@ -407,26 +413,22 @@ public class Jackson2UberModule extends SimpleModule {
* @see com.fasterxml.jackson.databind.JsonDeserializer#deserialize(com.fasterxml.jackson.core.JsonParser, com.fasterxml.jackson.databind.DeserializationContext)
*/
@Override
public ResourceSupport deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
public RepresentationModel<?> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
UberDocument doc = p.getCodec().readValue(p, UberDocument.class);
Links links = doc.getUber().getLinks();
return doc.getUber().getData().stream() //
RepresentationModel<?> result = doc.getUber().getData().stream() //
.filter(uberData -> !StringUtils.isEmpty(uberData.getName())) //
.findFirst() //
.map(uberData -> convertToResourceSupport(uberData, links)) //
.orElseGet(() -> {
.orElse(null);
ResourceSupport resourceSupport = new ResourceSupport();
resourceSupport.add(links);
return resourceSupport;
});
return result == null ? new RepresentationModel<>().add(links) : result;
}
@NotNull
private ResourceSupport convertToResourceSupport(UberData uberData, Links links) {
private RepresentationModel<?> convertToResourceSupport(UberData uberData, Links links) {
List<UberData> data = uberData.getData();
Map<String, Object> properties;
@@ -437,12 +439,11 @@ public class Jackson2UberModule extends SimpleModule {
properties = data.stream() //
.collect(Collectors.toMap(UberData::getName, UberData::getValue));
}
ResourceSupport resourceSupport = (ResourceSupport) PropertyUtils
RepresentationModel<?> resourceSupport = (RepresentationModel<?>) PropertyUtils
.createObjectFromProperties(this.getContentType().getRawClass(), properties);
resourceSupport.add(links);
return resourceSupport;
return resourceSupport.add(links);
}
/*
@@ -464,9 +465,9 @@ public class Jackson2UberModule extends SimpleModule {
if (property != null) {
JavaType vc = property.getType().getContentType();
return new UberResourceSupportDeserializer(vc);
return new UberRepresentationModelDeserializer(vc);
} else {
return new UberResourceSupportDeserializer(ctxt.getContextualType());
return new UberRepresentationModelDeserializer(ctxt.getContextualType());
}
}
@@ -480,27 +481,27 @@ public class Jackson2UberModule extends SimpleModule {
}
/**
* Custom {@link StdDeserializer} to deserialize {@link Resource}.
* Custom {@link StdDeserializer} to deserialize {@link EntityModel}.
*/
static class UberResourceDeserializer extends ContainerDeserializerBase<Resource<?>>
static class UberEntityModelDeserializer extends ContainerDeserializerBase<EntityModel<?>>
implements ContextualDeserializer {
private static final long serialVersionUID = 1776321413269082414L;
private final JavaType contentType;
UberResourceDeserializer() {
UberEntityModelDeserializer() {
this(TypeFactory.defaultInstance().constructSimpleType(UberDocument.class, new JavaType[0]));
}
private UberResourceDeserializer(JavaType contentType) {
private UberEntityModelDeserializer(JavaType contentType) {
super(contentType);
this.contentType = contentType;
}
@Override
public Resource<?> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
public EntityModel<?> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
UberDocument doc = p.getCodec().readValue(p, UberDocument.class);
Links links = doc.getUber().getLinks();
@@ -514,13 +515,13 @@ public class Jackson2UberModule extends SimpleModule {
}
@NotNull
private Resource<Object> convertToResource(UberData uberData, Links links) {
private EntityModel<Object> convertToResource(UberData uberData, Links links) {
// Primitive type
List<UberData> data = uberData.getData();
if (isPrimitiveType(data)) {
Object scalarValue = data.get(0).getValue();
return new Resource<>(scalarValue, links);
return new EntityModel<>(scalarValue, links);
}
Map<String, Object> properties;
@@ -534,7 +535,7 @@ public class Jackson2UberModule extends SimpleModule {
Object value = PropertyUtils.createObjectFromProperties(rootType.getRawClass(), properties);
return new Resource<>(value, links);
return new EntityModel<>(value, links);
}
/*
@@ -556,9 +557,9 @@ public class Jackson2UberModule extends SimpleModule {
if (property != null) {
JavaType vc = property.getType().getContentType();
return new UberResourceDeserializer(vc);
return new UberEntityModelDeserializer(vc);
} else {
return new UberResourceDeserializer(ctxt.getContextualType());
return new UberEntityModelDeserializer(ctxt.getContextualType());
}
}
@@ -572,22 +573,22 @@ public class Jackson2UberModule extends SimpleModule {
}
/**
* Custom {@link StdDeserializer} to deserialize {@link Resources}.
* Custom {@link StdDeserializer} to deserialize {@link CollectionModel}.
*/
static class UberResourcesDeserializer extends ContainerDeserializerBase<Resources<?>>
static class UberCollectionModelDeserializer extends ContainerDeserializerBase<CollectionModel<?>>
implements ContextualDeserializer {
private static final long serialVersionUID = 8722467561709171145L;
private final JavaType contentType;
UberResourcesDeserializer(JavaType contentType) {
UberCollectionModelDeserializer(JavaType contentType) {
super(contentType);
this.contentType = contentType;
}
UberResourcesDeserializer() {
UberCollectionModelDeserializer() {
this(TypeFactory.defaultInstance().constructSimpleType(UberDocument.class, new JavaType[0]));
}
@@ -596,7 +597,7 @@ public class Jackson2UberModule extends SimpleModule {
* @see com.fasterxml.jackson.databind.JsonDeserializer#deserialize(com.fasterxml.jackson.core.JsonParser, com.fasterxml.jackson.databind.DeserializationContext)
*/
@Override
public Resources<?> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
public CollectionModel<?> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
JavaType rootType = JacksonHelper.findRootType(this.contentType);
@@ -619,9 +620,9 @@ public class Jackson2UberModule extends SimpleModule {
if (property != null) {
JavaType vc = property.getType().getContentType();
return new UberResourcesDeserializer(vc);
return new UberCollectionModelDeserializer(vc);
} else {
return new UberResourcesDeserializer(ctxt.getContextualType());
return new UberCollectionModelDeserializer(ctxt.getContextualType());
}
}
@@ -635,22 +636,22 @@ public class Jackson2UberModule extends SimpleModule {
}
/**
* Custom {@link StdDeserializer} to deserialize {@link PagedResources}.
* Custom {@link StdDeserializer} to deserialize {@link PagedModel}.
*/
static class UberPagedResourcesDeserializer extends ContainerDeserializerBase<PagedResources<?>>
static class UberPagedModelDeserializer extends ContainerDeserializerBase<PagedModel<?>>
implements ContextualDeserializer {
private static final long serialVersionUID = 4123359694609188745L;
private JavaType contentType;
UberPagedResourcesDeserializer(JavaType contentType) {
UberPagedModelDeserializer(JavaType contentType) {
super(contentType);
this.contentType = contentType;
}
UberPagedResourcesDeserializer() {
UberPagedModelDeserializer() {
this(TypeFactory.defaultInstance().constructSimpleType(UberDocument.class, new JavaType[0]));
}
@@ -659,16 +660,16 @@ public class Jackson2UberModule extends SimpleModule {
* @see com.fasterxml.jackson.databind.JsonDeserializer#deserialize(com.fasterxml.jackson.core.JsonParser, com.fasterxml.jackson.databind.DeserializationContext)
*/
@Override
public PagedResources<?> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
public PagedModel<?> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
JavaType rootType = JacksonHelper.findRootType(this.contentType);
UberDocument doc = p.getCodec().readValue(p, UberDocument.class);
Resources<?> resources = extractResources(doc, rootType, this.contentType);
CollectionModel<?> resources = extractResources(doc, rootType, this.contentType);
PageMetadata pageMetadata = extractPagingMetadata(doc);
return new PagedResources<>(resources.getContent(), pageMetadata, resources.getLinks());
return new PagedModel<>(resources.getContent(), pageMetadata, resources.getLinks());
}
/**
@@ -685,9 +686,9 @@ public class Jackson2UberModule extends SimpleModule {
if (property != null) {
JavaType vc = property.getType().getContentType();
return new UberPagedResourcesDeserializer(vc);
return new UberPagedModelDeserializer(vc);
} else {
return new UberPagedResourcesDeserializer(ctxt.getContextualType());
return new UberPagedModelDeserializer(ctxt.getContextualType());
}
}
@@ -701,14 +702,15 @@ public class Jackson2UberModule extends SimpleModule {
}
/**
* Convert an {@link UberDocument} into a {@link Resources}.
* Convert an {@link UberDocument} into a {@link CollectionModel}.
*
* @param doc
* @param rootType
* @param contentType
* @return
*/
private static Resources<?> extractResources(UberDocument doc, JavaType rootType, JavaType contentType) {
private static CollectionModel<?> extractResources(UberDocument doc, JavaType rootType,
JavaType contentType) {
List<Object> content = new ArrayList<>();
@@ -721,7 +723,7 @@ public class Jackson2UberModule extends SimpleModule {
if (uberData.getLinks().isEmpty()) {
List<Link> resourceLinks = new ArrayList<>();
Resource<?> resource = null;
EntityModel<?> resource = null;
List<UberData> data = uberData.getData();
if (data == null) {
@@ -739,7 +741,7 @@ public class Jackson2UberModule extends SimpleModule {
if (isPrimitiveType(itemData)) {
Object scalarValue = itemData.get(0).getValue();
resource = new Resource<>(scalarValue, uberData.getLinks());
resource = new EntityModel<>(scalarValue, uberData.getLinks());
} else {
Map<String, Object> properties;
@@ -751,7 +753,7 @@ public class Jackson2UberModule extends SimpleModule {
}
Object obj = PropertyUtils.createObjectFromProperties(rootType.getRawClass(), properties);
resource = new Resource<>(obj, uberData.getLinks());
resource = new EntityModel<>(obj, uberData.getLinks());
}
}
}
@@ -770,16 +772,16 @@ public class Jackson2UberModule extends SimpleModule {
/*
* Either return a Resources<Resource<T>>...
*/
return new Resources<>(content, doc.getUber().getLinks());
return new CollectionModel<>(content, doc.getUber().getLinks());
} else {
/*
* ...or return a Resources<T>
*/
List<Object> resourceLessContent = content.stream().map(item -> (Resource<?>) item).map(Resource::getContent)
.collect(Collectors.toList());
List<Object> resourceLessContent = content.stream().map(item -> (EntityModel<?>) item)
.map(EntityModel::getContent).collect(Collectors.toList());
return new Resources<>(resourceLessContent, doc.getUber().getLinks());
return new CollectionModel<>(resourceLessContent, doc.getUber().getLinks());
}
}

View File

@@ -31,14 +31,14 @@ import java.util.Optional;
import java.util.stream.Collectors;
import org.springframework.hateoas.Affordance;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.LinkRelation;
import org.springframework.hateoas.Links;
import org.springframework.hateoas.MediaTypes;
import org.springframework.hateoas.PagedResources;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.hateoas.Resources;
import org.springframework.hateoas.PagedModel;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.hateoas.mediatype.PropertyUtils;
import org.springframework.http.HttpMethod;
import org.springframework.util.StringUtils;
@@ -146,16 +146,16 @@ class UberData {
/**
* Set of all Spring HATEOAS resource types.
*/
private static final HashSet<Class<?>> RESOURCE_TYPES = new HashSet<>(
Arrays.asList(ResourceSupport.class, Resource.class, Resources.class, PagedResources.class));
private static final HashSet<Class<?>> RESOURCE_TYPES = new HashSet<>(Arrays.asList(RepresentationModel.class,
EntityModel.class, CollectionModel.class, PagedModel.class));
/**
* Convert a {@link ResourceSupport} into a list of {@link UberData}s, containing links and content.
* Convert a {@link RepresentationModel} into a list of {@link UberData}s, containing links and content.
*
* @param resource
* @return
*/
static List<UberData> extractLinksAndContent(ResourceSupport resource) {
static List<UberData> extractLinksAndContent(RepresentationModel<?> resource) {
List<UberData> data = extractLinks(resource);
@@ -165,12 +165,12 @@ class UberData {
}
/**
* Convert a {@link Resource} into a list of {@link UberData}s, containing links and content.
* Convert a {@link EntityModel} into a list of {@link UberData}s, containing links and content.
*
* @param resource
* @return
*/
static List<UberData> extractLinksAndContent(Resource<?> resource) {
static List<UberData> extractLinksAndContent(EntityModel<?> resource) {
List<UberData> data = extractLinks(resource);
@@ -180,12 +180,13 @@ class UberData {
}
/**
* Convert {@link Resources} into a list of {@link UberData}, with each item nested in a sub-UberData.
* Convert {@link CollectionModel} into a list of {@link UberData}, with each item nested in a
* sub-UberData.
*
* @param resources
* @return
*/
static List<UberData> extractLinksAndContent(Resources<?> resources) {
static List<UberData> extractLinksAndContent(CollectionModel<?> resources) {
List<UberData> data = extractLinks(resources);
@@ -195,9 +196,9 @@ class UberData {
return data;
}
static List<UberData> extractLinksAndContent(PagedResources<?> resources) {
static List<UberData> extractLinksAndContent(PagedModel<?> resources) {
List<UberData> collectionOfResources = extractLinksAndContent((Resources<?>) resources);
List<UberData> collectionOfResources = extractLinksAndContent((CollectionModel<?>) resources);
if (resources.getMetadata() != null) {
@@ -227,12 +228,12 @@ class UberData {
}
/**
* Extract all the direct {@link Link}s and {@link Affordance}-based links from a {@link ResourceSupport}.
* Extract all the direct {@link Link}s and {@link Affordance}-based links from a {@link RepresentationModel}.
*
* @param resource
* @return
*/
private static List<UberData> extractLinks(ResourceSupport resource) {
private static List<UberData> extractLinks(RepresentationModel<?> resource) {
List<UberData> data = new ArrayList<>();
@@ -268,15 +269,15 @@ class UberData {
*/
private static List<UberData> doExtractLinksAndContent(Object item) {
if (item instanceof Resource) {
return extractLinksAndContent((Resource<?>) item);
if (item instanceof EntityModel) {
return extractLinksAndContent((EntityModel<?>) item);
}
if (item instanceof ResourceSupport) {
return extractLinksAndContent((ResourceSupport) item);
if (item instanceof RepresentationModel) {
return extractLinksAndContent((RepresentationModel<?>) item);
}
return extractLinksAndContent(new Resource<>(item));
return extractLinksAndContent(new EntityModel<>(item));
}
/**
@@ -371,7 +372,7 @@ class UberData {
}
/**
* Transform the payload of a {@link Resource} into {@link UberData}.
* Transform the payload of a {@link EntityModel} into {@link UberData}.
*
* @param obj
* @return

View File

@@ -21,7 +21,7 @@ import java.util.Iterator;
import java.util.List;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -157,7 +157,7 @@ public class VndErrors implements Iterable<VndErrors.VndError> {
*
* @author Oliver Gierke
*/
public static class VndError extends ResourceSupport {
public static class VndError extends RepresentationModel<VndError> {
@JsonProperty private final String logref;
@JsonProperty private final String message;

View File

@@ -60,17 +60,17 @@ public interface EntityLinks extends Plugin<Class<?>> {
* {@literal null}.
* @throws IllegalArgumentException in case the given type is unknown the entity links infrastructure.
*/
LinkBuilder linkForSingleResource(Class<?> type, Object id);
LinkBuilder linkForItemResource(Class<?> type, Object id);
/**
* Returns a {@link LinkBuilder} able to create links to the controller managing the given entity.
*
* @see #linkForSingleResource(Class, Object)
* @see #linkForItemResource(Class, Object)
* @param entity the entity type to point to, must not be {@literal null}.
* @return the {@link LinkBuilder} pointing the given entity. Will never be {@literal null}.
* @throws IllegalArgumentException in case the type of the given entity is unknown the entity links infrastructure.
*/
LinkBuilder linkForSingleResource(Identifiable<?> entity);
LinkBuilder linkForItemResource(Identifiable<?> entity);
/**
* Creates a {@link Link} pointing to the collection resource of the given type. The relation type of the link will be
@@ -93,7 +93,7 @@ public interface EntityLinks extends Plugin<Class<?>> {
* {@literal null}.
* @throws IllegalArgumentException in case the given type is unknown the entity links infrastructure.
*/
Link linkToSingleResource(Class<?> type, Object id);
Link linkToItemResource(Class<?> type, Object id);
/**
* Creates a {@link Link} pointing to single resource backing the given entity. The relation type of the link will be
@@ -103,5 +103,5 @@ public interface EntityLinks extends Plugin<Class<?>> {
* @return the {@link Link} pointing to the resource exposed for the given entity. Will never be {@literal null}.
* @throws IllegalArgumentException in case the type of the given entity is unknown the entity links infrastructure.
*/
Link linkToSingleResource(Identifiable<?> entity);
Link linkToItemResource(Identifiable<?> entity);
}

View File

@@ -15,41 +15,39 @@
*/
package org.springframework.hateoas.server;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.hateoas.Resources;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.RepresentationModel;
/**
* Interface for components that convert a domain type into a {@link ResourceSupport}.
* Interface for components that convert a domain type into a {@link RepresentationModel}.
*
* @author Oliver Gierke
* @author Greg Turnquist
*/
public interface ResourceAssembler<T, D extends ResourceSupport> {
public interface RepresentationModelAssembler<T, D extends RepresentationModel<?>> {
/**
* Converts the given entity into a {@code D}, which extends {@link ResourceSupport}.
* Converts the given entity into a {@code D}, which extends {@link RepresentationModel}.
*
* @param entity
* @return
*/
D toResource(T entity);
D toModel(T entity);
/**
* Converts an {@link Iterable} or {@code T}s into an {@link Iterable} of {@link ResourceSupport} and wraps them in a
* {@link Resources} instance.
* Converts an {@link Iterable} or {@code T}s into an {@link Iterable} of {@link RepresentationModel} and wraps them
* in a {@link CollectionModel} instance.
*
* @param entities must not be {@literal null}.
* @return {@link Resources} containing {@code D}.
* @return {@link CollectionModel} containing {@code D}.
*/
default Resources<D> toResources(Iterable<? extends T> entities) {
default CollectionModel<D> toCollectionModel(Iterable<? extends T> entities) {
List<D> resources = new ArrayList<>();
for (T entity : entities) {
resources.add(toResource(entity));
}
return new Resources<>(resources);
return StreamSupport.stream(entities.spliterator(), false) //
.map(this::toModel) //
.collect(Collectors.collectingAndThen(Collectors.toList(), CollectionModel::new));
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012 the original author or authors.
* Copyright 2012-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,23 +15,23 @@
*/
package org.springframework.hateoas.server;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.hateoas.Resources;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.RepresentationModel;
/**
* SPI interface to allow components to process the {@link ResourceSupport} instances returned from Spring MVC
* SPI interface to allow components to process the {@link RepresentationModel} instances returned from Spring MVC
* controllers.
*
* @see Resource
* @see Resources
*
* @see EntityModel
* @see CollectionModel
* @author Oliver Gierke
*/
public interface ResourceProcessor<T extends ResourceSupport> {
public interface RepresentationModelProcessor<T extends RepresentationModel<?>> {
/**
* Processes the given resource, add links, alter the domain data etc.
*
* Processes the given representation model, add links, alter the domain data etc.
*
* @param resource
* @return the processed resource
*/

View File

@@ -18,65 +18,68 @@ package org.springframework.hateoas.server;
import java.util.ArrayList;
import java.util.List;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.Resources;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.EntityModel;
import org.springframework.util.Assert;
/**
* A {@link ResourceAssembler} based purely on the domain type, using {@code Resource<T>} as the enclosing
* "resource" type.
* A {@link RepresentationModelAssembler} based purely on the domain type, using {@code EntityRepresentationModel<T>} as
* the enclosing representation model type.
*
* @author Greg Turnquist
* @since 1.0
*/
public interface SimpleResourceAssembler<T> extends ResourceAssembler<T, Resource<T>> {
public interface SimpleRepresentationModelAssembler<T>
extends RepresentationModelAssembler<T, EntityModel<T>> {
/**
* Converts the given entity into a {@link Resource}.
* Converts the given entity into a {@link EntityModel}.
*
* @param entity
* @return
*/
default Resource<T> toResource(T entity) {
Resource<T> resource = new Resource<>(entity);
default EntityModel<T> toModel(T entity) {
EntityModel<T> resource = new EntityModel<>(entity);
addLinks(resource);
return resource;
}
/**
* Define links to add to every individual {@link Resource}.
* Define links to add to every individual {@link EntityModel}.
*
* @param resource
*/
void addLinks(Resource<T> resource);
void addLinks(EntityModel<T> resource);
/**
* Converts all given entities into resources and wraps the collection as a resource as well.
*
* @see #toResource(Object)
* @see #toModel(Object)
* @param entities must not be {@literal null}.
* @return {@link Resources} containing {@link Resource} of {@code T}.
* @return {@link CollectionModel} containing {@link EntityModel} of {@code T}.
*/
@Override
default Resources<Resource<T>> toResources(Iterable<? extends T> entities) {
default CollectionModel<EntityModel<T>> toCollectionModel(
Iterable<? extends T> entities) {
Assert.notNull(entities, "entities must not be null!");
List<Resource<T>> resourceList = new ArrayList<>();
List<EntityModel<T>> resourceList = new ArrayList<>();
for (T entity : entities) {
resourceList.add(toResource(entity));
resourceList.add(toModel(entity));
}
Resources<Resource<T>> resources = new Resources<>(resourceList);
CollectionModel<EntityModel<T>> resources = new CollectionModel<>(
resourceList);
addLinks(resources);
return resources;
}
/**
* Define links to add to the {@link Resources} collection.
* Define links to add to the {@link CollectionModel} collection.
*
* @param resources
*/
void addLinks(Resources<Resource<T>> resources);
void addLinks(CollectionModel<EntityModel<T>> resources);
}

View File

@@ -34,9 +34,9 @@ public abstract class AbstractEntityLinks implements EntityLinks {
* @see org.springframework.hateoas.EntityLinks#getLinkToSingleResource(org.springframework.hateoas.Identifiable)
*/
@Override
public Link linkToSingleResource(Identifiable<?> entity) {
public Link linkToItemResource(Identifiable<?> entity) {
Assert.notNull(entity, "Entity must not be null!");
return linkToSingleResource(entity.getClass(), entity.getId());
return linkToItemResource(entity.getClass(), entity.getId());
}
/*
@@ -44,7 +44,7 @@ public abstract class AbstractEntityLinks implements EntityLinks {
* @see org.springframework.hateoas.EntityLinks#linkForSingleResource(java.lang.Class, java.lang.Object)
*/
@Override
public LinkBuilder linkForSingleResource(Class<?> type, Object id) {
public LinkBuilder linkForItemResource(Class<?> type, Object id) {
return linkFor(type).slash(id);
}
@@ -53,8 +53,8 @@ public abstract class AbstractEntityLinks implements EntityLinks {
* @see org.springframework.hateoas.EntityLinks#linkForSingleResource(org.springframework.hateoas.Identifiable)
*/
@Override
public LinkBuilder linkForSingleResource(Identifiable<?> entity) {
public LinkBuilder linkForItemResource(Identifiable<?> entity) {
Assert.notNull(entity, "Entity must not be null!");
return linkForSingleResource(entity.getClass(), entity.getId());
return linkForItemResource(entity.getClass(), entity.getId());
}
}

View File

@@ -130,7 +130,7 @@ public class ControllerEntityLinks extends AbstractEntityLinks {
* @see org.springframework.hateoas.EntityLinks#getLinkToSingleResource(java.lang.Class, java.lang.Object)
*/
@Override
public Link linkToSingleResource(Class<?> entity, Object id) {
public Link linkToItemResource(Class<?> entity, Object id) {
return linkFor(entity).slash(id).withSelfRel();
}

View File

@@ -74,8 +74,8 @@ public class DelegatingEntityLinks extends AbstractEntityLinks {
* @see org.springframework.hateoas.EntityLinks#getLinkToSingleResource(java.lang.Class, java.lang.Object)
*/
@Override
public Link linkToSingleResource(Class<?> type, Object id) {
return getPluginFor(type).linkToSingleResource(type, id);
public Link linkToItemResource(Class<?> type, Object id) {
return getPluginFor(type).linkToItemResource(type, id);
}
/*

View File

@@ -18,10 +18,10 @@ package org.springframework.hateoas.server.core;
import java.util.Optional;
import org.springframework.hateoas.LinkRelation;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.EntityModel;
/**
* A wrapper to handle values to be embedded into a {@link Resource}.
* A wrapper to handle values to be embedded into a {@link EntityModel}.
*
* @author Oliver Gierke
*/

View File

@@ -21,7 +21,7 @@ import java.util.Optional;
import org.springframework.aop.support.AopUtils;
import org.springframework.hateoas.LinkRelation;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.EntityModel;
import org.springframework.util.Assert;
/**
@@ -142,7 +142,7 @@ public class EmbeddedWrappers {
return null;
}
peek = peek instanceof Resource ? ((Resource<Object>) peek).getContent() : peek;
peek = peek instanceof EntityModel ? ((EntityModel<Object>) peek).getContent() : peek;
return AopUtils.getTargetClass(peek);
}

View File

@@ -17,8 +17,8 @@ package org.springframework.hateoas.server.core;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.Links;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.hateoas.server.ResourceProcessor;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.hateoas.server.RepresentationModelProcessor;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
@@ -26,15 +26,15 @@ import org.springframework.http.ResponseEntity;
import org.springframework.util.Assert;
/**
* Special {@link ResponseEntity} that exposes {@link Link} instances in the contained {@link ResourceSupport} as link
* headers instead of in the body. Note, that this class is not intended to be used directly from user code but by
* Special {@link ResponseEntity} that exposes {@link Link} instances in the contained {@link RepresentationModel} as
* link headers instead of in the body. Note, that this class is not intended to be used directly from user code but by
* support code that will transparently invoke the header exposure. If you use this class from a controller directly,
* the {@link Link}s will not be present in the {@link ResourceSupport} instance anymore when {@link ResourceProcessor}s
* kick in.
* the {@link Link}s will not be present in the {@link RepresentationModel} instance anymore when
* {@link RepresentationModelProcessor}s kick in.
*
* @author Oliver Gierke
*/
public class HeaderLinksResponseEntity<T extends ResourceSupport> extends ResponseEntity<T> {
public class HeaderLinksResponseEntity<T extends RepresentationModel<?>> extends ResponseEntity<T> {
/**
* Creates a new {@link HeaderLinksResponseEntity} from the given {@link ResponseEntity}.
@@ -64,7 +64,7 @@ public class HeaderLinksResponseEntity<T extends ResourceSupport> extends Respon
* @param entity must not be {@literal null}.
* @return
*/
public static <S extends ResourceSupport> HeaderLinksResponseEntity<S> wrap(HttpEntity<S> entity) {
public static <S extends RepresentationModel<?>> HeaderLinksResponseEntity<S> wrap(HttpEntity<S> entity) {
Assert.notNull(entity, "Given HttpEntity must not be null!");
@@ -76,13 +76,13 @@ public class HeaderLinksResponseEntity<T extends ResourceSupport> extends Respon
}
/**
* Wraps the given {@link ResourceSupport} into a {@link HeaderLinksResponseEntity}. Will default the status code to
* {@link HttpStatus#OK}.
* Wraps the given {@link RepresentationModel} into a {@link HeaderLinksResponseEntity}. Will default the status code
* to {@link HttpStatus#OK}.
*
* @param entity must not be {@literal null}.
* @return
*/
public static <S extends ResourceSupport> HeaderLinksResponseEntity<S> wrap(S entity) {
public static <S extends RepresentationModel<?>> HeaderLinksResponseEntity<S> wrap(S entity) {
Assert.notNull(entity, "ResourceSupport must not be null!");
@@ -90,13 +90,13 @@ public class HeaderLinksResponseEntity<T extends ResourceSupport> extends Respon
}
/**
* Returns the {@link Link}s contained in the {@link ResourceSupport} of the given {@link ResponseEntity} as
* Returns the {@link Link}s contained in the {@link RepresentationModel} of the given {@link ResponseEntity} as
* {@link HttpHeaders}.
*
* @param entity must not be {@literal null}.
* @return
*/
private static <T extends ResourceSupport> HttpHeaders getHeadersWithLinks(ResponseEntity<T> entity) {
private static <T extends RepresentationModel<?>> HttpHeaders getHeadersWithLinks(ResponseEntity<T> entity) {
Links links = entity.getBody().getLinks();

View File

@@ -20,12 +20,12 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.Resources;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.CollectionModel;
/**
* Annotation to configure the relation to be used when embedding objects in HAL representations of {@link Resource}s
* and {@link Resources}.
* Annotation to configure the relation to be used when embedding objects in HAL representations of {@link EntityModel}s
* and {@link CollectionModel}.
*
* @author Alexander Baetz
* @author Oliver Gierke

View File

@@ -20,28 +20,28 @@ import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*;
import java.util.Arrays;
import org.springframework.hateoas.Identifiable;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.hateoas.server.ResourceAssembler;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.hateoas.server.RepresentationModelAssembler;
import org.springframework.util.Assert;
/**
* Base class to implement {@link ResourceAssembler}s. Will automate {@link ResourceSupport} instance creation and make
* sure a self-link is always added.
* Base class to implement {@link RepresentationModelAssembler}s. Will automate {@link RepresentationModel} instance
* creation and make sure a self-link is always added.
*
* @author Oliver Gierke
*/
public abstract class IdentifiableResourceAssemblerSupport<T extends Identifiable<?>, D extends ResourceSupport>
extends ResourceAssemblerSupport<T, D> {
public abstract class IdentifiableRepresentationModelAssemblerSupport<T extends Identifiable<?>, D extends RepresentationModel<D>>
extends RepresentationModelAssemblerSupport<T, D> {
private final Class<?> controllerClass;
/**
* Creates a new {@link ResourceAssemblerSupport} using the given controller class and resource type.
* Creates a new {@link RepresentationModelAssemblerSupport} using the given controller class and resource type.
*
* @param controllerClass must not be {@literal null}.
* @param resourceType must not be {@literal null}.
*/
public IdentifiableResourceAssemblerSupport(Class<?> controllerClass, Class<D> resourceType) {
public IdentifiableRepresentationModelAssemblerSupport(Class<?> controllerClass, Class<D> resourceType) {
super(controllerClass, resourceType);
this.controllerClass = controllerClass;
@@ -53,21 +53,21 @@ public abstract class IdentifiableResourceAssemblerSupport<T extends Identifiabl
* @param entity must not be {@literal null}.
* @return
*/
protected D createResource(T entity) {
return createResource(entity, new Object[0]);
protected D createModel(T entity) {
return createModel(entity, new Object[0]);
}
protected D createResource(T entity, Object... parameters) {
return createResourceWithId(entity.getId(), entity, parameters);
protected D createModel(T entity, Object... parameters) {
return createModelWithId(entity.getId(), entity, parameters);
}
@Override
protected D createResourceWithId(Object id, T entity, Object... parameters) {
protected D createModelWithId(Object id, T entity, Object... parameters) {
Assert.notNull(entity, "Entity must not be null!");
Assert.notNull(id, "Id must not be null!");
D instance = instantiateResource(entity);
D instance = instantiateModel(entity);
instance.add(linkTo(controllerClass, unwrapIdentifyables(parameters)).slash(id).withSelfRel());
return instance;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,30 +22,31 @@ import java.util.List;
import java.util.Objects;
import org.springframework.beans.BeanUtils;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.hateoas.Resources;
import org.springframework.hateoas.server.ResourceAssembler;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.hateoas.server.RepresentationModelAssembler;
import org.springframework.util.Assert;
/**
* Base class to implement {@link ResourceAssembler}s. Will automate {@link ResourceSupport} instance creation and make
* sure a self-link is always added.
* Base class to implement {@link RepresentationModelAssembler}s. Will automate {@link RepresentationModel} instance
* creation and make sure a self-link is always added.
*
* @author Oliver Gierke
* @author Greg Turnquist
*/
public abstract class ResourceAssemblerSupport<T, D extends ResourceSupport> implements ResourceAssembler<T, D> {
public abstract class RepresentationModelAssemblerSupport<T, D extends RepresentationModel<D>>
implements RepresentationModelAssembler<T, D> {
private final Class<?> controllerClass;
private final Class<D> resourceType;
/**
* Creates a new {@link ResourceAssemblerSupport} using the given controller class and resource type.
* Creates a new {@link RepresentationModelAssemblerSupport} using the given controller class and resource type.
*
* @param controllerClass must not be {@literal null}.
* @param resourceType must not be {@literal null}.
*/
public ResourceAssemblerSupport(Class<?> controllerClass, Class<D> resourceType) {
public RepresentationModelAssemblerSupport(Class<?> controllerClass, Class<D> resourceType) {
Assert.notNull(controllerClass, "ControllerClass must not be null!");
Assert.notNull(resourceType, "ResourceType must not be null!");
@@ -56,10 +57,10 @@ public abstract class ResourceAssemblerSupport<T, D extends ResourceSupport> imp
/*
* (non-Javadoc)
* @see org.springframework.hateoas.ResourceAssembler#toResources(java.lang.Iterable)
* @see org.springframework.hateoas.server.RepresentationModelAssembler#toCollectionModel(java.lang.Iterable)
*/
@Override
public Resources<D> toResources(Iterable<? extends T> entities) {
public CollectionModel<D> toCollectionModel(Iterable<? extends T> entities) {
return this.map(entities).toResources();
}
@@ -74,16 +75,16 @@ public abstract class ResourceAssemblerSupport<T, D extends ResourceSupport> imp
* @param id must not be {@literal null}.
* @return
*/
protected D createResourceWithId(Object id, T entity) {
return createResourceWithId(id, entity, new Object[0]);
protected D createModelWithId(Object id, T entity) {
return createModelWithId(id, entity, new Object[0]);
}
protected D createResourceWithId(Object id, T entity, Object... parameters) {
protected D createModelWithId(Object id, T entity, Object... parameters) {
Assert.notNull(entity, "Entity must not be null!");
Assert.notNull(id, "Id must not be null!");
D instance = instantiateResource(entity);
D instance = instantiateModel(entity);
instance.add(linkTo(this.controllerClass, parameters).slash(id).withSelfRel());
return instance;
}
@@ -96,23 +97,23 @@ public abstract class ResourceAssemblerSupport<T, D extends ResourceSupport> imp
* @param entity
* @return
*/
protected D instantiateResource(T entity) {
protected D instantiateModel(T entity) {
return BeanUtils.instantiateClass(this.resourceType);
}
static class Builder<T, D extends ResourceSupport> {
static class Builder<T, D extends RepresentationModel<D>> {
private final Iterable<? extends T> entities;
private final ResourceAssemblerSupport<T, D> resourceAssembler;
private final RepresentationModelAssemblerSupport<T, D> resourceAssembler;
Builder(Iterable<? extends T> entities, ResourceAssemblerSupport<T, D> resourceAssembler) {
Builder(Iterable<? extends T> entities, RepresentationModelAssemblerSupport<T, D> resourceAssembler) {
this.entities = Objects.requireNonNull(entities, "entities must not null!");
this.resourceAssembler = resourceAssembler;
}
/**
* Transform a list of {@code T}s into a list of {@link ResourceSupport}s.
* Transform a list of {@code T}s into a list of {@link RepresentationModel}s.
*
* @see #toListOfResources() if you need this transformed list rendered as hypermedia
* @return
@@ -122,20 +123,21 @@ public abstract class ResourceAssemblerSupport<T, D extends ResourceSupport> imp
List<D> result = new ArrayList<>();
for (T entity : this.entities) {
result.add(this.resourceAssembler.toResource(entity));
result.add(this.resourceAssembler.toModel(entity));
}
return result;
}
/**
* Converts all given entities into resources and wraps the result in a {@link Resources} instance.
* Converts all given entities into resources and wraps the result in a {@link CollectionModel}
* instance.
*
* @see #toListOfResources() and {@link ResourceAssembler#toResource(Object)}
* @see #toListOfResources() and {@link RepresentationModelAssembler#toModel(Object)}
* @return
*/
public Resources<D> toResources() {
return new Resources<>(toListOfResources());
public CollectionModel<D> toResources() {
return new CollectionModel<>(toListOfResources());
}
}
}

View File

@@ -22,10 +22,10 @@ import java.lang.reflect.Field;
import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.hateoas.Resources;
import org.springframework.hateoas.server.ResourceProcessor;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.hateoas.server.RepresentationModelProcessor;
import org.springframework.hateoas.server.core.HeaderLinksResponseEntity;
import org.springframework.http.HttpEntity;
import org.springframework.http.ResponseEntity;
@@ -36,27 +36,27 @@ import org.springframework.web.method.support.ModelAndViewContainer;
/**
* {@link HandlerMethodReturnValueHandler} to post-process the objects returned from controller methods using the
* configured {@link ResourceProcessor}s.
*
* configured {@link RepresentationModelProcessor}s.
*
* @author Oliver Gierke
* @since 0.20
* @soundtrack Doppelkopf - Balance (Von Abseits)
*/
@RequiredArgsConstructor
public class ResourceProcessorHandlerMethodReturnValueHandler implements HandlerMethodReturnValueHandler {
public class RepresentationModelProcessorHandlerMethodReturnValueHandler implements HandlerMethodReturnValueHandler {
static final ResolvableType RESOURCE_TYPE = ResolvableType.forRawClass(Resource.class);
static final ResolvableType RESOURCES_TYPE = ResolvableType.forRawClass(Resources.class);
static final ResolvableType RESOURCE_TYPE = ResolvableType.forRawClass(EntityModel.class);
static final ResolvableType RESOURCES_TYPE = ResolvableType.forRawClass(CollectionModel.class);
private static final ResolvableType HTTP_ENTITY_TYPE = ResolvableType.forRawClass(HttpEntity.class);
static final Field CONTENT_FIELD = ReflectionUtils.findField(Resources.class, "content");
static final Field CONTENT_FIELD = ReflectionUtils.findField(CollectionModel.class, "content");
static {
ReflectionUtils.makeAccessible(CONTENT_FIELD);
}
private final @NonNull HandlerMethodReturnValueHandler delegate;
private final @NonNull ResourceProcessorInvoker invoker;
private final @NonNull RepresentationModelProcessorInvoker invoker;
private boolean rootLinksAsHeaders = false;
@@ -81,6 +81,7 @@ public class ResourceProcessorHandlerMethodReturnValueHandler implements Handler
* @see org.springframework.web.method.support.HandlerMethodReturnValueHandler#handleReturnValue(java.lang.Object, org.springframework.core.MethodParameter, org.springframework.web.method.support.ModelAndViewContainer, org.springframework.web.context.request.NativeWebRequest)
*/
@Override
@SuppressWarnings({ "rawtypes", "unchecked" })
public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest) throws Exception {
@@ -91,7 +92,7 @@ public class ResourceProcessorHandlerMethodReturnValueHandler implements Handler
}
// No post-processable type found - proceed with delegate
if (!(value instanceof ResourceSupport)) {
if (!(value instanceof RepresentationModel)) {
delegate.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
return;
}
@@ -111,7 +112,7 @@ public class ResourceProcessorHandlerMethodReturnValueHandler implements Handler
targetType = returnValueType;
}
ResourceSupport result = invoker.invokeProcessorsFor((ResourceSupport) value, targetType);
RepresentationModel<?> result = invoker.invokeProcessorsFor((RepresentationModel) value, targetType);
delegate.handleReturnValue(rewrapResult(result, returnValue), returnType, mavContainer, webRequest);
}
@@ -119,18 +120,18 @@ public class ResourceProcessorHandlerMethodReturnValueHandler implements Handler
* Re-wraps the result of the post-processing work into an {@link HttpEntity} or {@link ResponseEntity} if the
* original value was one of those two types. Copies headers and status code from the original value but uses the new
* body.
*
*
* @param newBody the post-processed value.
* @param originalValue the original input value.
* @return
*/
Object rewrapResult(ResourceSupport newBody, Object originalValue) {
Object rewrapResult(RepresentationModel<?> newBody, Object originalValue) {
if (!(originalValue instanceof HttpEntity)) {
return rootLinksAsHeaders ? HeaderLinksResponseEntity.wrap(newBody) : newBody;
}
HttpEntity<ResourceSupport> entity = null;
HttpEntity<RepresentationModel<?>> entity = null;
if (originalValue instanceof ResponseEntity) {
ResponseEntity<?> source = (ResponseEntity<?>) originalValue;

View File

@@ -23,46 +23,47 @@ import java.util.List;
import org.springframework.core.Ordered;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.hateoas.Resources;
import org.springframework.hateoas.server.ResourceProcessor;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.hateoas.server.RepresentationModelProcessor;
import org.springframework.hateoas.server.core.EmbeddedWrapper;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
/**
* Component to easily invoke all {@link ResourceProcessor} instances registered for values of type
* {@link ResourceSupport}.
* Component to easily invoke all {@link RepresentationModelProcessor} instances registered for values of type
* {@link RepresentationModel}.
*
* @author Oliver Gierke
* @since 0.20
* @soundtrack Doppelkopf - Die fabelhaften Vier (Von Abseits)
*/
public class ResourceProcessorInvoker {
public class RepresentationModelProcessorInvoker {
private final List<ProcessorWrapper> processors;
/**
* Creates a new {@link ResourceProcessorInvoker} to consider the given {@link ResourceProcessor} to post-process the
* controller methods return value to before invoking the delegate.
*
* @param processors the {@link ResourceProcessor}s to be considered, must not be {@literal null}.
* Creates a new {@link RepresentationModelProcessorInvoker} to consider the given
* {@link RepresentationModelProcessor} to post-process the controller methods return value to before invoking the
* delegate.
*
* @param processors the {@link RepresentationModelProcessor}s to be considered, must not be {@literal null}.
*/
public ResourceProcessorInvoker(Collection<ResourceProcessor<?>> processors) {
public RepresentationModelProcessorInvoker(Collection<RepresentationModelProcessor<?>> processors) {
Assert.notNull(processors, "ResourceProcessors must not be null!");
this.processors = new ArrayList<>();
for (ResourceProcessor<?> processor : processors) {
for (RepresentationModelProcessor<?> processor : processors) {
ResolvableType processorType = ResolvableType.forClass(ResourceProcessor.class, processor.getClass());
ResolvableType processorType = ResolvableType.forClass(RepresentationModelProcessor.class, processor.getClass());
Class<?> rawType = processorType.getGeneric(0).resolve();
if (Resource.class.isAssignableFrom(rawType)) {
if (EntityModel.class.isAssignableFrom(rawType)) {
this.processors.add(new ResourceProcessorWrapper(processor));
} else if (Resources.class.isAssignableFrom(rawType)) {
} else if (CollectionModel.class.isAssignableFrom(rawType)) {
this.processors.add(new ResourcesProcessorWrapper(processor));
} else {
this.processors.add(new DefaultProcessorWrapper(processor));
@@ -73,12 +74,12 @@ public class ResourceProcessorInvoker {
}
/**
* Invokes all {@link ResourceProcessor} instances registered for the type of the given value.
*
* Invokes all {@link RepresentationModelProcessor} instances registered for the type of the given value.
*
* @param value must not be {@literal null}.
* @return
*/
public <T extends ResourceSupport> T invokeProcessorsFor(T value) {
public <T extends RepresentationModel<T>> T invokeProcessorsFor(T value) {
Assert.notNull(value, "Value must not be null!");
@@ -86,24 +87,25 @@ public class ResourceProcessorInvoker {
}
/**
* Invokes all {@link ResourceProcessor} instances registered for the type of the given value and reference type.
*
* Invokes all {@link RepresentationModelProcessor} instances registered for the type of the given value and reference
* type.
*
* @param value must not be {@literal null}.
* @param referenceType must not be {@literal null}.
* @return
*/
@SuppressWarnings("unchecked")
public <T extends ResourceSupport> T invokeProcessorsFor(T value, ResolvableType referenceType) {
public <T extends RepresentationModel<T>> T invokeProcessorsFor(T value, ResolvableType referenceType) {
Assert.notNull(value, "Value must not be null!");
Assert.notNull(referenceType, "Reference type must not be null!");
// For Resources implementations, process elements first
if (ResourceProcessorHandlerMethodReturnValueHandler.RESOURCES_TYPE.isAssignableFrom(referenceType)) {
if (RepresentationModelProcessorHandlerMethodReturnValueHandler.RESOURCES_TYPE.isAssignableFrom(referenceType)) {
Resources<?> resources = (Resources<?>) value;
ResolvableType elementTargetType = ResolvableType.forClass(Resources.class, referenceType.getRawClass())
.getGeneric(0);
CollectionModel<?> resources = (CollectionModel<?>) value;
ResolvableType elementTargetType = ResolvableType
.forClass(CollectionModel.class, referenceType.getRawClass()).getGeneric(0);
List<Object> result = new ArrayList<>(resources.getContent().size());
for (Object element : resources) {
@@ -117,15 +119,16 @@ public class ResourceProcessorInvoker {
result.add(invokeProcessorsFor(element, elementTargetType));
}
ReflectionUtils.setField(ResourceProcessorHandlerMethodReturnValueHandler.CONTENT_FIELD, resources, result);
ReflectionUtils.setField(RepresentationModelProcessorHandlerMethodReturnValueHandler.CONTENT_FIELD, resources,
result);
}
return (T) invokeProcessorsFor((Object) value, referenceType);
return (T) invokeProcessorsFor(Object.class.cast(value), referenceType);
}
/**
* Invokes all registered {@link ResourceProcessor}s registered for the given {@link ResolvableType}.
*
* Invokes all registered {@link RepresentationModelProcessor}s registered for the given {@link ResolvableType}.
*
* @param value the object to process
* @param type
* @return
@@ -135,7 +138,7 @@ public class ResourceProcessorInvoker {
Object currentValue = value;
// Process actual value
for (ResourceProcessorInvoker.ProcessorWrapper wrapper : this.processors) {
for (RepresentationModelProcessorInvoker.ProcessorWrapper wrapper : this.processors) {
if (wrapper.supports(type, currentValue)) {
currentValue = wrapper.invokeProcessor(currentValue);
}
@@ -155,9 +158,9 @@ public class ResourceProcessorInvoker {
}
/**
* Interface to unify interaction with {@link ResourceProcessor}s. The {@link Ordered} rank should be determined by
* the underlying processor.
*
* Interface to unify interaction with {@link RepresentationModelProcessor}s. The {@link Ordered} rank should be
* determined by the underlying processor.
*
* @author Oliver Gierke
*/
private interface ProcessorWrapper extends Ordered {
@@ -165,7 +168,7 @@ public class ResourceProcessorInvoker {
/**
* Returns whether the underlying processor supports the given {@link ResolvableType}. It might also additionally
* inspect the object that would eventually be handed to the processor.
*
*
* @param type the type of object to be post processed, will never be {@literal null}.
* @param value the object that would be passed into the processor eventually, can be {@literal null}.
* @return
@@ -175,33 +178,33 @@ public class ResourceProcessorInvoker {
/**
* Performs the actual invocation of the processor. Implementations can be sure
* {@link #supports(ResolvableType, Object)} has been called before and returned {@literal true}.
*
*
* @param object
*/
Object invokeProcessor(Object object);
<S> S invokeProcessor(S object);
}
/**
* Default implementation of {@link ProcessorWrapper} to generically deal with {@link ResourceSupport} types.
*
* Default implementation of {@link ProcessorWrapper} to generically deal with {@link RepresentationModel} types.
*
* @author Oliver Gierke
*/
private static class DefaultProcessorWrapper implements ResourceProcessorInvoker.ProcessorWrapper {
private static class DefaultProcessorWrapper implements RepresentationModelProcessorInvoker.ProcessorWrapper {
private final ResourceProcessor<?> processor;
private final RepresentationModelProcessor<?> processor;
private final ResolvableType targetType;
/**
* Creates a new {@link DefaultProcessorWrapper} with the given {@link ResourceProcessor}.
*
* Creates a new {@link DefaultProcessorWrapper} with the given {@link RepresentationModelProcessor}.
*
* @param processor must not be {@literal null}.
*/
DefaultProcessorWrapper(ResourceProcessor<?> processor) {
DefaultProcessorWrapper(RepresentationModelProcessor<?> processor) {
Assert.notNull(processor, "Processor must not be null!");
this.processor = processor;
this.targetType = ResolvableType.forClass(ResourceProcessor.class, processor.getClass()).getGeneric(0);
this.targetType = ResolvableType.forClass(RepresentationModelProcessor.class, processor.getClass()).getGeneric(0);
}
/*
@@ -213,14 +216,15 @@ public class ResourceProcessorInvoker {
return isRawTypeAssignable(targetType, getRawType(type));
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.rest.webmvc.ResourceProcessorHandlerMethodReturnValueHandler.PostProcessorWrapper#invokeProcessor(java.lang.Object)
*/
@Override
@SuppressWarnings("unchecked")
public Object invokeProcessor(Object object) {
return ((ResourceProcessor<ResourceSupport>) processor).process((ResourceSupport) object);
return ((RepresentationModelProcessor<RepresentationModel<?>>) processor)
.process((RepresentationModel<?>) object);
}
/*
@@ -233,8 +237,8 @@ public class ResourceProcessorInvoker {
}
/**
* Returns the target type the underlying {@link ResourceProcessor} wants to get invoked for.
*
* Returns the target type the underlying {@link RepresentationModelProcessor} wants to get invoked for.
*
* @return the targetType
*/
public ResolvableType getTargetType() {
@@ -243,19 +247,19 @@ public class ResourceProcessorInvoker {
}
/**
* {@link ProcessorWrapper} to deal with {@link ResourceProcessor}s for {@link Resource}s. Will fall back to peeking
* into the {@link Resource}'s content for type resolution.
*
* {@link ProcessorWrapper} to deal with {@link RepresentationModelProcessor}s for {@link EntityModel}s.
* Will fall back to peeking into the {@link EntityModel}'s content for type resolution.
*
* @author Oliver Gierke
*/
private static class ResourceProcessorWrapper extends ResourceProcessorInvoker.DefaultProcessorWrapper {
private static class ResourceProcessorWrapper extends RepresentationModelProcessorInvoker.DefaultProcessorWrapper {
/**
* Creates a new {@link ResourceProcessorWrapper} for the given {@link ResourceProcessor}.
*
* Creates a new {@link ResourceProcessorWrapper} for the given {@link RepresentationModelProcessor}.
*
* @param processor must not be {@literal null}.
*/
public ResourceProcessorWrapper(ResourceProcessor<?> processor) {
public ResourceProcessorWrapper(RepresentationModelProcessor<?> processor) {
super(processor);
}
@@ -266,22 +270,23 @@ public class ResourceProcessorInvoker {
@Override
public boolean supports(ResolvableType type, Object value) {
if (!ResourceProcessorHandlerMethodReturnValueHandler.RESOURCE_TYPE.isAssignableFrom(type)) {
if (!RepresentationModelProcessorHandlerMethodReturnValueHandler.RESOURCE_TYPE.isAssignableFrom(type)) {
return false;
}
return super.supports(type, value) && isValueTypeMatch((Resource<?>) value, getTargetType());
return super.supports(type, value) && isValueTypeMatch((EntityModel<?>) value, getTargetType());
}
/**
* Returns whether the given {@link Resource} matches the given target {@link ResolvableType}. We inspect the
* {@link Resource}'s value to determine the match.
*
* Returns whether the given {@link EntityModel} matches the given target {@link ResolvableType}. We
* inspect the {@link EntityModel}'s value to determine the match.
*
* @param resource
* @param target must not be {@literal null}.
* @return whether the given {@link Resource} can be assigned to the given target {@link ResolvableType}
* @return whether the given {@link EntityModel} can be assigned to the given target
* {@link ResolvableType}
*/
private static boolean isValueTypeMatch(Resource<?> resource, ResolvableType target) {
private static boolean isValueTypeMatch(EntityModel<?> resource, ResolvableType target) {
if (resource == null || !isRawTypeAssignable(target, resource.getClass())) {
return false;
@@ -293,7 +298,7 @@ public class ResourceProcessorInvoker {
return false;
}
ResolvableType type = findGenericType(target, Resource.class);
ResolvableType type = findGenericType(target, EntityModel.class);
return type != null && type.getGeneric(0).isAssignableFrom(ResolvableType.forClass(content.getClass()));
}
@@ -314,19 +319,19 @@ public class ResourceProcessorInvoker {
}
/**
* {@link ProcessorWrapper} for {@link ResourceProcessor}s targeting {@link Resources}. Will peek into the content of
* the {@link Resources} for type matching decisions if needed.
*
* {@link ProcessorWrapper} for {@link RepresentationModelProcessor}s targeting {@link CollectionModel}.
* Will peek into the content of the {@link CollectionModel} for type matching decisions if needed.
*
* @author Oliver Gierke
*/
public static class ResourcesProcessorWrapper extends ResourceProcessorInvoker.DefaultProcessorWrapper {
public static class ResourcesProcessorWrapper extends RepresentationModelProcessorInvoker.DefaultProcessorWrapper {
/**
* Creates a new {@link ResourcesProcessorWrapper} for the given {@link ResourceProcessor}.
*
* Creates a new {@link ResourcesProcessorWrapper} for the given {@link RepresentationModelProcessor}.
*
* @param processor must not be {@literal null}.
*/
public ResourcesProcessorWrapper(ResourceProcessor<?> processor) {
public ResourcesProcessorWrapper(RepresentationModelProcessor<?> processor) {
super(processor);
}
@@ -337,22 +342,23 @@ public class ResourceProcessorInvoker {
@Override
public boolean supports(ResolvableType type, Object value) {
if (!ResourceProcessorHandlerMethodReturnValueHandler.RESOURCES_TYPE.isAssignableFrom(type)) {
if (!RepresentationModelProcessorHandlerMethodReturnValueHandler.RESOURCES_TYPE.isAssignableFrom(type)) {
return false;
}
return super.supports(type, value) && isValueTypeMatch((Resources<?>) value, getTargetType());
return super.supports(type, value) && isValueTypeMatch((CollectionModel<?>) value, getTargetType());
}
/**
* Returns whether the given {@link Resources} instance matches the given {@link ResolvableType}. We predict this by
* inspecting the first element of the content of the {@link Resources}.
*
* @param resources the {@link Resources} to inspect.
* Returns whether the given {@link CollectionModel} instance matches the given
* {@link ResolvableType}. We predict this by inspecting the first element of the content of the
* {@link CollectionModel}.
*
* @param resources the {@link CollectionModel} to inspect.
* @param target that target {@link ResolvableType}.
* @return
*/
static boolean isValueTypeMatch(Resources<?> resources, ResolvableType target) {
static boolean isValueTypeMatch(CollectionModel<?> resources, ResolvableType target) {
if (resources == null) {
return false;
@@ -366,7 +372,8 @@ public class ResourceProcessorInvoker {
ResolvableType superType = null;
for (Class<?> resourcesType : Arrays.<Class<?>>asList(resources.getClass(), Resources.class)) {
for (Class<?> resourcesType : Arrays.<Class<?>> asList(resources.getClass(),
CollectionModel.class)) {
superType = getSuperType(target, resourcesType);
@@ -382,8 +389,8 @@ public class ResourceProcessorInvoker {
Object element = content.iterator().next();
ResolvableType resourceType = superType.getGeneric(0);
if (element instanceof Resource) {
return ResourceProcessorWrapper.isValueTypeMatch((Resource<?>) element, resourceType);
if (element instanceof EntityModel) {
return ResourceProcessorWrapper.isValueTypeMatch((EntityModel<?>) element, resourceType);
} else if (element instanceof EmbeddedWrapper) {
return isRawTypeAssignable(resourceType, ((EmbeddedWrapper) element).getRelTargetType());
}
@@ -393,7 +400,7 @@ public class ResourceProcessorInvoker {
/**
* Returns the {@link ResolvableType} for the given raw super class.
*
*
* @param source must not be {@literal null}.
* @param superType must not be {@literal null}.
* @return
@@ -423,12 +430,12 @@ public class ResourceProcessorInvoker {
/**
* Helper extension of {@link AnnotationAwareOrderComparator} to make {@link #getOrder(Object)} public to allow it
* being used in a standalone fashion.
*
*
* @author Oliver Gierke
*/
private static class CustomOrderAwareComparator extends AnnotationAwareOrderComparator {
public static ResourceProcessorInvoker.CustomOrderAwareComparator INSTANCE = new CustomOrderAwareComparator();
public static RepresentationModelProcessorInvoker.CustomOrderAwareComparator INSTANCE = new CustomOrderAwareComparator();
@Override
protected int getOrder(Object obj) {

View File

@@ -22,7 +22,7 @@ import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import org.springframework.hateoas.server.ResourceProcessor;
import org.springframework.hateoas.server.RepresentationModelProcessor;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite;
@@ -30,7 +30,7 @@ import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandl
/**
* Special {@link RequestMappingHandlerAdapter} that tweaks the {@link HandlerMethodReturnValueHandlerComposite} to be
* proxied by a {@link ResourceProcessorHandlerMethodReturnValueHandler} which will invoke the {@link ResourceProcessor}
* proxied by a {@link RepresentationModelProcessorHandlerMethodReturnValueHandler} which will invoke the {@link RepresentationModelProcessor}
* s found in the application context and eventually delegate to the originally configured
* {@link HandlerMethodReturnValueHandler}.
* <p/>
@@ -43,12 +43,12 @@ import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandl
* @soundtrack Dopplekopf - Regen für immer (Von Abseits)
*/
@RequiredArgsConstructor
public class ResourceProcessorInvokingHandlerAdapter extends RequestMappingHandlerAdapter {
public class RepresentationModelProcessorInvokingHandlerAdapter extends RequestMappingHandlerAdapter {
private static final Method RETURN_VALUE_HANDLER_METHOD = ReflectionUtils
.findMethod(ResourceProcessorInvokingHandlerAdapter.class, "getReturnValueHandlers");
.findMethod(RepresentationModelProcessorInvokingHandlerAdapter.class, "getReturnValueHandlers");
private @NonNull final ResourceProcessorInvoker invoker;
private @NonNull final RepresentationModelProcessorInvoker invoker;
/*
* (non-Javadoc)
@@ -64,7 +64,7 @@ public class ResourceProcessorInvokingHandlerAdapter extends RequestMappingHandl
// Set up ResourceProcessingHandlerMethodResolver to delegate to originally configured ones
List<HandlerMethodReturnValueHandler> newHandlers = new ArrayList<>();
newHandlers.add(new ResourceProcessorHandlerMethodReturnValueHandler(oldHandlers, invoker));
newHandlers.add(new RepresentationModelProcessorHandlerMethodReturnValueHandler(oldHandlers, invoker));
// Configure the new handler to be used
this.setReturnValueHandlers(newHandlers);

View File

@@ -26,7 +26,8 @@ import org.springframework.util.Assert;
/**
* Helper to easily create {@link ParameterizedTypeReference} instances to Spring HATEOAS resource types. They're
* basically a shortcut over using a verbose {@code new ParameterizedTypeReference<Resources<DomainType>>()}.
* basically a shortcut over using a verbose
* {@code new ParameterizedTypeReference<CollectionRepresentationModel<DomainType>>()}.
*
* @author Oliver Gierke
* @since 0.17
@@ -34,31 +35,31 @@ import org.springframework.util.Assert;
public class TypeReferences {
/**
* A {@link ParameterizedTypeReference} to return a {@link org.springframework.hateoas.Resource} of some type.
* A {@link ParameterizedTypeReference} to return a {@link org.springframework.hateoas.EntityModel} of some type.
*
* @author Oliver Gierke
* @since 0.17
*/
public static class ResourceType<T>
extends SyntheticParameterizedTypeReference<org.springframework.hateoas.Resource<T>> {}
public static class EntityModelType<T>
extends SyntheticParameterizedTypeReference<org.springframework.hateoas.EntityModel<T>> {}
/**
* A {@link ParameterizedTypeReference} to return a {@link org.springframework.hateoas.Resources} of some type.
* A {@link ParameterizedTypeReference} to return a {@link org.springframework.hateoas.CollectionModel} of some type.
*
* @author Oliver Gierke
* @since 0.17
*/
public static class ResourcesType<T>
extends SyntheticParameterizedTypeReference<org.springframework.hateoas.Resources<T>> {}
public static class CollectionModelType<T>
extends SyntheticParameterizedTypeReference<org.springframework.hateoas.CollectionModel<T>> {}
/**
* A {@link ParameterizedTypeReference} to return a {@link org.springframework.hateoas.PagedResources} of some type.
* A {@link ParameterizedTypeReference} to return a {@link org.springframework.hateoas.PagedModel} of some type.
*
* @author Oliver Gierke
* @since 0.17
*/
public static class PagedResourcesType<T>
extends SyntheticParameterizedTypeReference<org.springframework.hateoas.PagedResources<T>> {}
public static class PagedModelType<T>
extends SyntheticParameterizedTypeReference<org.springframework.hateoas.PagedModel<T>> {}
/**
* Special {@link ParameterizedTypeReference} to customize the generic type detection and eventually return a
@@ -144,7 +145,7 @@ public class TypeReferences {
}
/**
* A sythetic {@link ParameterizedType}.
* A synthetic {@link ParameterizedType}.
*
* @author Oliver Gierke
* @since 0.17

View File

@@ -35,7 +35,7 @@ import org.springframework.web.util.UriComponentsBuilder;
class UriComponentsBuilderFactory {
static final String REQUEST_ATTRIBUTES_MISSING = "Could not find current request via RequestContextHolder. Is this being called from a Spring MVC handler?";
private static final String CACHE_KEY = ControllerLinkBuilder.class.getName() + "#BUILDER_CACHE";
private static final String CACHE_KEY = UriComponentsBuilderFactory.class.getName() + "#BUILDER_CACHE";
/**
* Returns a {@link UriComponentsBuilder} obtained from the current servlet mapping with scheme tweaked in case the

View File

@@ -1,6 +1,6 @@
/**
* Spring MVC helper classes to build {@link org.springframework.hateoas.Link}s and assemble
* {@link org.springframework.hateoas.ResourceSupport} types.
* {@link org.springframework.hateoas.RepresentationModel} types.
*/
package org.springframework.hateoas.server.mvc;

View File

@@ -18,41 +18,40 @@ package org.springframework.hateoas.server.reactive;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.hateoas.Resources;
import org.springframework.hateoas.server.ResourceAssembler;
import org.springframework.hateoas.server.SimpleResourceAssembler;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.hateoas.server.RepresentationModelAssembler;
import org.springframework.hateoas.server.SimpleRepresentationModelAssembler;
import org.springframework.web.server.ServerWebExchange;
/**
* Reactive variant of {@link ResourceAssembler} combined with {@link SimpleResourceAssembler}.
* Reactive variant of {@link RepresentationModelAssembler} combined with {@link SimpleRepresentationModelAssembler}.
*
* @author Greg Turnquist
* @since 1.0
* @author Oliver Drotbohm
*/
public interface ReactiveResourceAssembler<T, D extends ResourceSupport> {
public interface ReactiveRepresentationModelAssembler<T, D extends RepresentationModel<D>> {
/**
* Converts the given entity into a {@code D}, which extends {@link ResourceSupport}.
* Converts the given entity into a {@code D}, which extends {@link RepresentationModel}.
*
* @param entity
* @return
*/
Mono<D> toResource(T entity, ServerWebExchange exchange);
Mono<D> toModel(T entity, ServerWebExchange exchange);
/**
* Converts an {@link Iterable} or {@code T}s into an {@link Iterable} of {@link ResourceSupport} and wraps
* them in a {@link Resources} instance.
* Converts an {@link Iterable} or {@code T}s into an {@link Iterable} of {@link RepresentationModel} and wraps them
* in a {@link CollectionModel} instance.
*
* @param entities must not be {@literal null}.
* @return {@link Resources} containing {@code D}.
* @return {@link CollectionModel} containing {@code D}.
*/
default Mono<Resources<D>> toResources(Flux<? extends T> entities, ServerWebExchange exchange) {
default Mono<CollectionModel<D>> toCollectionModel(Flux<? extends T> entities,
ServerWebExchange exchange) {
return entities
.flatMap(entity -> toResource(entity, exchange))
.collectList()
.map(listOfResources -> new Resources<>(listOfResources));
return entities.flatMap(entity -> toModel(entity, exchange)) //
.collectList() //
.map(CollectionModel::new);
}
}

View File

@@ -0,0 +1,84 @@
/*
* Copyright 2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.hateoas.server.reactive;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.server.RepresentationModelAssembler;
import org.springframework.hateoas.server.SimpleRepresentationModelAssembler;
import org.springframework.web.server.ServerWebExchange;
/**
* Reactive variant of {@link RepresentationModelAssembler} combined with {@link SimpleRepresentationModelAssembler}.
*
* @author Greg Turnquist
* @author Oliver Drotbohm
*/
public interface SimpleReactiveRepresentationModelAssembler<T>
extends ReactiveRepresentationModelAssembler<T, EntityModel<T>> {
/**
* Converts the given entity into a {@link EntityModel} wrapped in a {@link Mono}.
*
* @param entity
* @return
*/
@Override
default Mono<EntityModel<T>> toModel(T entity, ServerWebExchange exchange) {
EntityModel<T> resource = new EntityModel<>(entity);
return Mono.just(addLinks(resource, exchange));
}
/**
* Define links to add to every individual {@link EntityModel}.
*
* @param resource
*/
default EntityModel<T> addLinks(EntityModel<T> resource, ServerWebExchange exchange) {
return resource;
}
/**
* Converts all given entities into resources and wraps the collection as a resource as well.
*
* @see #toResource(Object, ServerWebExchange)
* @param entities must not be {@literal null}.
* @return {@link CollectionModel} containing {@link EntityModel} of {@code T}.
*/
default Mono<CollectionModel<EntityModel<T>>> toCollectionModel(
Flux<? extends T> entities, ServerWebExchange exchange) {
return entities //
.flatMap(entity -> toModel(entity, exchange)) //
.collectList() //
.map(CollectionModel::new) //
.map(it -> addLinks(it, exchange));
}
/**
* Define links to add to the {@link CollectionModel} collection.
*
* @param resources
*/
default CollectionModel<EntityModel<T>> addLinks(
CollectionModel<EntityModel<T>> resources, ServerWebExchange exchange) {
return resources;
}
}

View File

@@ -1,80 +0,0 @@
/*
* Copyright 2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.hateoas.server.reactive;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.Resources;
import org.springframework.hateoas.server.ResourceAssembler;
import org.springframework.hateoas.server.SimpleResourceAssembler;
import org.springframework.web.server.ServerWebExchange;
/**
* Reactive variant of {@link ResourceAssembler} combined with {@link SimpleResourceAssembler}.
*
* @author Greg Turnquist
* @since 1.0
*/
public interface SimpleReactiveResourceAssembler<T> extends ReactiveResourceAssembler<T, Resource<T>> {
/**
* Converts the given entity into a {@link Resource} wrapped in a {@link Mono}.
*
* @param entity
* @return
*/
default Mono<Resource<T>> toResource(T entity, ServerWebExchange exchange) {
Resource<T> resource = new Resource<>(entity);
addLinks(resource, exchange);
return Mono.just(resource);
}
/**
* Define links to add to every individual {@link Resource}.
*
* @param resource
*/
void addLinks(Resource<T> resource, ServerWebExchange exchange);
/**
* Converts all given entities into resources and wraps the collection as a resource as well.
*
* @see #toResource(Object, ServerWebExchange)
* @param entities must not be {@literal null}.
* @return {@link Resources} containing {@link Resource} of {@code T}.
*/
default Mono<Resources<Resource<T>>> toResources(Flux<? extends T> entities, ServerWebExchange exchange) {
return entities //
.flatMap(entity -> toResource(entity, exchange)) //
.collectList() //
.map(listOfResources -> {
Resources<Resource<T>> resources = new Resources<>(listOfResources);
addLinks(resources, exchange);
return resources;
});
}
/**
* Define links to add to the {@link Resources} collection.
*
* @param resources
*/
void addLinks(Resources<Resource<T>> resources, ServerWebExchange exchange);
}

View File

@@ -18,7 +18,7 @@ package org.springframework.hateoas.server.mvc
import org.springframework.hateoas.Link
import org.springframework.hateoas.LinkRelation
import org.springframework.hateoas.ResourceSupport
import org.springframework.hateoas.RepresentationModel
import org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo
import org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn
@@ -49,7 +49,7 @@ infix fun WebMvcLinkBuilder.withRel(rel: String): Link = withRel(rel)
* @author Roland Kulcsár
* @since 1.0
*/
fun <C, R : ResourceSupport> R.add(controller: Class<C>, links: WebMvcLinkBuilderDsl<C, R>.(R) -> Unit): R {
fun <C, R : RepresentationModel<R>> R.add(controller: Class<C>, links: WebMvcLinkBuilderDsl<C, R>.(R) -> Unit): R {
val builder = WebMvcLinkBuilderDsl(controller, this)
builder.links(this)
@@ -63,7 +63,7 @@ fun <C, R : ResourceSupport> R.add(controller: Class<C>, links: WebMvcLinkBuilde
* @author Roland Kulcsár
* @since 1.0
*/
fun <C : Any, R : ResourceSupport> R.add(controller: KClass<C>, links: WebMvcLinkBuilderDsl<C, R>.(R) -> Unit): R {
fun <C : Any, R : RepresentationModel<R>> R.add(controller: KClass<C>, links: WebMvcLinkBuilderDsl<C, R>.(R) -> Unit): R {
return add(controller.java, links)
}
@@ -73,7 +73,7 @@ fun <C : Any, R : ResourceSupport> R.add(controller: KClass<C>, links: WebMvcLin
* @author Roland Kulcsár
* @since 1.0
*/
open class WebMvcLinkBuilderDsl<C, R : ResourceSupport>(val controller: Class<C>, val resource: R) {
open class WebMvcLinkBuilderDsl<C, R : RepresentationModel<R>>(val controller: Class<C>, val resource: R) {
/**
* Create a [WebMvcLinkBuilder] pointing to [func] method.

View File

@@ -23,27 +23,27 @@ import java.util.Set;
import org.junit.Test;
/**
* Unit tests for {@link Resources}.
* Unit tests for {@link CollectionModel}.
*
* @author Oliver Gierke
*/
public class ResourcesUnitTest {
public class CollectionModelUnitTest {
Set<Resource<String>> foo = Collections.singleton(new Resource<>("foo"));
Set<Resource<String>> bar = Collections.singleton(new Resource<>("bar"));
Set<EntityModel<String>> foo = Collections.singleton(new EntityModel<>("foo"));
Set<EntityModel<String>> bar = Collections.singleton(new EntityModel<>("bar"));
@Test
public void equalsForSelfReference() {
Resources<Resource<String>> resource = new Resources<>(foo);
CollectionModel<EntityModel<String>> resource = new CollectionModel<>(foo);
assertThat(resource).isEqualTo(resource);
}
@Test
public void equalsWithEqualContent() {
Resources<Resource<String>> left = new Resources<>(foo);
Resources<Resource<String>> right = new Resources<>(foo);
CollectionModel<EntityModel<String>> left = new CollectionModel<>(foo);
CollectionModel<EntityModel<String>> right = new CollectionModel<>(foo);
assertThat(left).isEqualTo(right);
assertThat(right).isEqualTo(left);
@@ -52,8 +52,8 @@ public class ResourcesUnitTest {
@Test
public void notEqualForDifferentContent() {
Resources<Resource<String>> left = new Resources<>(foo);
Resources<Resource<String>> right = new Resources<>(bar);
CollectionModel<EntityModel<String>> left = new CollectionModel<>(foo);
CollectionModel<EntityModel<String>> right = new CollectionModel<>(bar);
assertThat(left).isNotEqualTo(right);
assertThat(right).isNotEqualTo(left);
@@ -62,8 +62,8 @@ public class ResourcesUnitTest {
@Test
public void notEqualForDifferentLinks() {
Resources<Resource<String>> left = new Resources<>(foo);
Resources<Resource<String>> right = new Resources<>(bar);
CollectionModel<EntityModel<String>> left = new CollectionModel<>(foo);
CollectionModel<EntityModel<String>> right = new CollectionModel<>(bar);
right.add(new Link("localhost"));
assertThat(left).isNotEqualTo(right);

View File

@@ -23,12 +23,12 @@ import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
/**
* Integration tests for {@link Resource}.
* Integration tests for {@link EntityModel}.
*
* @author Oliver Gierke
* @author Greg Turnquist
*/
public class ResourceIntegrationTest extends AbstractJackson2MarshallingIntegrationTest {
public class EntityModelIntegrationTest extends AbstractJackson2MarshallingIntegrationTest {
static final String REFERENCE = "{\"firstname\":\"Dave\",\"lastname\":\"Matthews\",\"links\":[{\"rel\":\"self\",\"href\":\"localhost\"}]}";
@@ -39,7 +39,7 @@ public class ResourceIntegrationTest extends AbstractJackson2MarshallingIntegrat
person.firstname = "Dave";
person.lastname = "Matthews";
Resource<Person> resource = new Resource<>(person);
EntityModel<Person> resource = new EntityModel<>(person);
resource.add(new Link("localhost"));
assertThat(write(resource)).isEqualTo(REFERENCE);
@@ -51,7 +51,7 @@ public class ResourceIntegrationTest extends AbstractJackson2MarshallingIntegrat
@Test
public void readsResourceSupportCorrectly() throws Exception {
PersonResource result = read(REFERENCE, PersonResource.class);
PersonModel result = read(REFERENCE, PersonModel.class);
assertThat(result.getLinks()).hasSize(1);
assertThat(result.getLinks()).contains(new Link("localhost"));
@@ -59,13 +59,13 @@ public class ResourceIntegrationTest extends AbstractJackson2MarshallingIntegrat
assertThat(result.getContent().lastname).isEqualTo("Matthews");
}
static class PersonResource extends Resource<Person> {
static class PersonModel extends EntityModel<Person> {
public PersonResource(Person person) {
public PersonModel(Person person) {
super(person);
}
protected PersonResource() {}
protected PersonModel() {}
}
@JsonAutoDetect(fieldVisibility = Visibility.ANY)

View File

@@ -22,24 +22,24 @@ import java.util.Collections;
import org.junit.Test;
/**
* Unit tests for {@link Resource}.
* Unit tests for {@link EntityModel}.
*
* @author Oliver Gierke
*/
public class ResourceUnitTest {
public class EntityModelUnitTest {
@Test
public void equalsForSelfReference() {
Resource<String> resource = new Resource<>("foo");
EntityModel<String> resource = new EntityModel<>("foo");
assertThat(resource).isEqualTo(resource);
}
@Test
public void equalsWithEqualContent() {
Resource<String> left = new Resource<>("foo");
Resource<String> right = new Resource<>("foo");
EntityModel<String> left = new EntityModel<>("foo");
EntityModel<String> right = new EntityModel<>("foo");
assertThat(left).isEqualTo(right);
assertThat(right).isEqualTo(left);
@@ -48,8 +48,8 @@ public class ResourceUnitTest {
@Test
public void notEqualForDifferentContent() {
Resource<String> left = new Resource<>("foo");
Resource<String> right = new Resource<>("bar");
EntityModel<String> left = new EntityModel<>("foo");
EntityModel<String> right = new EntityModel<>("bar");
assertThat(left).isNotEqualTo(right);
assertThat(right).isNotEqualTo(left);
@@ -58,8 +58,8 @@ public class ResourceUnitTest {
@Test
public void notEqualForDifferentLinks() {
Resource<String> left = new Resource<>("foo");
Resource<String> right = new Resource<>("foo");
EntityModel<String> left = new EntityModel<>("foo");
EntityModel<String> right = new EntityModel<>("foo");
right.add(new Link("localhost"));
assertThat(left).isNotEqualTo(right);
@@ -68,6 +68,6 @@ public class ResourceUnitTest {
@Test(expected = IllegalArgumentException.class)
public void rejectsCollectionContent() {
new Resource<Object>(Collections.emptyList());
new EntityModel<Object>(Collections.emptyList());
}
}

View File

@@ -27,7 +27,7 @@ import java.util.Collections;
import org.apache.commons.io.output.WriterOutputStream;
import org.junit.Assume;
import org.junit.Test;
import org.springframework.hateoas.PagedResources.PageMetadata;
import org.springframework.hateoas.PagedModel.PageMetadata;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
@@ -35,7 +35,7 @@ import org.springframework.http.converter.json.MappingJackson2HttpMessageConvert
import org.springframework.util.ReflectionUtils;
/**
* Integration tests for serialization of {@link PagedResources}.
* Integration tests for serialization of {@link PagedModel}.
*
* @author Oliver Gierke
*/
@@ -65,8 +65,8 @@ public class Jackson2PagedResourcesIntegrationTest {
user.firstname = "Dave";
user.lastname = "Matthews";
PageMetadata metadata = new PagedResources.PageMetadata(1, 0, 2);
PagedResources<User> resources = new PagedResources<>(Collections.singleton(user), metadata);
PageMetadata metadata = new PagedModel.PageMetadata(1, 0, 2);
PagedModel<User> resources = new PagedModel<>(Collections.singleton(user), metadata);
Method method = Sample.class.getMethod("someMethod");
StringWriter writer = new StringWriter();
@@ -84,7 +84,7 @@ public class Jackson2PagedResourcesIntegrationTest {
}
interface Sample {
Resources<?> someMethod();
CollectionModel<?> someMethod();
}
static class User {

View File

@@ -7,7 +7,7 @@ import org.junit.Test;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
/**
* Integration tests for {@link Resource}.
* Integration tests for {@link EntityModel}.
*
* @author Oliver Gierke
* @author Jon Brisbin
@@ -27,7 +27,7 @@ public class Jackson2ResourceIntegrationTest extends AbstractJackson2Marshalling
person.firstname = "Dave";
person.lastname = "Matthews";
Resource<Person> resource = new Resource<>(person);
EntityModel<Person> resource = new EntityModel<>(person);
resource.add(new Link("localhost"));
assertThat(write(resource)).isEqualTo(REFERENCE);
@@ -47,7 +47,7 @@ public class Jackson2ResourceIntegrationTest extends AbstractJackson2Marshalling
assertThat(result.getContent().lastname).isEqualTo("Matthews");
}
static class PersonResource extends Resource<Person> {
static class PersonResource extends EntityModel<Person> {
public PersonResource() {

View File

@@ -20,8 +20,8 @@ import static org.assertj.core.api.Assertions.*;
import org.junit.Test;
/**
* Integration tests for {@link org.springframework.hateoas.ResourceSupport}.
*
* Integration tests for {@link org.springframework.hateoas.RepresentationModel}.
*
* @author Oliver Gierke
*/
public class Jackson2ResourceSupportIntegrationTest extends AbstractJackson2MarshallingIntegrationTest {
@@ -34,7 +34,7 @@ public class Jackson2ResourceSupportIntegrationTest extends AbstractJackson2Mars
@Test
public void doesNotRenderId() throws Exception {
ResourceSupport resourceSupport = new ResourceSupport();
RepresentationModel<?> resourceSupport = new RepresentationModel<>();
resourceSupport.add(new Link("localhost"));
assertThat(write(resourceSupport)).isEqualTo(REFERENCE);
@@ -46,7 +46,7 @@ public class Jackson2ResourceSupportIntegrationTest extends AbstractJackson2Mars
@Test
public void readResourceSupportCorrectly() throws Exception {
ResourceSupport result = read(REFERENCE, ResourceSupport.class);
RepresentationModel<?> result = read(REFERENCE, RepresentationModel.class);
assertThat(result.getLinks()).hasSize(1);
assertThat(result.getLinks()).contains(new Link("localhost"));

View File

@@ -106,7 +106,7 @@ public class LinkUnitTest {
@Test
public void differentTypeDoesNotEqual() {
assertThat(new Link("foo")).isNotEqualTo(new ResourceSupport());
assertThat(new Link("foo")).isNotEqualTo(new RepresentationModel<>());
}
@Test

View File

@@ -21,22 +21,22 @@ import java.util.Collections;
import org.junit.Before;
import org.junit.Test;
import org.springframework.hateoas.PagedResources.PageMetadata;
import org.springframework.hateoas.PagedModel.PageMetadata;
/**
* Unit tests for {@link PagedResources}.
* Unit tests for {@link PagedModel}.
*
* @author Oliver Gierke
*/
public class PagedResourcesUnitTest {
public class PagedModelUnitTest {
static final PageMetadata metadata = new PagedResources.PageMetadata(10, 1, 200);
static final PageMetadata metadata = new PagedModel.PageMetadata(10, 1, 200);
PagedResources<Object> resources;
PagedModel<Object> resources;
@Before
public void setUp() {
resources = new PagedResources<>(Collections.emptyList(), metadata);
resources = new PagedModel<>(Collections.emptyList(), metadata);
}
@Test

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012 the original author or authors.
* Copyright 2012-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,35 +20,29 @@ import static org.assertj.core.api.Assertions.*;
import org.junit.Test;
/**
* Integration tests for {@link ResourceSupport}.
*
* Integration tests for {@link RepresentationModel}.
*
* @author Oliver Gierke
*/
public class ResourceSupportIntegrationTest extends AbstractJackson2MarshallingIntegrationTest {
public class RepresentationModelIntegrationTest extends AbstractJackson2MarshallingIntegrationTest {
static final String REFERENCE = "{\"links\":[{\"rel\":\"self\",\"href\":\"localhost\"}]}";
/**
* @see #7
*/
@Test
@Test // #7
public void doesNotRenderId() throws Exception {
ResourceSupport resourceSupport = new ResourceSupport();
resourceSupport.add(new Link("localhost"));
RepresentationModel<?> model = new RepresentationModel<>();
model.add(new Link("localhost"));
assertThat(write(resourceSupport)).isEqualTo(REFERENCE);
assertThat(write(model)).isEqualTo(REFERENCE);
}
/**
* @see #14
*/
@Test
@Test // #14
public void readResourceSupportCorrectly() throws Exception {
ResourceSupport result = read(REFERENCE, ResourceSupport.class);
RepresentationModel<?> model = read(REFERENCE, RepresentationModel.class);
assertThat(result.getLinks()).hasSize(1);
assertThat(result.getLinks()).contains(new Link("localhost"));
assertThat(model.getLinks()).hasSize(1);
assertThat(model.getLinks()).contains(new Link("localhost"));
}
}

View File

@@ -22,16 +22,16 @@ import java.util.Arrays;
import org.junit.Test;
/**
* Unit tests for {@link ResourceSupport}.
*
* Unit tests for {@link RepresentationModel}.
*
* @author Oliver Gierke
*/
public class ResourceSupportUnitTest {
public class RepresentationModelUnitTest {
@Test
public void setsUpWithEmptyLinkList() {
ResourceSupport support = new ResourceSupport();
RepresentationModel<?> support = new RepresentationModel<>();
assertThat(support.hasLinks()).isFalse();
assertThat(support.hasLink(IanaLinkRelations.SELF.value())).isFalse();
assertThat(support.getLinks().isEmpty()).isTrue();
@@ -42,7 +42,7 @@ public class ResourceSupportUnitTest {
public void addsLinkCorrectly() {
Link link = new Link("foo", IanaLinkRelations.NEXT.value());
ResourceSupport support = new ResourceSupport();
RepresentationModel<?> support = new RepresentationModel<>();
support.add(link);
assertThat(support.getId()).isEmpty();
@@ -57,7 +57,7 @@ public class ResourceSupportUnitTest {
Link link = new Link("/customers/1", "customers");
Link link2 = new Link("/orders/1/customer", "customers");
ResourceSupport support = new ResourceSupport();
RepresentationModel<?> support = new RepresentationModel<>();
support.add(link, link2);
assertThat(support.getLinks("customers")).hasSize(2);
@@ -72,7 +72,7 @@ public class ResourceSupportUnitTest {
Link first = new Link("foo", IanaLinkRelations.PREV.value());
Link second = new Link("bar", IanaLinkRelations.NEXT.value());
ResourceSupport support = new ResourceSupport();
RepresentationModel<?> support = new RepresentationModel<>();
support.add(Arrays.asList(first, second));
assertThat(support.getId()).isEmpty();
@@ -87,7 +87,7 @@ public class ResourceSupportUnitTest {
public void selfLinkBecomesId() {
Link link = new Link("foo");
ResourceSupport support = new ResourceSupport();
RepresentationModel<?> support = new RepresentationModel<>();
support.add(link);
assertThat(support.getId()).hasValue(link);
@@ -96,21 +96,21 @@ public class ResourceSupportUnitTest {
@Test(expected = IllegalArgumentException.class)
public void preventsNullLinkBeingAdded() {
ResourceSupport support = new ResourceSupport();
RepresentationModel<?> support = new RepresentationModel<>();
support.add((Link) null);
}
@Test(expected = IllegalArgumentException.class)
public void preventsNullLinksBeingAdded() {
ResourceSupport support = new ResourceSupport();
RepresentationModel<?> support = new RepresentationModel<>();
support.add((Iterable<Link>) null);
}
@Test
public void sameLinkListMeansSameResource() {
ResourceSupport first = new ResourceSupport();
ResourceSupport second = new ResourceSupport();
RepresentationModel<?> first = new RepresentationModel<>();
RepresentationModel<?> second = new RepresentationModel<>();
TestUtils.assertEqualAndSameHashCode(first, second);
@@ -124,18 +124,19 @@ public class ResourceSupportUnitTest {
@Test
public void differentLinkListsNotEqual() {
ResourceSupport first = new ResourceSupport();
ResourceSupport second = new ResourceSupport();
RepresentationModel<?> first = new RepresentationModel<>();
RepresentationModel<?> second = new RepresentationModel<>();
second.add(new Link("foo"));
TestUtils.assertNotEqualAndDifferentHashCode(first, second);
}
@Test
@SuppressWarnings("rawtypes")
public void subclassNotEquals() {
ResourceSupport left = new ResourceSupport();
ResourceSupport right = new ResourceSupport() {
RepresentationModel<?> left = new RepresentationModel<>();
RepresentationModel<?> right = new RepresentationModel() {
@Override
public int hashCode() {
@@ -157,7 +158,7 @@ public class ResourceSupportUnitTest {
@Test
public void doesNotEqualNull() {
ResourceSupport support = new ResourceSupport();
RepresentationModel<?> support = new RepresentationModel<>();
assertThat(support.equals(null)).isFalse();
}
@@ -167,7 +168,7 @@ public class ResourceSupportUnitTest {
@Test
public void addsLinksViaVarargs() {
ResourceSupport support = new ResourceSupport();
RepresentationModel<?> support = new RepresentationModel<>();
support.add(new Link("/self", "self"), new Link("/another", "another"));
assertThat(support.hasLink("self")).isTrue();

View File

@@ -23,12 +23,12 @@ import lombok.Data;
import java.util.Collections;
import org.junit.Test;
import org.springframework.hateoas.server.SimpleResourceAssembler;
import org.springframework.hateoas.server.SimpleRepresentationModelAssembler;
/**
* @author Greg Turnquist
*/
public class SimpleResourceAssemblerTest {
public class SimpleRepresentationModelAssemblerTest {
/**
* @see #572
@@ -37,7 +37,7 @@ public class SimpleResourceAssemblerTest {
public void convertingToResourceShouldWork() {
TestResourceAssembler assembler = new TestResourceAssembler();
Resource<Employee> resource = assembler.toResource(new Employee("Frodo"));
EntityModel<Employee> resource = assembler.toModel(new Employee("Frodo"));
assertThat(resource.getContent().getName()).isEqualTo("Frodo");
assertThat(resource.getLinks()).isEmpty();
@@ -50,9 +50,10 @@ public class SimpleResourceAssemblerTest {
public void convertingToResourcesShouldWork() {
TestResourceAssembler assembler = new TestResourceAssembler();
Resources<Resource<Employee>> resources = assembler.toResources(Collections.singletonList(new Employee("Frodo")));
CollectionModel<EntityModel<Employee>> resources = assembler
.toCollectionModel(Collections.singletonList(new Employee("Frodo")));
assertThat(resources.getContent()).containsExactly(new Resource<>(new Employee("Frodo")));
assertThat(resources.getContent()).containsExactly(new EntityModel<>(new Employee("Frodo")));
assertThat(resources.getLinks()).isEmpty();
}
@@ -63,7 +64,7 @@ public class SimpleResourceAssemblerTest {
public void convertingToResourceWithCustomLinksShouldWork() {
ResourceAssemblerWithCustomLink assembler = new ResourceAssemblerWithCustomLink();
Resource<Employee> resource = assembler.toResource(new Employee("Frodo"));
EntityModel<Employee> resource = assembler.toModel(new Employee("Frodo"));
assertThat(resource.getContent().getName()).isEqualTo("Frodo");
assertThat(resource.getLinks()).containsExactly(new Link("/employees").withRel("employees"));
@@ -76,34 +77,32 @@ public class SimpleResourceAssemblerTest {
public void convertingToResourcesWithCustomLinksShouldWork() {
ResourceAssemblerWithCustomLink assembler = new ResourceAssemblerWithCustomLink();
Resources<Resource<Employee>> resources = assembler.toResources(Collections.singletonList(new Employee("Frodo")));
CollectionModel<EntityModel<Employee>> resources = assembler
.toCollectionModel(Collections.singletonList(new Employee("Frodo")));
assertThat(resources.getContent())
.containsExactly(new Resource<>(new Employee("Frodo"), new Link("/employees").withRel("employees")));
assertThat(resources.getContent()).containsExactly(
new EntityModel<>(new Employee("Frodo"), new Link("/employees").withRel("employees")));
assertThat(resources.getLinks()).isEmpty();
}
class TestResourceAssembler implements SimpleResourceAssembler<Employee> {
class TestResourceAssembler implements SimpleRepresentationModelAssembler<Employee> {
@Override
public void addLinks(Resource<Employee> resource) {
}
public void addLinks(EntityModel<Employee> resource) {}
@Override
public void addLinks(Resources<Resource<Employee>> resources) {
}
public void addLinks(CollectionModel<EntityModel<Employee>> resources) {}
}
class ResourceAssemblerWithCustomLink implements SimpleResourceAssembler<Employee> {
class ResourceAssemblerWithCustomLink implements SimpleRepresentationModelAssembler<Employee> {
@Override
public void addLinks(Resource<Employee> resource) {
public void addLinks(EntityModel<Employee> resource) {
resource.add(new Link("/employees").withRel("employees"));
}
@Override
public void addLinks(Resources<Resource<Employee>> resources) {
}
public void addLinks(CollectionModel<EntityModel<Employee>> resources) {}
}
@Data

View File

@@ -29,8 +29,8 @@ import org.springframework.core.io.ResourceLoader;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.LinkRelation;
import org.springframework.hateoas.MediaTypes;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.Resources;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.mediatype.hal.Jackson2HalModule;
import org.springframework.hateoas.server.RelProvider;
import org.springframework.hateoas.server.core.EvoInflectorRelProvider;
@@ -168,7 +168,7 @@ public class Server implements Closeable {
return "http://localhost:" + port();
}
public String mockResourceFor(Resource<?> resource) {
public String mockResourceFor(EntityModel<?> resource) {
Object content = resource.getContent();
@@ -188,13 +188,13 @@ public class Server implements Closeable {
public void finishMocking() {
Resources<String> resources = new Resources<>(Collections.emptyList());
CollectionModel<String> resources = new CollectionModel<>(Collections.emptyList());
for (Link link : baseResources.keySet()) {
resources.add(link);
Resources<String> nested = new Resources<>(Collections.emptyList());
CollectionModel<String> nested = new CollectionModel<>(Collections.emptyList());
nested.add(baseResources.get(link));
register(link.getHref(), nested);

View File

@@ -35,7 +35,7 @@ import org.junit.Test;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.MediaTypes;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.client.Traverson.TraversalBuilder;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRequest;
@@ -141,8 +141,8 @@ public class TraversonTest {
@Test
public void readsTraversalIntoResourceInstance() {
ParameterizedTypeReference<Resource<Actor>> typeReference = new ParameterizedTypeReference<Resource<Actor>>() {};
Resource<Actor> result = traverson.follow("movies", "movie", "actor").toObject(typeReference);
ParameterizedTypeReference<EntityModel<Actor>> typeReference = new ParameterizedTypeReference<EntityModel<Actor>>() {};
EntityModel<Actor> result = traverson.follow("movies", "movie", "actor").toObject(typeReference);
assertThat(result.getContent().name).isEqualTo("Keanu Reaves");
}
@@ -284,8 +284,8 @@ public class TraversonTest {
@Test
public void chainMultipleFollowOperations() {
ParameterizedTypeReference<Resource<Actor>> typeReference = new ParameterizedTypeReference<Resource<Actor>>() {};
Resource<Actor> result = traverson.follow("movies").follow("movie").follow("actor").toObject(typeReference);
ParameterizedTypeReference<EntityModel<Actor>> typeReference = new ParameterizedTypeReference<EntityModel<Actor>>() {};
EntityModel<Actor> result = traverson.follow("movies").follow("movie").follow("actor").toObject(typeReference);
assertThat(result.getContent().name).isEqualTo("Keanu Reaves");
}
@@ -299,9 +299,9 @@ public class TraversonTest {
this.traverson = new Traverson(URI.create(server.rootResource() + "/springagram"), MediaTypes.HAL_JSON);
// tag::hop-with-param[]
ParameterizedTypeReference<Resource<Item>> resourceParameterizedTypeReference = new ParameterizedTypeReference<Resource<Item>>() {};
ParameterizedTypeReference<EntityModel<Item>> resourceParameterizedTypeReference = new ParameterizedTypeReference<EntityModel<Item>>() {};
Resource<Item> itemResource = traverson.//
EntityModel<Item> itemResource = traverson.//
follow(rel("items").withParameter("projection", "noImages")).//
follow("$._embedded.items[0]._links.self.href").//
toObject(resourceParameterizedTypeReference);
@@ -325,11 +325,11 @@ public class TraversonTest {
this.traverson = new Traverson(URI.create(server.rootResource() + "/springagram"), MediaTypes.HAL_JSON);
// tag::hop-put[]
ParameterizedTypeReference<Resource<Item>> resourceParameterizedTypeReference = new ParameterizedTypeReference<Resource<Item>>() {};
ParameterizedTypeReference<EntityModel<Item>> resourceParameterizedTypeReference = new ParameterizedTypeReference<EntityModel<Item>>() {};
Map<String, Object> params = Collections.singletonMap("projection", "noImages");
Resource<Item> itemResource = traverson.//
EntityModel<Item> itemResource = traverson.//
follow(rel("items").withParameters(params)).//
follow("$._embedded.items[0]._links.self.href").//
toObject(resourceParameterizedTypeReference);
@@ -355,8 +355,8 @@ public class TraversonTest {
Map<String, Object> params = new HashMap<>();
params.put("projection", "thisShouldGetOverwrittenByLocalHop");
ParameterizedTypeReference<Resource<Item>> resourceParameterizedTypeReference = new ParameterizedTypeReference<Resource<Item>>() {};
Resource<Item> itemResource = traverson.follow(rel("items").withParameter("projection", "noImages"))
ParameterizedTypeReference<EntityModel<Item>> resourceParameterizedTypeReference = new ParameterizedTypeReference<EntityModel<Item>>() {};
EntityModel<Item> itemResource = traverson.follow(rel("items").withParameter("projection", "noImages"))
.follow("$._embedded.items[0]._links.self.href") // retrieve first Item in the collection
.withTemplateParameters(params).toObject(resourceParameterizedTypeReference);
@@ -377,9 +377,9 @@ public class TraversonTest {
this.traverson = new Traverson(URI.create(server.rootResource() + "/springagram"), MediaTypes.HAL_JSON);
Resource<?> itemResource = traverson.//
EntityModel<?> itemResource = traverson.//
follow(rel("items").withParameters(Collections.singletonMap("projection", "no images"))).//
toObject(Resource.class);
toObject(EntityModel.class);
assertThat(itemResource.hasLink("self")).isTrue();
assertThat(itemResource.getRequiredLink("self").expand().getHref())
@@ -417,11 +417,11 @@ public class TraversonTest {
private static void setUpActors() {
Resource<Actor> actor = new Resource<>(new Actor("Keanu Reaves"));
EntityModel<Actor> actor = new EntityModel<>(new Actor("Keanu Reaves"));
String actorUri = server.mockResourceFor(actor);
Movie movie = new Movie("The Matrix");
Resource<Movie> resource = new Resource<>(movie);
EntityModel<Movie> resource = new EntityModel<>(movie);
resource.add(new Link(actorUri, "actor"));
server.mockResourceFor(resource);

View File

@@ -29,7 +29,7 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.config.EnableHypermediaSupport.HypermediaType;
import org.springframework.hateoas.support.CustomHypermediaType;
import org.springframework.hateoas.support.Employee;
@@ -92,11 +92,11 @@ public class CustomHypermediaWebFluxTest {
static class EmployeeController {
@GetMapping("/employees/1")
public Mono<Resource<Employee>> findOne() {
public Mono<EntityModel<Employee>> findOne() {
return linkTo(methodOn(EmployeeController.class).findOne()).withSelfRel() //
.toMono() //
.map(link -> new Resource<>(new Employee("Frodo Baggins", "ring bearer"), link)); //
.map(link -> new EntityModel<>(new Employee("Frodo Baggins", "ring bearer"), link)); //
}
}
}

View File

@@ -30,7 +30,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.config.EnableHypermediaSupport.HypermediaType;
import org.springframework.hateoas.support.CustomHypermediaType;
import org.springframework.hateoas.support.Employee;
@@ -94,8 +94,8 @@ public class CustomHypermediaWebMvcTest {
static class EmployeeController {
@GetMapping("/employees/1")
public Resource<Employee> findOne() {
return new Resource<>(new Employee("Frodo Baggins", "ring bearer"),
public EntityModel<Employee> findOne() {
return new EntityModel<>(new Employee("Frodo Baggins", "ring bearer"),
linkTo(methodOn(EmployeeController.class).findOne()).withSelfRel());
}
}

View File

@@ -33,7 +33,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.MediaTypes;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.hateoas.client.LinkDiscoverer;
import org.springframework.hateoas.client.LinkDiscoverers;
import org.springframework.hateoas.config.EnableHypermediaSupport.HypermediaType;
@@ -493,7 +493,7 @@ public class EnableHypermediaSupportIntegrationTest {
assertThat(mapper).hasValueSatisfying(it -> {
ResourceSupport resourceSupport = new ResourceSupport();
RepresentationModel<?> resourceSupport = new RepresentationModel<>();
resourceSupport.add(new Link("localhost").withSelfRel());
assertThatCode(() -> {
@@ -513,7 +513,7 @@ public class EnableHypermediaSupportIntegrationTest {
context, //
MediaTypes.HAL_JSON, //
mapper -> { //
ResourceSupport resourceSupport = new ResourceSupport(); //
RepresentationModel<?> resourceSupport = new RepresentationModel<>(); //
resourceSupport.add(new Link("localhost").withSelfRel()); //
assertThat(mapper.writeValueAsString(resourceSupport)) //
.isEqualTo("{\"_links\":{\"self\":[{\"href\":\"localhost\"}]}}"); //

View File

@@ -30,14 +30,14 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.MediaTypes;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.hateoas.client.Actor;
import org.springframework.hateoas.client.Movie;
import org.springframework.hateoas.client.Server;
import org.springframework.hateoas.config.EnableHypermediaSupport;
import org.springframework.hateoas.config.EnableHypermediaSupport.HypermediaType;
import org.springframework.hateoas.server.mvc.TypeReferences.ResourceType;
import org.springframework.hateoas.server.mvc.TypeReferences.EntityModelType;
import org.springframework.web.reactive.function.client.WebClient;
/**
@@ -55,11 +55,11 @@ public class HypermediaWebClientBeanPostProcessorTest {
this.server = new Server();
Resource<Actor> actor = new Resource<>(new Actor("Keanu Reaves"));
EntityModel<Actor> actor = new EntityModel<>(new Actor("Keanu Reaves"));
String actorUri = this.server.mockResourceFor(actor);
Movie movie = new Movie("The Matrix");
Resource<Movie> resource = new Resource<>(movie);
EntityModel<Movie> resource = new EntityModel<>(movie);
resource.add(new Link(actorUri, "actor"));
this.server.mockResourceFor(resource);
@@ -90,7 +90,7 @@ public class HypermediaWebClientBeanPostProcessorTest {
.get().uri(this.baseUri) //
.accept(MediaTypes.HAL_JSON) //
.retrieve() //
.bodyToMono(ResourceSupport.class) //
.bodyToMono(RepresentationModel.class) //
.as(StepVerifier::create) //
.expectNextMatches(root -> { //
assertThat(root.getLinks()).hasSize(2);
@@ -106,7 +106,7 @@ public class HypermediaWebClientBeanPostProcessorTest {
@Test
public void shouldHandleNavigatingToAResourceObject() {
ParameterizedTypeReference<Resource<Actor>> typeReference = new ResourceType<Actor>() {};
ParameterizedTypeReference<EntityModel<Actor>> typeReference = new EntityModelType<Actor>() {};
withContext(HalConfig.class, context -> {
@@ -115,19 +115,19 @@ public class HypermediaWebClientBeanPostProcessorTest {
webClient //
.get().uri(this.baseUri) //
.retrieve() //
.bodyToMono(ResourceSupport.class) //
.bodyToMono(RepresentationModel.class) //
.map(resourceSupport -> resourceSupport.getRequiredLink("actors")) //
.flatMap(link -> webClient //
.get().uri(link.expand().getHref()) //
.retrieve() //
.bodyToMono(ResourceSupport.class)) //
.bodyToMono(RepresentationModel.class)) //
.map(resourceSupport -> resourceSupport.getLinks().toList().get(0)) //
.flatMap(link -> webClient //
.get().uri(link.expand().getHref()) //
.retrieve() //
.bodyToMono(typeReference)) //
.as(StepVerifier::create) //
.expectNext(new Resource<>(new Actor("Keanu Reaves"))) //
.expectNext(new EntityModel<>(new Actor("Keanu Reaves"))) //
.verifyComplete();
});
}

View File

@@ -31,18 +31,15 @@ import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.IanaLinkRelations;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.MediaTypes;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.hateoas.Resources;
import org.springframework.hateoas.config.EnableHypermediaSupport;
import org.springframework.hateoas.config.WebClientConfigurer;
import org.springframework.hateoas.server.SimpleResourceAssembler;
import org.springframework.hateoas.server.mvc.TypeReferences.ResourceType;
import org.springframework.hateoas.server.mvc.TypeReferences.ResourcesType;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.hateoas.server.SimpleRepresentationModelAssembler;
import org.springframework.hateoas.server.mvc.TypeReferences.CollectionModelType;
import org.springframework.hateoas.server.mvc.TypeReferences.EntityModelType;
import org.springframework.hateoas.support.Employee;
import org.springframework.http.MediaType;
import org.springframework.test.web.reactive.server.WebTestClient;
@@ -59,8 +56,8 @@ import org.springframework.web.reactive.config.EnableWebFlux;
*/
public class HypermediaWebFluxConfigurerTest {
ParameterizedTypeReference<Resource<Employee>> resourceEmployeeType = new ResourceType<Employee>() {};
ParameterizedTypeReference<Resources<Resource<Employee>>> resourcesEmployeeType = new ResourcesType<Resource<Employee>>() {};
EntityModelType<Employee> resourceEmployeeType = new EntityModelType<Employee>() {};
CollectionModelType<EntityModel<Employee>> resourcesEmployeeType = new CollectionModelType<EntityModel<Employee>>() {};
WebTestClient testClient;
@@ -280,7 +277,7 @@ public class HypermediaWebFluxConfigurerTest {
this.testClient.get().uri("/reactive").accept(MediaTypes.HAL_JSON).exchange() //
.expectStatus().isOk() //
.expectHeader().contentType(MediaTypes.HAL_JSON_UTF8) //
.returnResult(ResourceSupport.class).getResponseBody().as(StepVerifier::create)
.returnResult(RepresentationModel.class).getResponseBody().as(StepVerifier::create)
.expectNextMatches(resourceSupport -> {
assertThat(resourceSupport.getLinks()).containsExactlyInAnyOrder(new Link("/", IanaLinkRelations.SELF),
@@ -296,7 +293,7 @@ public class HypermediaWebFluxConfigurerTest {
assertThat(resources.getLinks()).containsExactlyInAnyOrder(new Link("/employees", IanaLinkRelations.SELF));
Resource<Employee> content = resources.getContent().iterator().next();
EntityModel<Employee> content = resources.getContent().iterator().next();
assertThat(content.getContent()).isEqualTo(new Employee("Frodo Baggins", "ring bearer"));
assertThat(content.getLinks()) //
@@ -328,7 +325,7 @@ public class HypermediaWebFluxConfigurerTest {
this.testClient.get().uri("/").accept(requestType).exchange() //
.expectStatus().isOk() //
.expectHeader().contentType(responseType) //
.returnResult(ResourceSupport.class).getResponseBody().as(StepVerifier::create)
.returnResult(RepresentationModel.class).getResponseBody().as(StepVerifier::create)
.expectNextMatches(resourceSupport -> {
assertThat(resourceSupport.getLinks()) //
@@ -350,10 +347,10 @@ public class HypermediaWebFluxConfigurerTest {
assertThat(resources.getLinks()).containsExactlyInAnyOrder(new Link("/employees", IanaLinkRelations.SELF));
Collection<Resource<Employee>> content = resources.getContent();
Collection<EntityModel<Employee>> content = resources.getContent();
assertThat(content).hasSize(1);
Resource<Employee> resource = content.iterator().next();
EntityModel<Employee> resource = content.iterator().next();
assertThat(resource.getContent()).isEqualTo(new Employee("Frodo Baggins", "ring bearer"));
assertThat(resource.getLinks()) //
@@ -464,9 +461,9 @@ public class HypermediaWebFluxConfigurerTest {
}
@GetMapping
ResourceSupport root() {
RepresentationModel<?> root() {
ResourceSupport root = new ResourceSupport();
RepresentationModel<?> root = new RepresentationModel<>();
root.add(new Link("/").withSelfRel());
root.add(new Link("/employees").withRel("employees"));
@@ -475,57 +472,57 @@ public class HypermediaWebFluxConfigurerTest {
}
@GetMapping("/employees")
Resources<Resource<Employee>> employees() {
return this.assembler.toResources(this.employees);
CollectionModel<EntityModel<Employee>> employees() {
return this.assembler.toCollectionModel(this.employees);
}
@PostMapping("/employees")
Resource<Employee> newEmployee(@RequestBody Employee newEmployee) {
EntityModel<Employee> newEmployee(@RequestBody Employee newEmployee) {
this.employees.add(newEmployee);
return this.assembler.toResource(newEmployee);
return this.assembler.toModel(newEmployee);
}
@GetMapping("/employees/{id}")
Resource<Employee> employee(@PathVariable String id) {
return this.assembler.toResource(this.employees.get(0));
EntityModel<Employee> employee(@PathVariable String id) {
return this.assembler.toModel(this.employees.get(0));
}
@PutMapping("/employees/{id}")
Resource<Employee> updateEmployee(@RequestBody Employee newEmployee, @PathVariable String id) {
EntityModel<Employee> updateEmployee(@RequestBody Employee newEmployee, @PathVariable String id) {
this.employees.add(newEmployee);
return this.assembler.toResource(newEmployee);
return this.assembler.toModel(newEmployee);
}
@GetMapping("/reactive")
Mono<ResourceSupport> reactiveRoot() {
Mono<RepresentationModel<?>> reactiveRoot() {
return Mono.just(root());
}
@GetMapping("/reactive/employees")
Mono<Resources<Resource<Employee>>> reactiveEmployees() {
Mono<CollectionModel<EntityModel<Employee>>> reactiveEmployees() {
return findAll() //
.collectList() //
.map(assembler::toResources);
.map(assembler::toCollectionModel);
}
@PostMapping("/reactive/employees")
Mono<Resource<Employee>> createReactiveEmployee(@RequestBody Mono<Employee> newEmployee) {
Mono<EntityModel<Employee>> createReactiveEmployee(@RequestBody Mono<Employee> newEmployee) {
return newEmployee.map(employee -> {
employees.add(employee);
return employee;
}).map(assembler::toResource);
}).map(assembler::toModel);
}
@GetMapping("/reactive/employees/{id}")
Mono<Resource<Employee>> reactiveEmployee(@PathVariable String id) {
Mono<EntityModel<Employee>> reactiveEmployee(@PathVariable String id) {
return findById(0) //
.map(assembler::toResource);
.map(assembler::toModel);
}
Mono<Employee> findById(int id) {
@@ -537,17 +534,17 @@ public class HypermediaWebFluxConfigurerTest {
}
}
static class EmployeeResourceAssembler implements SimpleResourceAssembler<Employee> {
static class EmployeeResourceAssembler implements SimpleRepresentationModelAssembler<Employee> {
@Override
public void addLinks(Resource<Employee> resource) {
public void addLinks(EntityModel<Employee> resource) {
resource.add(new Link("/employees/1").withSelfRel());
resource.add(new Link("/employees").withRel("employees"));
}
@Override
public void addLinks(Resources<Resource<Employee>> resources) {
public void addLinks(CollectionModel<EntityModel<Employee>> resources) {
resources.add(new Link("/employees").withSelfRel());
}
}

View File

@@ -26,12 +26,11 @@ import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.springframework.core.io.ClassPathResource;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.IanaLinkRelations;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.hateoas.Resources;
import org.springframework.hateoas.mediatype.collectionjson.Jackson2CollectionJsonModule;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.hateoas.support.Employee;
import org.springframework.hateoas.support.MappingUtils;
@@ -68,7 +67,7 @@ public class CollectionJsonSpecTest {
String specBasedJson = MappingUtils.read(new ClassPathResource("spec-part1.json", getClass()));
ResourceSupport resource = mapper.readValue(specBasedJson, ResourceSupport.class);
RepresentationModel<?> resource = mapper.readValue(specBasedJson, RepresentationModel.class);
assertThat(resource.getLinks()).hasSize(1);
assertThat(resource.getRequiredLink(IanaLinkRelations.SELF)).isEqualTo(new Link("http://example.org/friends/"));
@@ -83,16 +82,16 @@ public class CollectionJsonSpecTest {
String specBasedJson = MappingUtils.read(new ClassPathResource("spec-part2.json", getClass()));
Resources<Resource<Friend>> resources = mapper.readValue(specBasedJson,
mapper.getTypeFactory().constructParametricType(Resources.class,
mapper.getTypeFactory().constructParametricType(Resource.class, Friend.class)));
CollectionModel<EntityModel<Friend>> resources = mapper.readValue(specBasedJson,
mapper.getTypeFactory().constructParametricType(CollectionModel.class,
mapper.getTypeFactory().constructParametricType(EntityModel.class, Friend.class)));
assertThat(resources.getLinks()).hasSize(2);
assertThat(resources.getRequiredLink(IanaLinkRelations.SELF)).isEqualTo(new Link("http://example.org/friends/"));
assertThat(resources.getRequiredLink("feed")).isEqualTo(new Link("http://example.org/friends/rss", "feed"));
assertThat(resources.getContent()).hasSize(3);
List<Resource<Friend>> friends = new ArrayList<>(resources.getContent());
List<EntityModel<Friend>> friends = new ArrayList<>(resources.getContent());
assertThat(friends.get(0).getContent().getEmail()).isEqualTo("jdoe@example.org");
assertThat(friends.get(0).getContent().getFullname()).isEqualTo("J. Doe");
@@ -129,8 +128,8 @@ public class CollectionJsonSpecTest {
String specBasedJson = MappingUtils.read(new ClassPathResource("spec-part3.json", getClass()));
Resource<Friend> resource = mapper.readValue(specBasedJson,
mapper.getTypeFactory().constructParametricType(Resource.class, Friend.class));
EntityModel<Friend> resource = mapper.readValue(specBasedJson,
mapper.getTypeFactory().constructParametricType(EntityModel.class, Friend.class));
assertThat(resource.getLinks()).hasSize(6);
assertThat(resource.getRequiredLink(IanaLinkRelations.SELF)).isEqualTo(new Link("http://example.org/friends/jdoe"));
@@ -155,9 +154,9 @@ public class CollectionJsonSpecTest {
String specBasedJson = MappingUtils.read(new ClassPathResource("spec-part4.json", getClass()));
Resources<Resource<Friend>> resources = mapper.readValue(specBasedJson,
mapper.getTypeFactory().constructParametricType(Resources.class,
mapper.getTypeFactory().constructParametricType(Resource.class, Friend.class)));
CollectionModel<EntityModel<Friend>> resources = mapper.readValue(specBasedJson,
mapper.getTypeFactory().constructParametricType(CollectionModel.class,
mapper.getTypeFactory().constructParametricType(EntityModel.class, Friend.class)));
assertThat(resources.getContent()).hasSize(0);
assertThat(resources.getRequiredLink(IanaLinkRelations.SELF.value()))
@@ -173,9 +172,9 @@ public class CollectionJsonSpecTest {
String specBasedJson = MappingUtils.read(new ClassPathResource("spec-part5.json", getClass()));
Resources<Resource<Friend>> resources = mapper.readValue(specBasedJson,
mapper.getTypeFactory().constructParametricType(Resources.class,
mapper.getTypeFactory().constructParametricType(Resource.class, Friend.class)));
CollectionModel<EntityModel<Friend>> resources = mapper.readValue(specBasedJson,
mapper.getTypeFactory().constructParametricType(CollectionModel.class,
mapper.getTypeFactory().constructParametricType(EntityModel.class, Friend.class)));
assertThat(resources.getContent()).hasSize(0);
assertThat(resources.getRequiredLink(IanaLinkRelations.SELF.value()))
@@ -191,9 +190,9 @@ public class CollectionJsonSpecTest {
String specBasedJson = MappingUtils.read(new ClassPathResource("spec-part6.json", getClass()));
Resources<Resource<Friend>> resources = mapper.readValue(specBasedJson,
mapper.getTypeFactory().constructParametricType(Resources.class,
mapper.getTypeFactory().constructParametricType(Resource.class, Friend.class)));
CollectionModel<EntityModel<Friend>> resources = mapper.readValue(specBasedJson,
mapper.getTypeFactory().constructParametricType(CollectionModel.class,
mapper.getTypeFactory().constructParametricType(EntityModel.class, Friend.class)));
assertThat(resources.getContent()).hasSize(0);
assertThat(resources.getRequiredLink(IanaLinkRelations.SELF.value()))
@@ -209,8 +208,8 @@ public class CollectionJsonSpecTest {
String specBasedJson = MappingUtils.read(new ClassPathResource("spec-part7-adjusted.json", getClass()));
Resource<Employee> resource = mapper.readValue(specBasedJson,
mapper.getTypeFactory().constructParametricType(Resource.class, Employee.class));
EntityModel<Employee> resource = mapper.readValue(specBasedJson,
mapper.getTypeFactory().constructParametricType(EntityModel.class, Employee.class));
assertThat(resource.getContent()).isEqualTo(new Employee("W. Chandry", "developer"));
assertThat(resource.getLinks()).isEmpty();

View File

@@ -40,8 +40,8 @@ import org.springframework.core.io.ClassPathResource;
import org.springframework.hateoas.IanaLinkRelations;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.MediaTypes;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.Resources;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.config.EnableHypermediaSupport;
import org.springframework.hateoas.config.EnableHypermediaSupport.HypermediaType;
import org.springframework.hateoas.support.Employee;
@@ -194,10 +194,10 @@ public class CollectionJsonWebMvcIntegrationTest {
private static Map<Integer, Employee> EMPLOYEES = new HashMap<>();
@GetMapping("/employees")
public Resources<Resource<Employee>> all() {
public CollectionModel<EntityModel<Employee>> all() {
// Create a list of Resource<Employee>'s to return
List<Resource<Employee>> employees = new ArrayList<>();
List<EntityModel<Employee>> employees = new ArrayList<>();
// Fetch each Resource<Employee> using the controller's findOne method.
for (int i = 0; i < EMPLOYEES.size(); i++) {
@@ -210,19 +210,19 @@ public class CollectionJsonWebMvcIntegrationTest {
.andAffordance(afford(methodOn(EmployeeController.class).search(null, null)));
// Return the collection of employee resources along with the composite affordance
return new Resources<>(employees, selfLink);
return new CollectionModel<>(employees, selfLink);
}
@GetMapping("/employees/search")
public Resources<Resource<Employee>> search(@RequestParam(value = "name", required = false) String name,
public CollectionModel<EntityModel<Employee>> search(@RequestParam(value = "name", required = false) String name,
@RequestParam(value = "role", required = false) String role) {
// Create a list of Resource<Employee>'s to return
List<Resource<Employee>> employees = new ArrayList<>();
List<EntityModel<Employee>> employees = new ArrayList<>();
// Fetch each Resource<Employee> using the controller's findOne method.
for (int i = 0; i < EMPLOYEES.size(); i++) {
Resource<Employee> employeeResource = findOne(i);
EntityModel<Employee> employeeResource = findOne(i);
boolean nameMatches = Optional.ofNullable(name).map(s -> employeeResource.getContent().getName().contains(s))
.orElse(true);
@@ -241,11 +241,11 @@ public class CollectionJsonWebMvcIntegrationTest {
.andAffordance(afford(methodOn(EmployeeController.class).search(null, null)));
// Return the collection of employee resources along with the composite affordance
return new Resources<>(employees, selfLink);
return new CollectionModel<>(employees, selfLink);
}
@GetMapping("/employees/{id}")
public Resource<Employee> findOne(@PathVariable Integer id) {
public EntityModel<Employee> findOne(@PathVariable Integer id) {
// Start the affordance with the "self" link, i.e. this method.
Link findOneLink = linkTo(methodOn(EmployeeController.class).findOne(id)).withSelfRel();
@@ -254,14 +254,14 @@ public class CollectionJsonWebMvcIntegrationTest {
Link employeesLink = linkTo(methodOn(EmployeeController.class).all()).withRel("employees");
// Return the affordance + a link back to the entire collection resource.
return new Resource<>(EMPLOYEES.get(id),
return new EntityModel<>(EMPLOYEES.get(id),
findOneLink.andAffordance(afford(methodOn(EmployeeController.class).updateEmployee(null, id))) //
.andAffordance(afford(methodOn(EmployeeController.class).partiallyUpdateEmployee(null, id))),
employeesLink);
}
@PostMapping("/employees")
public ResponseEntity<?> newEmployee(@RequestBody Resource<Employee> employee) {
public ResponseEntity<?> newEmployee(@RequestBody EntityModel<Employee> employee) {
int newEmployeeId = EMPLOYEES.size();
@@ -279,7 +279,7 @@ public class CollectionJsonWebMvcIntegrationTest {
}
@PutMapping("/employees/{id}")
public ResponseEntity<?> updateEmployee(@RequestBody Resource<Employee> employee, @PathVariable Integer id) {
public ResponseEntity<?> updateEmployee(@RequestBody EntityModel<Employee> employee, @PathVariable Integer id) {
EMPLOYEES.put(id, employee.getContent());
@@ -296,7 +296,7 @@ public class CollectionJsonWebMvcIntegrationTest {
}
@PatchMapping("/employees/{id}")
public ResponseEntity<?> partiallyUpdateEmployee(@RequestBody Resource<Employee> employee,
public ResponseEntity<?> partiallyUpdateEmployee(@RequestBody EntityModel<Employee> employee,
@PathVariable Integer id) {
Employee oldEmployee = EMPLOYEES.get(id);

View File

@@ -29,14 +29,13 @@ import org.junit.Before;
import org.junit.Test;
import org.springframework.core.io.ClassPathResource;
import org.springframework.hateoas.AbstractJackson2MarshallingIntegrationTest;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.IanaLinkRelations;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.Links;
import org.springframework.hateoas.PagedResources;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.hateoas.Resources;
import org.springframework.hateoas.mediatype.collectionjson.Jackson2CollectionJsonModule;
import org.springframework.hateoas.PagedModel;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.hateoas.mediatype.hal.SimplePojo;
import org.springframework.hateoas.support.MappingUtils;
@@ -65,7 +64,7 @@ public class Jackson2CollectionJsonIntegrationTest extends AbstractJackson2Marsh
@Test
public void rendersSingleLinkAsObject() throws Exception {
ResourceSupport resourceSupport = new ResourceSupport();
RepresentationModel<?> resourceSupport = new RepresentationModel<>();
resourceSupport.add(new Link("localhost").withSelfRel());
assertThat(write(resourceSupport))
@@ -75,18 +74,18 @@ public class Jackson2CollectionJsonIntegrationTest extends AbstractJackson2Marsh
@Test
public void deserializeSingleLink() throws Exception {
ResourceSupport expected = new ResourceSupport();
RepresentationModel<?> expected = new RepresentationModel<>();
expected.add(new Link("localhost"));
assertThat(
read(MappingUtils.read(new ClassPathResource("resource-support.json", getClass())), ResourceSupport.class))
read(MappingUtils.read(new ClassPathResource("resource-support.json", getClass())), RepresentationModel.class))
.isEqualTo(expected);
}
@Test
public void rendersMultipleLinkAsArray() throws Exception {
ResourceSupport resourceSupport = new ResourceSupport();
RepresentationModel<?> resourceSupport = new RepresentationModel<>();
resourceSupport.add(new Link("localhost"));
resourceSupport.add(new Link("localhost2").withRel("orders"));
@@ -117,12 +116,12 @@ public class Jackson2CollectionJsonIntegrationTest extends AbstractJackson2Marsh
@Test
public void deserializeMultipleLinks() throws Exception {
ResourceSupport expected = new ResourceSupport();
RepresentationModel<?> expected = new RepresentationModel<>();
expected.add(new Link("localhost"));
expected.add(new Link("localhost2").withRel("orders"));
String read = MappingUtils.read(new ClassPathResource("resource-support-2.json", getClass()));
ResourceSupport readResourceSupport = read(read, ResourceSupport.class);
RepresentationModel<?> readResourceSupport = read(read, RepresentationModel.class);
assertThat(readResourceSupport.getLinks()).containsAll(expected.getLinks());
}
@@ -134,7 +133,7 @@ public class Jackson2CollectionJsonIntegrationTest extends AbstractJackson2Marsh
content.add("first");
content.add("second");
Resources<String> resources = new Resources<>(content);
CollectionModel<String> resources = new CollectionModel<>(content);
resources.add(new Link("localhost"));
assertThat(write(resources)).isEqualTo(MappingUtils.read(new ClassPathResource("resources.json", getClass())));
@@ -147,11 +146,12 @@ public class Jackson2CollectionJsonIntegrationTest extends AbstractJackson2Marsh
content.add("first");
content.add("second");
Resources<String> expected = new Resources<>(content);
CollectionModel<String> expected = new CollectionModel<>(content);
expected.add(new Link("localhost"));
Resources<String> result = mapper.readValue(MappingUtils.read(new ClassPathResource("resources.json", getClass())),
mapper.getTypeFactory().constructParametricType(Resources.class, String.class));
CollectionModel<String> result = mapper.readValue(
MappingUtils.read(new ClassPathResource("resources.json", getClass())),
mapper.getTypeFactory().constructParametricType(CollectionModel.class, String.class));
assertThat(result).isEqualTo(expected);
}
@@ -159,7 +159,7 @@ public class Jackson2CollectionJsonIntegrationTest extends AbstractJackson2Marsh
@Test
public void renderResource() throws Exception {
Resource<String> data = new Resource<>("first", new Link("localhost"));
EntityModel<String> data = new EntityModel<>("first", new Link("localhost"));
assertThat(write(data)).isEqualTo(MappingUtils.read(new ClassPathResource("resource.json", getClass())));
}
@@ -167,11 +167,11 @@ public class Jackson2CollectionJsonIntegrationTest extends AbstractJackson2Marsh
@Test
public void deserializeResource() throws Exception {
Resource<?> expected = new Resource<>("first", new Link("localhost"));
EntityModel<?> expected = new EntityModel<>("first", new Link("localhost"));
String source = MappingUtils.read(new ClassPathResource("resource.json", getClass()));
Resource<String> actual = mapper.readValue(source,
mapper.getTypeFactory().constructParametricType(Resource.class, String.class));
EntityModel<String> actual = mapper.readValue(source,
mapper.getTypeFactory().constructParametricType(EntityModel.class, String.class));
assertThat(actual).isEqualTo(expected);
}
@@ -179,11 +179,12 @@ public class Jackson2CollectionJsonIntegrationTest extends AbstractJackson2Marsh
@Test
public void renderComplexStructure() throws Exception {
List<Resource<String>> data = new ArrayList<>();
data.add(new Resource<>("first", new Link("localhost"), new Link("orders").withRel("orders")));
data.add(new Resource<>("second", new Link("remotehost"), new Link("order").withRel("orders")));
List<EntityModel<String>> data = new ArrayList<>();
data.add(new EntityModel<>("first", new Link("localhost"), new Link("orders").withRel("orders")));
data.add(new EntityModel<>("second", new Link("remotehost"), new Link("order").withRel("orders")));
Resources<Resource<String>> resources = new Resources<>(data);
CollectionModel<EntityModel<String>> resources = new CollectionModel<>(
data);
resources.add(new Link("localhost"));
resources.add(new Link("/page/2").withRel("next"));
@@ -194,18 +195,18 @@ public class Jackson2CollectionJsonIntegrationTest extends AbstractJackson2Marsh
@Test
public void deserializeResources() throws Exception {
List<Resource<String>> data = new ArrayList<>();
data.add(new Resource<>("first", new Link("localhost"), new Link("orders").withRel("orders")));
data.add(new Resource<>("second", new Link("remotehost"), new Link("order").withRel("orders")));
List<EntityModel<String>> data = new ArrayList<>();
data.add(new EntityModel<>("first", new Link("localhost"), new Link("orders").withRel("orders")));
data.add(new EntityModel<>("second", new Link("remotehost"), new Link("order").withRel("orders")));
Resources<?> expected = new Resources<>(data);
CollectionModel<?> expected = new CollectionModel<>(data);
expected.add(new Link("localhost"));
expected.add(new Link("/page/2").withRel("next"));
Resources<Resource<String>> actual = mapper.readValue(
CollectionModel<EntityModel<String>> actual = mapper.readValue(
MappingUtils.read(new ClassPathResource("resources-with-resource-objects.json", getClass())),
mapper.getTypeFactory().constructParametricType(Resources.class,
mapper.getTypeFactory().constructParametricType(Resource.class, String.class)));
mapper.getTypeFactory().constructParametricType(CollectionModel.class,
mapper.getTypeFactory().constructParametricType(EntityModel.class, String.class)));
assertThat(actual).isEqualTo(expected);
@@ -214,11 +215,13 @@ public class Jackson2CollectionJsonIntegrationTest extends AbstractJackson2Marsh
@Test
public void renderSimplePojos() throws Exception {
List<Resource<SimplePojo>> data = new ArrayList<>();
data.add(new Resource<>(new SimplePojo("text", 1), new Link("localhost"), new Link("orders").withRel("orders")));
data.add(new Resource<>(new SimplePojo("text2", 2), new Link("localhost")));
List<EntityModel<SimplePojo>> data = new ArrayList<>();
data.add(new EntityModel<>(new SimplePojo("text", 1), new Link("localhost"),
new Link("orders").withRel("orders")));
data.add(new EntityModel<>(new SimplePojo("text2", 2), new Link("localhost")));
Resources<Resource<SimplePojo>> resources = new Resources<>(data);
CollectionModel<EntityModel<SimplePojo>> resources = new CollectionModel<>(
data);
resources.add(new Link("localhost"));
resources.add(new Link("/page/2").withRel("next"));
@@ -236,28 +239,28 @@ public class Jackson2CollectionJsonIntegrationTest extends AbstractJackson2Marsh
@Test
public void deserializesPagedResource() throws Exception {
PagedResources<Resource<SimplePojo>> result = mapper.readValue(
PagedModel<EntityModel<SimplePojo>> result = mapper.readValue(
MappingUtils.read(new ClassPathResource("paged-resources.json", getClass())),
mapper.getTypeFactory().constructParametricType(PagedResources.class,
mapper.getTypeFactory().constructParametricType(Resource.class, SimplePojo.class)));
mapper.getTypeFactory().constructParametricType(PagedModel.class,
mapper.getTypeFactory().constructParametricType(EntityModel.class, SimplePojo.class)));
assertThat(result).isEqualTo(setupAnnotatedPagedResources());
}
private static Resources<Resource<SimplePojo>> setupAnnotatedPagedResources() {
private static CollectionModel<EntityModel<SimplePojo>> setupAnnotatedPagedResources() {
List<Resource<SimplePojo>> content = new ArrayList<>();
content.add(new Resource<>(new SimplePojo("test1", 1), new Link("localhost")));
content.add(new Resource<>(new SimplePojo("test2", 2), new Link("localhost")));
List<EntityModel<SimplePojo>> content = new ArrayList<>();
content.add(new EntityModel<>(new SimplePojo("test1", 1), new Link("localhost")));
content.add(new EntityModel<>(new SimplePojo("test2", 2), new Link("localhost")));
return new PagedResources<>(content, null, PAGINATION_LINKS);
return new PagedModel<>(content, null, PAGINATION_LINKS);
}
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
public static class ResourceWithAttributes extends ResourceSupport {
public static class ResourceWithAttributes extends RepresentationModel<ResourceWithAttributes> {
private String attribute;
}

View File

@@ -32,21 +32,17 @@ import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.context.support.StaticMessageSource;
import org.springframework.hateoas.AbstractJackson2MarshallingIntegrationTest;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.IanaLinkRelations;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.Links;
import org.springframework.hateoas.PagedResources;
import org.springframework.hateoas.PagedResources.PageMetadata;
import org.springframework.hateoas.mediatype.hal.CurieProvider;
import org.springframework.hateoas.mediatype.hal.DefaultCurieProvider;
import org.springframework.hateoas.mediatype.hal.HalConfiguration;
import org.springframework.hateoas.mediatype.hal.Jackson2HalModule;
import org.springframework.hateoas.PagedModel;
import org.springframework.hateoas.PagedModel.PageMetadata;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.hateoas.UriTemplate;
import org.springframework.hateoas.mediatype.hal.HalConfiguration.RenderSingleLinks;
import org.springframework.hateoas.mediatype.hal.Jackson2HalModule.HalHandlerInstantiator;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.hateoas.Resources;
import org.springframework.hateoas.UriTemplate;
import org.springframework.hateoas.server.core.AnnotationRelProvider;
import org.springframework.hateoas.server.core.EmbeddedWrappers;
@@ -103,7 +99,7 @@ public class Jackson2HalIntegrationTest extends AbstractJackson2MarshallingInteg
@Test
public void rendersSingleLinkAsObject() throws Exception {
ResourceSupport resourceSupport = new ResourceSupport();
RepresentationModel<?> resourceSupport = new RepresentationModel<>();
resourceSupport.add(new Link("localhost"));
assertThat(write(resourceSupport)).isEqualTo(SINGLE_LINK_REFERENCE);
@@ -115,7 +111,7 @@ public class Jackson2HalIntegrationTest extends AbstractJackson2MarshallingInteg
@Test
public void rendersAllExtraRFC5988Attributes() throws Exception {
ResourceSupport resourceSupport = new ResourceSupport();
RepresentationModel<?> resourceSupport = new RepresentationModel<>();
resourceSupport.add(new Link("localhost", "self") //
.withHreflang("en") //
.withTitle("the title") //
@@ -134,20 +130,20 @@ public class Jackson2HalIntegrationTest extends AbstractJackson2MarshallingInteg
@Test
public void deserializeAllExtraRFC5988Attributes() throws Exception {
ResourceSupport expected = new ResourceSupport();
RepresentationModel<?> expected = new RepresentationModel<>();
expected.add(new Link("localhost", "self") //
.withHreflang("en") //
.withTitle("the title") //
.withType("the type") //
.withDeprecation("/customers/deprecated"));
assertThat(read(SINGLE_WITH_ALL_EXTRA_ATTRIBUTES, ResourceSupport.class)).isEqualTo(expected);
assertThat(read(SINGLE_WITH_ALL_EXTRA_ATTRIBUTES, RepresentationModel.class)).isEqualTo(expected);
}
@Test
public void rendersWithOneExtraRFC5988Attribute() throws Exception {
ResourceSupport resourceSupport = new ResourceSupport();
RepresentationModel<?> resourceSupport = new RepresentationModel<>();
resourceSupport.add(new Link("localhost", "self").withTitle("the title"));
assertThat(write(resourceSupport)).isEqualTo(SINGLE_WITH_ONE_EXTRA_ATTRIBUTES);
@@ -159,17 +155,17 @@ public class Jackson2HalIntegrationTest extends AbstractJackson2MarshallingInteg
@Test
public void deserializeOneExtraRFC5988Attribute() throws Exception {
ResourceSupport expected = new ResourceSupport();
RepresentationModel<?> expected = new RepresentationModel<>();
expected.add(new Link("localhost", "self").withTitle("the title"));
assertThat(read(SINGLE_WITH_ONE_EXTRA_ATTRIBUTES, ResourceSupport.class)).isEqualTo(expected);
assertThat(read(SINGLE_WITH_ONE_EXTRA_ATTRIBUTES, RepresentationModel.class)).isEqualTo(expected);
}
@Test
public void deserializeSingleLink() throws Exception {
ResourceSupport expected = new ResourceSupport();
RepresentationModel<?> expected = new RepresentationModel<>();
expected.add(new Link("localhost"));
assertThat(read(SINGLE_LINK_REFERENCE, ResourceSupport.class)).isEqualTo(expected);
assertThat(read(SINGLE_LINK_REFERENCE, RepresentationModel.class)).isEqualTo(expected);
}
/**
@@ -178,7 +174,7 @@ public class Jackson2HalIntegrationTest extends AbstractJackson2MarshallingInteg
@Test
public void rendersMultipleLinkAsArray() throws Exception {
ResourceSupport resourceSupport = new ResourceSupport();
RepresentationModel<?> resourceSupport = new RepresentationModel<>();
resourceSupport.add(new Link("localhost"));
resourceSupport.add(new Link("localhost2"));
@@ -188,11 +184,11 @@ public class Jackson2HalIntegrationTest extends AbstractJackson2MarshallingInteg
@Test
public void deserializeMultipleLinks() throws Exception {
ResourceSupport expected = new ResourceSupport();
RepresentationModel<?> expected = new RepresentationModel<>();
expected.add(new Link("localhost"));
expected.add(new Link("localhost2"));
assertThat(read(LIST_LINK_REFERENCE, ResourceSupport.class)).isEqualTo(expected);
assertThat(read(LIST_LINK_REFERENCE, RepresentationModel.class)).isEqualTo(expected);
}
@Test
@@ -202,7 +198,7 @@ public class Jackson2HalIntegrationTest extends AbstractJackson2MarshallingInteg
content.add("first");
content.add("second");
Resources<String> resources = new Resources<>(content);
CollectionModel<String> resources = new CollectionModel<>(content);
resources.add(new Link("localhost"));
assertThat(write(resources)).isEqualTo(SIMPLE_EMBEDDED_RESOURCE_REFERENCE);
@@ -215,11 +211,11 @@ public class Jackson2HalIntegrationTest extends AbstractJackson2MarshallingInteg
content.add("first");
content.add("second");
Resources<String> expected = new Resources<>(content);
CollectionModel<String> expected = new CollectionModel<>(content);
expected.add(new Link("localhost"));
Resources<String> result = mapper.readValue(SIMPLE_EMBEDDED_RESOURCE_REFERENCE,
mapper.getTypeFactory().constructParametricType(Resources.class, String.class));
CollectionModel<String> result = mapper.readValue(SIMPLE_EMBEDDED_RESOURCE_REFERENCE,
mapper.getTypeFactory().constructParametricType(CollectionModel.class, String.class));
assertThat(result).isEqualTo(expected);
@@ -228,10 +224,11 @@ public class Jackson2HalIntegrationTest extends AbstractJackson2MarshallingInteg
@Test
public void rendersSingleResourceResourcesAsEmbedded() throws Exception {
List<Resource<SimplePojo>> content = new ArrayList<>();
content.add(new Resource<>(new SimplePojo("test1", 1), new Link("localhost")));
List<EntityModel<SimplePojo>> content = new ArrayList<>();
content.add(new EntityModel<>(new SimplePojo("test1", 1), new Link("localhost")));
Resources<Resource<SimplePojo>> resources = new Resources<>(content);
CollectionModel<EntityModel<SimplePojo>> resources = new CollectionModel<>(
content);
resources.add(new Link("localhost"));
assertThat(write(resources)).isEqualTo(SINGLE_EMBEDDED_RESOURCE_REFERENCE);
@@ -240,15 +237,17 @@ public class Jackson2HalIntegrationTest extends AbstractJackson2MarshallingInteg
@Test
public void deserializesSingleResourceResourcesAsEmbedded() throws Exception {
List<Resource<SimplePojo>> content = new ArrayList<>();
content.add(new Resource<>(new SimplePojo("test1", 1), new Link("localhost")));
List<EntityModel<SimplePojo>> content = new ArrayList<>();
content.add(new EntityModel<>(new SimplePojo("test1", 1), new Link("localhost")));
Resources<Resource<SimplePojo>> expected = new Resources<>(content);
CollectionModel<EntityModel<SimplePojo>> expected = new CollectionModel<>(
content);
expected.add(new Link("localhost"));
Resources<Resource<SimplePojo>> result = mapper.readValue(SINGLE_EMBEDDED_RESOURCE_REFERENCE,
mapper.getTypeFactory().constructParametricType(Resources.class,
mapper.getTypeFactory().constructParametricType(Resource.class, SimplePojo.class)));
CollectionModel<EntityModel<SimplePojo>> result = mapper.readValue(
SINGLE_EMBEDDED_RESOURCE_REFERENCE,
mapper.getTypeFactory().constructParametricType(CollectionModel.class,
mapper.getTypeFactory().constructParametricType(EntityModel.class, SimplePojo.class)));
assertThat(result).isEqualTo(expected);
@@ -257,7 +256,7 @@ public class Jackson2HalIntegrationTest extends AbstractJackson2MarshallingInteg
@Test
public void rendersMultipleResourceResourcesAsEmbedded() throws Exception {
Resources<Resource<SimplePojo>> resources = setupResources();
CollectionModel<EntityModel<SimplePojo>> resources = setupResources();
resources.add(new Link("localhost"));
assertThat(write(resources)).isEqualTo(LIST_EMBEDDED_RESOURCE_REFERENCE);
@@ -266,12 +265,13 @@ public class Jackson2HalIntegrationTest extends AbstractJackson2MarshallingInteg
@Test
public void deserializesMultipleResourceResourcesAsEmbedded() throws Exception {
Resources<Resource<SimplePojo>> expected = setupResources();
CollectionModel<EntityModel<SimplePojo>> expected = setupResources();
expected.add(new Link("localhost"));
Resources<Resource<SimplePojo>> result = mapper.readValue(LIST_EMBEDDED_RESOURCE_REFERENCE,
mapper.getTypeFactory().constructParametricType(Resources.class,
mapper.getTypeFactory().constructParametricType(Resource.class, SimplePojo.class)));
CollectionModel<EntityModel<SimplePojo>> result = mapper.readValue(
LIST_EMBEDDED_RESOURCE_REFERENCE,
mapper.getTypeFactory().constructParametricType(CollectionModel.class,
mapper.getTypeFactory().constructParametricType(EntityModel.class, SimplePojo.class)));
assertThat(result).isEqualTo(expected);
}
@@ -282,10 +282,11 @@ public class Jackson2HalIntegrationTest extends AbstractJackson2MarshallingInteg
@Test
public void serializesAnnotatedResourceResourcesAsEmbedded() throws Exception {
List<Resource<SimpleAnnotatedPojo>> content = new ArrayList<>();
content.add(new Resource<>(new SimpleAnnotatedPojo("test1", 1), new Link("localhost")));
List<EntityModel<SimpleAnnotatedPojo>> content = new ArrayList<>();
content.add(new EntityModel<>(new SimpleAnnotatedPojo("test1", 1), new Link("localhost")));
Resources<Resource<SimpleAnnotatedPojo>> resources = new Resources<>(content);
CollectionModel<EntityModel<SimpleAnnotatedPojo>> resources = new CollectionModel<>(
content);
resources.add(new Link("localhost"));
assertThat(write(resources)).isEqualTo(ANNOTATED_EMBEDDED_RESOURCE_REFERENCE);
@@ -297,15 +298,17 @@ public class Jackson2HalIntegrationTest extends AbstractJackson2MarshallingInteg
@Test
public void deserializesAnnotatedResourceResourcesAsEmbedded() throws Exception {
List<Resource<SimpleAnnotatedPojo>> content = new ArrayList<>();
content.add(new Resource<>(new SimpleAnnotatedPojo("test1", 1), new Link("localhost")));
List<EntityModel<SimpleAnnotatedPojo>> content = new ArrayList<>();
content.add(new EntityModel<>(new SimpleAnnotatedPojo("test1", 1), new Link("localhost")));
Resources<Resource<SimpleAnnotatedPojo>> expected = new Resources<>(content);
CollectionModel<EntityModel<SimpleAnnotatedPojo>> expected = new CollectionModel<>(
content);
expected.add(new Link("localhost"));
Resources<Resource<SimpleAnnotatedPojo>> result = mapper.readValue(ANNOTATED_EMBEDDED_RESOURCE_REFERENCE,
mapper.getTypeFactory().constructParametricType(Resources.class,
mapper.getTypeFactory().constructParametricType(Resource.class, SimpleAnnotatedPojo.class)));
CollectionModel<EntityModel<SimpleAnnotatedPojo>> result = mapper.readValue(
ANNOTATED_EMBEDDED_RESOURCE_REFERENCE,
mapper.getTypeFactory().constructParametricType(CollectionModel.class, mapper.getTypeFactory()
.constructParametricType(EntityModel.class, SimpleAnnotatedPojo.class)));
assertThat(result).isEqualTo(expected);
}
@@ -324,9 +327,10 @@ public class Jackson2HalIntegrationTest extends AbstractJackson2MarshallingInteg
@Test
public void deserializesMultipleAnnotatedResourceResourcesAsEmbedded() throws Exception {
Resources<Resource<SimpleAnnotatedPojo>> result = mapper.readValue(ANNOTATED_EMBEDDED_RESOURCES_REFERENCE,
mapper.getTypeFactory().constructParametricType(Resources.class,
mapper.getTypeFactory().constructParametricType(Resource.class, SimpleAnnotatedPojo.class)));
CollectionModel<EntityModel<SimpleAnnotatedPojo>> result = mapper.readValue(
ANNOTATED_EMBEDDED_RESOURCES_REFERENCE,
mapper.getTypeFactory().constructParametricType(CollectionModel.class, mapper.getTypeFactory()
.constructParametricType(EntityModel.class, SimpleAnnotatedPojo.class)));
assertThat(result).isEqualTo(setupAnnotatedResources());
}
@@ -344,9 +348,10 @@ public class Jackson2HalIntegrationTest extends AbstractJackson2MarshallingInteg
*/
@Test
public void deserializesPagedResource() throws Exception {
PagedResources<Resource<SimpleAnnotatedPojo>> result = mapper.readValue(ANNOTATED_PAGED_RESOURCES,
mapper.getTypeFactory().constructParametricType(PagedResources.class,
mapper.getTypeFactory().constructParametricType(Resource.class, SimpleAnnotatedPojo.class)));
PagedModel<EntityModel<SimpleAnnotatedPojo>> result = mapper.readValue(
ANNOTATED_PAGED_RESOURCES,
mapper.getTypeFactory().constructParametricType(PagedModel.class, mapper.getTypeFactory()
.constructParametricType(EntityModel.class, SimpleAnnotatedPojo.class)));
assertThat(result).isEqualTo(setupAnnotatedPagedResources());
}
@@ -357,7 +362,8 @@ public class Jackson2HalIntegrationTest extends AbstractJackson2MarshallingInteg
@Test
public void rendersCuriesCorrectly() throws Exception {
Resources<Object> resources = new Resources<>(Collections.emptySet(), new Link("foo"), new Link("bar", "myrel"));
CollectionModel<Object> resources = new CollectionModel<>(Collections.emptySet(),
new Link("foo"), new Link("bar", "myrel"));
assertThat(getCuriedObjectMapper().writeValueAsString(resources)).isEqualTo(CURIED_DOCUMENT);
}
@@ -368,7 +374,7 @@ public class Jackson2HalIntegrationTest extends AbstractJackson2MarshallingInteg
@Test
public void doesNotRenderCuriesIfNoLinkIsPresent() throws Exception {
Resources<Object> resources = new Resources<>(Collections.emptySet());
CollectionModel<Object> resources = new CollectionModel<>(Collections.emptySet());
assertThat(getCuriedObjectMapper().writeValueAsString(resources)).isEqualTo(EMPTY_DOCUMENT);
}
@@ -378,7 +384,7 @@ public class Jackson2HalIntegrationTest extends AbstractJackson2MarshallingInteg
@Test
public void doesNotRenderCuriesIfNoCurieLinkIsPresent() throws Exception {
Resources<Object> resources = new Resources<>(Collections.emptySet());
CollectionModel<Object> resources = new CollectionModel<>(Collections.emptySet());
resources.add(new Link("foo"));
assertThat(getCuriedObjectMapper().writeValueAsString(resources)).isEqualTo(SINGLE_NON_CURIE_LINK);
@@ -390,7 +396,7 @@ public class Jackson2HalIntegrationTest extends AbstractJackson2MarshallingInteg
@Test
public void rendersTemplate() throws Exception {
ResourceSupport support = new ResourceSupport();
RepresentationModel<?> support = new RepresentationModel<>();
support.add(new Link("/foo{?bar}", "search"));
assertThat(write(support)).isEqualTo(LINK_TEMPLATE);
@@ -402,7 +408,7 @@ public class Jackson2HalIntegrationTest extends AbstractJackson2MarshallingInteg
@Test
public void rendersMultipleCuries() throws Exception {
Resources<Object> resources = new Resources<>(Collections.emptySet());
CollectionModel<Object> resources = new CollectionModel<>(Collections.emptySet());
resources.add(new Link("foo", "myrel"));
CurieProvider provider = new DefaultCurieProvider("default", new UriTemplate("/doc{?rel}")) {
@@ -426,7 +432,7 @@ public class Jackson2HalIntegrationTest extends AbstractJackson2MarshallingInteg
List<Object> values = new ArrayList<>();
values.add(wrappers.emptyCollectionOf(SimpleAnnotatedPojo.class));
Resources<Object> resources = new Resources<>(values);
CollectionModel<Object> resources = new CollectionModel<>(values);
assertThat(write(resources)).isEqualTo("{\"_embedded\":{\"pojos\":[]}}");
}
@@ -453,7 +459,7 @@ public class Jackson2HalIntegrationTest extends AbstractJackson2MarshallingInteg
mapper.setHandlerInstantiator(new HalHandlerInstantiator(new AnnotationRelProvider(), null, null,
new HalConfiguration().withRenderSingleLinks(RenderSingleLinks.AS_ARRAY)));
ResourceSupport resourceSupport = new ResourceSupport();
RepresentationModel<?> resourceSupport = new RepresentationModel<>();
resourceSupport.add(new Link("localhost").withSelfRel());
assertThat(write(resourceSupport)).isEqualTo("{\"_links\":{\"self\":[{\"href\":\"localhost\"}]}}");
@@ -465,7 +471,7 @@ public class Jackson2HalIntegrationTest extends AbstractJackson2MarshallingInteg
@Test
public void handleTemplatedLinksOnDeserialization() throws IOException {
ResourceSupport original = new ResourceSupport();
RepresentationModel<?> original = new RepresentationModel<>();
original.add(new Link("/orders{?id}", "order"));
String serialized = mapper.writeValueAsString(original);
@@ -474,7 +480,7 @@ public class Jackson2HalIntegrationTest extends AbstractJackson2MarshallingInteg
assertThat(serialized).isEqualTo(expected);
ResourceSupport deserialized = mapper.readValue(serialized, ResourceSupport.class);
RepresentationModel<?> deserialized = mapper.readValue(serialized, RepresentationModel.class);
assertThat(deserialized).isEqualTo(original);
}
@@ -485,7 +491,7 @@ public class Jackson2HalIntegrationTest extends AbstractJackson2MarshallingInteg
mapper.setHandlerInstantiator(new HalHandlerInstantiator(new AnnotationRelProvider(), null, null,
new HalConfiguration().withRenderSingleLinksFor("foo", RenderSingleLinks.AS_ARRAY)));
ResourceSupport resource = new ResourceSupport();
RepresentationModel<?> resource = new RepresentationModel<>();
resource.add(new Link("/some-href", "foo"));
assertThat(mapper.writeValueAsString(resource)) //
@@ -501,37 +507,37 @@ public class Jackson2HalIntegrationTest extends AbstractJackson2MarshallingInteg
ObjectMapper objectMapper = getCuriedObjectMapper(null, messageSource);
ResourceSupport resource = new ResourceSupport();
RepresentationModel<?> resource = new RepresentationModel<>();
resource.add(new Link("target", "ns:foobar"));
assertThat(objectMapper.writeValueAsString(resource)).isEqualTo(LINK_WITH_TITLE);
}
private static Resources<Resource<SimpleAnnotatedPojo>> setupAnnotatedPagedResources() {
private static CollectionModel<EntityModel<SimpleAnnotatedPojo>> setupAnnotatedPagedResources() {
List<Resource<SimpleAnnotatedPojo>> content = new ArrayList<>();
content.add(new Resource<>(new SimpleAnnotatedPojo("test1", 1), new Link("localhost")));
content.add(new Resource<>(new SimpleAnnotatedPojo("test2", 2), new Link("localhost")));
List<EntityModel<SimpleAnnotatedPojo>> content = new ArrayList<>();
content.add(new EntityModel<>(new SimpleAnnotatedPojo("test1", 1), new Link("localhost")));
content.add(new EntityModel<>(new SimpleAnnotatedPojo("test2", 2), new Link("localhost")));
return new PagedResources<>(content, new PageMetadata(2, 0, 4), PAGINATION_LINKS);
return new PagedModel<>(content, new PageMetadata(2, 0, 4), PAGINATION_LINKS);
}
private static Resources<Resource<SimpleAnnotatedPojo>> setupAnnotatedResources() {
private static CollectionModel<EntityModel<SimpleAnnotatedPojo>> setupAnnotatedResources() {
List<Resource<SimpleAnnotatedPojo>> content = new ArrayList<>();
content.add(new Resource<>(new SimpleAnnotatedPojo("test1", 1), new Link("localhost")));
content.add(new Resource<>(new SimpleAnnotatedPojo("test2", 2), new Link("localhost")));
List<EntityModel<SimpleAnnotatedPojo>> content = new ArrayList<>();
content.add(new EntityModel<>(new SimpleAnnotatedPojo("test1", 1), new Link("localhost")));
content.add(new EntityModel<>(new SimpleAnnotatedPojo("test2", 2), new Link("localhost")));
return new Resources<>(content);
return new CollectionModel<>(content);
}
private static Resources<Resource<SimplePojo>> setupResources() {
private static CollectionModel<EntityModel<SimplePojo>> setupResources() {
List<Resource<SimplePojo>> content = new ArrayList<>();
content.add(new Resource<>(new SimplePojo("test1", 1), new Link("localhost")));
content.add(new Resource<>(new SimplePojo("test2", 2), new Link("localhost")));
List<EntityModel<SimplePojo>> content = new ArrayList<>();
content.add(new EntityModel<>(new SimplePojo("test1", 1), new Link("localhost")));
content.add(new EntityModel<>(new SimplePojo("test2", 2), new Link("localhost")));
return new Resources<>(content);
return new CollectionModel<>(content);
}
private static ObjectMapper getCuriedObjectMapper() {

View File

@@ -34,8 +34,8 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.MediaTypes;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.Resources;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.config.EnableHypermediaSupport;
import org.springframework.hateoas.config.EnableHypermediaSupport.HypermediaType;
import org.springframework.http.HttpHeaders;
@@ -105,10 +105,10 @@ public class RenderHypermediaForDefaultAcceptHeadersTest {
}
@GetMapping("/employees")
public Resources<Resource<Employee>> all() {
public CollectionModel<EntityModel<Employee>> all() {
// Create a list of Resource<Employee>'s to return
List<Resource<Employee>> employees = new ArrayList<>();
List<EntityModel<Employee>> employees = new ArrayList<>();
// Fetch each Resource<Employee> using the controller's findOne method.
for (int i = 0; i < EMPLOYEES.size(); i++) {
@@ -119,11 +119,11 @@ public class RenderHypermediaForDefaultAcceptHeadersTest {
Link selfLink = linkTo(methodOn(EmployeeController.class).all()).withSelfRel();
// Return the collection of employee resources along with the composite affordance
return new Resources<>(employees, selfLink);
return new CollectionModel<>(employees, selfLink);
}
@GetMapping("/employees/{id}")
public Resource<Employee> findOne(@PathVariable Integer id) {
public EntityModel<Employee> findOne(@PathVariable Integer id) {
// Start the affordance with the "self" link, i.e. this method.
Link findOneLink = linkTo(methodOn(EmployeeController.class).findOne(id)).withSelfRel();
@@ -132,7 +132,7 @@ public class RenderHypermediaForDefaultAcceptHeadersTest {
Link employeesLink = linkTo(methodOn(EmployeeController.class).all()).withRel("employees");
// Return the affordance + a link back to the entire collection resource.
return new Resource<>(EMPLOYEES.get(id), findOneLink, employeesLink);
return new EntityModel<>(EMPLOYEES.get(id), findOneLink, employeesLink);
}
}

View File

@@ -31,7 +31,7 @@ import org.junit.Test;
import org.springframework.core.io.ClassPathResource;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.MediaTypes;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.hateoas.mediatype.hal.forms.HalFormsDocument;
import org.springframework.hateoas.mediatype.hal.forms.HalFormsProperty;
import org.springframework.hateoas.mediatype.hal.forms.HalFormsTemplate;
@@ -61,7 +61,7 @@ public class HalFormsMessageConverterUnitTest {
this.mapper.registerModule(new Jackson2HalFormsModule());
TypeConstrainedMappingJackson2HttpMessageConverter converter = new TypeConstrainedMappingJackson2HttpMessageConverter(
ResourceSupport.class);
RepresentationModel.class);
converter.setObjectMapper(mapper);
this.messageConverter = converter;

View File

@@ -38,8 +38,8 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.hateoas.IanaLinkRelations;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.MediaTypes;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.Resources;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.config.EnableHypermediaSupport;
import org.springframework.hateoas.config.EnableHypermediaSupport.HypermediaType;
import org.springframework.hateoas.support.Employee;
@@ -115,10 +115,10 @@ public class HalFormsValidationIntegrationTest {
}
@GetMapping("/employees")
public Resources<Resource<Employee>> all() {
public CollectionModel<EntityModel<Employee>> all() {
// Create a list of Resource<Employee>'s to return
List<Resource<Employee>> employees = new ArrayList<>();
List<EntityModel<Employee>> employees = new ArrayList<>();
// Fetch each Resource<Employee> using the controller's findOne method.
for (int i = 0; i < EMPLOYEES.size(); i++) {
@@ -130,11 +130,11 @@ public class HalFormsValidationIntegrationTest {
.andAffordance(afford(methodOn(BadController.class).updateEmployee(null, 0)));
// Return the collection of employee resources along with the composite affordance
return new Resources<>(employees, selfLink);
return new CollectionModel<>(employees, selfLink);
}
@GetMapping("/employees/{id}")
public Resource<Employee> findOne(@PathVariable Integer id) {
public EntityModel<Employee> findOne(@PathVariable Integer id) {
// Start the affordance with the "self" link, i.e. this method.
Link findOneLink = linkTo(methodOn(BadController.class).findOne(id)).withSelfRel();
@@ -144,7 +144,7 @@ public class HalFormsValidationIntegrationTest {
.andAffordance(afford(methodOn(BadController.class).newEmployee(null)));
// Return the affordance + a link back to the entire collection resource.
return new Resource<>(EMPLOYEES.get(id), findOneLink.andAffordances(employeesLink.getAffordances()),
return new EntityModel<>(EMPLOYEES.get(id), findOneLink.andAffordances(employeesLink.getAffordances()),
employeesLink);
}

View File

@@ -33,20 +33,18 @@ import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.context.support.StaticMessageSource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.hateoas.AbstractJackson2MarshallingIntegrationTest;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.IanaLinkRelations;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.Links;
import org.springframework.hateoas.PagedResources;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.hateoas.Resources;
import org.springframework.hateoas.PagedModel;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.hateoas.UriTemplate;
import org.springframework.hateoas.mediatype.hal.CurieProvider;
import org.springframework.hateoas.mediatype.hal.DefaultCurieProvider;
import org.springframework.hateoas.mediatype.hal.SimpleAnnotatedPojo;
import org.springframework.hateoas.mediatype.hal.SimplePojo;
import org.springframework.hateoas.mediatype.hal.forms.HalFormsConfiguration;
import org.springframework.hateoas.mediatype.hal.forms.Jackson2HalFormsModule;
import org.springframework.hateoas.mediatype.hal.forms.Jackson2HalFormsModule.HalFormsHandlerInstantiator;
import org.springframework.hateoas.server.core.AnnotationRelProvider;
import org.springframework.hateoas.server.core.EmbeddedWrappers;
@@ -78,7 +76,7 @@ public class Jackson2HalFormsIntegrationTest extends AbstractJackson2Marshalling
@Test
public void rendersSingleLinkAsObject() throws Exception {
ResourceSupport resourceSupport = new ResourceSupport();
RepresentationModel<?> resourceSupport = new RepresentationModel<>();
resourceSupport.add(new Link("localhost"));
assertThat(write(resourceSupport))
@@ -88,18 +86,17 @@ public class Jackson2HalFormsIntegrationTest extends AbstractJackson2Marshalling
@Test
public void deserializeSingleLink() throws Exception {
ResourceSupport expected = new ResourceSupport();
RepresentationModel<?> expected = new RepresentationModel<>();
expected.add(new Link("localhost"));
assertThat(
read(MappingUtils.read(new ClassPathResource("single-link-reference.json", getClass())), ResourceSupport.class))
.isEqualTo(expected);
assertThat(read(MappingUtils.read(new ClassPathResource("single-link-reference.json", getClass())),
RepresentationModel.class)).isEqualTo(expected);
}
@Test
public void rendersMultipleLinkAsArray() throws Exception {
ResourceSupport resourceSupport = new ResourceSupport();
RepresentationModel<?> resourceSupport = new RepresentationModel<>();
resourceSupport.add(new Link("localhost"));
resourceSupport.add(new Link("localhost2"));
@@ -110,19 +107,19 @@ public class Jackson2HalFormsIntegrationTest extends AbstractJackson2Marshalling
@Test
public void deserializeMultipleLinks() throws Exception {
ResourceSupport expected = new ResourceSupport();
RepresentationModel<?> expected = new RepresentationModel<>();
expected.add(new Link("localhost"));
expected.add(new Link("localhost2"));
assertThat(
read(MappingUtils.read(new ClassPathResource("list-link-reference.json", getClass())), ResourceSupport.class))
.isEqualTo(expected);
assertThat(read(MappingUtils.read(new ClassPathResource("list-link-reference.json", getClass())),
RepresentationModel.class)).isEqualTo(expected);
}
@Test
public void rendersResource() throws Exception {
Resource<SimplePojo> resource = new Resource<>(new SimplePojo("test1", 1), new Link("localhost"));
EntityModel<SimplePojo> resource = new EntityModel<>(new SimplePojo("test1", 1),
new Link("localhost"));
assertThat(write(resource))
.isEqualTo(MappingUtils.read(new ClassPathResource("simple-resource-unwrapped.json", getClass())));
@@ -131,11 +128,12 @@ public class Jackson2HalFormsIntegrationTest extends AbstractJackson2Marshalling
@Test
public void deserializesResource() throws IOException {
Resource<SimplePojo> expected = new Resource<>(new SimplePojo("test1", 1), new Link("localhost"));
EntityModel<SimplePojo> expected = new EntityModel<>(new SimplePojo("test1", 1),
new Link("localhost"));
Resource<SimplePojo> result = mapper.readValue(
EntityModel<SimplePojo> result = mapper.readValue(
MappingUtils.read(new ClassPathResource("simple-resource-unwrapped.json", getClass())),
mapper.getTypeFactory().constructParametricType(Resource.class, SimplePojo.class));
mapper.getTypeFactory().constructParametricType(EntityModel.class, SimplePojo.class));
assertThat(result).isEqualTo(expected);
}
@@ -147,7 +145,7 @@ public class Jackson2HalFormsIntegrationTest extends AbstractJackson2Marshalling
content.add("first");
content.add("second");
Resources<String> resources = new Resources<>(content);
CollectionModel<String> resources = new CollectionModel<>(content);
resources.add(new Link("localhost"));
assertThat(write(resources))
@@ -161,12 +159,12 @@ public class Jackson2HalFormsIntegrationTest extends AbstractJackson2Marshalling
content.add("first");
content.add("second");
Resources<String> expected = new Resources<>(content);
CollectionModel<String> expected = new CollectionModel<>(content);
expected.add(new Link("localhost"));
Resources<String> result = mapper.readValue(
CollectionModel<String> result = mapper.readValue(
MappingUtils.read(new ClassPathResource("simple-embedded-resource-reference.json", getClass())),
mapper.getTypeFactory().constructParametricType(Resources.class, String.class));
mapper.getTypeFactory().constructParametricType(CollectionModel.class, String.class));
assertThat(result).isEqualTo(expected);
@@ -175,10 +173,11 @@ public class Jackson2HalFormsIntegrationTest extends AbstractJackson2Marshalling
@Test
public void rendersSingleResourceResourcesAsEmbedded() throws Exception {
List<Resource<SimplePojo>> content = new ArrayList<>();
content.add(new Resource<>(new SimplePojo("test1", 1), new Link("localhost")));
List<EntityModel<SimplePojo>> content = new ArrayList<>();
content.add(new EntityModel<>(new SimplePojo("test1", 1), new Link("localhost")));
Resources<Resource<SimplePojo>> resources = new Resources<>(content);
CollectionModel<EntityModel<SimplePojo>> resources = new CollectionModel<>(
content);
resources.add(new Link("localhost"));
assertThat(write(resources))
@@ -188,16 +187,17 @@ public class Jackson2HalFormsIntegrationTest extends AbstractJackson2Marshalling
@Test
public void deserializesSingleResourceResourcesAsEmbedded() throws Exception {
List<Resource<SimplePojo>> content = new ArrayList<>();
content.add(new Resource<>(new SimplePojo("test1", 1), new Link("localhost")));
List<EntityModel<SimplePojo>> content = new ArrayList<>();
content.add(new EntityModel<>(new SimplePojo("test1", 1), new Link("localhost")));
Resources<Resource<SimplePojo>> expected = new Resources<>(content);
CollectionModel<EntityModel<SimplePojo>> expected = new CollectionModel<>(
content);
expected.add(new Link("localhost"));
Resources<Resource<SimplePojo>> result = mapper.readValue(
CollectionModel<EntityModel<SimplePojo>> result = mapper.readValue(
MappingUtils.read(new ClassPathResource("single-embedded-resource-reference.json", getClass())),
mapper.getTypeFactory().constructParametricType(Resources.class,
mapper.getTypeFactory().constructParametricType(Resource.class, SimplePojo.class)));
mapper.getTypeFactory().constructParametricType(CollectionModel.class,
mapper.getTypeFactory().constructParametricType(EntityModel.class, SimplePojo.class)));
assertThat(result).isEqualTo(expected);
}
@@ -205,7 +205,7 @@ public class Jackson2HalFormsIntegrationTest extends AbstractJackson2Marshalling
@Test
public void rendersMultipleResourceResourcesAsEmbedded() throws Exception {
Resources<Resource<SimplePojo>> resources = setupResources();
CollectionModel<EntityModel<SimplePojo>> resources = setupResources();
resources.add(new Link("localhost"));
assertThat(write(resources))
@@ -215,13 +215,13 @@ public class Jackson2HalFormsIntegrationTest extends AbstractJackson2Marshalling
@Test
public void deserializesMultipleResourceResourcesAsEmbedded() throws Exception {
Resources<Resource<SimplePojo>> expected = setupResources();
CollectionModel<EntityModel<SimplePojo>> expected = setupResources();
expected.add(new Link("localhost"));
Resources<Resource<SimplePojo>> result = mapper.readValue(
CollectionModel<EntityModel<SimplePojo>> result = mapper.readValue(
MappingUtils.read(new ClassPathResource("multiple-resource-resources.json", getClass())),
mapper.getTypeFactory().constructParametricType(Resources.class,
mapper.getTypeFactory().constructParametricType(Resource.class, SimplePojo.class)));
mapper.getTypeFactory().constructParametricType(CollectionModel.class,
mapper.getTypeFactory().constructParametricType(EntityModel.class, SimplePojo.class)));
assertThat(result).isEqualTo(expected);
}
@@ -229,10 +229,11 @@ public class Jackson2HalFormsIntegrationTest extends AbstractJackson2Marshalling
@Test
public void serializesAnnotatedResourceResourcesAsEmbedded() throws Exception {
List<Resource<SimpleAnnotatedPojo>> content = new ArrayList<>();
content.add(new Resource<>(new SimpleAnnotatedPojo("test1", 1), new Link("localhost")));
List<EntityModel<SimpleAnnotatedPojo>> content = new ArrayList<>();
content.add(new EntityModel<>(new SimpleAnnotatedPojo("test1", 1), new Link("localhost")));
Resources<Resource<SimpleAnnotatedPojo>> resources = new Resources<>(content);
CollectionModel<EntityModel<SimpleAnnotatedPojo>> resources = new CollectionModel<>(
content);
resources.add(new Link("localhost"));
assertThat(write(resources))
@@ -242,16 +243,17 @@ public class Jackson2HalFormsIntegrationTest extends AbstractJackson2Marshalling
@Test
public void deserializesAnnotatedResourceResourcesAsEmbedded() throws Exception {
List<Resource<SimpleAnnotatedPojo>> content = new ArrayList<>();
content.add(new Resource<>(new SimpleAnnotatedPojo("test1", 1), new Link("localhost")));
List<EntityModel<SimpleAnnotatedPojo>> content = new ArrayList<>();
content.add(new EntityModel<>(new SimpleAnnotatedPojo("test1", 1), new Link("localhost")));
Resources<Resource<SimpleAnnotatedPojo>> expected = new Resources<>(content);
CollectionModel<EntityModel<SimpleAnnotatedPojo>> expected = new CollectionModel<>(
content);
expected.add(new Link("localhost"));
Resources<Resource<SimpleAnnotatedPojo>> result = mapper.readValue(
CollectionModel<EntityModel<SimpleAnnotatedPojo>> result = mapper.readValue(
MappingUtils.read(new ClassPathResource("annotated-resource-resources.json", getClass())),
mapper.getTypeFactory().constructParametricType(Resources.class,
mapper.getTypeFactory().constructParametricType(Resource.class, SimpleAnnotatedPojo.class)));
mapper.getTypeFactory().constructParametricType(CollectionModel.class, mapper.getTypeFactory()
.constructParametricType(EntityModel.class, SimpleAnnotatedPojo.class)));
assertThat(result).isEqualTo(expected);
}
@@ -265,10 +267,10 @@ public class Jackson2HalFormsIntegrationTest extends AbstractJackson2Marshalling
@Test
public void deserializesMultipleAnnotatedResourceResourcesAsEmbedded() throws Exception {
Resources<Resource<SimpleAnnotatedPojo>> result = mapper.readValue(
CollectionModel<EntityModel<SimpleAnnotatedPojo>> result = mapper.readValue(
MappingUtils.read(new ClassPathResource("annotated-embedded-resources-reference.json", getClass())),
mapper.getTypeFactory().constructParametricType(Resources.class,
mapper.getTypeFactory().constructParametricType(Resource.class, SimpleAnnotatedPojo.class)));
mapper.getTypeFactory().constructParametricType(CollectionModel.class, mapper.getTypeFactory()
.constructParametricType(EntityModel.class, SimpleAnnotatedPojo.class)));
assertThat(result).isEqualTo(setupAnnotatedResources());
}
@@ -281,10 +283,10 @@ public class Jackson2HalFormsIntegrationTest extends AbstractJackson2Marshalling
@Test
public void deserializesPagedResource() throws Exception {
PagedResources<Resource<SimpleAnnotatedPojo>> result = mapper.readValue(
PagedModel<EntityModel<SimpleAnnotatedPojo>> result = mapper.readValue(
MappingUtils.read(new ClassPathResource("annotated-paged-resources.json", getClass())),
mapper.getTypeFactory().constructParametricType(PagedResources.class,
mapper.getTypeFactory().constructParametricType(Resource.class, SimpleAnnotatedPojo.class)));
mapper.getTypeFactory().constructParametricType(PagedModel.class, mapper.getTypeFactory()
.constructParametricType(EntityModel.class, SimpleAnnotatedPojo.class)));
assertThat(result).isEqualTo(setupAnnotatedPagedResources());
}
@@ -292,7 +294,8 @@ public class Jackson2HalFormsIntegrationTest extends AbstractJackson2Marshalling
@Test
public void rendersCuriesCorrectly() throws Exception {
Resources<Object> resources = new Resources<>(Collections.emptySet(), new Link("foo"), new Link("bar", "myrel"));
CollectionModel<Object> resources = new CollectionModel<>(Collections.emptySet(),
new Link("foo"), new Link("bar", "myrel"));
assertThat(getCuriedObjectMapper().writeValueAsString(resources))
.isEqualTo(MappingUtils.read(new ClassPathResource("curied-document.json", getClass())));
@@ -301,7 +304,7 @@ public class Jackson2HalFormsIntegrationTest extends AbstractJackson2Marshalling
@Test
public void doesNotRenderCuriesIfNoLinkIsPresent() throws Exception {
Resources<Object> resources = new Resources<>(Collections.emptySet());
CollectionModel<Object> resources = new CollectionModel<>(Collections.emptySet());
assertThat(getCuriedObjectMapper().writeValueAsString(resources))
.isEqualTo(MappingUtils.read(new ClassPathResource("empty-document.json", getClass())));
}
@@ -309,7 +312,7 @@ public class Jackson2HalFormsIntegrationTest extends AbstractJackson2Marshalling
@Test
public void doesNotRenderCuriesIfNoCurieLinkIsPresent() throws Exception {
Resources<Object> resources = new Resources<>(Collections.emptySet());
CollectionModel<Object> resources = new CollectionModel<>(Collections.emptySet());
resources.add(new Link("foo"));
assertThat(getCuriedObjectMapper().writeValueAsString(resources))
@@ -319,7 +322,7 @@ public class Jackson2HalFormsIntegrationTest extends AbstractJackson2Marshalling
@Test
public void rendersTemplate() throws Exception {
ResourceSupport support = new ResourceSupport();
RepresentationModel<?> support = new RepresentationModel<>();
support.add(new Link("/foo{?bar}", "search"));
assertThat(write(support)).isEqualTo(MappingUtils.read(new ClassPathResource("link-template.json", getClass())));
@@ -328,7 +331,7 @@ public class Jackson2HalFormsIntegrationTest extends AbstractJackson2Marshalling
@Test
public void rendersMultipleCuries() throws Exception {
Resources<Object> resources = new Resources<>(Collections.emptySet());
CollectionModel<Object> resources = new CollectionModel<>(Collections.emptySet());
resources.add(new Link("foo", "myrel"));
CurieProvider provider = new DefaultCurieProvider("default", new UriTemplate("/doc{?rel}")) {
@@ -350,7 +353,7 @@ public class Jackson2HalFormsIntegrationTest extends AbstractJackson2Marshalling
List<Object> values = new ArrayList<>();
values.add(wrappers.emptyCollectionOf(SimpleAnnotatedPojo.class));
Resources<Object> resources = new Resources<>(values);
CollectionModel<Object> resources = new CollectionModel<>(values);
assertThat(write(resources))
.isEqualTo(MappingUtils.read(new ClassPathResource("empty-embedded-pojos.json", getClass())));
@@ -372,7 +375,7 @@ public class Jackson2HalFormsIntegrationTest extends AbstractJackson2Marshalling
@Test
public void handleTemplatedLinksOnDeserialization() throws IOException {
ResourceSupport original = new ResourceSupport();
RepresentationModel<?> original = new RepresentationModel<>();
original.add(new Link("/orders{?id}", "order"));
String serialized = mapper.writeValueAsString(original);
@@ -381,7 +384,7 @@ public class Jackson2HalFormsIntegrationTest extends AbstractJackson2Marshalling
assertThat(serialized).isEqualTo(expected);
ResourceSupport deserialized = mapper.readValue(serialized, ResourceSupport.class);
RepresentationModel<?> deserialized = mapper.readValue(serialized, RepresentationModel.class);
assertThat(deserialized).isEqualTo(original);
}
@@ -395,38 +398,39 @@ public class Jackson2HalFormsIntegrationTest extends AbstractJackson2Marshalling
ObjectMapper objectMapper = getCuriedObjectMapper(null, messageSource);
ResourceSupport resource = new ResourceSupport();
RepresentationModel<?> resource = new RepresentationModel<>();
resource.add(new Link("target", "ns:foobar"));
assertThat(objectMapper.writeValueAsString(resource))
.isEqualTo(MappingUtils.read(new ClassPathResource("link-with-title.json", getClass())));
}
private static Resources<Resource<SimplePojo>> setupResources() {
private static CollectionModel<EntityModel<SimplePojo>> setupResources() {
List<Resource<SimplePojo>> content = new ArrayList<>();
content.add(new Resource<>(new SimplePojo("test1", 1), new Link("localhost")));
content.add(new Resource<>(new SimplePojo("test2", 2), new Link("localhost")));
List<EntityModel<SimplePojo>> content = new ArrayList<>();
content.add(new EntityModel<>(new SimplePojo("test1", 1), new Link("localhost")));
content.add(new EntityModel<>(new SimplePojo("test2", 2), new Link("localhost")));
return new Resources<>(content);
return new CollectionModel<>(content);
}
private static Resources<Resource<SimpleAnnotatedPojo>> setupAnnotatedResources() {
private static CollectionModel<EntityModel<SimpleAnnotatedPojo>> setupAnnotatedResources() {
List<Resource<SimpleAnnotatedPojo>> content = new ArrayList<>();
content.add(new Resource<>(new SimpleAnnotatedPojo("test1", 1), new Link("localhost")));
content.add(new Resource<>(new SimpleAnnotatedPojo("test2", 2), new Link("localhost")));
List<EntityModel<SimpleAnnotatedPojo>> content = new ArrayList<>();
content.add(new EntityModel<>(new SimpleAnnotatedPojo("test1", 1), new Link("localhost")));
content.add(new EntityModel<>(new SimpleAnnotatedPojo("test2", 2), new Link("localhost")));
return new Resources<>(content);
return new CollectionModel<>(content);
}
private static Resources<Resource<SimpleAnnotatedPojo>> setupAnnotatedPagedResources() {
private static CollectionModel<EntityModel<SimpleAnnotatedPojo>> setupAnnotatedPagedResources() {
List<Resource<SimpleAnnotatedPojo>> content = new ArrayList<>();
content.add(new Resource<>(new SimpleAnnotatedPojo("test1", 1), new Link("localhost")));
content.add(new Resource<>(new SimpleAnnotatedPojo("test2", 2), new Link("localhost")));
List<EntityModel<SimpleAnnotatedPojo>> content = new ArrayList<>();
content.add(new EntityModel<>(new SimpleAnnotatedPojo("test1", 1), new Link("localhost")));
content.add(new EntityModel<>(new SimpleAnnotatedPojo("test2", 2), new Link("localhost")));
return new PagedResources<>(content, new PagedResources.PageMetadata(2, 0, 4), PAGINATION_LINKS);
return new PagedModel<>(content, new PagedModel.PageMetadata(2, 0, 4),
PAGINATION_LINKS);
}
private static ObjectMapper getCuriedObjectMapper() {

View File

@@ -31,14 +31,13 @@ import org.junit.Before;
import org.junit.Test;
import org.springframework.core.io.ClassPathResource;
import org.springframework.hateoas.AbstractJackson2MarshallingIntegrationTest;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.IanaLinkRelations;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.Links;
import org.springframework.hateoas.PagedResources;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.hateoas.Resources;
import org.springframework.hateoas.mediatype.uber.Jackson2UberModule;
import org.springframework.hateoas.PagedModel;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.hateoas.support.MappingUtils;
import com.fasterxml.jackson.databind.JavaType;
@@ -69,7 +68,7 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte
@Test
public void rendersSingleLinkAsObject() throws Exception {
ResourceSupport resourceSupport = new ResourceSupport();
RepresentationModel<?> resourceSupport = new RepresentationModel<>();
resourceSupport.add(new Link("localhost").withSelfRel());
assertThat(write(resourceSupport))
@@ -82,11 +81,11 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte
@Test
public void deserializeSingleLink() throws Exception {
ResourceSupport expected = new ResourceSupport();
RepresentationModel<?> expected = new RepresentationModel<>();
expected.add(new Link("localhost"));
assertThat(
read(MappingUtils.read(new ClassPathResource("resource-support.json", getClass())), ResourceSupport.class))
read(MappingUtils.read(new ClassPathResource("resource-support.json", getClass())), RepresentationModel.class))
.isEqualTo(expected);
}
@@ -96,7 +95,7 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte
@Test
public void rendersMultipleLinkAsArray() throws Exception {
ResourceSupport resourceSupport = new ResourceSupport();
RepresentationModel<?> resourceSupport = new RepresentationModel<>();
resourceSupport.add(new Link("localhost"));
resourceSupport.add(new Link("localhost2").withRel("orders"));
@@ -110,13 +109,12 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte
@Test
public void deserializeMultipleLinks() throws Exception {
ResourceSupport expected = new ResourceSupport();
RepresentationModel<?> expected = new RepresentationModel<>();
expected.add(new Link("localhost"));
expected.add(new Link("localhost2").withRel("orders"));
assertThat(
read(MappingUtils.read(new ClassPathResource("resource-support-2.json", getClass())), ResourceSupport.class))
.isEqualTo(expected);
assertThat(read(MappingUtils.read(new ClassPathResource("resource-support-2.json", getClass())),
RepresentationModel.class)).isEqualTo(expected);
}
/**
@@ -129,7 +127,7 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte
content.add("first");
content.add("second");
Resources<String> resources = new Resources<>(content);
CollectionModel<String> resources = new CollectionModel<>(content);
resources.add(new Link("localhost"));
assertThat(write(resources)).isEqualTo(MappingUtils.read(new ClassPathResource("resources.json", getClass())));
@@ -145,12 +143,13 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte
content.add("first");
content.add("second");
Resources<String> expected = new Resources<>(content);
CollectionModel<String> expected = new CollectionModel<>(content);
expected.add(new Link("localhost"));
String resourcesJson = MappingUtils.read(new ClassPathResource("resources.json", getClass()));
JavaType resourcesType = mapper.getTypeFactory().constructParametricType(Resources.class, String.class);
Resources<String> result = mapper.readValue(resourcesJson, resourcesType);
JavaType resourcesType = mapper.getTypeFactory().constructParametricType(CollectionModel.class,
String.class);
CollectionModel<String> result = mapper.readValue(resourcesJson, resourcesType);
assertThat(result).isEqualTo(expected);
}
@@ -161,19 +160,21 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte
@Test
public void deserializeComplexResourcesSimply() throws IOException {
List<Resource<String>> content = new ArrayList<>();
content.add(new Resource<>("first"));
content.add(new Resource<>("second"));
List<EntityModel<String>> content = new ArrayList<>();
content.add(new EntityModel<>("first"));
content.add(new EntityModel<>("second"));
Resources<Resource<String>> expected = new Resources<>(content);
CollectionModel<EntityModel<String>> expected = new CollectionModel<>(
content);
expected.add(new Link("localhost"));
String resourcesJson = MappingUtils.read(new ClassPathResource("resources.json", getClass()));
JavaType resourcesType = mapper.getTypeFactory().constructParametricType(Resources.class,
mapper.getTypeFactory().constructParametricType(Resource.class, String.class));
JavaType resourcesType = mapper.getTypeFactory().constructParametricType(CollectionModel.class,
mapper.getTypeFactory().constructParametricType(EntityModel.class, String.class));
Resources<Resource<String>> result = mapper.readValue(resourcesJson, resourcesType);
CollectionModel<EntityModel<String>> result = mapper.readValue(resourcesJson,
resourcesType);
assertThat(result).isEqualTo(expected);
}
@@ -184,7 +185,7 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte
@Test
public void renderSimpleResource() throws Exception {
Resource<String> data = new Resource<>("first", new Link("localhost"));
EntityModel<String> data = new EntityModel<>("first", new Link("localhost"));
assertThat(write(data)).isEqualTo(MappingUtils.read(new ClassPathResource("resource.json", getClass())));
}
@@ -195,7 +196,8 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte
@Test
public void renderResourceWithCustomRel() throws Exception {
Resource<String> data2 = new Resource<>("second", new Link("localhost").withRel("custom"));
EntityModel<String> data2 = new EntityModel<>("second",
new Link("localhost").withRel("custom"));
assertThat(write(data2)).isEqualTo(MappingUtils.read(new ClassPathResource("resource2.json", getClass())));
}
@@ -206,8 +208,8 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte
@Test
public void renderResourceWithMultipleLinks() throws Exception {
Resource<String> data3 = new Resource<>("third", new Link("localhost"), new Link("second").withRel("second"),
new Link("third").withRel("third"));
EntityModel<String> data3 = new EntityModel<>("third", new Link("localhost"),
new Link("second").withRel("second"), new Link("third").withRel("third"));
assertThat(write(data3)).isEqualTo(MappingUtils.read(new ClassPathResource("resource3.json", getClass())));
}
@@ -218,7 +220,7 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte
@Test
public void renderResourceWithMultipleRels() throws Exception {
Resource<String> data4 = new Resource<>("third", new Link("localhost"),
EntityModel<String> data4 = new EntityModel<>("third", new Link("localhost"),
new Link("localhost").withRel("http://example.org/rels/todo"), new Link("second").withRel("second"),
new Link("third").withRel("third"));
@@ -231,32 +233,34 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte
@Test
public void deserializeResource() throws IOException {
JavaType resourceStringType = mapper.getTypeFactory().constructParametricType(Resource.class, String.class);
JavaType resourceStringType = mapper.getTypeFactory().constructParametricType(EntityModel.class,
String.class);
Resource<?> expected = new Resource<>("first", new Link("localhost"));
Resource<String> actual = mapper.readValue(MappingUtils.read(new ClassPathResource("resource.json", getClass())),
resourceStringType);
EntityModel<?> expected = new EntityModel<>("first", new Link("localhost"));
EntityModel<String> actual = mapper
.readValue(MappingUtils.read(new ClassPathResource("resource.json", getClass())), resourceStringType);
assertThat(actual).isEqualTo(expected);
Resource<String> expected2 = new Resource<>("second", new Link("localhost").withRel("custom"));
Resource<String> actual2 = mapper.readValue(MappingUtils.read(new ClassPathResource("resource2.json", getClass())),
resourceStringType);
EntityModel<String> expected2 = new EntityModel<>("second",
new Link("localhost").withRel("custom"));
EntityModel<String> actual2 = mapper
.readValue(MappingUtils.read(new ClassPathResource("resource2.json", getClass())), resourceStringType);
assertThat(actual2).isEqualTo(expected2);
Resource<String> expected3 = new Resource<>("third", new Link("localhost"), new Link("second").withRel("second"),
new Link("third").withRel("third"));
Resource<String> actual3 = mapper.readValue(MappingUtils.read(new ClassPathResource("resource3.json", getClass())),
resourceStringType);
EntityModel<String> expected3 = new EntityModel<>("third", new Link("localhost"),
new Link("second").withRel("second"), new Link("third").withRel("third"));
EntityModel<String> actual3 = mapper
.readValue(MappingUtils.read(new ClassPathResource("resource3.json", getClass())), resourceStringType);
assertThat(actual3).isEqualTo(expected3);
Resource<String> expected4 = new Resource<>("third", new Link("localhost"),
EntityModel<String> expected4 = new EntityModel<>("third", new Link("localhost"),
new Link("localhost").withRel("http://example.org/rels/todo"), new Link("second").withRel("second"),
new Link("third").withRel("third"));
Resource<String> actual4 = mapper.readValue(MappingUtils.read(new ClassPathResource("resource4.json", getClass())),
resourceStringType);
EntityModel<String> actual4 = mapper
.readValue(MappingUtils.read(new ClassPathResource("resource4.json", getClass())), resourceStringType);
assertThat(actual4).isEqualTo(expected4);
}
@@ -267,11 +271,12 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte
@Test
public void renderComplexStructure() throws Exception {
List<Resource<String>> data = new ArrayList<>();
data.add(new Resource<>("first", new Link("localhost"), new Link("orders").withRel("orders")));
data.add(new Resource<>("second", new Link("remotehost"), new Link("order").withRel("orders")));
List<EntityModel<String>> data = new ArrayList<>();
data.add(new EntityModel<>("first", new Link("localhost"), new Link("orders").withRel("orders")));
data.add(new EntityModel<>("second", new Link("remotehost"), new Link("order").withRel("orders")));
Resources<Resource<String>> resources = new Resources<>(data);
CollectionModel<EntityModel<String>> resources = new CollectionModel<>(
data);
resources.add(new Link("localhost"));
resources.add(new Link("/page/2").withRel("next"));
@@ -285,18 +290,18 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte
@Test
public void deserializeResources() throws Exception {
List<Resource<String>> data = new ArrayList<>();
data.add(new Resource<>("first", new Link("localhost"), new Link("orders").withRel("orders")));
data.add(new Resource<>("second", new Link("remotehost"), new Link("order").withRel("orders")));
List<EntityModel<String>> data = new ArrayList<>();
data.add(new EntityModel<>("first", new Link("localhost"), new Link("orders").withRel("orders")));
data.add(new EntityModel<>("second", new Link("remotehost"), new Link("order").withRel("orders")));
Resources<?> expected = new Resources<>(data);
CollectionModel<?> expected = new CollectionModel<>(data);
expected.add(new Link("localhost"));
expected.add(new Link("/page/2").withRel("next"));
Resources<Resource<String>> actual = mapper.readValue(
CollectionModel<EntityModel<String>> actual = mapper.readValue(
MappingUtils.read(new ClassPathResource("resources-with-resource-objects.json", getClass())),
mapper.getTypeFactory().constructParametricType(Resources.class,
mapper.getTypeFactory().constructParametricType(Resource.class, String.class)));
mapper.getTypeFactory().constructParametricType(CollectionModel.class,
mapper.getTypeFactory().constructParametricType(EntityModel.class, String.class)));
assertThat(actual).isEqualTo(expected);
}
@@ -307,18 +312,18 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte
@Test
public void deserializeEmptyValue() throws Exception {
List<Resource<String>> data = new ArrayList<>();
data.add(new Resource<>("", new Link("localhost"), new Link("orders").withRel("orders")));
data.add(new Resource<>("second", new Link("remotehost"), new Link("order").withRel("orders")));
List<EntityModel<String>> data = new ArrayList<>();
data.add(new EntityModel<>("", new Link("localhost"), new Link("orders").withRel("orders")));
data.add(new EntityModel<>("second", new Link("remotehost"), new Link("order").withRel("orders")));
Resources<?> expected = new Resources<>(data);
CollectionModel<?> expected = new CollectionModel<>(data);
expected.add(new Link("localhost"));
expected.add(new Link("/page/2").withRel("next"));
Resources<Resource<String>> actual = mapper.readValue(
CollectionModel<EntityModel<String>> actual = mapper.readValue(
MappingUtils.read(new ClassPathResource("resources-with-resource-objects-and-empty-value.json", getClass())),
mapper.getTypeFactory().constructParametricType(Resources.class,
mapper.getTypeFactory().constructParametricType(Resource.class, String.class)));
mapper.getTypeFactory().constructParametricType(CollectionModel.class,
mapper.getTypeFactory().constructParametricType(EntityModel.class, String.class)));
assertThat(actual).isEqualTo(expected);
}
@@ -329,11 +334,11 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte
@Test
public void serializeEmptyResources() throws Exception {
List<Resource<String>> data = new ArrayList<>();
data.add(new Resource<>("first", new Link("localhost"), new Link("orders").withRel("orders")));
data.add(new Resource<>("second", new Link("remotehost"), new Link("order").withRel("orders")));
List<EntityModel<String>> data = new ArrayList<>();
data.add(new EntityModel<>("first", new Link("localhost"), new Link("orders").withRel("orders")));
data.add(new EntityModel<>("second", new Link("remotehost"), new Link("order").withRel("orders")));
Resources<?> source = new Resources<>(data);
CollectionModel<?> source = new CollectionModel<>(data);
source.add(new Link("localhost"));
source.add(new Link("/page/2").withRel("next"));
@@ -347,11 +352,11 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte
@Test
public void deserializeEmptyResources() {
List<Resource<String>> data = new ArrayList<>();
data.add(new Resource<>("first", new Link("localhost"), new Link("orders").withRel("orders")));
data.add(new Resource<>("second", new Link("remotehost"), new Link("order").withRel("orders")));
List<EntityModel<String>> data = new ArrayList<>();
data.add(new EntityModel<>("first", new Link("localhost"), new Link("orders").withRel("orders")));
data.add(new EntityModel<>("second", new Link("remotehost"), new Link("order").withRel("orders")));
Resources<?> expected = new Resources<>(data);
CollectionModel<?> expected = new CollectionModel<>(data);
expected.add(new Link("localhost"));
expected.add(new Link("/page/2").withRel("next"));
@@ -359,8 +364,8 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte
MappingUtils.read(new ClassPathResource("resources-with-empty-resource-objects.json", getClass())), //
mapper.getTypeFactory() //
.constructParametricType( //
Resources.class, //
mapper.getTypeFactory().constructParametricType(Resource.class, String.class) //
CollectionModel.class, //
mapper.getTypeFactory().constructParametricType(EntityModel.class, String.class) //
) //
)).isInstanceOf(RuntimeException.class);
}
@@ -375,13 +380,13 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte
data.add("first");
data.add("second");
Resources<?> expected = new Resources<>(data);
CollectionModel<?> expected = new CollectionModel<>(data);
expected.add(new Link("localhost"));
expected.add(new Link("/page/2").withRel("next"));
Resources<String> actual = mapper.readValue(
CollectionModel<String> actual = mapper.readValue(
MappingUtils.read(new ClassPathResource("resources-with-resource-objects.json", getClass())),
mapper.getTypeFactory().constructParametricType(Resources.class, String.class));
mapper.getTypeFactory().constructParametricType(CollectionModel.class, String.class));
assertThat(actual).isEqualTo(expected);
}
@@ -393,7 +398,8 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte
public void serializeWrappedSimplePojo() throws Exception {
Employee employee = new Employee("Frodo", "ring bearer");
Resource<Employee> expected = new Resource<>(employee, new Link("/employees/1").withSelfRel());
EntityModel<Employee> expected = new EntityModel<>(employee,
new Link("/employees/1").withSelfRel());
String actual = MappingUtils.read(new ClassPathResource("resource-with-simple-pojo.json", getClass()));
@@ -407,11 +413,12 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte
public void deserializeWrappedSimplePojo() throws IOException {
Employee employee = new Employee("Frodo", "ring bearer");
Resource<Employee> expected = new Resource<>(employee, new Link("/employees/1").withSelfRel());
EntityModel<Employee> expected = new EntityModel<>(employee,
new Link("/employees/1").withSelfRel());
Resource<Employee> actual = mapper.readValue(
EntityModel<Employee> actual = mapper.readValue(
MappingUtils.read(new ClassPathResource("resource-with-simple-pojo.json", getClass())),
mapper.getTypeFactory().constructParametricType(Resource.class, Employee.class));
mapper.getTypeFactory().constructParametricType(EntityModel.class, Employee.class));
assertThat(actual).isEqualTo(expected);
}
@@ -423,11 +430,12 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte
public void deserializeWrappedEmptyPojo() throws IOException {
Employee employee = new Employee();
Resource<Employee> expected = new Resource<>(employee, new Link("/employees/1").withSelfRel());
EntityModel<Employee> expected = new EntityModel<>(employee,
new Link("/employees/1").withSelfRel());
Resource<Employee> actual = mapper.readValue(
EntityModel<Employee> actual = mapper.readValue(
MappingUtils.read(new ClassPathResource("resource-with-empty-pojo.json", getClass())),
mapper.getTypeFactory().constructParametricType(Resource.class, Employee.class));
mapper.getTypeFactory().constructParametricType(EntityModel.class, Employee.class));
assertThat(actual).isEqualTo(expected);
}
@@ -496,10 +504,10 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte
@Test
public void deserializesPagedResource() throws Exception {
PagedResources<Resource<Employee>> result = mapper.readValue(
PagedModel<EntityModel<Employee>> result = mapper.readValue(
MappingUtils.read(new ClassPathResource("paged-resources.json", getClass())),
mapper.getTypeFactory().constructParametricType(PagedResources.class,
mapper.getTypeFactory().constructParametricType(Resource.class, Employee.class)));
mapper.getTypeFactory().constructParametricType(PagedModel.class,
mapper.getTypeFactory().constructParametricType(EntityModel.class, Employee.class)));
assertThat(result).isEqualTo(setupAnnotatedPagedResources());
}
@@ -510,10 +518,10 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte
@Test
public void deserializesPagedResourceWithEmptyPageInformation() throws Exception {
PagedResources<Resource<Employee>> result = mapper.readValue(
PagedModel<EntityModel<Employee>> result = mapper.readValue(
MappingUtils.read(new ClassPathResource("paged-resources-empty-page.json", getClass())),
mapper.getTypeFactory().constructParametricType(PagedResources.class,
mapper.getTypeFactory().constructParametricType(Resource.class, Employee.class)));
mapper.getTypeFactory().constructParametricType(PagedModel.class,
mapper.getTypeFactory().constructParametricType(EntityModel.class, Employee.class)));
assertThat(result).isEqualTo(setupAnnotatedPagedResources(0, 0));
}
@@ -524,7 +532,7 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte
@Test
public void handleTemplatedLinksOnDeserialization() throws IOException {
ResourceSupport original = new ResourceSupport();
RepresentationModel<?> original = new RepresentationModel<>();
original.add(new Link("/orders{?id}", "order"));
String serialized = mapper.writeValueAsString(original);
@@ -533,25 +541,28 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte
assertThat(serialized).isEqualTo(expected);
ResourceSupport deserialized = mapper.readValue(serialized, ResourceSupport.class);
RepresentationModel<?> deserialized = mapper.readValue(serialized, RepresentationModel.class);
assertThat(deserialized).isEqualTo(original);
}
private static Resources<Resource<Employee>> setupAnnotatedPagedResources() {
private static CollectionModel<EntityModel<Employee>> setupAnnotatedPagedResources() {
return setupAnnotatedPagedResources(2, 4);
}
@NotNull
private static Resources<Resource<Employee>> setupAnnotatedPagedResources(int size, int totalElements) {
private static CollectionModel<EntityModel<Employee>> setupAnnotatedPagedResources(
int size, int totalElements) {
List<Resource<Employee>> content = new ArrayList<>();
List<EntityModel<Employee>> content = new ArrayList<>();
Employee employee = new Employee("Frodo", "ring bearer");
Resource<Employee> employeeResource = new Resource<>(employee, new Link("/employees/1").withSelfRel());
EntityModel<Employee> employeeResource = new EntityModel<>(employee,
new Link("/employees/1").withSelfRel());
content.add(employeeResource);
return new PagedResources<>(content, new PagedResources.PageMetadata(size, 0, totalElements), PAGINATION_LINKS);
return new PagedModel<>(content, new PagedModel.PageMetadata(size, 0, totalElements),
PAGINATION_LINKS);
}
@Data
@@ -567,7 +578,7 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
static class EmployeeResource extends ResourceSupport {
static class EmployeeResource extends RepresentationModel<EmployeeResource> {
private String name;
private String role;

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.hateoas;
package org.springframework.hateoas.mediatype.vnderror;
import static org.assertj.core.api.Assertions.*;
@@ -26,6 +26,7 @@ import java.nio.charset.Charset;
import org.junit.Before;
import org.junit.Test;
import org.springframework.core.io.ClassPathResource;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.mediatype.hal.Jackson2HalModule;
import org.springframework.hateoas.mediatype.vnderrors.VndErrors;
import org.springframework.hateoas.mediatype.vnderrors.VndErrors.VndError;

View File

@@ -13,11 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.hateoas;
package org.springframework.hateoas.mediatype.vnderror;
import static org.assertj.core.api.Assertions.*;
import org.junit.Test;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.mediatype.vnderrors.VndErrors;
import org.springframework.hateoas.mediatype.vnderrors.VndErrors.VndError;

View File

@@ -21,7 +21,7 @@ import java.util.List;
import org.junit.Test;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.server.core.HeaderLinksResponseEntity;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpStatus;
@@ -37,13 +37,13 @@ public class HeaderLinksResponseEntityUnitTest {
static final Object CONTENT = new Object();
static final Link LINK = new Link("href", "rel");
Resource<Object> resource = new Resource<>(CONTENT, LINK);
ResponseEntity<Resource<Object>> entity = new ResponseEntity<>(resource, HttpStatus.OK);
EntityModel<Object> resource = new EntityModel<>(CONTENT, LINK);
ResponseEntity<EntityModel<Object>> entity = new ResponseEntity<>(resource, HttpStatus.OK);
@Test
public void movesRootResourceLinksToHeader() {
HttpEntity<Resource<Object>> wrapper = HeaderLinksResponseEntity.wrap(entity);
HttpEntity<EntityModel<Object>> wrapper = HeaderLinksResponseEntity.wrap(entity);
// No links in resource anymore
assertThat(wrapper.getBody().getLinks()).isEmpty();
@@ -59,8 +59,8 @@ public class HeaderLinksResponseEntityUnitTest {
@Test
public void defaultStatusCodeToOkForHttpEntities() {
HttpEntity<Resource<Object>> entity = new HttpEntity<>(resource);
ResponseEntity<Resource<Object>> wrappedEntity = HeaderLinksResponseEntity.wrap(entity);
HttpEntity<EntityModel<Object>> entity = new HttpEntity<>(resource);
ResponseEntity<EntityModel<Object>> wrappedEntity = HeaderLinksResponseEntity.wrap(entity);
assertThat(wrappedEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
}

View File

@@ -24,18 +24,17 @@ import java.util.Optional;
import org.junit.Before;
import org.junit.Test;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.IanaLinkRelations;
import org.springframework.hateoas.Identifiable;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.hateoas.Resources;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.hateoas.TestUtils;
import org.springframework.hateoas.server.LinkBuilder;
import org.springframework.hateoas.server.mvc.IdentifiableResourceAssemblerSupport;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* Unit tests for {@link IdentifiableResourceAssemblerSupport}.
* Unit tests for {@link IdentifiableRepresentationModelAssemblerSupport}.
*
* @author Oliver Gierke
* @author Greg Turnquist
@@ -57,7 +56,7 @@ public class IdentifiableResourceAssemblerSupportUnitTest extends TestUtils {
@Test
public void createsInstanceWithSelfLinkToController() {
PersonResource resource = assembler.createResource(person);
PersonResource resource = assembler.createModel(person);
Link link = resource.getRequiredLink(IanaLinkRelations.SELF.value());
assertThat(link).isNotNull();
@@ -67,7 +66,7 @@ public class IdentifiableResourceAssemblerSupportUnitTest extends TestUtils {
@Test
public void usesAlternateIdIfGivenExplicitly() {
PersonResource resource = assembler.createResourceWithId(person.alternateId, person);
PersonResource resource = assembler.createModelWithId(person.alternateId, person);
Optional<Link> selfLink = resource.getId();
assertThat(selfLink.map(Link::getHref)) //
@@ -77,7 +76,7 @@ public class IdentifiableResourceAssemblerSupportUnitTest extends TestUtils {
@Test
public void unwrapsIdentifyablesForParameters() {
PersonResource resource = new PersonResourceAssembler(ParameterizedController.class).createResource(person, person,
PersonResource resource = new PersonResourceAssembler(ParameterizedController.class).createModel(person, person,
"bar");
Optional<Link> selfLink = resource.getId();
@@ -121,7 +120,7 @@ public class IdentifiableResourceAssemblerSupportUnitTest extends TestUtils {
Person second = new Person();
second.id = 2L;
Resources<PersonResource> result = assembler.map(Arrays.asList(first, second)).toResources();
CollectionModel<PersonResource> result = assembler.map(Arrays.asList(first, second)).toResources();
LinkBuilder builder = linkTo(PersonController.class);
@@ -156,11 +155,11 @@ public class IdentifiableResourceAssemblerSupportUnitTest extends TestUtils {
}
}
static class PersonResource extends ResourceSupport {
static class PersonResource extends RepresentationModel<PersonResource> {
}
class PersonResourceAssembler extends IdentifiableResourceAssemblerSupport<Person, PersonResource> {
class PersonResourceAssembler extends IdentifiableRepresentationModelAssemblerSupport<Person, PersonResource> {
PersonResourceAssembler() {
this(PersonController.class);
@@ -171,8 +170,8 @@ public class IdentifiableResourceAssemblerSupportUnitTest extends TestUtils {
}
@Override
public PersonResource toResource(Person entity) {
return createResource(entity);
public PersonResource toModel(Person entity) {
return createModel(entity);
}
}
}

View File

@@ -40,8 +40,8 @@ import org.springframework.core.io.ClassPathResource;
import org.springframework.hateoas.IanaLinkRelations;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.MediaTypes;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.Resources;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.config.EnableHypermediaSupport;
import org.springframework.hateoas.config.EnableHypermediaSupport.HypermediaType;
import org.springframework.hateoas.mediatype.collectionjson.CollectionJsonLinkDiscoverer;
@@ -434,10 +434,10 @@ public class MultiMediaTypeWebMvcIntegrationTest {
static class EmployeeController {
@GetMapping("/employees")
public Resources<Resource<Employee>> all() {
public CollectionModel<EntityModel<Employee>> all() {
// Create a list of Resource<Employee>'s to return
List<Resource<Employee>> employees = new ArrayList<>();
List<EntityModel<Employee>> employees = new ArrayList<>();
// Fetch each Resource<Employee> using the controller's findOne method.
for (int i = 0; i < EMPLOYEES.size(); i++) {
@@ -450,19 +450,19 @@ public class MultiMediaTypeWebMvcIntegrationTest {
.andAffordance(afford(methodOn(EmployeeController.class).search(null, null)));
// Return the collection of employee resources along with the composite affordance
return new Resources<>(employees, selfLink);
return new CollectionModel<>(employees, selfLink);
}
@GetMapping("/employees/search")
public Resources<Resource<Employee>> search(@RequestParam(value = "name", required = false) String name,
public CollectionModel<EntityModel<Employee>> search(@RequestParam(value = "name", required = false) String name,
@RequestParam(value = "role", required = false) String role) {
// Create a list of Resource<Employee>'s to return
List<Resource<Employee>> employees = new ArrayList<>();
List<EntityModel<Employee>> employees = new ArrayList<>();
// Fetch each Resource<Employee> using the controller's findOne method.
for (int i = 0; i < EMPLOYEES.size(); i++) {
Resource<Employee> employeeResource = findOne(i);
EntityModel<Employee> employeeResource = findOne(i);
boolean nameMatches = Optional.ofNullable(name).map(s -> employeeResource.getContent().getName().contains(s))
.orElse(true);
@@ -481,11 +481,11 @@ public class MultiMediaTypeWebMvcIntegrationTest {
.andAffordance(afford(methodOn(EmployeeController.class).search(null, null)));
// Return the collection of employee resources along with the composite affordance
return new Resources<>(employees, selfLink);
return new CollectionModel<>(employees, selfLink);
}
@GetMapping("/employees/{id}")
public Resource<Employee> findOne(@PathVariable Integer id) {
public EntityModel<Employee> findOne(@PathVariable Integer id) {
// Start the affordance with the "self" link, i.e. this method.
Link findOneLink = linkTo(methodOn(EmployeeController.class).findOne(id)).withSelfRel();
@@ -494,14 +494,14 @@ public class MultiMediaTypeWebMvcIntegrationTest {
Link employeesLink = linkTo(methodOn(EmployeeController.class).all()).withRel("employees");
// Return the affordance + a link back to the entire collection resource.
return new Resource<>(EMPLOYEES.get(id),
return new EntityModel<>(EMPLOYEES.get(id),
findOneLink.andAffordance(afford(methodOn(EmployeeController.class).updateEmployee(null, id))) //
.andAffordance(afford(methodOn(EmployeeController.class).partiallyUpdateEmployee(null, id))),
employeesLink);
}
@PostMapping("/employees")
public ResponseEntity<?> newEmployee(@RequestBody Resource<Employee> employee) {
public ResponseEntity<?> newEmployee(@RequestBody EntityModel<Employee> employee) {
int newEmployeeId = EMPLOYEES.size();
@@ -515,7 +515,7 @@ public class MultiMediaTypeWebMvcIntegrationTest {
}
@PutMapping("/employees/{id}")
public ResponseEntity<?> updateEmployee(@RequestBody Resource<Employee> employee, @PathVariable Integer id) {
public ResponseEntity<?> updateEmployee(@RequestBody EntityModel<Employee> employee, @PathVariable Integer id) {
EMPLOYEES.put(id, employee.getContent());
@@ -527,7 +527,7 @@ public class MultiMediaTypeWebMvcIntegrationTest {
}
@PatchMapping("/employees/{id}")
public ResponseEntity<?> partiallyUpdateEmployee(@RequestBody Resource<Employee> employee,
public ResponseEntity<?> partiallyUpdateEmployee(@RequestBody EntityModel<Employee> employee,
@PathVariable Integer id) {
Employee newEmployee = EMPLOYEES.get(id);

View File

@@ -39,22 +39,22 @@ import org.springframework.aop.framework.ProxyFactory;
import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.PagedResources;
import org.springframework.hateoas.PagedResources.PageMetadata;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.Resources;
import org.springframework.hateoas.server.ResourceProcessor;
import org.springframework.hateoas.PagedModel;
import org.springframework.hateoas.PagedModel.PageMetadata;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.server.RepresentationModelProcessor;
import org.springframework.hateoas.server.core.EmbeddedWrappers;
import org.springframework.hateoas.server.core.HeaderLinksResponseEntity;
import org.springframework.hateoas.server.mvc.ResourceProcessorInvoker;
import org.springframework.hateoas.server.mvc.ResourceProcessorInvoker.ResourcesProcessorWrapper;
import org.springframework.hateoas.server.mvc.RepresentationModelProcessorInvoker;
import org.springframework.hateoas.server.mvc.RepresentationModelProcessorInvoker.ResourcesProcessorWrapper;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
/**
* Unit tests for {@link ResourceProcessorHandlerMethodReturnValueHandler}.
* Unit tests for {@link RepresentationModelProcessorHandlerMethodReturnValueHandler}.
*
* @author Oliver Gierke
* @author Jon Brisbin
@@ -62,29 +62,29 @@ import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
@RunWith(MockitoJUnitRunner.class)
public class ResourceProcessorHandlerMethodReturnValueHandlerUnitTest {
static final Resource<String> FOO = new Resource<>("foo");
static final Resources<Resource<String>> FOOS = new Resources<>(Collections.singletonList(FOO));
static final PagedResources<Resource<String>> FOO_PAGE = new PagedResources<>(
static final EntityModel<String> FOO = new EntityModel<>("foo");
static final CollectionModel<EntityModel<String>> FOOS = new CollectionModel<>(Collections.singletonList(FOO));
static final PagedModel<EntityModel<String>> FOO_PAGE = new PagedModel<>(
Collections.singleton(FOO), new PageMetadata(1, 0, 10));
static final StringResource FOO_RES = new StringResource("foo");
static final HttpEntity<Resource<String>> FOO_ENTITY = new HttpEntity<>(FOO);
static final ResponseEntity<Resource<String>> FOO_RESP_ENTITY = new ResponseEntity<>(FOO,
static final HttpEntity<EntityModel<String>> FOO_ENTITY = new HttpEntity<>(FOO);
static final ResponseEntity<EntityModel<String>> FOO_RESP_ENTITY = new ResponseEntity<>(FOO,
HttpStatus.OK);
static final HttpEntity<StringResource> FOO_RES_ENTITY = new HttpEntity<>(FOO_RES);
static final Resource<String> BAR = new Resource<>("bar");
static final Resources<Resource<String>> BARS = new Resources<>(Collections.singletonList(BAR));
static final EntityModel<String> BAR = new EntityModel<>("bar");
static final CollectionModel<EntityModel<String>> BARS = new CollectionModel<>(Collections.singletonList(BAR));
static final StringResource BAR_RES = new StringResource("bar");
static final HttpEntity<Resource<String>> BAR_ENTITY = new HttpEntity<>(BAR);
static final ResponseEntity<Resource<String>> BAR_RESP_ENTITY = new ResponseEntity<>(BAR,
static final HttpEntity<EntityModel<String>> BAR_ENTITY = new HttpEntity<>(BAR);
static final ResponseEntity<EntityModel<String>> BAR_RESP_ENTITY = new ResponseEntity<>(BAR,
HttpStatus.OK);
static final HttpEntity<StringResource> BAR_RES_ENTITY = new HttpEntity<>(BAR_RES);
static final Resource<Long> LONG_10 = new Resource<>(10L);
static final Resource<Long> LONG_20 = new Resource<>(20L);
static final EntityModel<Long> LONG_10 = new EntityModel<>(10L);
static final EntityModel<Long> LONG_20 = new EntityModel<>(20L);
static final LongResource LONG_10_RES = new LongResource(10L);
static final LongResource LONG_20_RES = new LongResource(20L);
static final HttpEntity<Resource<Long>> LONG_10_ENTITY = new HttpEntity<>(LONG_10);
static final HttpEntity<EntityModel<Long>> LONG_10_ENTITY = new HttpEntity<>(LONG_10);
static final HttpEntity<LongResource> LONG_10_RES_ENTITY = new HttpEntity<>(LONG_10_RES);
static final HttpEntity<Resource<Long>> LONG_20_ENTITY = new HttpEntity<>(LONG_20);
static final HttpEntity<EntityModel<Long>> LONG_20_ENTITY = new HttpEntity<>(LONG_20);
static final HttpEntity<LongResource> LONG_20_RES_ENTITY = new HttpEntity<>(LONG_20_RES);
static final Map<String, MethodParameter> METHOD_PARAMS = new HashMap<>();
@@ -93,7 +93,7 @@ public class ResourceProcessorHandlerMethodReturnValueHandlerUnitTest {
}
@Mock HandlerMethodReturnValueHandler delegate;
List<ResourceProcessor<?>> resourceProcessors;
List<RepresentationModelProcessor<?>> resourceProcessors;
@Before
public void setUp() {
@@ -254,11 +254,11 @@ public class ResourceProcessorHandlerMethodReturnValueHandlerUnitTest {
private void usesHeaderLinksResponseEntityIfConfigured(Function<Object, Object> mapper) throws Exception {
Resource<String> resource = new Resource<>("foo", new Link("href", "rel"));
EntityModel<String> resource = new EntityModel<>("foo", new Link("href", "rel"));
MethodParameter parameter = METHOD_PARAMS.get("resource");
ResourceProcessorHandlerMethodReturnValueHandler handler = new ResourceProcessorHandlerMethodReturnValueHandler(
delegate, new ResourceProcessorInvoker(resourceProcessors));
RepresentationModelProcessorHandlerMethodReturnValueHandler handler = new RepresentationModelProcessorHandlerMethodReturnValueHandler(
delegate, new RepresentationModelProcessorInvoker(resourceProcessors));
handler.setRootLinksAsHeaders(true);
handler.handleReturnValue(mapper.apply(resource), parameter, null, null);
@@ -284,7 +284,7 @@ public class ResourceProcessorHandlerMethodReturnValueHandlerUnitTest {
public void doesNotInvokeAProcessorForASpecializedType() throws Exception {
EmbeddedWrappers wrappers = new EmbeddedWrappers(false);
Resources<Object> value = new Resources<>(
CollectionModel<Object> value = new CollectionModel<>(
Collections.singleton(wrappers.emptyCollectionOf(Object.class)));
ResourcesProcessorWrapper wrapper = new ResourcesProcessorWrapper(new SpecialResourcesProcessor());
@@ -302,9 +302,9 @@ public class ResourceProcessorHandlerMethodReturnValueHandlerUnitTest {
ProjectionProcessor processor = new ProjectionProcessor();
ProxyFactory factory = new ProxyFactory(processor);
resourceProcessors.add((ResourceProcessor<?>) factory.getProxy());
resourceProcessors.add((RepresentationModelProcessor<?>) factory.getProxy());
new ResourceProcessorHandlerMethodReturnValueHandler(delegate, new ResourceProcessorInvoker(resourceProcessors));
new RepresentationModelProcessorHandlerMethodReturnValueHandler(delegate, new RepresentationModelProcessorInvoker(resourceProcessors));
}
/**
@@ -326,8 +326,8 @@ public class ResourceProcessorHandlerMethodReturnValueHandlerUnitTest {
throw new IllegalArgumentException("Invalid method!");
}
HandlerMethodReturnValueHandler handler = new ResourceProcessorHandlerMethodReturnValueHandler(delegate,
new ResourceProcessorInvoker(resourceProcessors));
HandlerMethodReturnValueHandler handler = new RepresentationModelProcessorHandlerMethodReturnValueHandler(delegate,
new RepresentationModelProcessorInvoker(resourceProcessors));
handler.handleReturnValue(returnValue, methodParam, null, null);
verify(delegate, times(1)).handleReturnValue(expected, methodParam, null, null);
@@ -338,40 +338,40 @@ public class ResourceProcessorHandlerMethodReturnValueHandlerUnitTest {
final MethodParameter parameter = Mockito.mock(MethodParameter.class);
when(delegate.supportsReturnType(Mockito.any(MethodParameter.class))).thenReturn(value);
HandlerMethodReturnValueHandler handler = new ResourceProcessorHandlerMethodReturnValueHandler(delegate,
new ResourceProcessorInvoker(resourceProcessors));
HandlerMethodReturnValueHandler handler = new RepresentationModelProcessorHandlerMethodReturnValueHandler(delegate,
new RepresentationModelProcessorInvoker(resourceProcessors));
assertThat(handler.supportsReturnType(parameter)).isEqualTo(value);
}
enum StringResourceProcessor implements ResourceProcessor<Resource<String>> {
enum StringResourceProcessor implements RepresentationModelProcessor<EntityModel<String>> {
INSTANCE;
@Override
public Resource<String> process(Resource<String> resource) {
public EntityModel<String> process(EntityModel<String> resource) {
return BAR;
}
}
enum LongResourceProcessor implements ResourceProcessor<Resource<Long>> {
enum LongResourceProcessor implements RepresentationModelProcessor<EntityModel<Long>> {
INSTANCE;
@Override
public Resource<Long> process(Resource<Long> resource) {
public EntityModel<Long> process(EntityModel<Long> resource) {
return LONG_20;
}
}
enum StringResourcesProcessor implements ResourceProcessor<Resources<Resource<String>>> {
enum StringResourcesProcessor implements RepresentationModelProcessor<CollectionModel<EntityModel<String>>> {
INSTANCE;
@Override
public Resources<Resource<String>> process(Resources<Resource<String>> resource) {
public CollectionModel<EntityModel<String>> process(CollectionModel<EntityModel<String>> resource) {
return BARS;
}
}
enum SpecializedStringResourceProcessor implements ResourceProcessor<StringResource> {
enum SpecializedStringResourceProcessor implements RepresentationModelProcessor<StringResource> {
INSTANCE;
@Override
@@ -380,7 +380,7 @@ public class ResourceProcessorHandlerMethodReturnValueHandlerUnitTest {
}
}
enum SpecializedLongResourceProcessor implements ResourceProcessor<LongResource> {
enum SpecializedLongResourceProcessor implements RepresentationModelProcessor<LongResource> {
INSTANCE;
@Override
@@ -391,52 +391,52 @@ public class ResourceProcessorHandlerMethodReturnValueHandlerUnitTest {
interface Controller {
Resources<Resource<String>> resources();
CollectionModel<EntityModel<String>> resources();
Resource<String> resource();
EntityModel<String> resource();
Resource<Long> longResource();
EntityModel<Long> longResource();
StringResource specializedResource();
Object object();
HttpEntity<Resource<?>> resourceEntity();
HttpEntity<EntityModel<?>> resourceEntity();
HttpEntity<Resources<?>> resourcesEntity();
HttpEntity<CollectionModel<?>> resourcesEntity();
HttpEntity<Object> objectEntity();
HttpEntity<Resource<String>> stringResourceEntity();
HttpEntity<EntityModel<String>> stringResourceEntity();
HttpEntity<Resource<? extends Number>> numberResourceEntity();
HttpEntity<EntityModel<? extends Number>> numberResourceEntity();
HttpEntity<StringResource> specializedStringResourceEntity();
HttpEntity<LongResource> specializedLongResourceEntity();
ResponseEntity<Resource<?>> resourceResponseEntity();
ResponseEntity<EntityModel<?>> resourceResponseEntity();
ResponseEntity<Resources<?>> resourcesResponseEntity();
ResponseEntity<CollectionModel<?>> resourcesResponseEntity();
Resources<Object> resourcesOfObject();
CollectionModel<Object> resourcesOfObject();
Resources<?> wildcardedResources();
CollectionModel<?> wildcardedResources();
}
static class StringResource extends Resource<String> {
static class StringResource extends EntityModel<String> {
public StringResource(String value) {
super(value);
}
}
static class LongResource extends Resource<Long> {
static class LongResource extends EntityModel<Long> {
public LongResource(Long value) {
super(value);
}
}
static class PagedStringResources extends PagedResources<Resource<String>> {}
static class PagedStringResources extends PagedModel<EntityModel<String>> {}
static class Sample {
@@ -446,24 +446,24 @@ public class ResourceProcessorHandlerMethodReturnValueHandlerUnitTest {
}
static class ProjectionProcessor implements ResourceProcessor<Resource<SampleProjection>> {
static class ProjectionProcessor implements RepresentationModelProcessor<EntityModel<SampleProjection>> {
boolean invoked = false;
@Override
public Resource<SampleProjection> process(Resource<SampleProjection> resource) {
public EntityModel<SampleProjection> process(EntityModel<SampleProjection> resource) {
this.invoked = true;
return resource;
}
}
static class SpecialResources extends Resources<Object> {
static class SpecialResources extends CollectionModel<Object> {
public SpecialResources() {
super(Collections.emptyList());
}
}
static class SpecialResourcesProcessor implements ResourceProcessor<SpecialResources> {
static class SpecialResourcesProcessor implements RepresentationModelProcessor<SpecialResources> {
boolean invoked = false;

View File

@@ -19,8 +19,8 @@ import static org.assertj.core.api.Assertions.*;
import static org.springframework.http.MediaType.*;
import org.junit.Test;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.hateoas.server.mvc.TypeConstrainedMappingJackson2HttpMessageConverter;
import org.springframework.http.converter.GenericHttpMessageConverter;
@@ -46,11 +46,11 @@ public class TypeConstrainedMappingJackson2HttpMessageConverterUnitTest {
public void canReadTypeIfAssignableToConfiguredType() {
GenericHttpMessageConverter<Object> converter = new TypeConstrainedMappingJackson2HttpMessageConverter(
ResourceSupport.class);
RepresentationModel.class);
assertCanRead(converter, Object.class, false);
assertCanRead(converter, ResourceSupport.class, true);
assertCanRead(converter, Resource.class, true);
assertCanRead(converter, RepresentationModel.class, true);
assertCanRead(converter, EntityModel.class, true);
}
/**
@@ -60,11 +60,11 @@ public class TypeConstrainedMappingJackson2HttpMessageConverterUnitTest {
public void canWriteTypeIfAssignableToConfiguredType() {
GenericHttpMessageConverter<Object> converter = new TypeConstrainedMappingJackson2HttpMessageConverter(
ResourceSupport.class);
RepresentationModel.class);
assertCanWrite(converter, Object.class, false);
assertCanWrite(converter, ResourceSupport.class, true);
assertCanWrite(converter, Resource.class, true);
assertCanWrite(converter, RepresentationModel.class, true);
assertCanWrite(converter, EntityModel.class, true);
}
private static void assertCanRead(GenericHttpMessageConverter<Object> converter, Class<?> type, boolean expected) {

View File

@@ -30,14 +30,13 @@ import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.MediaTypes;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.Resources;
import org.springframework.hateoas.config.EnableHypermediaSupport;
import org.springframework.hateoas.config.EnableHypermediaSupport.HypermediaType;
import org.springframework.hateoas.server.mvc.TypeReferences;
import org.springframework.hateoas.server.mvc.TypeReferences.ResourceType;
import org.springframework.hateoas.server.mvc.TypeReferences.ResourcesType;
import org.springframework.hateoas.server.mvc.TypeReferences.CollectionModelType;
import org.springframework.hateoas.server.mvc.TypeReferences.EntityModelType;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.ContextConfiguration;
@@ -47,7 +46,7 @@ import org.springframework.web.client.RestTemplate;
/**
* Integration tests for {@link TypeReferences}.
*
*
* @author Oliver Gierke
* @author Greg Turnquist
*/
@@ -59,21 +58,25 @@ public class TypeReferencesIntegrationTest {
private static final String COLLECTION_JSON_USER = "{ \"name\" : \"firstname\", \"value\" : \"Dave\" }, { \"name\" : \"lastname\", \"value\" : \"Matthews\" }";
private static final String RESOURCE_HAL = String.format("{ \"_links\" : { \"self\" : \"/resource\" }, %s }", HAL_USER);
private static final String RESOURCES_OF_USER_HAL = String.format(
"{ \"_links\" : { \"self\" : \"/resources\" }, \"_embedded\" : { \"users\" : [ { %s } ] }}", HAL_USER);
private static final String RESOURCES_OF_RESOURCE_HAL = String.format(
"{ \"_links\" : { \"self\" : \"/resources\" }, \"_embedded\" : { \"users\" : [ %s ] }}", RESOURCE_HAL);
private static final String RESOURCE_HAL = String.format("{ \"_links\" : { \"self\" : \"/resource\" }, %s }",
HAL_USER);
private static final String RESOURCES_OF_USER_HAL = String
.format("{ \"_links\" : { \"self\" : \"/resources\" }, \"_embedded\" : { \"users\" : [ { %s } ] }}", HAL_USER);
private static final String RESOURCES_OF_RESOURCE_HAL = String
.format("{ \"_links\" : { \"self\" : \"/resources\" }, \"_embedded\" : { \"users\" : [ %s ] }}", RESOURCE_HAL);
private static final String RESOURCE_COLLECTION_JSON =
String.format("{ \"collection\": { \"version\": \"1.0\", \"href\": \"localhost\", \"links\": [{ \"rel\": \"self\", \"href\": \"localhost\" }], \"items\": [{\"href\": \"localhost\", \"data\": [%s]}]}}", COLLECTION_JSON_USER);
private static final String RESOURCES_OF_USER_COLLECTION_JSON =
String.format("{ \"collection\": { \"version\": \"1.0\", \"href\": \"localhost\", \"links\": [{ \"rel\": \"self\", \"href\": \"localhost\" }], \"items\": [{\"href\": \"localhost\", \"data\": [%s]}]}}", COLLECTION_JSON_USER);
private static final String RESOURCES_OF_RESOURCE_COLLECTION_JSON =
String.format("{ \"collection\": { \"version\": \"1.0\", \"href\": \"localhost\", \"links\": [{ \"rel\": \"self\", \"href\": \"localhost\" }], \"items\": [{\"href\": \"localhost\", \"data\": [%s], \"links\": [{\"rel\":\"self\", \"href\": \"localhost\"}]}]}}", COLLECTION_JSON_USER);
private static final String RESOURCE_COLLECTION_JSON = String.format(
"{ \"collection\": { \"version\": \"1.0\", \"href\": \"localhost\", \"links\": [{ \"rel\": \"self\", \"href\": \"localhost\" }], \"items\": [{\"href\": \"localhost\", \"data\": [%s]}]}}",
COLLECTION_JSON_USER);
private static final String RESOURCES_OF_USER_COLLECTION_JSON = String.format(
"{ \"collection\": { \"version\": \"1.0\", \"href\": \"localhost\", \"links\": [{ \"rel\": \"self\", \"href\": \"localhost\" }], \"items\": [{\"href\": \"localhost\", \"data\": [%s]}]}}",
COLLECTION_JSON_USER);
private static final String RESOURCES_OF_RESOURCE_COLLECTION_JSON = String.format(
"{ \"collection\": { \"version\": \"1.0\", \"href\": \"localhost\", \"links\": [{ \"rel\": \"self\", \"href\": \"localhost\" }], \"items\": [{\"href\": \"localhost\", \"data\": [%s], \"links\": [{\"rel\":\"self\", \"href\": \"localhost\"}]}]}}",
COLLECTION_JSON_USER);
@Configuration
@EnableHypermediaSupport(type = { HypermediaType.HAL, HypermediaType.COLLECTION_JSON})
@EnableHypermediaSupport(type = { HypermediaType.HAL, HypermediaType.COLLECTION_JSON })
static class Config {
public @Bean RestTemplate template() {
@@ -97,8 +100,8 @@ public class TypeReferencesIntegrationTest {
server.expect(requestTo("/resource")).andRespond(withSuccess(RESOURCE_HAL, MediaTypes.HAL_JSON));
ResponseEntity<Resource<User>> response = template.exchange("/resource", HttpMethod.GET, null,
new ResourceType<User>() {});
ResponseEntity<EntityModel<User>> response = template.exchange("/resource", HttpMethod.GET, null,
new EntityModelType<User>() {});
assertExpectedUserResource(response.getBody());
}
@@ -111,8 +114,8 @@ public class TypeReferencesIntegrationTest {
server.expect(requestTo("/resource")).andRespond(withSuccess(RESOURCE_COLLECTION_JSON, MediaTypes.COLLECTION_JSON));
ResponseEntity<Resource<User>> response = template.exchange("/resource", HttpMethod.GET, null,
new ResourceType<User>() {});
ResponseEntity<EntityModel<User>> response = template.exchange("/resource", HttpMethod.GET, null,
new EntityModelType<User>() {});
assertExpectedUserResource(response.getBody());
}
@@ -125,9 +128,9 @@ public class TypeReferencesIntegrationTest {
server.expect(requestTo("/resources")).andRespond(withSuccess(RESOURCES_OF_USER_HAL, MediaTypes.HAL_JSON));
ResponseEntity<Resources<User>> response = template.exchange("/resources", HttpMethod.GET, null,
new ResourcesType<User>() {});
Resources<User> body = response.getBody();
ResponseEntity<CollectionModel<User>> response = template.exchange("/resources", HttpMethod.GET, null,
new CollectionModelType<User>() {});
CollectionModel<User> body = response.getBody();
assertThat(body.hasLink("self")).isTrue();
@@ -143,11 +146,12 @@ public class TypeReferencesIntegrationTest {
@Test
public void usesResourcesTypeReferenceWithCollectionJson() {
server.expect(requestTo("/resources")).andRespond(withSuccess(RESOURCES_OF_USER_COLLECTION_JSON, MediaTypes.COLLECTION_JSON));
server.expect(requestTo("/resources"))
.andRespond(withSuccess(RESOURCES_OF_USER_COLLECTION_JSON, MediaTypes.COLLECTION_JSON));
ResponseEntity<Resources<User>> response = template.exchange("/resources", HttpMethod.GET, null,
new ResourcesType<User>() {});
Resources<User> body = response.getBody();
ResponseEntity<CollectionModel<User>> response = template.exchange("/resources", HttpMethod.GET, null,
new CollectionModelType<User>() {});
CollectionModel<User> body = response.getBody();
assertThat(body.hasLink("self")).isTrue();
@@ -165,13 +169,13 @@ public class TypeReferencesIntegrationTest {
server.expect(requestTo("/resources")).andRespond(withSuccess(RESOURCES_OF_RESOURCE_HAL, MediaTypes.HAL_JSON));
ResponseEntity<Resources<Resource<User>>> response = template.exchange("/resources", HttpMethod.GET, null,
new ResourcesType<Resource<User>>() {});
Resources<Resource<User>> body = response.getBody();
ResponseEntity<CollectionModel<EntityModel<User>>> response = template.exchange("/resources", HttpMethod.GET, null,
new CollectionModelType<EntityModel<User>>() {});
CollectionModel<EntityModel<User>> body = response.getBody();
assertThat(body.hasLink("self")).isTrue();
Collection<Resource<User>> nested = body.getContent();
Collection<EntityModel<User>> nested = body.getContent();
assertThat(nested).hasSize(1);
assertExpectedUserResource(nested.iterator().next());
@@ -183,21 +187,22 @@ public class TypeReferencesIntegrationTest {
@Test
public void usesResourcesOfResourceTypeReferenceWithCollectionJson() {
server.expect(requestTo("/resources")).andRespond(withSuccess(RESOURCES_OF_RESOURCE_COLLECTION_JSON, MediaTypes.COLLECTION_JSON));
server.expect(requestTo("/resources"))
.andRespond(withSuccess(RESOURCES_OF_RESOURCE_COLLECTION_JSON, MediaTypes.COLLECTION_JSON));
ResponseEntity<Resources<Resource<User>>> response = template.exchange("/resources", HttpMethod.GET, null,
new ResourcesType<Resource<User>>() {});
Resources<Resource<User>> body = response.getBody();
ResponseEntity<CollectionModel<EntityModel<User>>> response = template.exchange("/resources", HttpMethod.GET, null,
new CollectionModelType<EntityModel<User>>() {});
CollectionModel<EntityModel<User>> body = response.getBody();
assertThat(body.hasLink("self")).isTrue();
Collection<Resource<User>> nested = body.getContent();
Collection<EntityModel<User>> nested = body.getContent();
assertThat(nested).hasSize(1);
assertExpectedUserResource(nested.iterator().next());
}
private static void assertExpectedUserResource(Resource<User> user) {
private static void assertExpectedUserResource(EntityModel<User> user) {
assertThat(user.hasLink("self")).isTrue();
assertExpectedUser(user.getContent());

View File

@@ -30,7 +30,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.hateoas.IanaLinkRelations;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.MediaTypes;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.hateoas.config.EnableHypermediaSupport;
import org.springframework.hateoas.config.WebClientConfigurer;
import org.springframework.test.web.reactive.server.WebTestClient;
@@ -70,7 +70,7 @@ public class HypermediaWebFilterTest {
.exchange() //
.expectStatus().isOk() //
.expectHeader().contentType(MediaTypes.HAL_JSON_UTF8) //
.returnResult(ResourceSupport.class) //
.returnResult(RepresentationModel.class) //
.getResponseBody() //
.as(StepVerifier::create) //
.expectNextMatches(resourceSupport -> {
@@ -87,8 +87,8 @@ public class HypermediaWebFilterTest {
static class TestController {
@GetMapping
Mono<ResourceSupport> root() {
return linkTo(methodOn(TestController.class).root()).withSelfRel().toMono().map(ResourceSupport::new);
Mono<RepresentationModel<?>> root() {
return linkTo(methodOn(TestController.class).root()).withSelfRel().toMono().map(RepresentationModel::new);
}
}

View File

@@ -30,10 +30,9 @@ import java.util.Collection;
import org.assertj.core.api.AssertionsForInterfaceTypes;
import org.junit.Before;
import org.junit.Test;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.hateoas.Resources;
import org.springframework.hateoas.server.reactive.ReactiveResourceAssembler;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.web.server.ServerWebExchange;
/**
@@ -64,7 +63,7 @@ public class ReactiveResourceAssemblerUnitTest {
@Test
public void simpleConversionShouldWork() {
this.assembler.toResource(this.employee, this.exchange).as(StepVerifier::create)
this.assembler.toModel(this.employee, this.exchange).as(StepVerifier::create)
.expectNextMatches(employeeResource -> {
assertThat(employeeResource.getEmployee()).isEqualTo(new Employee("Frodo Baggins"));
@@ -81,7 +80,7 @@ public class ReactiveResourceAssemblerUnitTest {
@Test
public void defaultResourcesConversionShouldWork() {
this.assembler.toResources(Flux.just(this.employee), this.exchange).as(StepVerifier::create)
this.assembler.toCollectionModel(Flux.just(this.employee), this.exchange).as(StepVerifier::create)
.expectNextMatches(employeeResources -> {
Collection<EmployeeResource> content = employeeResources.getContent();
@@ -103,7 +102,7 @@ public class ReactiveResourceAssemblerUnitTest {
@Test
public void customResourcesShouldWork() {
this.assemblerWithCustomResources.toResources(Flux.just(this.employee), this.exchange) //
this.assemblerWithCustomResources.toCollectionModel(Flux.just(this.employee), this.exchange) //
.as(StepVerifier::create) //
.expectNextMatches(employeeResources -> {
@@ -119,10 +118,10 @@ public class ReactiveResourceAssemblerUnitTest {
}).verifyComplete();
}
class TestAssembler implements ReactiveResourceAssembler<Employee, EmployeeResource> {
class TestAssembler implements ReactiveRepresentationModelAssembler<Employee, EmployeeResource> {
@Override
public Mono<EmployeeResource> toResource(Employee entity, ServerWebExchange exchange) {
public Mono<EmployeeResource> toModel(Employee entity, ServerWebExchange exchange) {
EmployeeResource employeeResource = new EmployeeResource(entity);
employeeResource.add(new Link("/employees", "employees"));
@@ -134,12 +133,13 @@ public class ReactiveResourceAssemblerUnitTest {
class TestAssemblerWithCustomResources extends TestAssembler {
@Override
public Mono<Resources<EmployeeResource>> toResources(Flux<? extends Employee> entities,
public Mono<CollectionModel<EmployeeResource>> toCollectionModel(Flux<? extends Employee> entities,
ServerWebExchange exchange) {
return entities.flatMap(entity -> toResource(entity, exchange)).collectList().map(listOfResources -> {
return entities.flatMap(entity -> toModel(entity, exchange)).collectList().map(listOfResources -> {
Resources<EmployeeResource> employeeResources = new Resources<>(listOfResources);
CollectionModel<EmployeeResource> employeeResources = new CollectionModel<>(
listOfResources);
employeeResources.add(new Link("/employees").withSelfRel());
employeeResources.add(new Link("/", "root"));
@@ -158,7 +158,7 @@ public class ReactiveResourceAssemblerUnitTest {
@Data
@EqualsAndHashCode(callSuper = true)
@AllArgsConstructor
class EmployeeResource extends ResourceSupport {
class EmployeeResource extends RepresentationModel<EmployeeResource> {
private Employee employee;
}
}

View File

@@ -18,16 +18,15 @@ package org.springframework.hateoas.server.reactive;
import static org.assertj.core.api.Assertions.*;
import lombok.Data;
import reactor.core.publisher.Flux;
import reactor.test.StepVerifier;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import reactor.core.publisher.Flux;
import reactor.test.StepVerifier;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.Resources;
import org.springframework.hateoas.server.reactive.SimpleReactiveResourceAssembler;
import org.springframework.web.server.ServerWebExchange;
/**
@@ -40,7 +39,7 @@ public class SimpleReactiveResourceAssemblerTest {
ResourceAssemblerWithCustomLinkSimple resourceAssemblerWithCustomLink;
@Mock ServerWebExchange exchange;
@Before
public void setUp() {
@@ -49,20 +48,18 @@ public class SimpleReactiveResourceAssemblerTest {
}
/**
* @see #728
* @see #728
*/
@Test
public void convertingToResourceShouldWork() {
this.testResourceAssembler.toResource(new Employee("Frodo"), this.exchange)
.as(StepVerifier::create)
.expectNextMatches(resource -> {
this.testResourceAssembler.toModel(new Employee("Frodo"), this.exchange).as(StepVerifier::create)
.expectNextMatches(resource -> {
assertThat(resource.getContent().getName()).isEqualTo("Frodo");
assertThat(resource.getLinks()).isEmpty();
return true;
})
.verifyComplete();
assertThat(resource.getContent().getName()).isEqualTo("Frodo");
assertThat(resource.getLinks()).isEmpty();
return true;
}).verifyComplete();
}
/**
@@ -71,15 +68,14 @@ public class SimpleReactiveResourceAssemblerTest {
@Test
public void convertingToResourcesShouldWork() {
this.testResourceAssembler.toResources(Flux.just(new Employee("Frodo")), this.exchange)
.as(StepVerifier::create)
.expectNextMatches(resources -> {
this.testResourceAssembler.toCollectionModel(Flux.just(new Employee("Frodo")), this.exchange)
.as(StepVerifier::create).expectNextMatches(resources -> {
assertThat(resources.getContent()).containsExactly(new Resource<>(new Employee("Frodo")));
assertThat(resources.getLinks()).isEmpty();
assertThat(resources.getContent()).containsExactly(new EntityModel<>(new Employee("Frodo")));
assertThat(resources.getLinks()).isEmpty();
return true;
});
return true;
});
}
/**
@@ -88,16 +84,14 @@ public class SimpleReactiveResourceAssemblerTest {
@Test
public void convertingToResourceWithCustomLinksShouldWork() {
this.resourceAssemblerWithCustomLink.toResource(new Employee("Frodo"), this.exchange)
.as(StepVerifier::create)
.expectNextMatches(resource -> {
this.resourceAssemblerWithCustomLink.toModel(new Employee("Frodo"), this.exchange).as(StepVerifier::create)
.expectNextMatches(resource -> {
assertThat(resource.getContent().getName()).isEqualTo("Frodo");
assertThat(resource.getLinks()).containsExactly(new Link("/employees").withRel("employees"));
return true;
})
.verifyComplete();
assertThat(resource.getContent().getName()).isEqualTo("Frodo");
assertThat(resource.getLinks()).containsExactly(new Link("/employees").withRel("employees"));
return true;
}).verifyComplete();
}
/**
@@ -106,40 +100,31 @@ public class SimpleReactiveResourceAssemblerTest {
@Test
public void convertingToResourcesWithCustomLinksShouldWork() {
this.resourceAssemblerWithCustomLink.toResources(Flux.just(new Employee("Frodo")), this.exchange)
.as(StepVerifier::create)
.expectNextMatches(resources -> {
this.resourceAssemblerWithCustomLink.toCollectionModel(Flux.just(new Employee("Frodo")), this.exchange)
.as(StepVerifier::create).expectNextMatches(resources -> {
assertThat(resources.getContent()).containsExactly(
new Resource<>(new Employee("Frodo"), new Link("/employees").withRel("employees")));
assertThat(resources.getLinks()).containsExactly(new Link("/", "root"));
assertThat(resources.getContent()).containsExactly(
new EntityModel<>(new Employee("Frodo"), new Link("/employees").withRel("employees")));
assertThat(resources.getLinks()).containsExactly(new Link("/", "root"));
return true;
})
.verifyComplete();
return true;
}).verifyComplete();
}
class TestResourceAssemblerSimple implements SimpleReactiveResourceAssembler<Employee> {
class TestResourceAssemblerSimple implements SimpleReactiveRepresentationModelAssembler<Employee> {}
class ResourceAssemblerWithCustomLinkSimple implements SimpleReactiveRepresentationModelAssembler<Employee> {
@Override
public void addLinks(Resource<Employee> resource, ServerWebExchange exchange) {
public EntityModel<Employee> addLinks(EntityModel<Employee> resource,
ServerWebExchange exchange) {
return resource.add(new Link("/employees").withRel("employees"));
}
@Override
public void addLinks(Resources<Resource<Employee>> resources, ServerWebExchange exchange) {
}
}
class ResourceAssemblerWithCustomLinkSimple implements SimpleReactiveResourceAssembler<Employee> {
@Override
public void addLinks(Resource<Employee> resource, ServerWebExchange exchange) {
resource.add(new Link("/employees").withRel("employees"));
}
@Override
public void addLinks(Resources<Resource<Employee>> resources, ServerWebExchange exchange) {
resources.add(new Link("/").withRel("root"));
public CollectionModel<EntityModel<Employee>> addLinks(
CollectionModel<EntityModel<Employee>> resources, ServerWebExchange exchange) {
return resources.add(new Link("/").withRel("root"));
}
}

View File

@@ -19,7 +19,7 @@ import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.hateoas.RepresentationModel;
/**
* @author Greg Turnquist
@@ -27,7 +27,7 @@ import org.springframework.hateoas.ResourceSupport;
@Data
@EqualsAndHashCode(callSuper = true)
@AllArgsConstructor
public class EmployeeResource extends ResourceSupport {
public class EmployeeResource extends RepresentationModel<EmployeeResource> {
private String name;
}

View File

@@ -27,7 +27,7 @@ import java.util.Map;
import org.junit.Test;
import org.springframework.core.ResolvableType;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.mediatype.PropertyUtils;
import org.springframework.hateoas.server.core.MethodParameters;
import org.springframework.util.ReflectionUtils;
@@ -60,7 +60,7 @@ public class PropertyUtilsTest {
public void simpleObjectWrappedAsResource() {
Employee employee = new Employee("Frodo Baggins", "ring bearer");
Resource<Employee> employeeResource = new Resource<>(employee);
EntityModel<Employee> employeeResource = new EntityModel<>(employee);
Map<String, Object> properties = PropertyUtils.findProperties(employeeResource);
@@ -73,7 +73,7 @@ public class PropertyUtilsTest {
@Test
public void resourceWrappedSpringMvcParameter() {
Method method = ReflectionUtils.findMethod(TestController.class, "newEmployee", Resource.class);
Method method = ReflectionUtils.findMethod(TestController.class, "newEmployee", EntityModel.class);
MethodParameters parameters = new MethodParameters(method);
ResolvableType resolvableType = parameters.getParametersWith(RequestBody.class).stream()
@@ -161,7 +161,7 @@ public class PropertyUtilsTest {
static class TestController {
@GetMapping("/")
public Employee newEmployee(@RequestBody Resource<Employee> employee) {
public Employee newEmployee(@RequestBody EntityModel<Employee> employee) {
return employee.getContent();
}
}

View File

@@ -30,8 +30,8 @@ import org.springframework.hateoas.Affordance;
import org.springframework.hateoas.IanaLinkRelations;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.Links;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.Resources;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.server.reactive.WebFluxLinkBuilder;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
@@ -63,7 +63,7 @@ public class WebFluxEmployeeController {
}
@GetMapping("/employees")
public Mono<Resources<Resource<Employee>>> all() {
public Mono<CollectionModel<EntityModel<Employee>>> all() {
Class<WebFluxEmployeeController> controller = WebFluxEmployeeController.class;
@@ -74,11 +74,11 @@ public class WebFluxEmployeeController {
.andAffordance(methodOn(controller).newEmployee(null)) //
.andAffordance(methodOn(controller).search(null, null)) //
.toMono() //
.map(selfLink -> new Resources<>(resources, selfLink)));
.map(selfLink -> new CollectionModel<>(resources, selfLink)));
}
@GetMapping("/employees/search")
public Mono<Resources<Resource<Employee>>> search( //
public Mono<CollectionModel<EntityModel<Employee>>> search( //
@RequestParam Optional<String> name, //
@RequestParam Optional<String> role) {
@@ -102,12 +102,12 @@ public class WebFluxEmployeeController {
.andAffordance(methodOn(controller).newEmployee(null)) //
.andAffordance(methodOn(controller).search(null, null)) //
.toMono() //
.map(selfLink -> new Resources<>(resources, selfLink));
.map(selfLink -> new CollectionModel<>(resources, selfLink));
});
}
@GetMapping("/employees/{id}")
public Mono<Resource<Employee>> findOne(@PathVariable Integer id) {
public Mono<EntityModel<Employee>> findOne(@PathVariable Integer id) {
Mono<Link> selfLink = linkTo(methodOn(WebFluxEmployeeController.class).findOne(id)).withSelfRel() //
.andAffordance(methodOn(WebFluxEmployeeController.class).updateEmployee(null, id)) //
@@ -119,11 +119,11 @@ public class WebFluxEmployeeController {
return selfLink.zipWith(employeesLink) //
.map(function((left, right) -> Links.of(left, right))) //
.map(links -> new Resource<>(EMPLOYEES.get(id), links));
.map(links -> new EntityModel<>(EMPLOYEES.get(id), links));
}
@PostMapping("/employees")
public Mono<ResponseEntity<?>> newEmployee(@RequestBody Mono<Resource<Employee>> employee) {
public Mono<ResponseEntity<?>> newEmployee(@RequestBody Mono<EntityModel<Employee>> employee) {
return employee.flatMap(resource -> {
@@ -142,7 +142,7 @@ public class WebFluxEmployeeController {
}
@PutMapping("/employees/{id}")
public Mono<ResponseEntity<?>> updateEmployee(@RequestBody Mono<Resource<Employee>> employee,
public Mono<ResponseEntity<?>> updateEmployee(@RequestBody Mono<EntityModel<Employee>> employee,
@PathVariable Integer id) {
return employee.flatMap(resource -> {
@@ -161,7 +161,7 @@ public class WebFluxEmployeeController {
@PatchMapping("/employees/{id}")
public Mono<ResponseEntity<?>> partiallyUpdateEmployee( //
@RequestBody Mono<Resource<Employee>> employee, @PathVariable Integer id) {
@RequestBody Mono<EntityModel<Employee>> employee, @PathVariable Integer id) {
return employee.flatMap(resource -> {

View File

@@ -29,8 +29,8 @@ import java.util.stream.IntStream;
import org.springframework.hateoas.IanaLinkRelations;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.Resources;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.CollectionModel;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
@@ -58,7 +58,7 @@ public class WebMvcEmployeeController {
}
@GetMapping("/employees")
public Resources<Resource<Employee>> all() {
public CollectionModel<EntityModel<Employee>> all() {
// Generate an "Affordance" based on this method (the "self" link)
Link selfLink = linkTo(methodOn(WebMvcEmployeeController.class).all()).withSelfRel() //
@@ -68,20 +68,20 @@ public class WebMvcEmployeeController {
// Return the collection of employee resources along with the composite affordance
return IntStream.range(0, EMPLOYEES.size()) //
.mapToObj(this::findOne) //
.collect(Collectors.collectingAndThen(Collectors.toList(), it -> new Resources<>(it, selfLink)));
.collect(Collectors.collectingAndThen(Collectors.toList(), it -> new CollectionModel<>(it, selfLink)));
}
@GetMapping("/employees/search")
public Resources<Resource<Employee>> search(@RequestParam(value = "name", required = false) String name,
public CollectionModel<EntityModel<Employee>> search(@RequestParam(value = "name", required = false) String name,
@RequestParam(value = "role", required = false) String role) {
// Create a list of Resource<Employee>'s to return
List<Resource<Employee>> employees = new ArrayList<>();
List<EntityModel<Employee>> employees = new ArrayList<>();
// Fetch each Resource<Employee> using the controller's findOne method.
for (int i = 0; i < EMPLOYEES.size(); i++) {
Resource<Employee> employeeResource = findOne(i);
EntityModel<Employee> employeeResource = findOne(i);
boolean nameMatches = Optional.ofNullable(name) //
.map(s -> employeeResource.getContent().getName().contains(s)) //
@@ -103,11 +103,11 @@ public class WebMvcEmployeeController {
.andAffordance(afford(methodOn(WebMvcEmployeeController.class).search(null, null)));
// Return the collection of employee resources along with the composite affordance
return new Resources<>(employees, selfLink);
return new CollectionModel<>(employees, selfLink);
}
@GetMapping("/employees/{id}")
public Resource<Employee> findOne(@PathVariable Integer id) {
public EntityModel<Employee> findOne(@PathVariable Integer id) {
// Start the affordance with the "self" link, i.e. this method.
Link findOneLink = linkTo(methodOn(WebMvcEmployeeController.class).findOne(id)).withSelfRel();
@@ -116,7 +116,7 @@ public class WebMvcEmployeeController {
Link employeesLink = linkTo(methodOn(WebMvcEmployeeController.class).all()).withRel("employees");
// Return the affordance + a link back to the entire collection resource.
return new Resource<>(EMPLOYEES.get(id), //
return new EntityModel<>(EMPLOYEES.get(id), //
findOneLink //
.andAffordance(afford(methodOn(WebMvcEmployeeController.class).updateEmployee(null, id))) // //
.andAffordance(afford(methodOn(WebMvcEmployeeController.class).partiallyUpdateEmployee(null, id))), //
@@ -124,7 +124,7 @@ public class WebMvcEmployeeController {
}
@PostMapping("/employees")
public ResponseEntity<?> newEmployee(@RequestBody Resource<Employee> employee) {
public ResponseEntity<?> newEmployee(@RequestBody EntityModel<Employee> employee) {
int newEmployeeId = EMPLOYEES.size();
@@ -136,7 +136,7 @@ public class WebMvcEmployeeController {
}
@PutMapping("/employees/{id}")
public ResponseEntity<?> updateEmployee(@RequestBody Resource<Employee> employee, @PathVariable Integer id) {
public ResponseEntity<?> updateEmployee(@RequestBody EntityModel<Employee> employee, @PathVariable Integer id) {
EMPLOYEES.put(id, employee.getContent());
@@ -148,7 +148,7 @@ public class WebMvcEmployeeController {
}
@PatchMapping("/employees/{id}")
public ResponseEntity<?> partiallyUpdateEmployee(@RequestBody Resource<Employee> employee, @PathVariable Integer id) {
public ResponseEntity<?> partiallyUpdateEmployee(@RequestBody EntityModel<Employee> employee, @PathVariable Integer id) {
Employee oldEmployee = EMPLOYEES.get(id);
Employee newEmployee = oldEmployee;

View File

@@ -76,20 +76,20 @@ class WebMvcAffordanceBuilderDslUnitTest : TestUtils() {
}
data class CustomerDTO(val name: String)
open class CustomerResource(val id: String, val name: String) : ResourceSupport()
open class ProductResource(val id: String) : ResourceSupport()
open class CustomerModel(val id: String, val name: String) : RepresentationModel<CustomerModel>()
open class ProductModel(val id: String) : RepresentationModel<ProductModel>()
@RequestMapping("/customers")
interface CustomerController {
@GetMapping("/{id}")
fun findById(@PathVariable id: String): ResponseEntity<CustomerResource>
fun findById(@PathVariable id: String): ResponseEntity<CustomerModel>
@GetMapping("/{id}/products")
fun findProductsById(@PathVariable id: String): PagedResources<ProductResource>
fun findProductsById(@PathVariable id: String): PagedModel<ProductModel>
@PutMapping("/{id}")
fun update(@PathVariable id: String, @RequestBody customer: CustomerDTO): ResponseEntity<CustomerResource>
fun update(@PathVariable id: String, @RequestBody customer: CustomerDTO): ResponseEntity<CustomerModel>
@DeleteMapping("/{id}")
fun delete(@PathVariable id: String): ResponseEntity<Unit>

View File

@@ -27,6 +27,7 @@ import org.springframework.web.bind.annotation.*
*
* @author Roland Kulcsár
* @author Greg Turnquist
* @author Oliver Drotbohm
*/
class WebMvcLinkBuilderDslUnitTest : TestUtils() {
@@ -51,7 +52,7 @@ class WebMvcLinkBuilderDslUnitTest : TestUtils() {
@Test
fun `adds links to wrapped domain object`() {
val customer = Resource(Customer("15", "John Doe"))
val customer = EntityModel(Customer("15", "John Doe"))
customer.add(CustomerController::class) {
linkTo { findById(it.content.id) } withRel IanaLinkRelations.SELF
@@ -69,7 +70,7 @@ class WebMvcLinkBuilderDslUnitTest : TestUtils() {
@Test
fun `adds links to resourcesupport object`() {
val customer = CustomerResource("15", "John Doe")
val customer = CustomerModel("15", "John Doe")
customer.add(CustomerController::class) {
linkTo { findById(it.id) } withRel IanaLinkRelations.SELF
@@ -83,20 +84,20 @@ class WebMvcLinkBuilderDslUnitTest : TestUtils() {
data class Customer(val id: String, val name: String)
data class CustomerDTO(val name: String)
open class CustomerResource(val id: String, val name: String) : ResourceSupport()
open class ProductResource(val id: String) : ResourceSupport()
open class CustomerModel(val id: String, val name: String) : RepresentationModel<CustomerModel>()
open class ProductModel(val id: String) : RepresentationModel<ProductModel>()
@RequestMapping("/customers")
interface CustomerController {
@GetMapping("/{id}")
fun findById(@PathVariable id: String): ResponseEntity<CustomerResource>
fun findById(@PathVariable id: String): ResponseEntity<CustomerModel>
@GetMapping("/{id}/products")
fun findProductsById(@PathVariable id: String): PagedResources<ProductResource>
fun findProductsById(@PathVariable id: String): PagedModel<ProductModel>
@PutMapping("/{id}")
fun update(@PathVariable id: String, @RequestBody customer: CustomerDTO): ResponseEntity<CustomerResource>
fun update(@PathVariable id: String, @RequestBody customer: CustomerDTO): ResponseEntity<CustomerModel>
@DeleteMapping("/{id}")
fun delete(@PathVariable id: String): ResponseEntity<Unit>