├── .gitattributes
├── .gitignore
├── .travis.yml
├── README.md
├── pom.xml
├── release-notes
├── CREDITS-2.x
└── VERSION-2.x
└── src
├── main
├── java
│ └── com
│ │ └── fasterxml
│ │ └── jackson
│ │ └── datatype
│ │ └── jsr353
│ │ ├── JSR353Module.java
│ │ ├── JsonMergePatchDeserializer.java
│ │ ├── JsonPatchDeserializer.java
│ │ ├── JsonValueDeserializer.java
│ │ ├── JsonValueSerializer.java
│ │ └── PackageVersion.java.in
└── resources
│ ├── LICENSE
│ └── META-INF
│ └── services
│ └── com.fasterxml.jackson.databind.Module
├── moditect
└── module-info.java
└── test
└── java
└── com
└── fasterxml
└── jackson
└── datatype
└── jsr353
├── JsonMergePatchDeserializationTest.java
├── JsonPatchDeserializationTest.java
├── JsonValueDeserializationTest.java
├── JsonValueSerializationTest.java
├── PolymorphicTest.java
└── TestBase.java
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Do not merge `pom.xml` from older version, as it will typically conflict
2 |
3 | pom.xml merge=ours
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # use glob syntax.
2 | syntax: glob
3 | *.class
4 | *~
5 | *.bak
6 | *.off
7 | *.old
8 | .DS_Store
9 |
10 | # building
11 | target
12 |
13 | # Eclipse
14 | .classpath
15 | .project
16 | .settings
17 |
18 | # IDEA
19 | *.iml
20 | *.ipr
21 | *.iws
22 | .idea
23 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: java
2 |
3 | jdk:
4 | - openjdk8
5 | - openjdk11
6 |
7 | # whitelist
8 | branches:
9 | only:
10 | - master
11 | - "2.11"
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | **NOTE**: This module has become part of [Jackson Misc Datatypes](../../../jackson-datatypes-misc)
2 | repository as of Jackson 2.11.0
3 |
4 | Versions prior to 2.11.x will still be built from maintenance branches in this repo, however.
5 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 |
5 | com.fasterxml.jackson
6 | jackson-base
7 | 3.0.0-SNAPSHOT
8 |
9 | com.fasterxml.jackson.datatype
10 | jackson-datatype-jsr353
11 | Jackson datatype: JSR-353
12 | 3.0.0-SNAPSHOT
13 | bundle
14 | Add-on module for Jackson (http://github.com/FasterXML/jackson) to support
15 | working with JSR-353 (JSON-P) node types via data-binding
16 | https://github.com/FasterXML/jackson-datatype-jsr353
17 |
18 | scm:git:git@github.com:FasterXML/jackson-datatype-jsr353.git
19 | scm:git:git@github.com:FasterXML/jackson-datatype-jsr353.git
20 | http://github.com/FasterXML/jackson-datatype-jsr353
21 | HEAD
22 |
23 |
24 |
25 | com/fasterxml/jackson/datatype/jsr353
26 | ${project.groupId}.jsr353
27 |
28 |
29 |
30 |
31 |
32 | com.fasterxml.jackson.core
33 | jackson-core
34 |
35 |
36 | com.fasterxml.jackson.core
37 | jackson-databind
38 |
39 |
40 |
41 |
42 | javax.json
43 | javax.json-api
44 | 1.1.4
45 |
46 |
47 |
48 |
49 | org.glassfish
50 | javax.json
51 | 1.1.4
52 | test
53 |
54 |
55 |
56 |
58 |
59 |
60 | sonatype-nexus-snapshots
61 | Sonatype Nexus Snapshots
62 | https://oss.sonatype.org/content/repositories/snapshots
63 | false
64 | true
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 | com.google.code.maven-replacer-plugin
73 | replacer
74 |
75 |
78 |
79 | org.moditect
80 | moditect-maven-plugin
81 |
82 |
83 |
84 |
85 |
86 |
--------------------------------------------------------------------------------
/release-notes/CREDITS-2.x:
--------------------------------------------------------------------------------
1 | Here are people who have contributed to the development of Jackson JSON processor
2 | JSR-353 (JSON-P) datatype component, version 2.x
3 | (version numbers in brackets indicate release in which the problem was fixed)
4 |
5 | Tatu Saloranta, tatu.saloranta@iki.fi: author
6 |
7 | Michał Regulski (regulskimichal@github)
8 |
9 | #13: Support for `JsonPatch` and `JsonMergePatch` defined in JSON-P 1.1
10 | w(contributed by Michał R)
11 |
12 |
--------------------------------------------------------------------------------
/release-notes/VERSION-2.x:
--------------------------------------------------------------------------------
1 | Project: jackson-datatype-jsr353
2 |
3 | ------------------------------------------------------------------------
4 | === Releases ===
5 | ------------------------------------------------------------------------
6 |
7 | 2.11.0 (not yet released)
8 |
9 | #13: Support for `JsonPatch` and `JsonMergePatch` defined in JSON-P 1.1
10 | (contributed by Michał R)
11 | - Update `javax.json` dependencies from 1.0 to 1.1.4
12 |
13 | 2.10.4 (03-May-2020)
14 |
15 | #16: Null being deserialized as null literal instead of JsonValue.NULL
16 | (reported, fix contributed by Marcos P)
17 |
18 | 2.10.3 (03-Mar-2020)
19 | 2.10.2 (05-Jan-2020)
20 | 2.10.1 (09-Nov-2019)
21 |
22 | No changes since 2.10.0
23 |
24 | 2.10.0 (26-Sep-2019)
25 |
26 | * Add JDK9 `module-info.class` using Moditect plugin
27 |
28 | 2.9.10 (21-Sep-2019)
29 | 2.9.9 (16-May-2019)
30 | 2.9.8 (15-Dec-2018)
31 | 2.9.7 (19-Sep-2018)
32 | 2.9.6 (12-Jun-2018)
33 | 2.9.5 (26-Mar-2018)
34 | 2.9.4 (24-Jan-2018)
35 | 2.9.3 (09-Dec-2017)
36 | 2.9.2 (14-Oct-2017)
37 | 2.9.0 (30-Jul-2017)
38 |
39 | No changes since 2.8.
40 |
41 | 2.8.11 (24-Dec-2017)
42 | 2.8.10 (24-Aug-2017)
43 | 2.8.9 (12-Jun-2017)
44 | 2.8.8 (05-Apr-2017)
45 | 2.8.7 (21-Feb-2017)
46 | 2.8.6 (12-Jan-2017)
47 | 2.8.5 (14-Nov-2016)
48 | 2.8.4 (14-Oct-2016)
49 | 2.8.3 (17-Sep-2016)
50 | 2.8.2 (30-Aug-2016)
51 | 2.8.1 (20-Jul-2016)
52 |
53 | No changes since 2.8.0.
54 |
55 | 2.8.0 (04-Jul-2016)
56 |
57 | No functional changes since 2.7
58 |
59 | 2.7.5 (11-Jun-2016)
60 | 2.7.4 (29-Apr-2016)
61 | 2.7.3 (16-Mar-2016)
62 | 2.7.2 (27-Feb-2016)
63 | 2.7.1 (02-Feb-2016)
64 | 2.7.0 (10-Jan-2016)
65 |
66 | No functional changes since 2.6
67 |
68 | 2.6.6 (05-Apr-2016)
69 | 2.6.5 (19-Jan-2016)
70 | 2.6.4 (07-Dec-2015)
71 | 2.6.3 (12-Oct-2015)
72 | 2.6.2 (15-Sep-2015)
73 | 2.6.1 (09-Aug-2015)
74 | 2.6.0 (19-Jul-2015)
75 |
76 | No functional changes since 2.5
77 |
78 | 2.5.3 (24-Apr-2015)
79 | 2.5.2 (29-Mar-2015)
80 | 2.5.1 (06-Feb-2015)
81 | 2.5.0 (01-Jan-2015)
82 |
83 | No functional changes since 2.4
84 |
85 | 2.4.5 (not released yet)
86 |
87 | #5: Support conversion of `BinaryNode`, as base64-encoded text
88 | (suggested by Gabor B, aborg0@github)
89 |
90 | 2.4.4 (24-Nov-2014)
91 | 2.4.3 (04-Oct-2014)
92 | 2.4.2 (15-Aug-2014)
93 | 2.4.1 (17-Jun-2014)
94 |
95 | No functional changes since 2.4.0.
96 |
97 | 2.4.0 (03-Jun-2013)
98 |
99 | No functional changes since 2.3.
100 |
101 | 2.3.3 (10-Apr-2014)
102 | 2.3.2 (01-Mar-2014)
103 | 2.3.1 (28-Dec-2013)
104 | 2.3.0 (14-Nov-2013)
105 | 2.2.3 (25-Aug-2013)
106 | 2.2.2 (27-May-2013)
107 | 2.2.1 (04-May-2013)
108 |
109 | No functional changes
110 |
111 | 2.2.0 (23-Apr-2013)
112 |
113 | First public release
114 |
--------------------------------------------------------------------------------
/src/main/java/com/fasterxml/jackson/datatype/jsr353/JSR353Module.java:
--------------------------------------------------------------------------------
1 | package com.fasterxml.jackson.datatype.jsr353;
2 |
3 | import com.fasterxml.jackson.databind.*;
4 | import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
5 | import com.fasterxml.jackson.databind.module.SimpleDeserializers;
6 | import com.fasterxml.jackson.databind.module.SimpleModule;
7 | import com.fasterxml.jackson.databind.type.CollectionType;
8 | import com.fasterxml.jackson.databind.type.MapType;
9 |
10 | import javax.json.*;
11 | import javax.json.spi.JsonProvider;
12 | import java.util.Collections;
13 |
14 | public class JSR353Module extends SimpleModule
15 | {
16 | private static final long serialVersionUID = 1L;
17 |
18 | protected final JsonBuilderFactory _builderFactory;
19 |
20 | @SuppressWarnings("serial")
21 | public JSR353Module() {
22 | super(PackageVersion.VERSION); //ModuleVersion.instance.version());
23 |
24 | JsonProvider jp = JsonProvider.provider();
25 | _builderFactory = jp.createBuilderFactory(Collections.emptyMap());
26 | final JsonValueDeserializer jsonValueDeser = new JsonValueDeserializer(_builderFactory);
27 | final JsonPatchDeserializer jsonPatchDeser = new JsonPatchDeserializer(jsonValueDeser);
28 | final JsonMergePatchDeserializer jsonMergePatchDeser = new JsonMergePatchDeserializer(jsonValueDeser);
29 |
30 | addSerializer(JsonValue.class, new JsonValueSerializer());
31 | setDeserializers(new SimpleDeserializers() {
32 | @Override
33 | public JsonDeserializer> findBeanDeserializer(
34 | JavaType type,
35 | DeserializationConfig config,
36 | BeanDescription beanDesc
37 | ) {
38 | if (JsonValue.class.isAssignableFrom(type.getRawClass())) {
39 | return jsonValueDeser;
40 | }
41 | if (JsonPatch.class.isAssignableFrom(type.getRawClass())) {
42 | return jsonPatchDeser;
43 | }
44 | if (JsonMergePatch.class.isAssignableFrom(type.getRawClass())) {
45 | return jsonMergePatchDeser;
46 | }
47 | return null;
48 | }
49 |
50 | @Override
51 | public JsonDeserializer> findCollectionDeserializer(
52 | CollectionType type,
53 | DeserializationConfig config,
54 | BeanDescription beanDesc,
55 | TypeDeserializer elementTypeDeserializer,
56 | JsonDeserializer> elementDeserializer
57 | ) {
58 | if (JsonArray.class.isAssignableFrom(type.getRawClass())) {
59 | return jsonValueDeser;
60 | }
61 | return null;
62 | }
63 |
64 | @Override
65 | public JsonDeserializer> findMapDeserializer(
66 | MapType type,
67 | DeserializationConfig config,
68 | BeanDescription beanDesc,
69 | KeyDeserializer keyDeserializer,
70 | TypeDeserializer elementTypeDeserializer,
71 | JsonDeserializer> elementDeserializer
72 | ) {
73 | if (JsonObject.class.isAssignableFrom(type.getRawClass())) {
74 | return jsonValueDeser;
75 | }
76 | return null;
77 | }
78 |
79 | @Override // since 2.11
80 | public boolean hasDeserializerFor(DeserializationConfig config, Class> valueType) {
81 | return JsonValue.class.isAssignableFrom(valueType) ||
82 | JsonPatch.class.isAssignableFrom(valueType) ||
83 | JsonMergePatch.class.isAssignableFrom(valueType);
84 | }
85 | });
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/src/main/java/com/fasterxml/jackson/datatype/jsr353/JsonMergePatchDeserializer.java:
--------------------------------------------------------------------------------
1 | package com.fasterxml.jackson.datatype.jsr353;
2 |
3 | import com.fasterxml.jackson.core.JsonParser;
4 | import com.fasterxml.jackson.databind.DeserializationContext;
5 | import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
6 |
7 | import javax.json.Json;
8 | import javax.json.JsonMergePatch;
9 | import java.io.IOException;
10 |
11 | public class JsonMergePatchDeserializer extends StdDeserializer {
12 |
13 | protected final JsonValueDeserializer jsonValueDeser;
14 |
15 | public JsonMergePatchDeserializer(JsonValueDeserializer jsonValueDeser) {
16 | super(JsonMergePatch.class);
17 | this.jsonValueDeser = jsonValueDeser;
18 | }
19 |
20 | @Override
21 | public JsonMergePatch deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
22 | return Json.createMergePatch(jsonValueDeser._deserializeObject(p, ctxt));
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/com/fasterxml/jackson/datatype/jsr353/JsonPatchDeserializer.java:
--------------------------------------------------------------------------------
1 | package com.fasterxml.jackson.datatype.jsr353;
2 |
3 | import com.fasterxml.jackson.core.JsonParser;
4 | import com.fasterxml.jackson.databind.DeserializationContext;
5 | import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
6 |
7 | import javax.json.Json;
8 | import javax.json.JsonPatch;
9 | import java.io.IOException;
10 |
11 | public class JsonPatchDeserializer extends StdDeserializer {
12 |
13 | protected final JsonValueDeserializer jsonValueDeser;
14 |
15 | public JsonPatchDeserializer(JsonValueDeserializer jsonValueDeser) {
16 | super(JsonPatch.class);
17 | this.jsonValueDeser = jsonValueDeser;
18 | }
19 |
20 | @Override
21 | public JsonPatch deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
22 | return Json.createPatch(jsonValueDeser._deserializeArray(p, ctxt));
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/com/fasterxml/jackson/datatype/jsr353/JsonValueDeserializer.java:
--------------------------------------------------------------------------------
1 | package com.fasterxml.jackson.datatype.jsr353;
2 |
3 | import java.io.IOException;
4 |
5 | import javax.json.*;
6 |
7 | import com.fasterxml.jackson.core.JsonParser;
8 | import com.fasterxml.jackson.core.JsonParser.NumberType;
9 | import com.fasterxml.jackson.core.JsonToken;
10 | import com.fasterxml.jackson.databind.DeserializationContext;
11 | import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
12 | import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
13 |
14 | public class JsonValueDeserializer extends StdDeserializer
15 | {
16 | protected final JsonBuilderFactory _builderFactory;
17 |
18 | public JsonValueDeserializer(JsonBuilderFactory bf) {
19 | super(JsonValue.class);
20 | _builderFactory = bf;
21 | }
22 |
23 | @Override
24 | public JsonValue deserialize(JsonParser p, DeserializationContext ctxt)
25 | throws IOException
26 | {
27 | switch (p.currentToken()) {
28 | case START_OBJECT:
29 | return _deserializeObject(p, ctxt);
30 | case START_ARRAY:
31 | return _deserializeArray(p, ctxt);
32 | default:
33 | return _deserializeScalar(p, ctxt);
34 | }
35 | }
36 |
37 | @Override
38 | public Object getNullValue(final DeserializationContext ctxt){
39 | return JsonValue.NULL;
40 | }
41 |
42 | @Override
43 | public Object deserializeWithType(JsonParser p,
44 | DeserializationContext ctxt, TypeDeserializer typeDeser)
45 | throws IOException
46 | {
47 | // we will always serialize using wrapper-array; approximated by claiming it's scalar
48 | return typeDeser.deserializeTypedFromScalar(p, ctxt);
49 | }
50 |
51 | /*
52 | /**********************************************************
53 | /* Helper methods
54 | /**********************************************************
55 | */
56 |
57 | protected JsonObject _deserializeObject(JsonParser p, DeserializationContext ctxt)
58 | throws IOException
59 | {
60 | JsonObjectBuilder b = _builderFactory.createObjectBuilder();
61 | while (p.nextToken() != JsonToken.END_OBJECT) {
62 | String name = p.currentName();
63 | JsonToken t = p.nextToken();
64 | switch (t) {
65 | case START_ARRAY:
66 | b.add(name, _deserializeArray(p, ctxt));
67 | break;
68 | case START_OBJECT:
69 | b.add(name, _deserializeObject(p, ctxt));
70 | break;
71 | case VALUE_FALSE:
72 | b.add(name, false);
73 | break;
74 | case VALUE_TRUE:
75 | b.add(name, true);
76 | break;
77 | case VALUE_NULL:
78 | b.addNull(name);
79 | break;
80 | case VALUE_NUMBER_FLOAT:
81 | if (p.getNumberType() == NumberType.BIG_DECIMAL) {
82 | b.add(name, p.getDecimalValue());
83 | } else {
84 | b.add(name, p.getDoubleValue());
85 | }
86 | break;
87 | case VALUE_NUMBER_INT:
88 | // very cumbersome... but has to be done
89 | switch (p.getNumberType()) {
90 | case LONG:
91 | b.add(name, p.getLongValue());
92 | break;
93 | case INT:
94 | b.add(name, p.getIntValue());
95 | break;
96 | default:
97 | b.add(name, p.getBigIntegerValue());
98 | }
99 | break;
100 | case VALUE_STRING:
101 | b.add(name, p.getText());
102 | break;
103 | case VALUE_EMBEDDED_OBJECT: {
104 | // 26-Nov-2014, tatu: As per [issue#5], should be able to support
105 | // binary data as Base64 embedded text
106 | Object ob = p.getEmbeddedObject();
107 | if (ob instanceof byte[]) {
108 | String b64 = ctxt.getBase64Variant().encode((byte[]) ob, false);
109 | b.add(name, b64);
110 | break;
111 | }
112 | }
113 | default:
114 | return (JsonObject) ctxt.handleUnexpectedToken(getValueType(ctxt), p);
115 | }
116 | }
117 | return b.build();
118 | }
119 |
120 | protected JsonArray _deserializeArray(JsonParser p, DeserializationContext ctxt)
121 | throws IOException
122 | {
123 | JsonArrayBuilder b = _builderFactory.createArrayBuilder();
124 | JsonToken t;
125 | while ((t = p.nextToken()) != JsonToken.END_ARRAY) {
126 | switch (t) {
127 | case START_ARRAY:
128 | b.add(_deserializeArray(p, ctxt));
129 | break;
130 | case START_OBJECT:
131 | b.add(_deserializeObject(p, ctxt));
132 | break;
133 | case VALUE_FALSE:
134 | b.add(false);
135 | break;
136 | case VALUE_TRUE:
137 | b.add(true);
138 | break;
139 | case VALUE_NULL:
140 | b.addNull();
141 | break;
142 | case VALUE_NUMBER_FLOAT:
143 | if (p.getNumberType() == NumberType.BIG_DECIMAL) {
144 | b.add(p.getDecimalValue());
145 | } else {
146 | b.add(p.getDoubleValue());
147 | }
148 | break;
149 | case VALUE_NUMBER_INT:
150 | // very cumbersome... but has to be done
151 | switch (p.getNumberType()) {
152 | case LONG:
153 | b.add(p.getLongValue());
154 | break;
155 | case INT:
156 | b.add(p.getIntValue());
157 | break;
158 | default:
159 | b.add(p.getBigIntegerValue());
160 | }
161 | break;
162 | case VALUE_STRING:
163 | b.add(p.getText());
164 | break;
165 | default:
166 | return (JsonArray) ctxt.handleUnexpectedToken(getValueType(ctxt), p);
167 | }
168 | }
169 | return b.build();
170 | }
171 |
172 | protected JsonValue _deserializeScalar(JsonParser p, DeserializationContext ctxt)
173 | throws IOException
174 | {
175 | switch (p.currentToken()) {
176 | case VALUE_EMBEDDED_OBJECT:
177 | // Not sure what to do with it -- could convert byte[] into Base64 encoded
178 | // if we wanted to... ?
179 | return (JsonValue) ctxt.handleUnexpectedToken(getValueType(ctxt), p);
180 | case VALUE_FALSE:
181 | return JsonValue.FALSE;
182 | case VALUE_TRUE:
183 | return JsonValue.TRUE;
184 | case VALUE_NULL:
185 | return JsonValue.NULL;
186 | case VALUE_NUMBER_FLOAT:
187 | // very cumbersome... but has to be done
188 | {
189 | JsonArrayBuilder b = _builderFactory.createArrayBuilder();
190 | if (p.getNumberType() == NumberType.BIG_DECIMAL) {
191 | return b.add(p.getDecimalValue()).build().get(0);
192 | }
193 | return b.add(p.getDoubleValue()).build().get(0);
194 | }
195 | case VALUE_NUMBER_INT:
196 | // very cumbersome... but has to be done
197 | {
198 | JsonArrayBuilder b = _builderFactory.createArrayBuilder();
199 | switch (p.getNumberType()) {
200 | case LONG:
201 | return b.add(p.getLongValue()).build().get(0);
202 | case INT:
203 | return b.add(p.getIntValue()).build().get(0);
204 | default:
205 | return b.add(p.getBigIntegerValue()).build().get(0);
206 | }
207 | }
208 | case VALUE_STRING:
209 | return _builderFactory.createArrayBuilder().add(p.getText()).build().get(0);
210 | default: // errors, should never get here
211 | // case END_ARRAY:
212 | // case END_OBJECT:
213 | // case FIELD_NAME:
214 | // case NOT_AVAILABLE:
215 | // case START_ARRAY:
216 | // case START_OBJECT:
217 | return (JsonValue) ctxt.handleUnexpectedToken(getValueType(ctxt), p);
218 | }
219 | }
220 | }
221 |
--------------------------------------------------------------------------------
/src/main/java/com/fasterxml/jackson/datatype/jsr353/JsonValueSerializer.java:
--------------------------------------------------------------------------------
1 | package com.fasterxml.jackson.datatype.jsr353;
2 |
3 | import java.io.IOException;
4 | import java.util.Map;
5 |
6 | import javax.json.*;
7 |
8 | import com.fasterxml.jackson.core.*;
9 | import com.fasterxml.jackson.core.type.WritableTypeId;
10 | import com.fasterxml.jackson.databind.SerializerProvider;
11 | import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
12 | import com.fasterxml.jackson.databind.ser.std.StdSerializer;
13 |
14 | public class JsonValueSerializer extends StdSerializer
15 | {
16 | public JsonValueSerializer() {
17 | super(JsonValue.class);
18 | }
19 |
20 | /*
21 | /**********************************************************
22 | /* Public API
23 | /**********************************************************
24 | */
25 |
26 | @Override
27 | public void serialize(JsonValue value, JsonGenerator g, SerializerProvider provider)
28 | throws IOException
29 | {
30 | switch (value.getValueType()) {
31 | case ARRAY:
32 | g.writeStartArray();
33 | serializeArrayContents((JsonArray) value, g, provider);
34 | g.writeEndArray();
35 | break;
36 | case OBJECT:
37 | g.writeStartObject(value);
38 | serializeObjectContents((JsonObject) value, g, provider);
39 | g.writeEndObject();
40 | break;
41 | default: // value type of some kind (scalar)
42 | serializeScalar(value, g, provider);
43 | }
44 | }
45 |
46 | @Override
47 | public void serializeWithType(JsonValue value, JsonGenerator g, SerializerProvider ctxt,
48 | TypeSerializer typeSer)
49 | throws IOException
50 | {
51 | g.setCurrentValue(value);
52 | // 25-Jul-2017, tatu: This may look wrong, but since we don't really know impl
53 | // classes we need to demote type to generic one, first: and as importantly,
54 | // need to claim that we don't really know shape to use (since that can vary
55 | // a lot). Safest way (and backwards compatible) is to claim it's scalar...
56 | // Not fully correct, but has to work for now.
57 | WritableTypeId typeIdDef = typeSer.writeTypePrefix(g, ctxt,
58 | typeSer.typeId(value, JsonValue.class, JsonToken.VALUE_EMBEDDED_OBJECT));
59 |
60 | serialize(value, g, ctxt);
61 | typeSer.writeTypeSuffix(g, ctxt, typeIdDef);
62 | }
63 |
64 | /*
65 | /**********************************************************
66 | /* Internal methods
67 | /**********************************************************
68 | */
69 |
70 | protected void serializeScalar(JsonValue value,
71 | JsonGenerator g, SerializerProvider provider)
72 | throws IOException
73 | {
74 | switch (value.getValueType()) {
75 | case FALSE:
76 | g.writeBoolean(false);
77 | break;
78 | case NULL: // hmmh. explicit nulls... I guess we may get them
79 | g.writeNull();
80 | break;
81 | case NUMBER:
82 | {
83 | JsonNumber num = (JsonNumber) value;
84 | if (num.isIntegral()) {
85 | g.writeNumber(num.longValue());
86 | } else {
87 | // 26-Feb-2013, tatu: Apparently no way to know if we need heavy BigDecimal
88 | // or not. Let's err on side of correct-if-slow to avoid losing precision.
89 | g.writeNumber(num.bigDecimalValue());
90 | }
91 | }
92 | break;
93 | case STRING:
94 | g.writeString(((JsonString) value).getString());
95 | break;
96 | case TRUE:
97 | g.writeBoolean(true);
98 | break;
99 | default:
100 | break;
101 | // default: // should never happen as array, object should not be called
102 | // throw new IllegalStateException("Unrecognized scalar JsonValue type: "+value.getClass().getName();
103 | }
104 | }
105 |
106 | protected void serializeArrayContents(JsonArray values,
107 | JsonGenerator g, SerializerProvider provider)
108 | throws IOException
109 | {
110 | if (!values.isEmpty()) {
111 | for (JsonValue value : values) {
112 | serialize(value, g, provider);
113 | }
114 | }
115 | }
116 |
117 | protected void serializeObjectContents(JsonObject ob,
118 | JsonGenerator g, SerializerProvider provider)
119 | throws IOException
120 | {
121 | if (!ob.isEmpty()) {
122 | for (Map.Entry entry : ob.entrySet()) {
123 | g.writeFieldName(entry.getKey());
124 | serialize(entry.getValue(), g, provider);
125 | }
126 | }
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/src/main/java/com/fasterxml/jackson/datatype/jsr353/PackageVersion.java.in:
--------------------------------------------------------------------------------
1 | package @package@;
2 |
3 | import com.fasterxml.jackson.core.Version;
4 | import com.fasterxml.jackson.core.Versioned;
5 | import com.fasterxml.jackson.core.util.VersionUtil;
6 |
7 | /**
8 | * Automatically generated from PackageVersion.java.in during
9 | * packageVersion-generate execution of maven-replacer-plugin in
10 | * pom.xml.
11 | */
12 | public final class PackageVersion implements Versioned {
13 | public final static Version VERSION = VersionUtil.parseVersion(
14 | "@projectversion@", "@projectgroupid@", "@projectartifactid@");
15 |
16 | @Override
17 | public Version version() {
18 | return VERSION;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/resources/LICENSE:
--------------------------------------------------------------------------------
1 | This copy of Jackson JSON processor streaming parser/generator is licensed under the
2 | Apache (Software) License, version 2.0 ("the License").
3 | See the License for details about distribution rights, and the
4 | specific rights regarding derivate works.
5 |
6 | You may obtain a copy of the License at:
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/services/com.fasterxml.jackson.databind.Module:
--------------------------------------------------------------------------------
1 | com.fasterxml.jackson.datatype.jsr353.JSR353Module
2 |
--------------------------------------------------------------------------------
/src/moditect/module-info.java:
--------------------------------------------------------------------------------
1 | // Generated 28-Mar-2019 using Moditect maven plugin
2 | module com.fasterxml.jackson.datatype.jsr353 {
3 | requires com.fasterxml.jackson.core;
4 | requires com.fasterxml.jackson.databind;
5 |
6 | requires javax.json.api;
7 |
8 | exports com.fasterxml.jackson.datatype.jsr353;
9 |
10 | provides com.fasterxml.jackson.databind.Module with
11 | com.fasterxml.jackson.datatype.jsr353.JSR353Module;
12 | }
13 |
--------------------------------------------------------------------------------
/src/test/java/com/fasterxml/jackson/datatype/jsr353/JsonMergePatchDeserializationTest.java:
--------------------------------------------------------------------------------
1 | package com.fasterxml.jackson.datatype.jsr353;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 |
5 | import javax.json.JsonMergePatch;
6 | import javax.json.JsonObject;
7 | import javax.json.JsonString;
8 | import javax.json.JsonValue;
9 | import java.util.Objects;
10 |
11 | import static org.hamcrest.CoreMatchers.instanceOf;
12 | import static org.hamcrest.CoreMatchers.is;
13 | import static org.hamcrest.MatcherAssert.assertThat;
14 |
15 | public class JsonMergePatchDeserializationTest extends TestBase {
16 |
17 | private static final ObjectMapper MAPPER = newMapper();
18 |
19 | public void testDeserializationAndPatching() throws Exception {
20 | final String json = "{" +
21 | "\"name\":\"Json\"" +
22 | "}";
23 |
24 | final JsonMergePatch jsonMergePatch = MAPPER.readValue(json, JsonMergePatch.class);
25 | final JsonValue jsonPatchAsJsonValue = jsonMergePatch.toJsonValue();
26 | assertThat(jsonPatchAsJsonValue, instanceOf(JsonObject.class));
27 |
28 | final JsonObject jsonPatchAsJsonObject = jsonPatchAsJsonValue.asJsonObject();
29 | assertTrue(jsonPatchAsJsonObject.containsKey("name"));
30 | assertThat(jsonPatchAsJsonObject.get("name"), instanceOf(JsonString.class));
31 | assertThat(jsonPatchAsJsonObject.getString("name"), is("Json"));
32 |
33 | assertThat(serializeAsString(jsonPatchAsJsonValue), is(json));
34 |
35 | final Person person = new Person("John", "Smith");
36 | final JsonValue personJson = MAPPER.convertValue(person, JsonValue.class);
37 | final JsonValue patchedPersonJson = jsonMergePatch.apply(personJson);
38 | final Person patchedPerson = MAPPER.convertValue(patchedPersonJson, Person.class);
39 | assertThat(patchedPerson, is(new Person("Json", "Smith")));
40 | }
41 |
42 | static class Person {
43 | private String name;
44 | private String lastName;
45 |
46 | public Person() {
47 | }
48 |
49 | public Person(String name, String lastName) {
50 | this.name = name;
51 | this.lastName = lastName;
52 | }
53 |
54 | public String getName() {
55 | return name;
56 | }
57 |
58 | public void setName(String name) {
59 | this.name = name;
60 | }
61 |
62 | public String getLastName() {
63 | return lastName;
64 | }
65 |
66 | public void setLastName(String lastName) {
67 | this.lastName = lastName;
68 | }
69 |
70 | @Override
71 | public int hashCode() {
72 | return Objects.hash(name, lastName);
73 | }
74 |
75 | @Override
76 | public boolean equals(Object o) {
77 | if (this == o) return true;
78 | if (o == null || getClass() != o.getClass()) return false;
79 | Person person = (Person) o;
80 | return Objects.equals(name, person.name) &&
81 | Objects.equals(lastName, person.lastName);
82 | }
83 |
84 | @Override
85 | public String toString() {
86 | return "Person{" +
87 | "name='" + name + '\'' +
88 | ", lastName='" + lastName + '\'' +
89 | '}';
90 | }
91 | }
92 |
93 | }
94 |
--------------------------------------------------------------------------------
/src/test/java/com/fasterxml/jackson/datatype/jsr353/JsonPatchDeserializationTest.java:
--------------------------------------------------------------------------------
1 | package com.fasterxml.jackson.datatype.jsr353;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 |
5 | import javax.json.*;
6 |
7 | import java.util.Objects;
8 |
9 | import static org.hamcrest.CoreMatchers.instanceOf;
10 | import static org.hamcrest.CoreMatchers.is;
11 | import static org.hamcrest.MatcherAssert.assertThat;
12 |
13 | public class JsonPatchDeserializationTest extends TestBase {
14 |
15 | private static final ObjectMapper MAPPER = newMapper();
16 |
17 | public void testDeserializationAndPatching() throws Exception {
18 | final String json = "[" +
19 | "{" +
20 | "\"op\":\"replace\"," +
21 | "\"path\":\"/name\"," +
22 | "\"value\":\"Json\"" +
23 | "}" +
24 | "]";
25 |
26 | final JsonPatch jsonPatch = MAPPER.readValue(json, JsonPatch.class);
27 | final JsonArray jsonPatchAsJsonArray = jsonPatch.toJsonArray();
28 | assertThat(jsonPatchAsJsonArray.get(0), instanceOf(JsonObject.class));
29 |
30 | final JsonObject firstOperation = jsonPatchAsJsonArray.get(0).asJsonObject();
31 | assertTrue(firstOperation.containsKey("op"));
32 | assertThat(firstOperation.get("op"), instanceOf(JsonString.class));
33 | assertThat(firstOperation.getString("op"), is("replace"));
34 |
35 | assertTrue(firstOperation.containsKey("path"));
36 | assertThat(firstOperation.get("path"), instanceOf(JsonString.class));
37 | assertThat(firstOperation.getString("path"), is("/name"));
38 |
39 | assertTrue(firstOperation.containsKey("value"));
40 | assertThat(firstOperation.get("value"), instanceOf(JsonString.class));
41 | assertThat(firstOperation.getString("value"), is("Json"));
42 |
43 | assertThat(serializeAsString(jsonPatchAsJsonArray), is(json));
44 |
45 | final Person person = new Person("John", "Smith");
46 | final JsonStructure personJson = MAPPER.convertValue(person, JsonStructure.class);
47 | final JsonStructure patchedPersonJson = jsonPatch.apply(personJson);
48 | final Person patchedPerson = MAPPER.convertValue(patchedPersonJson, Person.class);
49 | assertThat(patchedPerson, is(new Person("Json", "Smith")));
50 | }
51 |
52 | static class Person {
53 | private String name;
54 | private String lastName;
55 |
56 | public Person() {
57 | }
58 |
59 | public Person(String name, String lastName) {
60 | this.name = name;
61 | this.lastName = lastName;
62 | }
63 |
64 | public String getName() {
65 | return name;
66 | }
67 |
68 | public void setName(String name) {
69 | this.name = name;
70 | }
71 |
72 | public String getLastName() {
73 | return lastName;
74 | }
75 |
76 | public void setLastName(String lastName) {
77 | this.lastName = lastName;
78 | }
79 |
80 | @Override
81 | public int hashCode() {
82 | return Objects.hash(name, lastName);
83 | }
84 |
85 | @Override
86 | public boolean equals(Object o) {
87 | if (this == o) return true;
88 | if (o == null || getClass() != o.getClass()) return false;
89 | Person person = (Person) o;
90 | return Objects.equals(name, person.name) &&
91 | Objects.equals(lastName, person.lastName);
92 | }
93 |
94 | @Override
95 | public String toString() {
96 | return "Person{" +
97 | "name='" + name + '\'' +
98 | ", lastName='" + lastName + '\'' +
99 | '}';
100 | }
101 | }
102 |
103 | }
104 |
--------------------------------------------------------------------------------
/src/test/java/com/fasterxml/jackson/datatype/jsr353/JsonValueDeserializationTest.java:
--------------------------------------------------------------------------------
1 | package com.fasterxml.jackson.datatype.jsr353;
2 |
3 | import com.fasterxml.jackson.databind.json.JsonMapper;
4 | import javax.json.*;
5 | import javax.json.JsonValue.ValueType;
6 |
7 | import com.fasterxml.jackson.databind.ObjectMapper;
8 | import com.fasterxml.jackson.databind.node.ObjectNode;
9 |
10 | public class JsonValueDeserializationTest extends TestBase
11 | {
12 | private final ObjectMapper MAPPER = newMapper();
13 |
14 | public void testSimpleArray() throws Exception
15 | {
16 | final String JSON = "[1,true,\"foo\"]";
17 | JsonValue v = MAPPER.readValue(JSON, JsonValue.class);
18 | assertTrue(v instanceof JsonArray);
19 | JsonArray a = (JsonArray) v;
20 | assertEquals(3, a.size());
21 | assertTrue(a.get(0) instanceof JsonNumber);
22 | assertSame(JsonValue.TRUE, a.get(1));
23 | assertTrue(a.get(2) instanceof JsonString);
24 |
25 | // also, should work with explicit type
26 | JsonArray array = MAPPER.readValue(JSON, JsonArray.class);
27 | assertEquals(3, array.size());
28 |
29 | // and round-tripping ought to be ok:
30 | assertEquals(JSON, serializeAsString(v));
31 | }
32 |
33 | public void testNestedArray() throws Exception
34 | {
35 | final String JSON = "[1,[false,45],{\"foo\":13}]";
36 | JsonValue v = MAPPER.readValue(JSON, JsonValue.class);
37 | assertTrue(v instanceof JsonArray);
38 | JsonArray a = (JsonArray) v;
39 | assertEquals(3, a.size());
40 | assertTrue(a.get(0) instanceof JsonNumber);
41 | assertTrue(a.get(1) instanceof JsonArray);
42 | assertTrue(a.get(2) instanceof JsonObject);
43 |
44 | // and round-tripping ought to be ok:
45 | assertEquals(JSON, serializeAsString(v));
46 | }
47 |
48 | public void testSimpleObject() throws Exception
49 | {
50 | final String JSON = "{\"a\":12.5,\"b\":\"Text\"}";
51 | JsonValue v = MAPPER.readValue(JSON, JsonValue.class);
52 | assertTrue(v instanceof JsonObject);
53 | JsonObject ob = (JsonObject) v;
54 | assertEquals(2, ob.size());
55 |
56 | assertTrue(ob.get("a") instanceof JsonNumber);
57 | assertEquals(12.5, ((JsonNumber) ob.get("a")).doubleValue());
58 | assertTrue(ob.get("b") instanceof JsonString);
59 | assertEquals("Text", ((JsonString) ob.get("b")).getString());
60 |
61 | // also, should work with explicit type
62 | ob = MAPPER.readValue(JSON, JsonObject.class);
63 | assertEquals(2, ob.size());
64 |
65 | // and round-tripping ought to be ok:
66 | assertEquals(JSON, serializeAsString(v));
67 | }
68 |
69 | public void testNestedObject() throws Exception
70 | {
71 | final String JSON = "{\"array\":[1,2],\"obj\":{\"first\":true}}";
72 | JsonValue v = MAPPER.readValue(JSON, JsonValue.class);
73 | assertTrue(v instanceof JsonObject);
74 | JsonObject ob = (JsonObject) v;
75 | assertEquals(2, ob.size());
76 |
77 | assertTrue(ob.get("array") instanceof JsonArray);
78 | assertEquals(2, ((JsonArray) ob.get("array")).size());
79 | assertTrue(ob.get("obj") instanceof JsonObject);
80 | assertEquals(1, ((JsonObject) ob.get("obj")).size());
81 |
82 | // also, should work with explicit type
83 | ob = MAPPER.readValue(JSON, JsonObject.class);
84 | assertEquals(2, ob.size());
85 |
86 | // and round-tripping ought to be ok:
87 | assertEquals(JSON, serializeAsString(v));
88 | }
89 |
90 | // for [datatype-jsr353#5]
91 | public void testBinaryNode() throws Exception
92 | {
93 | ObjectNode root = MAPPER.createObjectNode();
94 | root.put("b", new byte[1]);
95 | JsonValue v = MAPPER.convertValue(root, JsonValue.class);
96 | assertNotNull(v);
97 | assertEquals(ValueType.OBJECT, v.getValueType());
98 | JsonValue v2 = ((javax.json.JsonObject) v).get("b");
99 | assertNotNull(v2);
100 | assertEquals(ValueType.STRING, v2.getValueType());
101 | String str = ((JsonString) v2).getString();
102 | assertEquals("AA==", str); // single zero byte
103 | }
104 |
105 | // for [datatype-jsr353#16]
106 | public void testNullNode() throws Exception
107 | {
108 | final String serializedNull = MAPPER.writeValueAsString(JsonValue.NULL);
109 | assertEquals("null", serializedNull);
110 | final JsonValue deserializedNull = MAPPER.readValue(serializedNull, JsonValue.class);
111 | assertEquals(JsonValue.NULL, deserializedNull);
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/src/test/java/com/fasterxml/jackson/datatype/jsr353/JsonValueSerializationTest.java:
--------------------------------------------------------------------------------
1 | package com.fasterxml.jackson.datatype.jsr353;
2 |
3 | import java.math.BigDecimal;
4 |
5 | import javax.json.*;
6 |
7 | public class JsonValueSerializationTest extends TestBase
8 | {
9 | public void testSimpleArray() throws Exception
10 | {
11 | JsonArray arr = arrayBuilder()
12 | .add(true)
13 | .addNull()
14 | .add(123)
15 | .add(new BigDecimal("15.25"))
16 | .build();
17 | assertEquals("[true,null,123,15.25]", serializeAsString(arr));
18 | }
19 |
20 | public void testNestedArray() throws Exception
21 | {
22 | JsonArray arr = arrayBuilder()
23 | .add(1)
24 | .add(arrayBuilder().add(false).add(45).build())
25 | .add(objectBuilder().add("foo", 13).build())
26 | .build();
27 | assertEquals("[1,[false,45],{\"foo\":13}]", serializeAsString(arr));
28 | }
29 |
30 | public void testSimpleObject() throws Exception
31 | {
32 | JsonObject ob = objectBuilder()
33 | .add("a", 123)
34 | .add("b", "Text")
35 | .build();
36 | // not sure if order is guaranteed but:
37 | assertEquals("{\"a\":123,\"b\":\"Text\"}", serializeAsString(ob));
38 | }
39 |
40 | public void testNestedObject() throws Exception
41 | {
42 | JsonObject ob = objectBuilder()
43 | .add("array", arrayBuilder().add(1).add(2))
44 | .add("obj", objectBuilder().add("first", true))
45 | .build();
46 | // not sure if order is guaranteed but:
47 | assertEquals("{\"array\":[1,2],\"obj\":{\"first\":true}}", serializeAsString(ob));
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/test/java/com/fasterxml/jackson/datatype/jsr353/PolymorphicTest.java:
--------------------------------------------------------------------------------
1 | package com.fasterxml.jackson.datatype.jsr353;
2 |
3 | import javax.json.*;
4 |
5 | import com.fasterxml.jackson.annotation.JsonTypeInfo;
6 | import com.fasterxml.jackson.databind.ObjectMapper;
7 |
8 | public class PolymorphicTest extends TestBase
9 | {
10 | static class Wrapper {
11 | @JsonTypeInfo(include = JsonTypeInfo.As.PROPERTY, use = JsonTypeInfo.Id.CLASS)
12 | public Object w;
13 |
14 | public Wrapper() { }
15 | public Wrapper(Object o) { w = o; }
16 | }
17 |
18 | private final ObjectMapper MAPPER = mapperBuilder()
19 | .polymorphicTypeValidator(new NoCheckSubTypeValidator())
20 | .build();
21 |
22 | public void testObjectAsTyped() throws Exception
23 | {
24 | final String INPUT = "{\"array\":[1,2],\"obj\":{\"first\":true}}";
25 | JsonValue v = MAPPER.readValue(INPUT, JsonValue.class);
26 |
27 | String POLY_JSON = MAPPER.writeValueAsString(new Wrapper(v));
28 |
29 | Wrapper w = MAPPER.readValue(POLY_JSON, Wrapper.class);
30 | assertTrue(w.w instanceof JsonObject);
31 | JsonObject ob = (JsonObject) w.w;
32 | assertEquals(2, ob.size());
33 | JsonArray arr = ob.getJsonArray("array");
34 | assertNotNull(arr);
35 | assertEquals(2, arr.size());
36 | assertEquals(1, arr.getInt(0));
37 | }
38 |
39 | public void testArrayAsTyped() throws Exception
40 | {
41 | final String INPUT = "[1,{\"a\":true}]";
42 | JsonValue v = MAPPER.readValue(INPUT, JsonValue.class);
43 |
44 | String POLY_JSON = MAPPER.writeValueAsString(new Wrapper(v));
45 |
46 | Wrapper w = MAPPER.readValue(POLY_JSON, Wrapper.class);
47 | assertTrue(w.w instanceof JsonArray);
48 | JsonArray arr = (JsonArray) w.w;
49 | assertEquals(2, arr.size());
50 | JsonObject ob = arr.getJsonObject(1);
51 | assertNotNull(arr);
52 | assertEquals(1, ob.size());
53 | assertEquals(JsonValue.TRUE, ob.get("a"));
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/test/java/com/fasterxml/jackson/datatype/jsr353/TestBase.java:
--------------------------------------------------------------------------------
1 | package com.fasterxml.jackson.datatype.jsr353;
2 |
3 | import java.io.IOException;
4 |
5 | import javax.json.*;
6 |
7 | import com.fasterxml.jackson.databind.*;
8 | import com.fasterxml.jackson.databind.json.JsonMapper;
9 | import com.fasterxml.jackson.databind.jsontype.PolymorphicTypeValidator;
10 |
11 | public abstract class TestBase extends junit.framework.TestCase
12 | {
13 | static class NoCheckSubTypeValidator
14 | extends PolymorphicTypeValidator.Base
15 | {
16 | private static final long serialVersionUID = 1L;
17 |
18 | @Override
19 | public Validity validateBaseType(DatabindContext ctxt, JavaType baseType) {
20 | return Validity.ALLOWED;
21 | }
22 | }
23 |
24 | private final static JSR353Module MODULE = new JSR353Module();
25 |
26 | private final static ObjectMapper SHARED_MAPPER = newMapper();
27 |
28 | protected static ObjectMapper newMapper() {
29 | return mapperBuilder().build();
30 | }
31 |
32 | protected static JsonMapper.Builder mapperBuilder() {
33 | return JsonMapper.builder()
34 | .addModule(MODULE);
35 | }
36 |
37 | protected static ObjectMapper sharedMapper() {
38 | return SHARED_MAPPER;
39 | }
40 |
41 | protected String serializeAsString(JsonValue node) throws IOException {
42 | return SHARED_MAPPER.writeValueAsString(node);
43 | }
44 |
45 | protected JsonArrayBuilder arrayBuilder() {
46 | return MODULE._builderFactory.createArrayBuilder();
47 | }
48 |
49 | protected JsonObjectBuilder objectBuilder() {
50 | return MODULE._builderFactory.createObjectBuilder();
51 | }
52 | }
53 |
--------------------------------------------------------------------------------