Skip to content
This repository was archived by the owner on Jun 26, 2021. It is now read-only.

Commit 56096a2

Browse files
committed
Add support for custom type de/serialisers.
1 parent bd94969 commit 56096a2

12 files changed

Lines changed: 486 additions & 17 deletions

File tree

emfjson-core/src/main/java/org/emfjson/EMFJs.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,18 @@ public final class EMFJs {
7979
* <p>By default org.emfjson.jackson.databind.deser.references.ReferenceAsObjectDeserializer will be use</p>
8080
*/
8181
public static final String OPTION_ID_DESERIALIZER = "OPTION_ID_DESERIALIZER";
82+
/**
83+
* Specify the TypeSerializer object to use during serialization of object's type.
84+
* <p/>
85+
* <p>By default org.emfjson.jackson.databind.deser.DefaultTypeSerializer will be use</p>
86+
*/
87+
public static final String OPTION_TYPE_SERIALIZER = "OPTION_ID_SERIALIZER";
88+
/**
89+
* Specify the TypeDeserializer object to use during deserialization of object's type.
90+
* <p/>
91+
* <p>By default org.emfjson.jackson.databind.deser.DefaultTypeDeserializer will be use</p>
92+
*/
93+
public static final String OPTION_TYPE_DESERIALIZER = "OPTION_ID_DESERIALIZER";
8294
/**
8395
* Specify the field name that will be use to denote the type of objects.
8496
* <p>By default eClass will be use</p>

emfjson-jackson/src/main/java/org/emfjson/jackson/JacksonOptions.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,16 @@
1414
import org.eclipse.emf.ecore.EClass;
1515
import org.emfjson.common.Options;
1616
import org.emfjson.handlers.URIHandler;
17+
import org.emfjson.jackson.databind.deser.DefaultTypeDeserializer;
1718
import org.emfjson.jackson.databind.deser.FragmentIdDeserializer;
1819
import org.emfjson.jackson.databind.deser.IdDeserializer;
20+
import org.emfjson.jackson.databind.deser.TypeDeserializer;
1921
import org.emfjson.jackson.databind.deser.references.ReferenceAsObjectDeserializer;
2022
import org.emfjson.jackson.databind.deser.references.ReferenceDeserializer;
23+
import org.emfjson.jackson.databind.ser.DefaultTypeSerializer;
2124
import org.emfjson.jackson.databind.ser.FragmentIdSerializer;
2225
import org.emfjson.jackson.databind.ser.IdSerializer;
26+
import org.emfjson.jackson.databind.ser.TypeSerializer;
2327
import org.emfjson.jackson.databind.ser.references.ReferenceAsObjectSerializer;
2428
import org.emfjson.jackson.databind.ser.references.ReferenceSerializer;
2529

@@ -34,6 +38,8 @@ public class JacksonOptions extends Options {
3438
public final ReferenceDeserializer referenceDeserializer;
3539
public final IdSerializer idSerializer;
3640
public final IdDeserializer idDeserializer;
41+
public final TypeSerializer typeSerializer;
42+
public final TypeDeserializer typeDeserializer;
3743

3844
protected JacksonOptions(JacksonOptions.Builder builder) {
3945
super(builder);
@@ -42,6 +48,8 @@ protected JacksonOptions(JacksonOptions.Builder builder) {
4248
this.referenceDeserializer = builder.referenceDeserializer;
4349
this.idSerializer = builder.idSerializer;
4450
this.idDeserializer = builder.idDeserializer;
51+
this.typeSerializer = builder.typeSerializer;
52+
this.typeDeserializer = builder.typeDeserializer;
4553
}
4654

4755
public static JacksonOptions from(Map<?, ?> options) {
@@ -54,6 +62,8 @@ public static final class Builder extends Options.Builder {
5462
protected ReferenceDeserializer referenceDeserializer = new ReferenceAsObjectDeserializer();
5563
protected IdSerializer idSerializer = new FragmentIdSerializer();
5664
protected IdDeserializer idDeserializer = new FragmentIdDeserializer();
65+
private TypeSerializer typeSerializer = new DefaultTypeSerializer();
66+
private TypeDeserializer typeDeserializer = new DefaultTypeDeserializer();
5767

5868
@Override
5969
public JacksonOptions build(Map<?, ?> options) {
@@ -116,6 +126,31 @@ public Builder withUriHandler(URIHandler uriHandler) {
116126
this.uriHandler = uriHandler;
117127
return this;
118128
}
129+
130+
public Builder withTypeField(String typeField) {
131+
this.typeField = typeField;
132+
return this;
133+
}
134+
135+
public Builder withIdField(String idField) {
136+
this.idField = idField;
137+
return this;
138+
}
139+
140+
public Builder withRefField(String refField) {
141+
this.refField = refField;
142+
return this;
143+
}
144+
145+
public Builder withTypeSerializer(TypeSerializer typeSerializer) {
146+
this.typeSerializer = typeSerializer;
147+
return this;
148+
}
149+
150+
public Builder withTypeDeserializer(TypeDeserializer typeDeserializer) {
151+
this.typeDeserializer = typeDeserializer;
152+
return this;
153+
}
119154
}
120155

121156
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright (c) 2015 Guillaume Hillairet.
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License v1.0
5+
* which accompanies this distribution, and is available at
6+
* http://www.eclipse.org/legal/epl-v10.html
7+
*
8+
* Contributors:
9+
* Guillaume Hillairet - initial API and implementation
10+
*
11+
*/
12+
package org.emfjson.jackson.databind.deser;
13+
14+
import com.fasterxml.jackson.core.JsonParser;
15+
import org.eclipse.emf.ecore.EClass;
16+
import org.eclipse.emf.ecore.resource.ResourceSet;
17+
import org.emfjson.common.Cache;
18+
19+
import java.io.IOException;
20+
21+
public class DefaultTypeDeserializer implements TypeDeserializer {
22+
@Override
23+
public EClass deserialize(JsonParser jp, ResourceSet resourceSet, Cache cache) throws IOException {
24+
return cache.getEClass(resourceSet, jp.nextTextValue());
25+
}
26+
}

emfjson-jackson/src/main/java/org/emfjson/jackson/databind/deser/EObjectDeserializer.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ protected EObject doDeserialize(JsonParser jp, EObject current, Deserialization
8585
if (options.typeField.equalsIgnoreCase(fieldName)) {
8686

8787
if (current == null) {
88-
current = create(resourceSet, jp.nextTextValue());
88+
current = create(resourceSet, jp);
8989
}
9090

9191
} else if (options.idField.equalsIgnoreCase(fieldName)) {
@@ -276,8 +276,8 @@ private void readAttribute(JsonParser jp, EObject owner, EAttribute attribute, R
276276
}
277277
}
278278

279-
protected EObject create(ResourceSet resourceSet, String type) {
280-
EClass eClass = cache.getEClass(resourceSet, type);
279+
protected EObject create(ResourceSet resourceSet, JsonParser jp) throws IOException {
280+
EClass eClass = options.typeDeserializer.deserialize(jp, resourceSet, cache);
281281
if (eClass != null) {
282282
return EcoreUtil.create(eClass);
283283
}

emfjson-jackson/src/main/java/org/emfjson/jackson/databind/deser/TypeDeserializer.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,13 @@
1313
import org.eclipse.emf.ecore.EClass;
1414

1515
import com.fasterxml.jackson.core.JsonParser;
16+
import org.eclipse.emf.ecore.resource.ResourceSet;
17+
import org.emfjson.common.Cache;
18+
19+
import java.io.IOException;
1620

1721
public interface TypeDeserializer {
1822

19-
EClass deserialize(JsonParser jp);
23+
EClass deserialize(JsonParser jp, ResourceSet resourceSet, Cache cache) throws IOException;
2024

2125
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright (c) 2015 Guillaume Hillairet.
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License v1.0
5+
* which accompanies this distribution, and is available at
6+
* http://www.eclipse.org/legal/epl-v10.html
7+
*
8+
* Contributors:
9+
* Guillaume Hillairet - initial API and implementation
10+
*
11+
*/
12+
package org.emfjson.jackson.databind.ser;
13+
14+
import com.fasterxml.jackson.core.JsonGenerator;
15+
import org.eclipse.emf.ecore.EClass;
16+
import org.emfjson.common.Cache;
17+
import org.emfjson.jackson.JacksonOptions;
18+
19+
import java.io.IOException;
20+
21+
public class DefaultTypeSerializer implements TypeSerializer {
22+
@Override
23+
public void serialize(EClass eClass, JsonGenerator jg, Cache cache, JacksonOptions options) throws IOException {
24+
if (options.serializeTypes) {
25+
jg.writeStringField(options.typeField, cache.getType(eClass));
26+
}
27+
}
28+
}

emfjson-jackson/src/main/java/org/emfjson/jackson/databind/ser/EObjectSerializer.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,9 +101,7 @@ protected void writeId(EObject object, JsonGenerator jg) throws IOException {
101101
}
102102

103103
protected void writeType(EClass eClass, JsonGenerator jg) throws IOException {
104-
if (options.serializeTypes) {
105-
jg.writeStringField(options.typeField, cache.getType(eClass));
106-
}
104+
options.typeSerializer.serialize(eClass, jg, cache, options);
107105
}
108106

109107
private void writeRef(JsonGenerator jg, EObject source, String field, Object value) throws IOException {

emfjson-jackson/src/main/java/org/emfjson/jackson/databind/ser/TypeSerializer.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,15 @@
1010
*/
1111
package org.emfjson.jackson.databind.ser;
1212

13+
import com.fasterxml.jackson.core.JsonGenerator;
1314
import org.eclipse.emf.ecore.EClass;
15+
import org.emfjson.common.Cache;
16+
import org.emfjson.jackson.JacksonOptions;
1417

15-
import org.emfjson.common.Options;
16-
17-
import com.fasterxml.jackson.core.JsonGenerator;
18+
import java.io.IOException;
1819

1920
public interface TypeSerializer {
2021

21-
void serialize(JsonGenerator jg, EClass eClass, Options options);
22+
void serialize(EClass eClass, JsonGenerator jg, Cache cache, JacksonOptions options) throws IOException;
2223

2324
}

emfjson-jackson/src/test/java/org/emfjson/jackson/junit/TestSuite.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
@SuiteClasses({
2222
AnnotationTest.class,
2323
ContainmentTest.class,
24+
CustomDeserializersTest.class,
25+
CustomSerializersTest.class,
2426
DynamicInstanceTest.class,
2527
DynamicPackageTest.class,
2628
EnumTest.class,
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
/*
2+
* Copyright (c) 2015 Guillaume Hillairet.
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License v1.0
5+
* which accompanies this distribution, and is available at
6+
* http://www.eclipse.org/legal/epl-v10.html
7+
*
8+
* Contributors:
9+
* Guillaume Hillairet - initial API and implementation
10+
*
11+
*/
12+
package org.emfjson.jackson.junit.tests;
13+
14+
import com.fasterxml.jackson.core.JsonParser;
15+
import com.fasterxml.jackson.core.JsonProcessingException;
16+
import com.fasterxml.jackson.core.JsonToken;
17+
import com.fasterxml.jackson.databind.JsonNode;
18+
import com.fasterxml.jackson.databind.ObjectMapper;
19+
import org.eclipse.emf.ecore.EClass;
20+
import org.eclipse.emf.ecore.EObject;
21+
import org.eclipse.emf.ecore.EReference;
22+
import org.eclipse.emf.ecore.resource.Resource;
23+
import org.eclipse.emf.ecore.resource.ResourceSet;
24+
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
25+
import org.emfjson.common.Cache;
26+
import org.emfjson.common.DefaultReferenceEntry;
27+
import org.emfjson.common.ReferenceEntries;
28+
import org.emfjson.jackson.JacksonOptions;
29+
import org.emfjson.jackson.databind.deser.IdDeserializer;
30+
import org.emfjson.jackson.databind.deser.TypeDeserializer;
31+
import org.emfjson.jackson.databind.deser.references.ReferenceDeserializer;
32+
import org.emfjson.jackson.junit.model.ModelPackage;
33+
import org.emfjson.jackson.junit.model.Sex;
34+
import org.emfjson.jackson.junit.model.User;
35+
import org.emfjson.jackson.module.EMFModule;
36+
import org.emfjson.jackson.resource.JsonResource;
37+
import org.emfjson.jackson.resource.JsonResourceFactory;
38+
import org.junit.Before;
39+
import org.junit.Test;
40+
41+
import java.io.IOException;
42+
43+
import static org.junit.Assert.assertEquals;
44+
import static org.junit.Assert.assertNotNull;
45+
import static org.junit.Assert.assertSame;
46+
47+
public class CustomDeserializersTest {
48+
49+
private IdDeserializer idDeserializer = new IdDeserializer() {
50+
@Override
51+
public void deserialize(JsonParser jp, Resource resource, EObject object) throws IOException {
52+
String text = jp.nextTextValue();
53+
54+
if (resource instanceof JsonResource) {
55+
object.eSet(ModelPackage.Literals.USER__USER_ID, text);
56+
((JsonResource) resource).setID(object, text);
57+
}
58+
}
59+
};
60+
61+
private TypeDeserializer typeDeserializer = new TypeDeserializer() {
62+
@Override
63+
public EClass deserialize(JsonParser jp, ResourceSet resourceSet, Cache cache) throws IOException {
64+
return ModelPackage.Literals.USER;
65+
}
66+
};
67+
68+
private ReferenceDeserializer referenceDeserializer = new ReferenceDeserializer() {
69+
@Override
70+
public ReferenceEntries.ReferenceEntry deserialize(JsonParser jp, EObject owner, EReference reference, JacksonOptions options)
71+
throws IOException {
72+
73+
if (JsonToken.VALUE_STRING.equals(jp.getCurrentToken())) {
74+
return new DefaultReferenceEntry(owner, reference, jp.getText());
75+
}
76+
77+
return null;
78+
}
79+
};
80+
81+
private ObjectMapper mapper;
82+
83+
@Before
84+
public void setUp() {
85+
mapper = new ObjectMapper();
86+
ResourceSet resourceSet = new ResourceSetImpl();
87+
resourceSet.getPackageRegistry().put(ModelPackage.eNS_URI, ModelPackage.eINSTANCE);
88+
resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap()
89+
.put("*", new JsonResourceFactory());
90+
91+
EMFModule module = new EMFModule(resourceSet, new JacksonOptions
92+
.Builder()
93+
.withIdField("userId")
94+
.withTypeField("type")
95+
.withIdDeserializer(idDeserializer)
96+
.withReferenceDeserializer(referenceDeserializer)
97+
.withTypeDeserializer(typeDeserializer)
98+
.build());
99+
100+
mapper.registerModule(module);
101+
}
102+
103+
@Test
104+
public void testDeserializers() throws JsonProcessingException {
105+
JsonNode data = mapper.createArrayNode()
106+
.add(mapper.createObjectNode()
107+
.put("type", "User")
108+
.put("userId", "u1")
109+
.put("sex", "MALE")
110+
.put("uniqueFriend", "u2"))
111+
.add(mapper.createObjectNode()
112+
.put("type", "User")
113+
.put("userId", "u2")
114+
.put("sex", "MALE")
115+
.set("friends", mapper.createArrayNode()
116+
.add("u1")
117+
.add("u3")))
118+
.add(mapper.createObjectNode()
119+
.put("type", "User")
120+
.put("userId", "u3")
121+
.put("sex", "MALE")
122+
.set("friends", mapper.createArrayNode()
123+
.add("u1")
124+
.add("u2")));
125+
126+
Resource resource = mapper.treeToValue(data, Resource.class);
127+
128+
assertEquals(3, resource.getContents().size());
129+
assertEquals(ModelPackage.Literals.USER, resource.getContents().get(0).eClass());
130+
assertEquals(ModelPackage.Literals.USER, resource.getContents().get(0).eClass());
131+
assertEquals(ModelPackage.Literals.USER, resource.getContents().get(0).eClass());
132+
133+
User u = (User) resource.getContents().get(0);
134+
135+
assertEquals("u1", u.getUserId());
136+
assertEquals(Sex.MALE, u.getSex());
137+
assertEquals(0, u.getFriends().size());
138+
assertNotNull(u.getUniqueFriend());
139+
assertSame(resource.getContents().get(1), u.getUniqueFriend());
140+
141+
u = (User) resource.getContents().get(1);
142+
143+
assertEquals("u2", u.getUserId());
144+
assertEquals(Sex.MALE, u.getSex());
145+
assertEquals(2, u.getFriends().size());
146+
assertSame(resource.getContents().get(0), u.getFriends().get(0));
147+
assertSame(resource.getContents().get(2), u.getFriends().get(1));
148+
149+
u = (User) resource.getContents().get(2);
150+
151+
assertEquals("u3", u.getUserId());
152+
assertEquals(Sex.MALE, u.getSex());
153+
assertEquals(2, u.getFriends().size());
154+
assertSame(resource.getContents().get(0), u.getFriends().get(0));
155+
assertSame(resource.getContents().get(1), u.getFriends().get(1));
156+
}
157+
158+
}

0 commit comments

Comments
 (0)