17
17
18
18
import java .io .IOException ;
19
19
import java .lang .reflect .Type ;
20
- import java .util .ArrayList ;
21
- import java .util .Collection ;
22
- import java .util .HashMap ;
23
- import java .util .Iterator ;
24
- import java .util .LinkedHashMap ;
25
- import java .util .List ;
26
- import java .util .Map ;
20
+ import java .util .*;
27
21
28
22
import org .springframework .beans .BeanUtils ;
29
- import org .springframework .hateoas .Link ;
30
- import org .springframework .hateoas .Links ;
31
- import org .springframework .hateoas .RelProvider ;
32
- import org .springframework .hateoas .Resource ;
33
- import org .springframework .hateoas .ResourceSupport ;
34
- import org .springframework .hateoas .Resources ;
23
+ import org .springframework .core .annotation .AnnotationUtils ;
24
+ import org .springframework .hateoas .*;
35
25
import org .springframework .util .Assert ;
36
26
37
27
import com .fasterxml .jackson .core .JsonGenerationException ;
@@ -130,15 +120,29 @@ public HalLinkListSerializer(BeanProperty property, CurieProvider curieProvider)
130
120
public void serialize (List <Link > value , JsonGenerator jgen , SerializerProvider provider ) throws IOException ,
131
121
JsonGenerationException {
132
122
123
+
124
+ // keeps track of any rels that need their links to be forced as multiple (i.e., serialized to array)
125
+ // regardless of cardinality
126
+ List <String > forcedMultipleLinkRels = new ArrayList <String >();
127
+ if (!value .isEmpty ()) {
128
+ Class <? extends ResourceSupport > owningResource = value .get (0 ).getOwningResource ();
129
+ ForceMultipleLinksOnRels annotation = AnnotationUtils .findAnnotation (owningResource , ForceMultipleLinksOnRels .class );
130
+ if (annotation != null ) {
131
+ forcedMultipleLinkRels .addAll (Arrays .asList (annotation .value ()));
132
+ }
133
+ }
134
+
133
135
// sort links according to their relation
134
136
Map <String , List <Object >> sortedLinks = new LinkedHashMap <String , List <Object >>();
137
+
135
138
List <Link > links = new ArrayList <Link >();
136
139
137
140
boolean prefixingRequired = curieProvider != null ;
138
141
boolean curiedLinkPresent = false ;
139
142
140
143
for (Link link : value ) {
141
144
145
+
142
146
String rel = prefixingRequired ? curieProvider .getNamespacedRelFrom (link ) : link .getRel ();
143
147
144
148
if (!link .getRel ().equals (rel )) {
@@ -167,7 +171,7 @@ public void serialize(List<Link> value, JsonGenerator jgen, SerializerProvider p
167
171
JavaType mapType = typeFactory .constructMapType (HashMap .class , keyType , valueType );
168
172
169
173
MapSerializer serializer = MapSerializer .construct (new String [] {}, mapType , true , null ,
170
- provider .findKeySerializer (keyType , null ), new OptionalListJackson2Serializer (property ), null );
174
+ provider .findKeySerializer (keyType , null ), new OptionalListJackson2Serializer (property , forcedMultipleLinkRels ), null );
171
175
172
176
serializer .serialize (sortedLinks , jgen , provider );
173
177
}
@@ -320,6 +324,7 @@ public static class OptionalListJackson2Serializer extends ContainerSerializer<O
320
324
321
325
private final BeanProperty property ;
322
326
private final Map <Class <?>, JsonSerializer <Object >> serializers ;
327
+ private final List <String > forcedMultipleLinkRels ;
323
328
324
329
public OptionalListJackson2Serializer () {
325
330
this (null );
@@ -331,10 +336,24 @@ public OptionalListJackson2Serializer() {
331
336
* @param property
332
337
*/
333
338
public OptionalListJackson2Serializer (BeanProperty property ) {
339
+ this (property , new ArrayList <String >());
340
+ }
341
+
342
+ /**
343
+ * Private constructor that creates a new instance using the given {@link BeanProperty}
344
+ * and a list of rels whose links need to be forced into an array representation regardless of
345
+ * cardinality.
346
+ *
347
+ * @param property
348
+ * @param forcedMultipleLinkRels
349
+ */
350
+ private OptionalListJackson2Serializer (BeanProperty property , List <String > forcedMultipleLinkRels ) {
334
351
335
352
super (List .class , false );
353
+
336
354
this .property = property ;
337
355
this .serializers = new HashMap <Class <?>, JsonSerializer <Object >>();
356
+ this .forcedMultipleLinkRels = forcedMultipleLinkRels ;
338
357
}
339
358
340
359
/*
@@ -360,14 +379,13 @@ public void serialize(Object value, JsonGenerator jgen, SerializerProvider provi
360
379
return ;
361
380
}
362
381
363
- if (list .size () == 1 ) {
364
- serializeContents (list .iterator (), jgen , provider );
365
- return ;
382
+ if (list .size () > 1 || ((list .get (0 ) instanceof Link ) && forcedMultipleLinkRels .contains (((Link ) list .get (0 )).getRel ()))) {
383
+ jgen .writeStartArray ();
384
+ serializeContents (list .iterator (), jgen , provider );
385
+ jgen .writeEndArray ();
386
+ } else {
387
+ serializeContents (list .iterator (), jgen , provider );
366
388
}
367
-
368
- jgen .writeStartArray ();
369
- serializeContents (list .iterator (), jgen , provider );
370
- jgen .writeEndArray ();
371
389
}
372
390
373
391
private void serializeContents (Iterator <?> value , JsonGenerator jgen , SerializerProvider provider )
0 commit comments