Skip to content

Commit cf9d317

Browse files
committed
Reworking the deserialization some more
1 parent 2b5b199 commit cf9d317

File tree

6 files changed

+85
-81
lines changed

6 files changed

+85
-81
lines changed

src/main/java/io/openapitools/jackson/dataformat/hal/deser/CurieMapping.java renamed to src/main/java/io/openapitools/jackson/dataformat/hal/deser/CurieMap.java

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package io.openapitools.jackson.dataformat.hal.deser;
22

33
import io.openapitools.jackson.dataformat.hal.annotation.Curie;
4-
import java.lang.management.OperatingSystemMXBean;
54
import java.net.URI;
65
import java.util.Arrays;
76
import java.util.Objects;
@@ -10,23 +9,26 @@
109
import java.util.concurrent.ConcurrentHashMap;
1110

1211
/**
13-
* Defining mapping of a curie in the context of HAL. That is this will only substitute
14-
* a curie reference into <code>{rel}</code> of a templated URI.
12+
* Defining map of a curies in the context of HAL. That is, this will only substitute
13+
* a curie reference into the <code>{rel}</code> placeholder of a templated URI.
1514
*
16-
* @see <a href="https://www.w3.org/TR/2010/NOTE-curie-20101216/">CURIE SYntax 1.0</a>
15+
* @see <a href="https://www.w3.org/TR/2010/NOTE-curie-20101216/">CURIE Syntax 1.0</a>
1716
*/
18-
public class CurieMapping {
17+
public class CurieMap {
1918

2019
private final ConcurrentHashMap<String, String> mappings = new ConcurrentHashMap<>();
2120

2221

23-
public CurieMapping(Mapping... mappings) {
22+
public CurieMap(Mapping... mappings) {
2423
Objects.requireNonNull(mappings, "Non-null array must be provided");
2524
Arrays.stream(mappings).forEach(m -> this.mappings.put(m.prefix, m.template));
2625
}
2726

2827
/**
2928
* Resolve the given curie using this mapping. Return empty if no relevant mapping could be found.
29+
*
30+
* @param curie Curie to resolve using this map in the standard form <code>prefix:rel</code>
31+
* @return Resolved URI if map contained mapping for the given prefix - empty otherwise
3032
*/
3133
public Optional<URI> resolve(String curie) {
3234
StringTokenizer st = new StringTokenizer(curie, ":");
@@ -43,6 +45,9 @@ public Optional<URI> resolve(String curie) {
4345
}
4446
}
4547

48+
/**
49+
* A single mapping definition in the map.
50+
*/
4651
public static class Mapping {
4752
private final String prefix;
4853
private final String template;

src/main/java/io/openapitools/jackson/dataformat/hal/deser/HALBeanDeserializer.java

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@
1212
import com.fasterxml.jackson.databind.node.ObjectNode;
1313
import java.io.IOException;
1414
import java.net.URI;
15-
import java.util.ArrayList;
1615
import java.util.Iterator;
16+
import java.util.List;
1717
import java.util.Map;
18+
import java.util.stream.Collectors;
19+
import java.util.stream.StreamSupport;
1820

1921
/**
2022
* Deserializer to handle incoming application/hal+json.
@@ -27,29 +29,25 @@ public HALBeanDeserializer(BeanDeserializerBase delegate) {
2729

2830
@Override
2931
public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
30-
TreeNode tn = p.getCodec().readTree(p);
32+
TreeNode tn = p.getCodec().readTree(p);
3133
if (tn.isObject()) {
3234
ObjectNode root = (ObjectNode) tn;
3335
for (ReservedProperty rp : ReservedProperty.values()) {
3436
ObjectNode on = (ObjectNode) tn.get(rp.getPropertyName());
3537
if (on != null) {
36-
ArrayList<CurieMapping.Mapping> mappings = new ArrayList<>();
37-
if (ReservedProperty.LINKS.equals(rp) && on.has("curies")) {
38-
ArrayNode curies = (ArrayNode) on.get("curies");
39-
curies.elements().forEachRemaining(node -> mappings.add(createMapping((ObjectNode) node)));
40-
on.remove("curies");
41-
}
42-
CurieMapping curieMapping = new CurieMapping(mappings.toArray(new CurieMapping.Mapping[0]));
38+
CurieMap curieMap = createCurieMap(rp, on);
39+
on.remove("curies");
4340

44-
Iterator<Map.Entry<String,JsonNode>> it = on.fields();
41+
Iterator<Map.Entry<String, JsonNode>> it = on.fields();
4542
while (it.hasNext()) {
46-
Map.Entry<String,JsonNode> jn = it.next();
47-
String propertyName = curieMapping.resolve(jn.getKey()).map(URI::toString).orElse(jn.getKey());
43+
Map.Entry<String, JsonNode> jn = it.next();
44+
String propertyName = curieMap.resolve(jn.getKey()).map(URI::toString).orElse(jn.getKey());
4845
root.set(rp.alternateName(propertyName), jn.getValue());
4946
}
50-
root.remove(rp.getPropertyName());
47+
48+
root.remove(rp.getPropertyName());
5149
}
52-
50+
5351
}
5452
}
5553

@@ -58,24 +56,25 @@ public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOEx
5856
return _delegatee.deserialize(modifiedParser, ctxt);
5957
}
6058

61-
private CurieMapping.Mapping createMapping(ObjectNode node) {
62-
return new CurieMapping.Mapping(node.get("name").textValue(), node.get("href").textValue());
59+
private CurieMap createCurieMap(ReservedProperty rp, ObjectNode on) {
60+
if (ReservedProperty.LINKS.equals(rp) && on.has("curies")) {
61+
ArrayNode curies = (ArrayNode) on.get("curies");
62+
List<CurieMap.Mapping> mappings = StreamSupport.stream(curies.spliterator(), false)
63+
.map(n -> createMapping((ObjectNode) n))
64+
.collect(Collectors.toList());
65+
return new CurieMap(mappings.toArray(new CurieMap.Mapping[0]));
66+
} else {
67+
return new CurieMap();
68+
}
6369
}
6470

65-
private void removeCuries(ReservedProperty rp, ObjectNode on) {
66-
// Check for curies in the _links object. If they exist, remove them
67-
// as we have nothing in the bean to deserialize into. Curies only exist
68-
// as annotations on the bean!
69-
if (rp == ReservedProperty.LINKS) {
70-
if (on.has("curies")) {
71-
on.remove("curies");
72-
}
73-
}
71+
private CurieMap.Mapping createMapping(ObjectNode node) {
72+
return new CurieMap.Mapping(node.get("name").textValue(), node.get("href").textValue());
7473
}
7574

7675
@Override
7776
protected JsonDeserializer<?> newDelegatingInstance(JsonDeserializer<?> newDelegatee) {
7877
return new HALBeanDeserializer((BeanDeserializerBase) newDelegatee);
7978
}
80-
79+
8180
}

src/main/java/io/openapitools/jackson/dataformat/hal/deser/HALBeanDeserializerModifier.java

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,3 @@
1-
/*
2-
* To change this license header, choose License Headers in Project Properties.
3-
* To change this template file, choose Tools | Templates
4-
* and open the template in the editor.
5-
*/
61
package io.openapitools.jackson.dataformat.hal.deser;
72

83
import com.fasterxml.jackson.databind.BeanDescription;
@@ -12,8 +7,11 @@
127
import com.fasterxml.jackson.databind.deser.BeanDeserializer;
138
import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier;
149
import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
10+
import io.openapitools.jackson.dataformat.hal.annotation.Curie;
11+
import io.openapitools.jackson.dataformat.hal.annotation.Curies;
1512
import io.openapitools.jackson.dataformat.hal.annotation.Resource;
1613
import java.util.ArrayList;
14+
import java.util.Arrays;
1715
import java.util.Iterator;
1816
import java.util.List;
1917

@@ -36,21 +34,35 @@ public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, Bean
3634
public List<BeanPropertyDefinition> updateProperties(DeserializationConfig config, BeanDescription beanDesc, List<BeanPropertyDefinition> propDefs) {
3735
Resource ann = beanDesc.getClassAnnotations().get(Resource.class);
3836
if (ann != null) {
37+
CurieMap map = createCurieMap(beanDesc);
3938
List<BeanPropertyDefinition> modified = new ArrayList<>();
40-
Iterator<BeanPropertyDefinition> defIt = propDefs.iterator();
41-
while (defIt.hasNext()) {
42-
BeanPropertyDefinition pbd = defIt.next();
39+
Iterator<BeanPropertyDefinition> properties = propDefs.iterator();
40+
while (properties.hasNext()) {
41+
BeanPropertyDefinition property = properties.next();
4342
for (ReservedProperty rp : ReservedProperty.values()) {
44-
String alternateName = rp.alternateName(beanDesc, pbd, pbd.getName());
45-
if (!pbd.getName().equals(alternateName)) {
46-
modified.add(pbd.withName(new PropertyName(alternateName)));
47-
defIt.remove();
43+
String alternateName = rp.alternateName(property, map);
44+
if (!property.getName().equals(alternateName)) {
45+
modified.add(property.withName(new PropertyName(alternateName)));
46+
properties.remove();
4847
}
4948
}
5049
}
5150
propDefs.addAll(modified);
5251
}
5352
return propDefs;
5453
}
55-
54+
55+
private CurieMap createCurieMap(BeanDescription beanDesc) {
56+
ArrayList<CurieMap.Mapping> mappings = new ArrayList<>();
57+
Curie sc = beanDesc.getClassAnnotations().get(Curie.class);
58+
if (sc != null) {
59+
mappings.add(new CurieMap.Mapping(sc));
60+
}
61+
Curies cs = beanDesc.getClassAnnotations().get(Curies.class);
62+
if (cs != null) {
63+
Arrays.stream(cs.value()).forEach(c -> mappings.add(new CurieMap.Mapping(c)));
64+
}
65+
return new CurieMap(mappings.toArray(new CurieMap.Mapping[0]));
66+
}
67+
5668
}

src/main/java/io/openapitools/jackson/dataformat/hal/deser/ReservedProperty.java

Lines changed: 5 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,13 @@
11
package io.openapitools.jackson.dataformat.hal.deser;
22

3-
import com.fasterxml.jackson.databind.BeanDescription;
43
import com.fasterxml.jackson.databind.introspect.AnnotatedMember;
54
import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
6-
import io.openapitools.jackson.dataformat.hal.annotation.Curie;
7-
import io.openapitools.jackson.dataformat.hal.annotation.Curies;
85
import io.openapitools.jackson.dataformat.hal.annotation.EmbeddedResource;
96
import io.openapitools.jackson.dataformat.hal.annotation.Link;
107
import java.lang.annotation.Annotation;
118
import java.lang.reflect.InvocationTargetException;
129
import java.lang.reflect.Method;
1310
import java.net.URI;
14-
import java.util.ArrayList;
15-
import java.util.Arrays;
1611
import java.util.Optional;
1712
import java.util.UUID;
1813

@@ -42,7 +37,9 @@ public String getPropertyName() {
4237
return name;
4338
}
4439

45-
public String alternateName(BeanDescription beanDescription, BeanPropertyDefinition bpd, String originalName) {
40+
public String alternateName(BeanPropertyDefinition bpd, CurieMap map) {
41+
String originalName = bpd.getName();
42+
4643
AnnotatedMember annotatedMember = firstNonNull(bpd.getField(), bpd.getSetter(), bpd.getGetter());
4744
if (annotatedMember == null) {
4845
return originalName;
@@ -54,7 +51,6 @@ public String alternateName(BeanDescription beanDescription, BeanPropertyDefinit
5451
}
5552

5653
String name;
57-
5854
try {
5955
String alternateName = (String) valueMethod.invoke(o);
6056
name = alternateName.isEmpty() ? originalName : alternateName;
@@ -65,21 +61,8 @@ public String alternateName(BeanDescription beanDescription, BeanPropertyDefinit
6561
if (o.annotationType() == Link.class) {
6662
String curiePrefix = ((Link) o).curie();
6763
if (!curiePrefix.isEmpty()) {
68-
ArrayList<CurieMapping.Mapping> mappings = new ArrayList<>();
69-
70-
Curie sc = beanDescription.getClassAnnotations().get(Curie.class);
71-
if (sc != null) {
72-
mappings.add(new CurieMapping.Mapping(sc));
73-
}
74-
75-
Curies cs = beanDescription.getClassAnnotations().get(Curies.class);
76-
if (cs != null) {
77-
Arrays.stream(cs.value()).forEach(c -> mappings.add(new CurieMapping.Mapping(c)));
78-
}
79-
80-
CurieMapping cm = new CurieMapping(mappings.toArray(new CurieMapping.Mapping[0]));
81-
Optional<URI> resolved = cm.resolve(curiePrefix + ":" + name);
82-
return alternateName(resolved.map(URI::toString).orElse(originalName));
64+
Optional<URI> resolved = map.resolve(curiePrefix + ":" + name);
65+
return alternateName(resolved.map(URI::toString).orElse(name));
8366
}
8467
}
8568

src/test/java/io/openapitoools/jackson/dataformat/hal/deser/CurieMappingTest.java renamed to src/test/java/io/openapitoools/jackson/dataformat/hal/deser/CurieMapTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
package io.openapitoools.jackson.dataformat.hal.deser;
22

3-
import io.openapitools.jackson.dataformat.hal.deser.CurieMapping;
3+
import io.openapitools.jackson.dataformat.hal.deser.CurieMap;
44
import java.net.URI;
55
import org.junit.Test;
66

77
import static org.junit.Assert.assertEquals;
88

9-
public class CurieMappingTest {
9+
public class CurieMapTest {
1010

1111
@Test
1212
public void testBasicSubstitution() {
13-
CurieMapping cm = new CurieMapping(new CurieMapping.Mapping("prefix", "https://www.example.com/doc/{rel}"));
13+
CurieMap cm = new CurieMap(new CurieMap.Mapping("prefix", "https://www.example.com/doc/{rel}"));
1414
URI uri = cm.resolve("prefix:reference").get();
1515
assertEquals(URI.create("https://www.example.com/doc/reference"), uri);
1616
}

src/test/java/io/openapitoools/jackson/dataformat/hal/deser/ReservedPropertyTest.java

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,75 @@
11
package io.openapitoools.jackson.dataformat.hal.deser;
22

3-
import com.fasterxml.jackson.databind.BeanDescription;
4-
import io.openapitools.jackson.dataformat.hal.deser.ReservedProperty;
53
import com.fasterxml.jackson.databind.introspect.AnnotatedField;
64
import com.fasterxml.jackson.databind.introspect.AnnotationMap;
75
import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
86
import io.openapitools.jackson.dataformat.hal.annotation.Link;
7+
import io.openapitools.jackson.dataformat.hal.deser.CurieMap;
8+
import io.openapitools.jackson.dataformat.hal.deser.ReservedProperty;
99
import java.lang.reflect.Field;
10+
import org.junit.Test;
11+
1012
import static org.junit.Assert.assertEquals;
1113
import static org.junit.Assert.assertTrue;
12-
import org.junit.Test;
1314
import static org.mockito.Mockito.mock;
1415
import static org.mockito.Mockito.when;
1516

1617
public class ReservedPropertyTest {
1718

1819
@Test
1920
public void testAlternateNameNone() {
20-
BeanDescription bd = mock(BeanDescription.class);
21+
CurieMap cm = mock(CurieMap.class);
2122
BeanPropertyDefinition bpd = mock(BeanPropertyDefinition.class);
23+
when(bpd.getName()).thenReturn("orig-name");
2224

23-
String alternateName = ReservedProperty.LINKS.alternateName(bd, bpd, "orig-name");
25+
String alternateName = ReservedProperty.LINKS.alternateName(bpd,cm );
2426

2527
assertEquals("orig-name", alternateName);
2628
}
2729

2830
@Test
2931
public void testAlternateNameFieldNoAnnotation() throws Exception {
30-
BeanDescription bd = mock(BeanDescription.class);
32+
CurieMap cm = mock(CurieMap.class);
3133
BeanPropertyDefinition bpd = mock(BeanPropertyDefinition.class);
3234
AnnotatedField af = new AnnotatedField(null, POJO.class.getDeclaredField("bareField"), null);
3335
when(bpd.getField()).thenReturn(af);
36+
when(bpd.getName()).thenReturn("orig-name");
3437

35-
String alternateName = ReservedProperty.LINKS.alternateName(bd, bpd, "orig-name");
38+
String alternateName = ReservedProperty.LINKS.alternateName(bpd, cm);
3639

3740
assertEquals("orig-name", alternateName);
3841
}
3942

4043
@Test
4144
public void testAlternateNameFieldNoValue() throws Exception {
42-
BeanDescription bd = mock(BeanDescription.class);
45+
CurieMap cm = mock(CurieMap.class);
4346
BeanPropertyDefinition bpd = mock(BeanPropertyDefinition.class);
4447

4548
final Field field = POJO.class.getDeclaredField("annotatedField");
4649
AnnotationMap am = new AnnotationMap();
4750
am.addIfNotPresent(field.getAnnotation(Link.class));
4851
AnnotatedField af = new AnnotatedField(null, field, am);
4952
when(bpd.getField()).thenReturn(af);
53+
when(bpd.getName()).thenReturn("orig-name");
5054

51-
String alternateName = ReservedProperty.LINKS.alternateName(bd, bpd, "orig-name");
55+
String alternateName = ReservedProperty.LINKS.alternateName(bpd, cm);
5256

5357
assertTrue(alternateName.matches(".+:orig-name"));
5458
}
5559

5660
@Test
5761
public void testAlternateNameField() throws Exception {
58-
BeanDescription bd = mock(BeanDescription.class);
62+
CurieMap cm = mock(CurieMap.class);
5963
BeanPropertyDefinition bpd = mock(BeanPropertyDefinition.class);
6064

6165
final Field field = POJO.class.getDeclaredField("annotatedFieldWithValue");
6266
AnnotationMap am = new AnnotationMap();
6367
am.addIfNotPresent(field.getAnnotation(Link.class));
6468
AnnotatedField af = new AnnotatedField(null, field, am);
6569
when(bpd.getField()).thenReturn(af);
70+
when(bpd.getName()).thenReturn("orig-name");
6671

67-
String alternateName = ReservedProperty.LINKS.alternateName(bd, bpd, "orig-name");
72+
String alternateName = ReservedProperty.LINKS.alternateName(bpd, cm);
6873

6974
assertTrue(alternateName.matches(".+:alternate-name"));
7075
}

0 commit comments

Comments
 (0)