Skip to content

Commit

Permalink
[spring-projects#1300] Integrate abstract class for collection model
Browse files Browse the repository at this point in the history
  • Loading branch information
Patouche committed Jun 3, 2020
1 parent f3198b7 commit ce5e66b
Show file tree
Hide file tree
Showing 15 changed files with 183 additions and 108 deletions.
116 changes: 116 additions & 0 deletions src/main/java/org/springframework/hateoas/AbstractCollectionModel.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/*
* Copyright 2012-2020 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
*
* https://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;

import com.fasterxml.jackson.annotation.JsonProperty;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.Objects;
import java.util.function.Supplier;

/**
* General helper to easily create a wrapper for a collection of entities.
*
* @author Oliver Gierke
* @author Greg Turnquist
*/
public class AbstractCollectionModel<S extends AbstractCollectionModel<S,T>, T> extends RepresentationModel<S> implements Iterable<T> {

private final Collection<T> content;

public AbstractCollectionModel() {
this(new ArrayList<>(), Collections.emptyList());
}

/**
* Creates a {@link AbstractCollectionModel} 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 AbstractCollectionModel}.
*/
protected AbstractCollectionModel(Iterable<T> content, Iterable<Link> links) {

Assert.notNull(content, "Content must not be null!");

this.content = new ArrayList<>();

for (T element : content) {
this.content.add(element);
}

this.add(links);
}

/**
* Returns the underlying elements.
*
* @return the content will never be {@literal null}.
*/
@JsonProperty("content")
public Collection<T> getContent() {
return Collections.unmodifiableCollection(content);
}

/*
* (non-Javadoc)
* @see java.lang.Iterable#iterator()
*/
@Override
public Iterator<T> iterator() {
return content.iterator();
}

/*
* (non-Javadoc)
* @see org.springframework.hateoas.ResourceSupport#equals(java.lang.Object)
*/
@Override
public boolean equals(@Nullable Object obj) {

if (obj == this) {
return true;
}

if (obj == null || !obj.getClass().equals(getClass())) {
return false;
}

if (!super.equals(obj)) {
return false;
}

AbstractCollectionModel<?, ?> that = (AbstractCollectionModel<?,?>) obj;
return Objects.equals(this.content, that.content);
}

/*
* (non-Javadoc)
* @see org.springframework.hateoas.ResourceSupport#hashCode()
*/
@Override
public int hashCode() {
int result = super.hashCode();
result += 17 * Objects.hashCode(content);
return result;
}

}
68 changes: 2 additions & 66 deletions src/main/java/org/springframework/hateoas/CollectionModel.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,7 @@
* @author Oliver Gierke
* @author Greg Turnquist
*/
public class CollectionModel<T> extends RepresentationModel<CollectionModel<T>> implements Iterable<T> {

private final Collection<T> content;
public class CollectionModel<T> extends AbstractCollectionModel<CollectionModel<T>, T> implements Iterable<T> {

/**
* Creates an empty {@link CollectionModel} instance.
Expand Down Expand Up @@ -64,16 +62,7 @@ public CollectionModel(Iterable<T> content, Link... links) {
*/
@Deprecated
public CollectionModel(Iterable<T> content, Iterable<Link> links) {

Assert.notNull(content, "Content must not be null!");

this.content = new ArrayList<>();

for (T element : content) {
this.content.add(element);
}

this.add(links);
super(content, links);
}

/**
Expand Down Expand Up @@ -115,7 +104,6 @@ public static <T> CollectionModel<T> empty(Iterable<Link> links) {
* Creates a {@link CollectionModel} instance with the given content.
*
* @param content must not be {@literal null}.
* @param links the links to be added to the {@link CollectionModel}.
* @return
* @since 1.1
*/
Expand Down Expand Up @@ -168,25 +156,6 @@ public static <T extends EntityModel<S>, S> CollectionModel<T> wrap(Iterable<S>
return CollectionModel.of(resources);
}

/**
* Returns the underlying elements.
*
* @return the content will never be {@literal null}.
*/
@JsonProperty("content")
public Collection<T> getContent() {
return Collections.unmodifiableCollection(content);
}

/*
* (non-Javadoc)
* @see java.lang.Iterable#iterator()
*/
@Override
public Iterator<T> iterator() {
return content.iterator();
}

/*
* (non-Javadoc)
* @see org.springframework.hateoas.ResourceSupport#toString()
Expand All @@ -196,37 +165,4 @@ public String toString() {
return String.format("Resources { content: %s, %s }", getContent(), super.toString());
}

/*
* (non-Javadoc)
* @see org.springframework.hateoas.ResourceSupport#equals(java.lang.Object)
*/
@Override
public boolean equals(@Nullable Object obj) {

if (obj == this) {
return true;
}

if (obj == null || !obj.getClass().equals(getClass())) {
return false;
}

CollectionModel<?> that = (CollectionModel<?>) 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()
*/
@Override
public int hashCode() {

int result = super.hashCode();
result += content == null ? 0 : 17 * content.hashCode();

return result;
}
}
1 change: 0 additions & 1 deletion src/main/java/org/springframework/hateoas/EntityModel.java
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ public EntityModel(T content, Iterable<Link> links) {
* Creates a new {@link EntityModel} with the given content.
*
* @param content must not be {@literal null}.
* @param links the links to add to the {@link EntityModel}.
* @return
* @since 1.1
*/
Expand Down
14 changes: 8 additions & 6 deletions src/main/java/org/springframework/hateoas/PagedModel.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Objects;
import java.util.Optional;

import org.springframework.lang.Nullable;
Expand All @@ -33,7 +34,7 @@
* @author Oliver Gierke
* @author Greg Turnquist
*/
public class PagedModel<T> extends CollectionModel<T> {
public class PagedModel<T> extends AbstractCollectionModel<PagedModel<T>, T> {

public static PagedModel<?> NO_PAGE = new PagedModel<>();

Expand Down Expand Up @@ -153,7 +154,6 @@ public static <T> PagedModel<T> empty(@Nullable PageMetadata metadata, Iterable<
*
* @param content must not be {@literal null}.
* @param metadata can be {@literal null}.
* @param links
*/
public static <T> PagedModel<T> of(Collection<T> content, @Nullable PageMetadata metadata) {
return new PagedModel<>(content, metadata);
Expand Down Expand Up @@ -256,10 +256,12 @@ public boolean equals(@Nullable Object obj) {
return false;
}

PagedModel<?> that = (PagedModel<?>) obj;
boolean metadataEquals = this.metadata == null ? that.metadata == null : this.metadata.equals(that.metadata);
if (!super.equals(obj)) {
return false;
}

return metadataEquals && super.equals(obj);
PagedModel<?> that = (PagedModel<?>) obj;
return Objects.equals(this.metadata, that.metadata);
}

/*
Expand All @@ -270,7 +272,7 @@ public boolean equals(@Nullable Object obj) {
public int hashCode() {

int result = super.hashCode();
result += this.metadata == null ? 0 : 31 * this.metadata.hashCode();
result += 31 * Objects.hashCode(this.metadata);
return result;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.util.function.Function;
import java.util.stream.Collectors;

import org.springframework.hateoas.AbstractCollectionModel;
import org.springframework.hateoas.Affordance;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.EntityModel;
Expand Down Expand Up @@ -793,22 +794,22 @@ public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanPro
}
}

static abstract class CollectionJsonDeserializerBase<T extends CollectionModel<?>>
static abstract class AbstractCollectionJsonDeserializer<T extends AbstractCollectionModel<?, ?>>
extends ContainerDeserializerBase<T> implements ContextualDeserializer {

private static final long serialVersionUID = 1007769482339850545L;

private final JavaType contentType;
private final BiFunction<List<Object>, Links, T> finalizer;
private final Function<JavaType, CollectionJsonDeserializerBase<T>> creator;
private final Function<JavaType, AbstractCollectionJsonDeserializer<T>> creator;

CollectionJsonDeserializerBase(BiFunction<List<Object>, Links, T> finalizer,
Function<JavaType, CollectionJsonDeserializerBase<T>> creator) {
AbstractCollectionJsonDeserializer(BiFunction<List<Object>, Links, T> finalizer,
Function<JavaType, AbstractCollectionJsonDeserializer<T>> creator) {
this(TypeFactory.defaultInstance().constructType(CollectionJson.class), finalizer, creator);
}

private CollectionJsonDeserializerBase(JavaType contentType, BiFunction<List<Object>, Links, T> finalizer,
Function<JavaType, CollectionJsonDeserializerBase<T>> creator) {
private AbstractCollectionJsonDeserializer(JavaType contentType, BiFunction<List<Object>, Links, T> finalizer,
Function<JavaType, AbstractCollectionJsonDeserializer<T>> creator) {

super(contentType);

Expand Down Expand Up @@ -883,11 +884,11 @@ public T deserialize(JsonParser parser, DeserializationContext ctxt) throws IOEx
}
}

static class CollectionJsonResourcesDeserializer extends CollectionJsonDeserializerBase<CollectionModel<?>> {
static class CollectionJsonResourcesDeserializer extends AbstractCollectionJsonDeserializer<CollectionModel<?>> {

private static final long serialVersionUID = 6406522912020578141L;
private static final BiFunction<List<Object>, Links, CollectionModel<?>> FINISHER = CollectionModel::of;
private static final Function<JavaType, CollectionJsonDeserializerBase<CollectionModel<?>>> CONTEXTUAL_CREATOR = CollectionJsonResourcesDeserializer::new;
private static final Function<JavaType, AbstractCollectionJsonDeserializer<CollectionModel<?>>> CONTEXTUAL_CREATOR = CollectionJsonResourcesDeserializer::new;

CollectionJsonResourcesDeserializer() {
super(FINISHER, CONTEXTUAL_CREATOR);
Expand All @@ -898,12 +899,12 @@ private CollectionJsonResourcesDeserializer(JavaType contentType) {
}
}

static class CollectionJsonPagedResourcesDeserializer extends CollectionJsonDeserializerBase<PagedModel<?>> {
static class CollectionJsonPagedResourcesDeserializer extends AbstractCollectionJsonDeserializer<PagedModel<?>> {

private static final long serialVersionUID = -7465448422501330790L;
private static final BiFunction<List<Object>, Links, PagedModel<?>> FINISHER = (content, links) -> PagedModel
.of(content, null, links);
private static final Function<JavaType, CollectionJsonDeserializerBase<PagedModel<?>>> CONTEXTUAL_CREATOR = CollectionJsonPagedResourcesDeserializer::new;
private static final Function<JavaType, AbstractCollectionJsonDeserializer<PagedModel<?>>> CONTEXTUAL_CREATOR = CollectionJsonPagedResourcesDeserializer::new;

CollectionJsonPagedResourcesDeserializer() {
super(FINISHER, CONTEXTUAL_CREATOR);
Expand All @@ -914,7 +915,7 @@ private CollectionJsonPagedResourcesDeserializer(JavaType contentType) {
}
}

private static List<CollectionJsonItem<Object>> resourcesToCollectionJsonItems(CollectionModel<?> resources) {
private static List<CollectionJsonItem<Object>> resourcesToCollectionJsonItems(AbstractCollectionModel<?,?> resources) {

return resources.getContent().stream().map(content -> {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.io.IOException;
import java.util.Map;

import org.springframework.hateoas.AbstractCollectionModel;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.PagedModel;
Expand Down Expand Up @@ -209,7 +210,7 @@ public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty
/**
* Serializer for {@link CollectionModel}
*/
static class HalFormsCollectionModelSerializer extends ContainerSerializer<CollectionModel<?>>
static class HalFormsCollectionModelSerializer extends ContainerSerializer<AbstractCollectionModel<?,?>>
implements ContextualSerializer {

private static final long serialVersionUID = -3601146866067500734L;
Expand Down Expand Up @@ -242,7 +243,7 @@ static class HalFormsCollectionModelSerializer extends ContainerSerializer<Colle
*/
@Override
@SuppressWarnings("null")
public void serialize(CollectionModel<?> value, JsonGenerator gen, SerializerProvider provider) throws IOException {
public void serialize(AbstractCollectionModel<?,?> value, JsonGenerator gen, SerializerProvider provider) throws IOException {

EmbeddedMapper mapper = configuration.isApplyPropertyNamingStrategy() //
? embeddedMapper.with(provider.getConfig().getPropertyNamingStrategy()) //
Expand Down Expand Up @@ -297,7 +298,7 @@ public JsonSerializer<?> getContentSerializer() {
*/
@Override
@SuppressWarnings("null")
public boolean hasSingleElement(CollectionModel<?> resources) {
public boolean hasSingleElement(AbstractCollectionModel<?,?> resources) {
return resources.getContent().size() == 1;
}

Expand Down
Loading

0 comments on commit ce5e66b

Please sign in to comment.