Skip to content

Commit ce5e66b

Browse files
committed
[spring-projects#1300] Integrate abstract class for collection model
1 parent f3198b7 commit ce5e66b

15 files changed

+183
-108
lines changed
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
/*
2+
* Copyright 2012-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.hateoas;
17+
18+
import com.fasterxml.jackson.annotation.JsonProperty;
19+
import org.springframework.lang.Nullable;
20+
import org.springframework.util.Assert;
21+
22+
import java.util.ArrayList;
23+
import java.util.Arrays;
24+
import java.util.Collection;
25+
import java.util.Collections;
26+
import java.util.Iterator;
27+
import java.util.Objects;
28+
import java.util.function.Supplier;
29+
30+
/**
31+
* General helper to easily create a wrapper for a collection of entities.
32+
*
33+
* @author Oliver Gierke
34+
* @author Greg Turnquist
35+
*/
36+
public class AbstractCollectionModel<S extends AbstractCollectionModel<S,T>, T> extends RepresentationModel<S> implements Iterable<T> {
37+
38+
private final Collection<T> content;
39+
40+
public AbstractCollectionModel() {
41+
this(new ArrayList<>(), Collections.emptyList());
42+
}
43+
44+
/**
45+
* Creates a {@link AbstractCollectionModel} instance with the given content and {@link Link}s.
46+
*
47+
* @param content must not be {@literal null}.
48+
* @param links the links to be added to the {@link AbstractCollectionModel}.
49+
*/
50+
protected AbstractCollectionModel(Iterable<T> content, Iterable<Link> links) {
51+
52+
Assert.notNull(content, "Content must not be null!");
53+
54+
this.content = new ArrayList<>();
55+
56+
for (T element : content) {
57+
this.content.add(element);
58+
}
59+
60+
this.add(links);
61+
}
62+
63+
/**
64+
* Returns the underlying elements.
65+
*
66+
* @return the content will never be {@literal null}.
67+
*/
68+
@JsonProperty("content")
69+
public Collection<T> getContent() {
70+
return Collections.unmodifiableCollection(content);
71+
}
72+
73+
/*
74+
* (non-Javadoc)
75+
* @see java.lang.Iterable#iterator()
76+
*/
77+
@Override
78+
public Iterator<T> iterator() {
79+
return content.iterator();
80+
}
81+
82+
/*
83+
* (non-Javadoc)
84+
* @see org.springframework.hateoas.ResourceSupport#equals(java.lang.Object)
85+
*/
86+
@Override
87+
public boolean equals(@Nullable Object obj) {
88+
89+
if (obj == this) {
90+
return true;
91+
}
92+
93+
if (obj == null || !obj.getClass().equals(getClass())) {
94+
return false;
95+
}
96+
97+
if (!super.equals(obj)) {
98+
return false;
99+
}
100+
101+
AbstractCollectionModel<?, ?> that = (AbstractCollectionModel<?,?>) obj;
102+
return Objects.equals(this.content, that.content);
103+
}
104+
105+
/*
106+
* (non-Javadoc)
107+
* @see org.springframework.hateoas.ResourceSupport#hashCode()
108+
*/
109+
@Override
110+
public int hashCode() {
111+
int result = super.hashCode();
112+
result += 17 * Objects.hashCode(content);
113+
return result;
114+
}
115+
116+
}

src/main/java/org/springframework/hateoas/CollectionModel.java

Lines changed: 2 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,7 @@
3232
* @author Oliver Gierke
3333
* @author Greg Turnquist
3434
*/
35-
public class CollectionModel<T> extends RepresentationModel<CollectionModel<T>> implements Iterable<T> {
36-
37-
private final Collection<T> content;
35+
public class CollectionModel<T> extends AbstractCollectionModel<CollectionModel<T>, T> implements Iterable<T> {
3836

3937
/**
4038
* Creates an empty {@link CollectionModel} instance.
@@ -64,16 +62,7 @@ public CollectionModel(Iterable<T> content, Link... links) {
6462
*/
6563
@Deprecated
6664
public CollectionModel(Iterable<T> content, Iterable<Link> links) {
67-
68-
Assert.notNull(content, "Content must not be null!");
69-
70-
this.content = new ArrayList<>();
71-
72-
for (T element : content) {
73-
this.content.add(element);
74-
}
75-
76-
this.add(links);
65+
super(content, links);
7766
}
7867

7968
/**
@@ -115,7 +104,6 @@ public static <T> CollectionModel<T> empty(Iterable<Link> links) {
115104
* Creates a {@link CollectionModel} instance with the given content.
116105
*
117106
* @param content must not be {@literal null}.
118-
* @param links the links to be added to the {@link CollectionModel}.
119107
* @return
120108
* @since 1.1
121109
*/
@@ -168,25 +156,6 @@ public static <T extends EntityModel<S>, S> CollectionModel<T> wrap(Iterable<S>
168156
return CollectionModel.of(resources);
169157
}
170158

171-
/**
172-
* Returns the underlying elements.
173-
*
174-
* @return the content will never be {@literal null}.
175-
*/
176-
@JsonProperty("content")
177-
public Collection<T> getContent() {
178-
return Collections.unmodifiableCollection(content);
179-
}
180-
181-
/*
182-
* (non-Javadoc)
183-
* @see java.lang.Iterable#iterator()
184-
*/
185-
@Override
186-
public Iterator<T> iterator() {
187-
return content.iterator();
188-
}
189-
190159
/*
191160
* (non-Javadoc)
192161
* @see org.springframework.hateoas.ResourceSupport#toString()
@@ -196,37 +165,4 @@ public String toString() {
196165
return String.format("Resources { content: %s, %s }", getContent(), super.toString());
197166
}
198167

199-
/*
200-
* (non-Javadoc)
201-
* @see org.springframework.hateoas.ResourceSupport#equals(java.lang.Object)
202-
*/
203-
@Override
204-
public boolean equals(@Nullable Object obj) {
205-
206-
if (obj == this) {
207-
return true;
208-
}
209-
210-
if (obj == null || !obj.getClass().equals(getClass())) {
211-
return false;
212-
}
213-
214-
CollectionModel<?> that = (CollectionModel<?>) obj;
215-
216-
boolean contentEqual = this.content == null ? that.content == null : this.content.equals(that.content);
217-
return contentEqual && super.equals(obj);
218-
}
219-
220-
/*
221-
* (non-Javadoc)
222-
* @see org.springframework.hateoas.ResourceSupport#hashCode()
223-
*/
224-
@Override
225-
public int hashCode() {
226-
227-
int result = super.hashCode();
228-
result += content == null ? 0 : 17 * content.hashCode();
229-
230-
return result;
231-
}
232168
}

src/main/java/org/springframework/hateoas/EntityModel.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ public EntityModel(T content, Iterable<Link> links) {
7878
* Creates a new {@link EntityModel} with the given content.
7979
*
8080
* @param content must not be {@literal null}.
81-
* @param links the links to add to the {@link EntityModel}.
8281
* @return
8382
* @since 1.1
8483
*/

src/main/java/org/springframework/hateoas/PagedModel.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.util.Arrays;
2020
import java.util.Collection;
2121
import java.util.Collections;
22+
import java.util.Objects;
2223
import java.util.Optional;
2324

2425
import org.springframework.lang.Nullable;
@@ -33,7 +34,7 @@
3334
* @author Oliver Gierke
3435
* @author Greg Turnquist
3536
*/
36-
public class PagedModel<T> extends CollectionModel<T> {
37+
public class PagedModel<T> extends AbstractCollectionModel<PagedModel<T>, T> {
3738

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

@@ -153,7 +154,6 @@ public static <T> PagedModel<T> empty(@Nullable PageMetadata metadata, Iterable<
153154
*
154155
* @param content must not be {@literal null}.
155156
* @param metadata can be {@literal null}.
156-
* @param links
157157
*/
158158
public static <T> PagedModel<T> of(Collection<T> content, @Nullable PageMetadata metadata) {
159159
return new PagedModel<>(content, metadata);
@@ -256,10 +256,12 @@ public boolean equals(@Nullable Object obj) {
256256
return false;
257257
}
258258

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

262-
return metadataEquals && super.equals(obj);
263+
PagedModel<?> that = (PagedModel<?>) obj;
264+
return Objects.equals(this.metadata, that.metadata);
263265
}
264266

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

272274
int result = super.hashCode();
273-
result += this.metadata == null ? 0 : 31 * this.metadata.hashCode();
275+
result += 31 * Objects.hashCode(this.metadata);
274276
return result;
275277
}
276278

src/main/java/org/springframework/hateoas/mediatype/collectionjson/Jackson2CollectionJsonModule.java

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import java.util.function.Function;
2424
import java.util.stream.Collectors;
2525

26+
import org.springframework.hateoas.AbstractCollectionModel;
2627
import org.springframework.hateoas.Affordance;
2728
import org.springframework.hateoas.CollectionModel;
2829
import org.springframework.hateoas.EntityModel;
@@ -793,22 +794,22 @@ public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanPro
793794
}
794795
}
795796

796-
static abstract class CollectionJsonDeserializerBase<T extends CollectionModel<?>>
797+
static abstract class AbstractCollectionJsonDeserializer<T extends AbstractCollectionModel<?, ?>>
797798
extends ContainerDeserializerBase<T> implements ContextualDeserializer {
798799

799800
private static final long serialVersionUID = 1007769482339850545L;
800801

801802
private final JavaType contentType;
802803
private final BiFunction<List<Object>, Links, T> finalizer;
803-
private final Function<JavaType, CollectionJsonDeserializerBase<T>> creator;
804+
private final Function<JavaType, AbstractCollectionJsonDeserializer<T>> creator;
804805

805-
CollectionJsonDeserializerBase(BiFunction<List<Object>, Links, T> finalizer,
806-
Function<JavaType, CollectionJsonDeserializerBase<T>> creator) {
806+
AbstractCollectionJsonDeserializer(BiFunction<List<Object>, Links, T> finalizer,
807+
Function<JavaType, AbstractCollectionJsonDeserializer<T>> creator) {
807808
this(TypeFactory.defaultInstance().constructType(CollectionJson.class), finalizer, creator);
808809
}
809810

810-
private CollectionJsonDeserializerBase(JavaType contentType, BiFunction<List<Object>, Links, T> finalizer,
811-
Function<JavaType, CollectionJsonDeserializerBase<T>> creator) {
811+
private AbstractCollectionJsonDeserializer(JavaType contentType, BiFunction<List<Object>, Links, T> finalizer,
812+
Function<JavaType, AbstractCollectionJsonDeserializer<T>> creator) {
812813

813814
super(contentType);
814815

@@ -883,11 +884,11 @@ public T deserialize(JsonParser parser, DeserializationContext ctxt) throws IOEx
883884
}
884885
}
885886

886-
static class CollectionJsonResourcesDeserializer extends CollectionJsonDeserializerBase<CollectionModel<?>> {
887+
static class CollectionJsonResourcesDeserializer extends AbstractCollectionJsonDeserializer<CollectionModel<?>> {
887888

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

892893
CollectionJsonResourcesDeserializer() {
893894
super(FINISHER, CONTEXTUAL_CREATOR);
@@ -898,12 +899,12 @@ private CollectionJsonResourcesDeserializer(JavaType contentType) {
898899
}
899900
}
900901

901-
static class CollectionJsonPagedResourcesDeserializer extends CollectionJsonDeserializerBase<PagedModel<?>> {
902+
static class CollectionJsonPagedResourcesDeserializer extends AbstractCollectionJsonDeserializer<PagedModel<?>> {
902903

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

908909
CollectionJsonPagedResourcesDeserializer() {
909910
super(FINISHER, CONTEXTUAL_CREATOR);
@@ -914,7 +915,7 @@ private CollectionJsonPagedResourcesDeserializer(JavaType contentType) {
914915
}
915916
}
916917

917-
private static List<CollectionJsonItem<Object>> resourcesToCollectionJsonItems(CollectionModel<?> resources) {
918+
private static List<CollectionJsonItem<Object>> resourcesToCollectionJsonItems(AbstractCollectionModel<?,?> resources) {
918919

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

src/main/java/org/springframework/hateoas/mediatype/hal/forms/HalFormsSerializers.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import java.io.IOException;
1919
import java.util.Map;
2020

21+
import org.springframework.hateoas.AbstractCollectionModel;
2122
import org.springframework.hateoas.CollectionModel;
2223
import org.springframework.hateoas.EntityModel;
2324
import org.springframework.hateoas.PagedModel;
@@ -209,7 +210,7 @@ public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty
209210
/**
210211
* Serializer for {@link CollectionModel}
211212
*/
212-
static class HalFormsCollectionModelSerializer extends ContainerSerializer<CollectionModel<?>>
213+
static class HalFormsCollectionModelSerializer extends ContainerSerializer<AbstractCollectionModel<?,?>>
213214
implements ContextualSerializer {
214215

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

247248
EmbeddedMapper mapper = configuration.isApplyPropertyNamingStrategy() //
248249
? embeddedMapper.with(provider.getConfig().getPropertyNamingStrategy()) //
@@ -297,7 +298,7 @@ public JsonSerializer<?> getContentSerializer() {
297298
*/
298299
@Override
299300
@SuppressWarnings("null")
300-
public boolean hasSingleElement(CollectionModel<?> resources) {
301+
public boolean hasSingleElement(AbstractCollectionModel<?,?> resources) {
301302
return resources.getContent().size() == 1;
302303
}
303304

0 commit comments

Comments
 (0)