Skip to content

Commit fececc6

Browse files
committed
feat: serialize _links
1 parent 9d082e6 commit fececc6

File tree

10 files changed

+108
-58
lines changed

10 files changed

+108
-58
lines changed

support/json/json-resources/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ dependencies {
1111
compile 'com.fasterxml.jackson.core:jackson-databind:2.9.0'
1212
compile 'com.fasterxml.jackson.core:jackson-annotations:2.9.0'
1313
compile 'com.fasterxml.jackson.core:jackson-core:2.9.0'
14+
compile 'com.damnhandy:handy-uri-templates:2.1.7'
1415
compile 'org.slf4j:slf4j-api:1.7.25'
1516

1617
testCompile project(':support:testing')

support/json/json-resources/src/main/java/sparkles/support/json/resources/Curie.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import java.lang.annotation.Target;
77

88
/**
9-
* Annotation specifying a CURIE for use with links. As defined by W3C in
9+
* Annotation specifying a CURIE for use with list. As defined by W3C in
1010
* <a href="https://www.w3.org/TR/2010/NOTE-curie-20101216/">CURIE Syntax 1.0</a>. Note that in
1111
* the context of HAL the only substitution done to the template URI of a curie is the
1212
* <code>{rel}</code> place holder.

support/json/json-resources/src/main/java/sparkles/support/json/resources/JacksonResourcesModule.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ public void serialize(Object value, JsonGenerator gen, SerializerProvider serial
164164
linksProps.put(rel, prop);
165165
} else if (object instanceof LinkCollection) {
166166
LinkCollection links = (LinkCollection) object;
167-
for (Link link : links.links()) {
167+
for (Link link : links.list()) {
168168
String rel = "".equals(link.rel()) ? prop.getName() : link.rel();
169169
linksProps.put(rel, prop);
170170
}
@@ -189,7 +189,7 @@ public void serialize(Object value, JsonGenerator gen, SerializerProvider serial
189189
gen.writeFieldName(rel);
190190
Object v = linksProps.get(rel).get(value);
191191
if (v instanceof LinkCollection || v instanceof Collection) {
192-
List<Link> links = v instanceof LinkCollection ? ((LinkCollection) v).links() : ((List<Link>) v);
192+
List<Link> links = v instanceof LinkCollection ? ((LinkCollection) v).list() : ((List<Link>) v);
193193
if (links.size() > 1) {
194194
gen.writeStartArray();
195195
}
@@ -350,8 +350,8 @@ public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOEx
350350

351351
JsonNode value = jsonProp.getValue();
352352
if (value.isArray()) {
353-
System.out.println("links array " + value.toString());
354-
//Iterator<Link> links = p.readValuesAs(Link.class);
353+
System.out.println("list array " + value.toString());
354+
//Iterator<Link> list = p.readValuesAs(Link.class);
355355

356356
/*
357357
ArrayNode arrayNode = (ArrayNode) value;

support/json/json-resources/src/main/java/sparkles/support/json/resources/JsonResourcesModule.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public void setupModule(SetupContext context) {
2323
// (/) add serializer + modifier
2424
// (/) add deserializer + modifier
2525
// - change serialization and deserialization...
26-
// - recognize custom @Embedded annotation
26+
// (/) recognize custom @Embedded annotation
2727
// - for @Links annotation and Link class
2828

2929
}

support/json/json-resources/src/main/java/sparkles/support/json/resources/Link.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package sparkles.support.json.resources;
22

3+
import com.fasterxml.jackson.annotation.JsonIgnore;
34
import com.fasterxml.jackson.annotation.JsonInclude;
45
import com.fasterxml.jackson.annotation.JsonProperty;
56

@@ -8,13 +9,13 @@
89

910
@Data
1011
@Accessors(fluent = true)
11-
@JsonInclude(JsonInclude.Include.NON_NULL)
12+
@JsonInclude(JsonInclude.Include.NON_EMPTY)
1213
public class Link {
1314

1415
@JsonProperty
1516
private String href;
1617

17-
@JsonProperty
18+
@JsonIgnore
1819
private String rel;
1920

2021
@JsonProperty
@@ -33,8 +34,9 @@ public class Link {
3334
@JsonProperty
3435
private String title;
3536

36-
3737
public String expand(Object... value) {
38+
// https://github.com/damnhandy/Handy-URI-Templates#basic-usage
39+
3840
if (this.templated) {
3941
// TODO: implement link expansion with uri templates
4042

@@ -44,4 +46,12 @@ public String expand(Object... value) {
4446
}
4547
}
4648

49+
public static Link withRel(String rel) {
50+
return new Link().rel(rel);
51+
}
52+
53+
public static Link withSelfRel() {
54+
return new Link().rel("self");
55+
}
56+
4757
}

support/json/json-resources/src/main/java/sparkles/support/json/resources/LinkCollection.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public LinkCollection clear() {
3939
return this;
4040
}
4141

42-
public List<Link> links() {
42+
public List<Link> list() {
4343
return links;
4444
}
4545

support/json/json-resources/src/main/java/sparkles/support/json/resources/internal/Serializer.java

Lines changed: 67 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828

2929
/**
3030
* Serializer to handle {@link Resource} beans ensuring they are serialized according to the HAL
31-
* specification. This implies placing links inside the <code>_links</code> property and embedded objects inside the <code>_embedded</code>
31+
* specification. This implies placing list inside the <code>_links</code> property and embedded objects inside the <code>_embedded</code>
3232
* property.
3333
*/
3434
public class Serializer extends BeanSerializerBase {
@@ -68,7 +68,7 @@ public void serialize(Object bean, JsonGenerator jgen, SerializerProvider provid
6868
}
6969

7070
/**
71-
* Modelling the properties of the bean segmented into HAL categories: links, embedded resources, and state
71+
* Modelling the properties of the bean segmented into HAL categories: list, embedded resources, and state
7272
*/
7373
private class FilteredProperties {
7474

@@ -81,8 +81,7 @@ private class FilteredProperties {
8181
// All of the curies that actually ARE being used (provided via Link annotations)
8282
private Set<String> curiesInUse = new TreeSet<>();
8383

84-
public FilteredProperties(Object bean, SerializerProvider provider,
85-
BeanDescription beanDescription) throws IOException {
84+
public FilteredProperties(Object bean, SerializerProvider provider, BeanDescription beanDescription) throws IOException {
8685

8786
populateCurieMap(beanDescription);
8887

@@ -98,20 +97,28 @@ public FilteredProperties(Object bean, SerializerProvider provider,
9897

9998
} else if (prop.getAnnotation(Links.class) != null) {
10099
Links l = prop.getAnnotation(Links.class);
101-
/*
102-
TODO
103-
String relation = "".equals(l.value()) ? prop.getName() : l.value();
104-
String curie = "".equals(l.curie()) ? null : l.curie();
105-
if (!"".equals(l.curie())) {
106-
curiesInUse.add(l.curie());
107-
}
108-
Object value = prop.get(bean);
109-
if (value instanceof Collection) {
110-
addLinks(relation, (Collection<HALLink>) prop.get(bean), curie);
111-
} else if (value instanceof HALLink) {
112-
addLink(relation, (HALLink) prop.get(bean), curie);
113-
}
114-
*/
100+
// TODO: curies support
101+
String curie = null;
102+
Object value = prop.get(bean);
103+
if (value instanceof LinkCollection) {
104+
addLinks((LinkCollection) prop.get(bean), curie);
105+
} else if (value instanceof Link) {
106+
addLink((Link) prop.get(bean), curie);
107+
}
108+
/*
109+
TODO
110+
String relation = "".equals(l.value()) ? prop.getName() : l.value();
111+
String curie = "".equals(l.curie()) ? null : l.curie();
112+
if (!"".equals(l.curie())) {
113+
curiesInUse.add(l.curie());
114+
}
115+
Object value = prop.get(bean);
116+
if (value instanceof Collection) {
117+
addLinks(relation, (Collection<HALLink>) prop.get(bean), curie);
118+
} else if (value instanceof HALLink) {
119+
addLink(relation, (HALLink) prop.get(bean), curie);
120+
}
121+
*/
115122
} else {
116123
state.add(prop);
117124
}
@@ -126,20 +133,20 @@ public FilteredProperties(Object bean, SerializerProvider provider,
126133
}
127134

128135
private void addCurieLinks() {
129-
/*
130-
TODO
131-
Collection<HALLink> curieLinks = new ArrayList<>();
132-
for (String curie: curiesInUse) {
133-
if (curieMap.containsKey(curie)) {
134-
curieLinks.add(new HALLink.Builder(curieMap.get(curie))
135-
.name(curie)
136-
.build());
137-
} else {
138-
LOG.warn("No Curie/Curies annotation provided for [{}]", curie);
139-
}
140-
}
141-
addLinks("curies", curieLinks, null);
142-
*/
136+
/*
137+
TODO
138+
Collection<HALLink> curieLinks = new ArrayList<>();
139+
for (String curie: curiesInUse) {
140+
if (curieMap.containsKey(curie)) {
141+
curieLinks.add(new HALLink.Builder(curieMap.get(curie))
142+
.name(curie)
143+
.build());
144+
} else {
145+
LOG.warn("No Curie/Curies annotation provided for [{}]", curie);
146+
}
147+
}
148+
addLinks("curies", curieLinks, null);
149+
*/
143150
}
144151

145152
private void populateCurieMap(BeanDescription beanDescription) {
@@ -209,15 +216,20 @@ private void addEmbeddedProperty(String rel, BeanPropertyWriter property) {
209216
}
210217
}
211218

212-
private void addLink(String rel, Link link, String curie) {
213-
if (links.put(applyCurieToRel(rel, curie), new LinkProperty(link)) != null) {
214-
LOG.warn("Link resource already existed with rel [{}] in class [{}]", rel, _handledType);
219+
private void addLink(Link link, String curie) {
220+
String rel = applyCurieToRel(link.rel(), curie);
221+
222+
if (links.containsKey(rel)) {
223+
LOG.warn("Link resource already existed with rel [{}] in class [{}]", link.rel(), _handledType);
224+
links.get(rel).add(link);
225+
} else {
226+
links.put(rel, new LinkProperty(link));
215227
}
216228
}
217229

218-
private void addLinks(String rel, LinkCollection links, String curie) {
219-
if (this.links.put(applyCurieToRel(rel, curie), new LinkProperty(links)) != null) {
220-
LOG.warn("Link resource already existed with rel [{}] in class [{}]", rel, _handledType);
230+
private void addLinks(LinkCollection links, String curie) {
231+
for (Link link : links.list()) {
232+
addLink(link, curie);
221233
}
222234
}
223235

@@ -228,27 +240,40 @@ private String applyCurieToRel(String rel, String curie) {
228240
}
229241

230242
/**
231-
* Representing either a single link (one-to-one relation) or a collection of links.
243+
* Representing either a single link (one-to-one relation) or a collection of list.
232244
*/
233245
private static class LinkProperty {
234246

235247
private Link link;
236-
private LinkCollection links;
248+
private List<Link> links;
237249

238250
public LinkProperty(Link link) {
239251
this.link = link;
240252
}
241253

242254
public LinkProperty(LinkCollection links) {
243-
this.links = links == null ? new LinkCollection() : links;
255+
this.links = links.list();
256+
}
257+
258+
public void add(Link value) {
259+
if (link == null) {
260+
link = value;
261+
} else {
262+
if (links == null) {
263+
links = new ArrayList<>();
264+
links.add(link);
265+
link = null;
266+
}
267+
links.add(value);
268+
}
244269
}
245270

246271
public void serialize(JsonGenerator jgen) throws IOException {
247272
if (link != null) {
248273
writeLinkObject(jgen, link);
249274
} else if (links != null) {
250275
jgen.writeStartArray();
251-
for (Link curLink : links.links()) {
276+
for (Link curLink : links) {
252277
writeLinkObject(jgen, curLink);
253278
}
254279
jgen.writeEndArray();

support/json/json-resources/src/test/java/sparkles/support/json/resources/JacksonResourcesModuleTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ public void itShouldDeserialize() throws IOException {
132132
assertThat(foo.entity.count).isEqualTo(2);
133133
/*
134134
assertThat(foo.getLinks()).isNotNull();
135-
assertThat(foo.getLinks().links()).hasSize(1);
135+
assertThat(foo.getLinks().list()).hasSize(1);
136136
*/
137137
assertThat(foo.getContent()).hasSize(2);
138138
}

support/json/json-resources/src/test/java/sparkles/support/json/resources/JsonResourcesModuleTest.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,18 @@ public void embedded_shouldDeserialize() throws Exception {
3434
assertThat(deserialized.related.name).isEqualTo("hello world!");
3535
}
3636

37+
@Test
38+
public void links_shouldSerialize() throws Exception {
39+
Foo foo = new Foo();
40+
foo.links = new LinkCollection()
41+
.add(Link.withSelfRel().href("/foo/bar"))
42+
.add(Link.withRel("bar").href("bar/123"))
43+
.add(Link.withRel("bar").href("bar/789"));
44+
45+
String serialized = om.writeValueAsString(foo);
46+
assertThat(serialized).isNull();
47+
}
48+
3749
@Test
3850
public void shouldSerializeProperties() throws Exception {
3951
Foo foo = new Foo();
@@ -48,7 +60,7 @@ public void itShouldConsiderOnlyResourceAnnotatedClasses() throws Exception {
4860
NoResource noResource = new NoResource();
4961
noResource.related = new Bar("foo");
5062
noResource.links = new LinkCollection()
51-
.add(new Link().rel("foo").href("/foo/bar"));
63+
.add(Link.withSelfRel().href("/foo/bar"));
5264

5365
String serialized = om.writeValueAsString(noResource);
5466
assertThat(serialized).doesNotContain("_embedded");
@@ -88,7 +100,9 @@ public Bar(String name) {
88100

89101
@Override
90102
public String toString() {
91-
return "Bar[name=" + name + "]";
103+
return new ToStringBuilder(Bar.class)
104+
.append("name", name)
105+
.toString();
92106
}
93107
}
94108

support/json/json-resources/src/test/java/sparkles/support/json/resources/LinkCollectionTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ public void add_shouldAddToBag() {
2222
l.add(one);
2323
l.add(two);
2424

25-
assertThat(l.links()).hasSize(2);
26-
assertThat(l.links()).contains(one, two);
25+
assertThat(l.list()).hasSize(2);
26+
assertThat(l.list()).contains(one, two);
2727
}
2828

2929
@Test
@@ -35,7 +35,7 @@ public void clear_shouldClearTheBag() {
3535
);
3636
l.clear();
3737

38-
assertThat(l.links()).hasSize(0);
38+
assertThat(l.list()).hasSize(0);
3939
}
4040

4141
@Test

0 commit comments

Comments
 (0)