#833 - Changed ResourceSupport class name hierarchy.
This commit is contained in:
@@ -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);
|
||||
@@ -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()
|
||||
*/
|
||||
@@ -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);
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -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())));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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> {
|
||||
|
||||
}
|
||||
@@ -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> {
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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> {
|
||||
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
@@ -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")
|
||||
@@ -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}.
|
||||
*/
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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")
|
||||
@@ -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") //
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
*/
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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) {
|
||||
@@ -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);
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user