jrjackson 0.3.9-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.__jrubyrc +433 -0
- data/.gitignore +10 -0
- data/.mvn/extensions.xml +8 -0
- data/Gemfile +10 -0
- data/Mavenfile +32 -0
- data/README.md +150 -0
- data/Rakefile +10 -0
- data/alt_bench.rb +46 -0
- data/changelog.md +131 -0
- data/jrjackson.gemspec +32 -0
- data/lib/com/fasterxml/jackson/core/jackson-annotations/2.7.1/jackson-annotations-2.7.1.jar +0 -0
- data/lib/com/fasterxml/jackson/core/jackson-core/2.7.1/jackson-core-2.7.1.jar +0 -0
- data/lib/com/fasterxml/jackson/core/jackson-databind/2.7.1/jackson-databind-2.7.1.jar +0 -0
- data/lib/com/fasterxml/jackson/module/jackson-module-afterburner/2.6.3/jackson-module-afterburner-2.6.3.jar +0 -0
- data/lib/com/fasterxml/jackson/module/jackson-module-afterburner/2.7.1/jackson-module-afterburner-2.7.1.jar +0 -0
- data/lib/jrjackson.rb +2 -0
- data/lib/jrjackson/build_info.rb +15 -0
- data/lib/jrjackson/jars/jrjackson-1.2.18.jar +0 -0
- data/lib/jrjackson/jars/jrjackson-1.2.7.jar +0 -0
- data/lib/jrjackson/jrjackson.rb +94 -0
- data/lib/jrjackson_jars.rb +7 -0
- data/lib/require_relative_patch.rb +6 -0
- data/pom.xml +193 -0
- data/profiling/profiled.rb +15 -0
- data/run_all_individual_bench.sh +25 -0
- data/run_jruby_individual_bench.sh +20 -0
- data/run_mri_individual_bench.sh +7 -0
- data/src/main/java/com/jrjackson/IParseHandler.java +53 -0
- data/src/main/java/com/jrjackson/JavaBigDecimalValueConverter.java +17 -0
- data/src/main/java/com/jrjackson/JavaBigIntValueConverter.java +17 -0
- data/src/main/java/com/jrjackson/JavaConverter.java +10 -0
- data/src/main/java/com/jrjackson/JavaFloatValueConverter.java +16 -0
- data/src/main/java/com/jrjackson/JavaHandler.java +118 -0
- data/src/main/java/com/jrjackson/JavaLongValueConverter.java +16 -0
- data/src/main/java/com/jrjackson/JjParse.java +147 -0
- data/src/main/java/com/jrjackson/JrJacksonBase.java +152 -0
- data/src/main/java/com/jrjackson/JrJacksonJava.java +81 -0
- data/src/main/java/com/jrjackson/JrJacksonRaw.java +108 -0
- data/src/main/java/com/jrjackson/JrJacksonRuby.java +89 -0
- data/src/main/java/com/jrjackson/JrJacksonSaj.java +26 -0
- data/src/main/java/com/jrjackson/JrJacksonSch.java +25 -0
- data/src/main/java/com/jrjackson/JrJacksonService.java +38 -0
- data/src/main/java/com/jrjackson/JrParse.java +149 -0
- data/src/main/java/com/jrjackson/ParseError.java +16 -0
- data/src/main/java/com/jrjackson/RubyAnySerializer.java +254 -0
- data/src/main/java/com/jrjackson/RubyBigDecimalValueConverter.java +18 -0
- data/src/main/java/com/jrjackson/RubyBigIntValueConverter.java +21 -0
- data/src/main/java/com/jrjackson/RubyConverter.java +12 -0
- data/src/main/java/com/jrjackson/RubyDateFormat.java +34 -0
- data/src/main/java/com/jrjackson/RubyFloatValueConverter.java +18 -0
- data/src/main/java/com/jrjackson/RubyHandler.java +119 -0
- data/src/main/java/com/jrjackson/RubyIntValueConverter.java +18 -0
- data/src/main/java/com/jrjackson/RubyJacksonModule.java +72 -0
- data/src/main/java/com/jrjackson/RubyKeyConverter.java +12 -0
- data/src/main/java/com/jrjackson/RubyNameConverter.java +9 -0
- data/src/main/java/com/jrjackson/RubyObjectDeserializer.java +182 -0
- data/src/main/java/com/jrjackson/RubyStringConverter.java +18 -0
- data/src/main/java/com/jrjackson/RubyStringKeyConverter.java +15 -0
- data/src/main/java/com/jrjackson/RubyStringNameConverter.java +12 -0
- data/src/main/java/com/jrjackson/RubySymbolKeyConverter.java +15 -0
- data/src/main/java/com/jrjackson/RubySymbolNameConverter.java +12 -0
- data/src/main/java/com/jrjackson/RubyUtils.java +150 -0
- data/src/main/java/com/jrjackson/SajParse.java +169 -0
- data/src/main/java/com/jrjackson/SchParse.java +209 -0
- data/src/main/java/com/jrjackson/StreamParse.java +66 -0
- data/test/jrjackson_test.rb +533 -0
- metadata +162 -0
@@ -0,0 +1,169 @@
|
|
1
|
+
package com.jrjackson;
|
2
|
+
|
3
|
+
import com.fasterxml.jackson.core.JsonParser;
|
4
|
+
import com.fasterxml.jackson.core.JsonProcessingException;
|
5
|
+
import com.fasterxml.jackson.core.JsonStreamContext;
|
6
|
+
import com.fasterxml.jackson.core.JsonLocation;
|
7
|
+
|
8
|
+
import java.io.IOException;
|
9
|
+
|
10
|
+
import org.jruby.internal.runtime.methods.DynamicMethod;
|
11
|
+
import org.jruby.runtime.ThreadContext;
|
12
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
13
|
+
import org.jruby.exceptions.RaiseException;
|
14
|
+
|
15
|
+
/**
|
16
|
+
*
|
17
|
+
* @author Guy Boertje
|
18
|
+
*/
|
19
|
+
public class SajParse extends StreamParse {
|
20
|
+
|
21
|
+
protected DynamicMethod _error;
|
22
|
+
protected boolean _no_error;
|
23
|
+
|
24
|
+
public SajParse(ThreadContext ctx, IRubyObject handler)
|
25
|
+
throws RaiseException {
|
26
|
+
super(ctx, handler);
|
27
|
+
|
28
|
+
if (_no_add_value) {
|
29
|
+
throw ParseError.newParseError(_ruby, "Handler does not implement public API");
|
30
|
+
}
|
31
|
+
_error = _meta.searchMethod("error");
|
32
|
+
_no_error = _error.isUndefined();
|
33
|
+
|
34
|
+
}
|
35
|
+
|
36
|
+
@Override
|
37
|
+
public IRubyObject deserialize(JsonParser jp) {
|
38
|
+
|
39
|
+
try {
|
40
|
+
while(jp.nextValue() != null) {
|
41
|
+
handleCurrentToken(jp);
|
42
|
+
}
|
43
|
+
}
|
44
|
+
catch (JsonProcessingException e) {
|
45
|
+
if(!_no_error) {
|
46
|
+
JsonLocation location = e.getLocation();
|
47
|
+
IRubyObject message = RubyUtils.rubyString(_ruby, e.getMessage());
|
48
|
+
IRubyObject line = RubyUtils.rubyFixnum(_ruby, location.getLineNr());
|
49
|
+
IRubyObject column = RubyUtils.rubyFixnum(_ruby, location.getColumnNr());
|
50
|
+
|
51
|
+
_error.call(_ctx, _handler, _meta, "error", message, line, column);
|
52
|
+
}
|
53
|
+
}
|
54
|
+
catch (IOException e) {
|
55
|
+
if(!_no_error) {
|
56
|
+
IRubyObject message = RubyUtils.rubyString(_ruby, e.getMessage());
|
57
|
+
IRubyObject line = RubyUtils.rubyFixnum(_ruby, 1);
|
58
|
+
IRubyObject column = RubyUtils.rubyFixnum(_ruby, 1);
|
59
|
+
|
60
|
+
_error.call(_ctx, _handler, _meta, "error", message, line, column);
|
61
|
+
}
|
62
|
+
}
|
63
|
+
|
64
|
+
return _ctx.nil;
|
65
|
+
}
|
66
|
+
|
67
|
+
private void callAddValue(IRubyObject val, IRubyObject key) {
|
68
|
+
_add_value.call(_ctx, _handler, _meta, "add_value", val, key);
|
69
|
+
}
|
70
|
+
|
71
|
+
private IRubyObject getParentName(JsonStreamContext x) {
|
72
|
+
String parentName = x.getCurrentName();
|
73
|
+
IRubyObject parent = _ctx.nil;
|
74
|
+
|
75
|
+
if (!x.inRoot()) {
|
76
|
+
parentName = x.getParent().getCurrentName();
|
77
|
+
}
|
78
|
+
if (parentName != null) {
|
79
|
+
parent = RubyUtils.rubyString(_ruby, parentName);
|
80
|
+
}
|
81
|
+
return parent;
|
82
|
+
}
|
83
|
+
|
84
|
+
private IRubyObject getFieldName(JsonStreamContext x) {
|
85
|
+
String currentName = x.getCurrentName();
|
86
|
+
IRubyObject name = _ctx.nil;
|
87
|
+
|
88
|
+
if (currentName != null) {
|
89
|
+
name = RubyUtils.rubyString(_ruby, currentName);
|
90
|
+
}
|
91
|
+
return name;
|
92
|
+
}
|
93
|
+
|
94
|
+
private void handleCurrentToken(JsonParser jp)
|
95
|
+
throws IOException, JsonProcessingException {
|
96
|
+
|
97
|
+
JsonStreamContext cx = jp.getParsingContext();
|
98
|
+
|
99
|
+
IRubyObject value;
|
100
|
+
|
101
|
+
switch (jp.getCurrentToken()) {
|
102
|
+
case START_OBJECT:
|
103
|
+
if (!_no_hash_start) {
|
104
|
+
_hash_start.call(_ctx, _handler, _meta, "hash_start", getParentName(cx));
|
105
|
+
}
|
106
|
+
break;
|
107
|
+
|
108
|
+
case START_ARRAY:
|
109
|
+
if (!_no_array_start) {
|
110
|
+
_array_start.call(_ctx, _handler, _meta, "array_start", getParentName(cx));
|
111
|
+
}
|
112
|
+
break;
|
113
|
+
|
114
|
+
case FIELD_NAME:
|
115
|
+
break;
|
116
|
+
|
117
|
+
case VALUE_EMBEDDED_OBJECT:
|
118
|
+
value = RubyUtils.rubyObject(_ruby, jp.getEmbeddedObject());
|
119
|
+
callAddValue(value, getFieldName(cx));
|
120
|
+
break;
|
121
|
+
|
122
|
+
case VALUE_STRING:
|
123
|
+
value = keyConverter.convert(_ruby, jp);
|
124
|
+
callAddValue(value, getFieldName(cx));
|
125
|
+
break;
|
126
|
+
|
127
|
+
case VALUE_NUMBER_INT:
|
128
|
+
/* [JACKSON-100]: caller may want to get all integral values
|
129
|
+
* returned as BigInteger, for consistency
|
130
|
+
*/
|
131
|
+
JsonParser.NumberType numberType = jp.getNumberType();
|
132
|
+
value = RubyUtils.rubyBignum(_ruby, jp.getBigIntegerValue());
|
133
|
+
callAddValue(value, getFieldName(cx));
|
134
|
+
break;
|
135
|
+
|
136
|
+
case VALUE_NUMBER_FLOAT:
|
137
|
+
value = RubyUtils.rubyBigDecimal(_ruby, jp.getDecimalValue());
|
138
|
+
callAddValue(value, getFieldName(cx));
|
139
|
+
break;
|
140
|
+
|
141
|
+
case VALUE_TRUE:
|
142
|
+
value = _ruby.newBoolean(Boolean.TRUE);
|
143
|
+
callAddValue(value, getFieldName(cx));
|
144
|
+
break;
|
145
|
+
|
146
|
+
case VALUE_FALSE:
|
147
|
+
value = _ruby.newBoolean(Boolean.FALSE);
|
148
|
+
callAddValue(value, getFieldName(cx));
|
149
|
+
break;
|
150
|
+
|
151
|
+
case VALUE_NULL: // should not get this but...
|
152
|
+
value = _ctx.nil;
|
153
|
+
callAddValue(value, getFieldName(cx));
|
154
|
+
break;
|
155
|
+
|
156
|
+
case END_ARRAY:
|
157
|
+
if (!_no_array_end) {
|
158
|
+
_array_end.call(_ctx, _handler, _meta, "array_end", getFieldName(cx));
|
159
|
+
}
|
160
|
+
break;
|
161
|
+
|
162
|
+
case END_OBJECT:
|
163
|
+
if (!_no_hash_end) {
|
164
|
+
_hash_end.call(_ctx, _handler, _meta, "hash_end", getFieldName(cx));
|
165
|
+
}
|
166
|
+
break;
|
167
|
+
}
|
168
|
+
}
|
169
|
+
}
|
@@ -0,0 +1,209 @@
|
|
1
|
+
package com.jrjackson;
|
2
|
+
|
3
|
+
import com.fasterxml.jackson.core.JsonParser;
|
4
|
+
import com.fasterxml.jackson.core.JsonProcessingException;
|
5
|
+
import com.fasterxml.jackson.core.JsonStreamContext;
|
6
|
+
import java.io.IOException;
|
7
|
+
import java.util.HashMap;
|
8
|
+
|
9
|
+
import org.jruby.internal.runtime.methods.DynamicMethod;
|
10
|
+
import org.jruby.runtime.ThreadContext;
|
11
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
12
|
+
import org.jruby.RubyString;
|
13
|
+
import org.jruby.exceptions.RaiseException;
|
14
|
+
|
15
|
+
/**
|
16
|
+
*
|
17
|
+
* @author Guy Boertje
|
18
|
+
*/
|
19
|
+
public class SchParse extends StreamParse {
|
20
|
+
|
21
|
+
protected final DynamicMethod _hash_key;
|
22
|
+
protected final boolean _no_hash_key;
|
23
|
+
|
24
|
+
protected final DynamicMethod _hash_set;
|
25
|
+
protected final boolean _no_hash_set;
|
26
|
+
|
27
|
+
protected final DynamicMethod _array_append;
|
28
|
+
protected final boolean _no_array_append;
|
29
|
+
|
30
|
+
protected final HashMap<JsonStreamContext, IRubyObject> _objectMap = new HashMap<JsonStreamContext, IRubyObject>();
|
31
|
+
protected JsonStreamContext _deepestContext;
|
32
|
+
|
33
|
+
public SchParse(ThreadContext ctx, IRubyObject handler)
|
34
|
+
throws RaiseException {
|
35
|
+
super(ctx, handler);
|
36
|
+
|
37
|
+
_hash_key = _meta.searchMethod("hash_key");
|
38
|
+
_no_hash_key = _hash_key.isUndefined();
|
39
|
+
|
40
|
+
_hash_set = _meta.searchMethod("hash_set");
|
41
|
+
_no_hash_set = _hash_set.isUndefined();
|
42
|
+
|
43
|
+
_array_append = _meta.searchMethod("array_append");
|
44
|
+
_no_array_append = _array_append.isUndefined();
|
45
|
+
|
46
|
+
//_hash_key is optional
|
47
|
+
if (
|
48
|
+
_no_hash_start || _no_hash_end ||
|
49
|
+
_no_array_start || _no_array_end ||
|
50
|
+
_no_add_value || _no_hash_set || _no_array_append
|
51
|
+
) {
|
52
|
+
throw ParseError.newParseError(_ruby, "Handler does not implement public API");
|
53
|
+
}
|
54
|
+
}
|
55
|
+
|
56
|
+
@Override
|
57
|
+
public IRubyObject deserialize(JsonParser jp) throws RaiseException {
|
58
|
+
try {
|
59
|
+
|
60
|
+
while (jp.nextValue() != null) {
|
61
|
+
handleCurrentToken(jp);
|
62
|
+
}
|
63
|
+
return _ctx.nil;
|
64
|
+
|
65
|
+
} catch (JsonProcessingException e) {
|
66
|
+
throw ParseError.newParseError(_ruby, e.getLocalizedMessage());
|
67
|
+
} catch (IOException e) {
|
68
|
+
throw _ruby.newIOError(e.getLocalizedMessage());
|
69
|
+
}
|
70
|
+
}
|
71
|
+
|
72
|
+
private void callAddValue(JsonStreamContext x) {
|
73
|
+
JsonStreamContext px = x.getParent();
|
74
|
+
IRubyObject target = _objectMap.get(x);
|
75
|
+
IRubyObject dtarget = _objectMap.get(_deepestContext);
|
76
|
+
|
77
|
+
if (px == null) {
|
78
|
+
_add_value.call(_ctx, _handler, _meta, "add_value", dtarget);
|
79
|
+
return;
|
80
|
+
}
|
81
|
+
|
82
|
+
if (x.inArray()) {
|
83
|
+
_array_append.call(_ctx, _handler, _meta, "array_append", target, dtarget);
|
84
|
+
} else if (x.inObject()) {
|
85
|
+
IRubyObject treatedKey = callHashKey(x);
|
86
|
+
_hash_set.call(_ctx, _handler, _meta, "hash_set", target, treatedKey, dtarget);
|
87
|
+
} else {
|
88
|
+
_add_value.call(_ctx, _handler, _meta, "add_value", target);
|
89
|
+
}
|
90
|
+
}
|
91
|
+
|
92
|
+
private void callAddValue(JsonStreamContext x, IRubyObject val) {
|
93
|
+
IRubyObject target = _objectMap.get(x);
|
94
|
+
|
95
|
+
if (x.inArray()) {
|
96
|
+
_array_append.call(_ctx, _handler, _meta, "array_append", target, val);
|
97
|
+
} else if (x.inObject()) {
|
98
|
+
IRubyObject treatedKey = callHashKey(x);
|
99
|
+
_hash_set.call(_ctx, _handler, _meta, "hash_set", target, treatedKey, val);
|
100
|
+
} else {
|
101
|
+
_add_value.call(_ctx, _handler, _meta, "add_value", val);
|
102
|
+
}
|
103
|
+
}
|
104
|
+
|
105
|
+
private IRubyObject callHashKey(JsonStreamContext x) {
|
106
|
+
String k = x.getCurrentName();
|
107
|
+
if (k == null) {
|
108
|
+
return _ctx.nil;
|
109
|
+
}
|
110
|
+
RubyString key = RubyUtils.rubyString(_ruby, k);
|
111
|
+
if (_no_hash_key) {
|
112
|
+
return key;
|
113
|
+
}
|
114
|
+
return _hash_key.call(_ctx, _handler, _meta, "hash_key", key);
|
115
|
+
}
|
116
|
+
|
117
|
+
private void handleCurrentToken(JsonParser jp)
|
118
|
+
throws IOException, JsonProcessingException {
|
119
|
+
|
120
|
+
JsonStreamContext cx = jp.getParsingContext();
|
121
|
+
IRubyObject value;
|
122
|
+
IRubyObject rubyObject;
|
123
|
+
|
124
|
+
switch (jp.getCurrentToken()) {
|
125
|
+
case START_OBJECT:
|
126
|
+
_deepestContext = cx;
|
127
|
+
rubyObject = _hash_start.call(_ctx, _handler, _meta, "hash_start");
|
128
|
+
_objectMap.put(cx, rubyObject);
|
129
|
+
break;
|
130
|
+
|
131
|
+
case START_ARRAY:
|
132
|
+
_deepestContext = cx;
|
133
|
+
rubyObject = _array_start.call(_ctx, _handler, _meta, "array_start");
|
134
|
+
_objectMap.put(cx, rubyObject);
|
135
|
+
break;
|
136
|
+
|
137
|
+
case FIELD_NAME:
|
138
|
+
break;
|
139
|
+
|
140
|
+
case VALUE_EMBEDDED_OBJECT:
|
141
|
+
value = RubyUtils.rubyObject(_ruby, jp.getEmbeddedObject());
|
142
|
+
callAddValue(cx, value);
|
143
|
+
break;
|
144
|
+
|
145
|
+
case VALUE_STRING:
|
146
|
+
value = keyConverter.convert(_ruby, jp);
|
147
|
+
callAddValue(cx, value);
|
148
|
+
break;
|
149
|
+
|
150
|
+
case VALUE_NUMBER_INT:
|
151
|
+
/* [JACKSON-100]: caller may want to get all integral values
|
152
|
+
* returned as BigInteger, for consistency
|
153
|
+
*/
|
154
|
+
JsonParser.NumberType numberType = jp.getNumberType();
|
155
|
+
value = RubyUtils.rubyBignum(_ruby, jp.getBigIntegerValue());
|
156
|
+
callAddValue(cx, value);
|
157
|
+
break;
|
158
|
+
|
159
|
+
case VALUE_NUMBER_FLOAT:
|
160
|
+
value = RubyUtils.rubyBigDecimal(_ruby, jp.getDecimalValue());
|
161
|
+
callAddValue(cx, value);
|
162
|
+
break;
|
163
|
+
|
164
|
+
case VALUE_TRUE:
|
165
|
+
value = _ruby.newBoolean(Boolean.TRUE);
|
166
|
+
callAddValue(cx, value);
|
167
|
+
break;
|
168
|
+
|
169
|
+
case VALUE_FALSE:
|
170
|
+
value = _ruby.newBoolean(Boolean.FALSE);
|
171
|
+
callAddValue(cx, value);
|
172
|
+
break;
|
173
|
+
|
174
|
+
case VALUE_NULL: // should not get this but...
|
175
|
+
value = _ctx.nil;
|
176
|
+
callAddValue(cx, value);
|
177
|
+
break;
|
178
|
+
|
179
|
+
case END_ARRAY:
|
180
|
+
_array_end.call(_ctx, _handler, _meta, "array_end");
|
181
|
+
callAddValue(cx);
|
182
|
+
_deepestContext = cx;
|
183
|
+
break;
|
184
|
+
|
185
|
+
case END_OBJECT:
|
186
|
+
_hash_end.call(_ctx, _handler, _meta, "hash_end");
|
187
|
+
callAddValue(cx);
|
188
|
+
_deepestContext = cx;
|
189
|
+
break;
|
190
|
+
}
|
191
|
+
|
192
|
+
}
|
193
|
+
|
194
|
+
}
|
195
|
+
// System.out.println("--- callAddValue final ---");
|
196
|
+
// if (px != null) {
|
197
|
+
// System.out.println("-------- parent --------");
|
198
|
+
// System.out.println(px.getTypeDesc());
|
199
|
+
// System.out.println(px.getCurrentName());
|
200
|
+
// }
|
201
|
+
// System.out.println("-------- current --------");
|
202
|
+
// System.out.println(x.getTypeDesc());
|
203
|
+
// System.out.println(x.getCurrentName());
|
204
|
+
// System.out.println(target);
|
205
|
+
//
|
206
|
+
// System.out.println("-------- deepest --------");
|
207
|
+
// System.out.println(_deepestContext.getTypeDesc());
|
208
|
+
// System.out.println(_deepestContext.getCurrentName());
|
209
|
+
// System.out.println(dtarget);
|
@@ -0,0 +1,66 @@
|
|
1
|
+
package com.jrjackson;
|
2
|
+
|
3
|
+
import com.fasterxml.jackson.core.JsonParser;
|
4
|
+
|
5
|
+
import org.jruby.Ruby;
|
6
|
+
import org.jruby.RubyClass;
|
7
|
+
import org.jruby.internal.runtime.methods.DynamicMethod;
|
8
|
+
import org.jruby.runtime.ThreadContext;
|
9
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
10
|
+
import org.jruby.exceptions.RaiseException;
|
11
|
+
|
12
|
+
/**
|
13
|
+
*
|
14
|
+
* @author Guy Boertje
|
15
|
+
*/
|
16
|
+
public abstract class StreamParse {
|
17
|
+
|
18
|
+
protected final ThreadContext _ctx;
|
19
|
+
protected final Ruby _ruby;
|
20
|
+
protected final IRubyObject _handler;
|
21
|
+
protected final RubyClass _meta;
|
22
|
+
protected final RubyStringConverter keyConverter = new RubyStringConverter();
|
23
|
+
|
24
|
+
protected final DynamicMethod _hash_start;
|
25
|
+
protected final boolean _no_hash_start;
|
26
|
+
|
27
|
+
protected final DynamicMethod _hash_end;
|
28
|
+
protected final boolean _no_hash_end;
|
29
|
+
|
30
|
+
protected final DynamicMethod _array_start;
|
31
|
+
protected final boolean _no_array_start;
|
32
|
+
|
33
|
+
protected final DynamicMethod _array_end;
|
34
|
+
protected final boolean _no_array_end;
|
35
|
+
|
36
|
+
protected final DynamicMethod _add_value;
|
37
|
+
protected final boolean _no_add_value;
|
38
|
+
|
39
|
+
public StreamParse(ThreadContext ctx, IRubyObject handler)
|
40
|
+
throws RaiseException {
|
41
|
+
|
42
|
+
_ctx = ctx;
|
43
|
+
_ruby = ctx.runtime;
|
44
|
+
_handler = handler;
|
45
|
+
_meta = _handler.getMetaClass();
|
46
|
+
|
47
|
+
_add_value = _meta.searchMethod("add_value");
|
48
|
+
_no_add_value = _add_value.isUndefined();
|
49
|
+
|
50
|
+
_hash_start = _meta.searchMethod("hash_start");
|
51
|
+
_no_hash_start = _hash_start.isUndefined();
|
52
|
+
|
53
|
+
_hash_end = _meta.searchMethod("hash_end");
|
54
|
+
_no_hash_end = _hash_end.isUndefined();
|
55
|
+
|
56
|
+
_array_start = _meta.searchMethod("array_start");
|
57
|
+
_no_array_start = _array_start.isUndefined();
|
58
|
+
|
59
|
+
_array_end = _meta.searchMethod("array_end");
|
60
|
+
_no_array_end = _array_end.isUndefined();
|
61
|
+
|
62
|
+
}
|
63
|
+
|
64
|
+
public abstract IRubyObject deserialize(JsonParser jp)
|
65
|
+
throws RaiseException;
|
66
|
+
}
|
@@ -0,0 +1,533 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
$LOAD_PATH << File.expand_path('../../lib', __FILE__)
|
4
|
+
|
5
|
+
require "java"
|
6
|
+
|
7
|
+
require 'securerandom'
|
8
|
+
|
9
|
+
require 'test/unit'
|
10
|
+
require 'thread'
|
11
|
+
require 'bigdecimal'
|
12
|
+
require 'jrjackson'
|
13
|
+
require 'stringio'
|
14
|
+
require 'time'
|
15
|
+
require 'date'
|
16
|
+
|
17
|
+
class JrJacksonTest < Test::Unit::TestCase
|
18
|
+
# def test_serialize_date
|
19
|
+
# # default date format
|
20
|
+
# time_string = "2014-12-18 18:18:18 +0000"
|
21
|
+
# source_time = Time.parse(time_string)
|
22
|
+
# # source_time = Date.today
|
23
|
+
# serialized_output = JrJackson::Json.dump({current_time: source_time})
|
24
|
+
# assert_equal %Q{{"current_time":"#{time_string}"}}, serialized_output
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
class Test::Unit::CustomObj
|
28
|
+
end
|
29
|
+
|
30
|
+
class ToJsonData
|
31
|
+
attr_reader :one, :two, :six
|
32
|
+
def initialize(a,b,c)
|
33
|
+
@one, @two, @six = a,b,c
|
34
|
+
end
|
35
|
+
def to_h
|
36
|
+
{'one' => one, 'two' => two, 'six' => six}
|
37
|
+
end
|
38
|
+
def to_json_data
|
39
|
+
[one, two, six]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class CustomToH
|
44
|
+
attr_accessor :one, :two, :six
|
45
|
+
def initialize(a,b,c)
|
46
|
+
@one, @two, @six = a,b,c
|
47
|
+
end
|
48
|
+
def to_h
|
49
|
+
{'one' => one, 'two' => two, 'six' => six}
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class CustomToHash
|
54
|
+
attr_accessor :one, :two, :six
|
55
|
+
def initialize(a,b,c)
|
56
|
+
@one, @two, @six = a,b,c
|
57
|
+
end
|
58
|
+
def to_hash
|
59
|
+
{'one' => one, 'two' => two, 'six' => six}
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class CustomToJson
|
64
|
+
attr_accessor :one, :two, :six
|
65
|
+
def initialize(a,b,c)
|
66
|
+
@one, @two, @six = a,b,c
|
67
|
+
end
|
68
|
+
def to_json
|
69
|
+
%Q|{"one":#{one},"two":#{two},"six":#{six}}|
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
class CustomToTime
|
74
|
+
def initialize(tm = Time.now)
|
75
|
+
@now = tm
|
76
|
+
end
|
77
|
+
def to_time
|
78
|
+
@now.to_time
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
CustomStruct = Struct.new(:one, :two, :six)
|
83
|
+
|
84
|
+
|
85
|
+
class ScHandler
|
86
|
+
attr_accessor :calls
|
87
|
+
|
88
|
+
def initialize(arr = [])
|
89
|
+
@calls = arr
|
90
|
+
end
|
91
|
+
|
92
|
+
def hash_start()
|
93
|
+
@calls << [:hash_start]
|
94
|
+
{}
|
95
|
+
end
|
96
|
+
|
97
|
+
def hash_end()
|
98
|
+
@calls << [:hash_end]
|
99
|
+
end
|
100
|
+
|
101
|
+
def hash_key(key)
|
102
|
+
@calls << [:hash_key, key]
|
103
|
+
return 'too' if 'two' == key
|
104
|
+
return :symbol if 'symbol' == key
|
105
|
+
key
|
106
|
+
end
|
107
|
+
|
108
|
+
def array_start()
|
109
|
+
@calls << [:array_start]
|
110
|
+
[]
|
111
|
+
end
|
112
|
+
|
113
|
+
def array_end()
|
114
|
+
@calls << [:array_end]
|
115
|
+
end
|
116
|
+
|
117
|
+
def add_value(value)
|
118
|
+
@calls << [:add_value, value]
|
119
|
+
end
|
120
|
+
|
121
|
+
def hash_set(h, key, value)
|
122
|
+
# h[key] = value
|
123
|
+
@calls << [:hash_set, key, value]
|
124
|
+
end
|
125
|
+
|
126
|
+
def array_append(a, value)
|
127
|
+
# a.push(value)
|
128
|
+
@calls << [:array_append, value]
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
JsonString = %Q|{
|
133
|
+
"array": [
|
134
|
+
{
|
135
|
+
"num" : 3,
|
136
|
+
"string": "message",
|
137
|
+
"hash" : {
|
138
|
+
"h2" : {
|
139
|
+
"a" : [ 1, 2, 3 ]
|
140
|
+
}
|
141
|
+
}
|
142
|
+
}
|
143
|
+
],
|
144
|
+
"boolean" : true
|
145
|
+
}|
|
146
|
+
|
147
|
+
def test_sc_parse
|
148
|
+
array = []
|
149
|
+
handler = ScHandler.new(array)
|
150
|
+
JrJackson::Json.sc_load(handler, JsonString)
|
151
|
+
assert_equal(
|
152
|
+
[
|
153
|
+
[:hash_start],
|
154
|
+
[:array_start],
|
155
|
+
[:hash_start],
|
156
|
+
[:hash_key, 'num'],
|
157
|
+
[:hash_set, "num", 3],
|
158
|
+
[:hash_key, 'string'],
|
159
|
+
[:hash_set, "string", "message"],
|
160
|
+
[:hash_start],
|
161
|
+
[:hash_start],
|
162
|
+
[:array_start],
|
163
|
+
[:array_append, 1],
|
164
|
+
[:array_append, 2],
|
165
|
+
[:array_append, 3],
|
166
|
+
[:array_end],
|
167
|
+
[:hash_key, "a"],
|
168
|
+
[:hash_set, "a", []],
|
169
|
+
[:hash_end],
|
170
|
+
[:hash_key, "h2"],
|
171
|
+
[:hash_set, "h2", {}],
|
172
|
+
[:hash_end],
|
173
|
+
[:hash_key, "hash"],
|
174
|
+
[:hash_set, "hash", {}],
|
175
|
+
[:hash_end],
|
176
|
+
[:array_append, {}],
|
177
|
+
[:array_end],
|
178
|
+
[:hash_key, "array"],
|
179
|
+
[:hash_set, "array", []],
|
180
|
+
[:hash_key, 'boolean'],
|
181
|
+
[:hash_set, "boolean", true],
|
182
|
+
[:hash_end],
|
183
|
+
[:add_value, {}]
|
184
|
+
],
|
185
|
+
handler.calls
|
186
|
+
)
|
187
|
+
end
|
188
|
+
|
189
|
+
class SjHandler
|
190
|
+
attr_reader :calls
|
191
|
+
def initialize(arr = []) @calls = arr; end
|
192
|
+
def hash_start(key) @calls << [:hash_start, key]; end
|
193
|
+
def hash_end(key) @calls << [:hash_end, key]; end
|
194
|
+
def array_start(key) @calls << [:array_start, key]; end
|
195
|
+
def array_end(key) @calls << [:array_end, key]; end
|
196
|
+
def add_value(value, key) @calls << [:add_value, value, key]; end
|
197
|
+
def error(message, line, column) @calls << [:error, message, line, column]; end
|
198
|
+
end
|
199
|
+
|
200
|
+
def test_sj_parse
|
201
|
+
handler = SjHandler.new()
|
202
|
+
JrJackson::Json.sj_load(handler, JsonString)
|
203
|
+
assert_equal(
|
204
|
+
[
|
205
|
+
[:hash_start, nil],
|
206
|
+
[:array_start, 'array'],
|
207
|
+
[:hash_start, nil],
|
208
|
+
[:add_value, 3, 'num'],
|
209
|
+
[:add_value, 'message', 'string'],
|
210
|
+
[:hash_start, 'hash'],
|
211
|
+
[:hash_start, 'h2'],
|
212
|
+
[:array_start, 'a'],
|
213
|
+
[:add_value, 1, nil],
|
214
|
+
[:add_value, 2, nil],
|
215
|
+
[:add_value, 3, nil],
|
216
|
+
[:array_end, 'a'],
|
217
|
+
[:hash_end, 'h2'],
|
218
|
+
[:hash_end, 'hash'],
|
219
|
+
[:hash_end, nil],
|
220
|
+
[:array_end, 'array'],
|
221
|
+
[:add_value, true, 'boolean'],
|
222
|
+
[:hash_end, nil]
|
223
|
+
],
|
224
|
+
handler.calls
|
225
|
+
)
|
226
|
+
end
|
227
|
+
|
228
|
+
def test_to_json_data
|
229
|
+
object = ToJsonData.new("uno", :two, 6.0)
|
230
|
+
expected = "[1,[\"uno\",\"two\",6.0]]"
|
231
|
+
actual = JrJackson::Json.dump([1, object])
|
232
|
+
assert_equal expected, actual
|
233
|
+
end
|
234
|
+
|
235
|
+
def test_datetime
|
236
|
+
h = {datetime: DateTime.parse("2014-01-27T18:24:46+01:00")}
|
237
|
+
expected = '{"datetime":"2014-01-27 17:24:46 +0000"}'
|
238
|
+
actual = JrJackson::Json.dump(h)
|
239
|
+
assert_equal expected, actual
|
240
|
+
end
|
241
|
+
|
242
|
+
def test_dump_date_in_array
|
243
|
+
expected = "[\"2016-04-10\"]"
|
244
|
+
td = Date.new(2016, 4, 10)
|
245
|
+
actual = JrJackson::Json.generate([td])
|
246
|
+
assert_equal(actual, expected)
|
247
|
+
end
|
248
|
+
|
249
|
+
def test_threading
|
250
|
+
q1, q2, q3 = Queue.new, Queue.new, Queue.new
|
251
|
+
|
252
|
+
s1 = %Q|{"a":2.5, "b":0.214, "c":3.4567, "d":-3.4567}|
|
253
|
+
th1 = Thread.new(s1) do |string|
|
254
|
+
q1 << JrJackson::Json.load(string, {use_bigdecimal: true, raw: true})
|
255
|
+
end
|
256
|
+
th2 = Thread.new(s1) do |string|
|
257
|
+
q2 << JrJackson::Json.load(string, {use_bigdecimal: true, symbolize_keys: true})
|
258
|
+
end
|
259
|
+
th3 = Thread.new(s1) do |string|
|
260
|
+
q3 << JrJackson::Json.load(string, {use_bigdecimal: false, symbolize_keys: true})
|
261
|
+
end
|
262
|
+
a1, a2, a3 = q1.pop, q2.pop, q3.pop
|
263
|
+
assert_equal ["a", "b", "c", "d"], a1.keys
|
264
|
+
assert a1.values.all? {|v| v.is_a?(Java::JavaMath::BigDecimal)}, "Expected all values to be Java::JavaMath::BigDecimal"
|
265
|
+
assert_equal [:a, :b, :c, :d], a2.keys
|
266
|
+
assert a2.values.all? {|v| v.is_a?(BigDecimal)}, "Expected all values to be BigDecimal"
|
267
|
+
assert a3.values.all? {|v| v.is_a?(Float)}, "Expected all values to be Float"
|
268
|
+
end
|
269
|
+
|
270
|
+
def test_deserialize_JSON_with_UTF8_characters
|
271
|
+
json_string = JrJackson::Json.dump({"utf8" => "żółć"})
|
272
|
+
expected = {utf8: "żółć"}
|
273
|
+
actual = JrJackson::Json.load(json_string, :symbolize_keys => true)
|
274
|
+
|
275
|
+
assert_equal expected, actual
|
276
|
+
end
|
277
|
+
|
278
|
+
def test_deserialize_JSON_with_two_entries
|
279
|
+
json_string = JrJackson::Json.dump({'foo' => 'foo_value', 'bar' => 'bar_value'})
|
280
|
+
expected = {foo: 'foo_value', bar: 'bar_value'}
|
281
|
+
actual = JrJackson::Json.load(json_string, :symbolize_keys => true)
|
282
|
+
assert_equal expected, actual
|
283
|
+
end
|
284
|
+
|
285
|
+
def test_serialize_non_json_datatypes_as_values
|
286
|
+
dt = Time.now
|
287
|
+
today = Date.today
|
288
|
+
co1 = CustomToH.new("uno", :two, 6.0)
|
289
|
+
co2 = CustomToHash.new("uno", :two, 6.0)
|
290
|
+
co3 = CustomToJson.new(1.0, 2, 6.0)
|
291
|
+
co4 = CustomStruct.new(1, 2, 6)
|
292
|
+
co5 = CustomToTime.new(today)
|
293
|
+
source = {'sym' => :a_symbol, 'dt' => dt, 'co1' => co1, 'co2' => co2, 'co3' => co3, 'co4' => co4, 'co5' => co5}
|
294
|
+
json_string = JrJackson::Json.dump(source)
|
295
|
+
expected = {
|
296
|
+
:sym => "a_symbol",
|
297
|
+
:dt => dt.to_s,
|
298
|
+
:co1 => {:one => "uno", :two => "two", :six => 6.0 },
|
299
|
+
:co2 => {:one => "uno", :two => "two", :six => 6.0 },
|
300
|
+
:co3 => {:one => 1.0, :two => 2.0, :six => 6.0 },
|
301
|
+
:co4 => [1, 2, 6],
|
302
|
+
:co5 => today.to_time.to_s
|
303
|
+
}
|
304
|
+
actual = JrJackson::Json.load(json_string, :symbolize_keys => true)
|
305
|
+
assert_equal expected, actual
|
306
|
+
end
|
307
|
+
|
308
|
+
def test_raw_serialize_base_classes
|
309
|
+
# String
|
310
|
+
assert_equal JrJackson::Json.dump("foo"), "\"foo\""
|
311
|
+
|
312
|
+
# Hash and implementations of the Java Hash interface
|
313
|
+
assert_equal JrJackson::Json.dump({"foo" => 1}), "{\"foo\":1}"
|
314
|
+
assert_equal JrJackson::Json.dump(Java::JavaUtil::HashMap.new({"foo" => 1})), "{\"foo\":1}"
|
315
|
+
assert_equal JrJackson::Json.dump(Java::JavaUtil::LinkedHashMap.new({"foo" => 1})), "{\"foo\":1}"
|
316
|
+
|
317
|
+
# Array and implementations of the Java List interface
|
318
|
+
assert_equal JrJackson::Json.dump(["foo", 1]), "[\"foo\",1]"
|
319
|
+
assert_equal JrJackson::Json.dump(Java::JavaUtil::ArrayList.new(["foo", 1])), "[\"foo\",1]"
|
320
|
+
assert_equal JrJackson::Json.dump(Java::JavaUtil::LinkedList.new(["foo", 1])), "[\"foo\",1]"
|
321
|
+
assert_equal JrJackson::Json.dump(Java::JavaUtil::Vector.new(["foo", 1])), "[\"foo\",1]"
|
322
|
+
|
323
|
+
# true/false
|
324
|
+
assert_equal JrJackson::Json.dump(true), "true"
|
325
|
+
assert_equal JrJackson::Json.dump(false), "false"
|
326
|
+
|
327
|
+
# nil
|
328
|
+
assert_equal JrJackson::Json.dump(nil), "null"
|
329
|
+
end
|
330
|
+
|
331
|
+
def test_serialize_date
|
332
|
+
# default date format
|
333
|
+
time_string = "2014-06-10 18:18:40 EDT"
|
334
|
+
source_time = Time.parse(time_string)
|
335
|
+
serialized_output = JrJackson::Json.dump({"time" => source_time})
|
336
|
+
other_time = Time.parse(serialized_output.split('"')[-2])
|
337
|
+
assert_equal other_time.to_f, source_time.to_f
|
338
|
+
end
|
339
|
+
|
340
|
+
def test_serialize_date_date_format
|
341
|
+
|
342
|
+
time = Time.new(2014,6,10,18,18,40, "-04:00")
|
343
|
+
# using date_format option
|
344
|
+
assert_equal "{\"time\":\"2014-06-10\"}", JrJackson::Json.dump({"time" => time}, :date_format => "yyyy-MM-dd")
|
345
|
+
assert_match /\{"time"\:"\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d{3}[+-]\d{4}"\}/, JrJackson::Json.dump({"time" => time}, :date_format => "yyyy-MM-dd'T'HH:mm:ss.SSSZ")
|
346
|
+
end
|
347
|
+
|
348
|
+
def test_serialize_date_date_format_timezone
|
349
|
+
|
350
|
+
time = Time.new(2014,6,10,18,18,40, "-04:00")
|
351
|
+
# using date_format and timezone options
|
352
|
+
assert_equal "{\"time\":\"2014-06-10T22:18:40.000+0000\"}", JrJackson::Json.dump({"time" => time}, :date_format => "yyyy-MM-dd'T'HH:mm:ss.SSSZ", :timezone => "UTC")
|
353
|
+
# iso8601 date_format and timezone
|
354
|
+
assert_equal "{\"time\":\"2014-06-10T22:18:40.000Z\"}", JrJackson::Json.dump({"time" => time}, :date_format => "yyyy-MM-dd'T'HH:mm:ss.SSSX", :timezone => "UTC")
|
355
|
+
end
|
356
|
+
|
357
|
+
def test_can_parse_returning_java_objects
|
358
|
+
expected = {"arr"=>[2, 3, 4],
|
359
|
+
"flo"=>0.333E1,
|
360
|
+
"moo"=>"bar",
|
361
|
+
"utf8"=>"żółć",
|
362
|
+
"zzz"=>{"bar"=>-9}}
|
363
|
+
json = '{"utf8":"żółć", "moo": "bar", "zzz": {"bar":-9}, "arr": [2,3,4], "flo": 3.33}'
|
364
|
+
|
365
|
+
actual = JrJackson::Json.parse_java(json)
|
366
|
+
|
367
|
+
assert_equal Java::JavaUtil::HashMap, actual.class
|
368
|
+
assert_equal Java::JavaUtil::ArrayList, actual["arr"].class
|
369
|
+
assert_equal Java::JavaMath::BigDecimal, actual["flo"].class
|
370
|
+
assert_equal "3.33", actual["flo"].to_s
|
371
|
+
assert_equal "bar", actual["moo"]
|
372
|
+
assert_equal "żółć", actual["utf8"]
|
373
|
+
assert_equal Java::JavaUtil::HashMap, actual["zzz"].class
|
374
|
+
assert_equal Bignum, actual["zzz"]["bar"].class
|
375
|
+
assert_equal -9, actual["zzz"]["bar"]
|
376
|
+
end
|
377
|
+
|
378
|
+
def test_can_parse_returning_ruby_objects_string_keys
|
379
|
+
expected = {
|
380
|
+
"a"=>"żółć", # string
|
381
|
+
"b"=>true, # boolean
|
382
|
+
"c"=>12345, # number
|
383
|
+
"d"=>
|
384
|
+
[true,
|
385
|
+
[false,
|
386
|
+
[-123456789, nil],
|
387
|
+
0.39676E1,
|
388
|
+
["Something else.", false],
|
389
|
+
nil]], # mix it up array
|
390
|
+
"e"=>{"zero"=>nil, "one"=>1, "two"=>2, "three"=>[3], "four"=>[0, 1, 2, 3, 4]}, # hash
|
391
|
+
"żółć"=>nil,# nil
|
392
|
+
"h"=>{"a"=>{"b"=>{"c"=>{"d"=>{"e"=>{"f"=>{"g"=>nil}}}}}}},# deep hash, not that deep
|
393
|
+
"i"=>[[[[[[[nil]]]]]]] # deep array, again, not that deep
|
394
|
+
}
|
395
|
+
json = JrJackson::Json.dump(expected)
|
396
|
+
actual = JrJackson::Json.parse_ruby(json)
|
397
|
+
assert_equal expected, actual
|
398
|
+
actual = JrJackson::Ruby.parse(json, {})
|
399
|
+
assert_equal expected, actual
|
400
|
+
end
|
401
|
+
|
402
|
+
def test_can_parse_returning_ruby_objects_symbol_keys
|
403
|
+
expected = {:a=>"Alpha",
|
404
|
+
:b=>true,
|
405
|
+
:c=>12345,
|
406
|
+
:d=>
|
407
|
+
[true, [false, [-123456789, nil], 3.9676, ["Something else.", false], nil]],
|
408
|
+
:e=>{:zero=>nil, :one=>1, :two=>2, :three=>[3], :four=>[0, 1, 2, 3, 4]},
|
409
|
+
:f=>nil,
|
410
|
+
:h=>{:a=>{:b=>{:c=>{:d=>{:e=>{:f=>{:g=>nil}}}}}}},
|
411
|
+
:i=>[[[[[[[nil]]]]]]]
|
412
|
+
}
|
413
|
+
json = JrJackson::Json.dump(expected)
|
414
|
+
actual = JrJackson::Ruby.parse_sym(json, {})
|
415
|
+
assert_equal expected, actual
|
416
|
+
end
|
417
|
+
|
418
|
+
def test_can_parse_nulls
|
419
|
+
expected = {"foo" => nil}
|
420
|
+
json = '{"foo":null}'
|
421
|
+
actual = JrJackson::Json.parse(json)
|
422
|
+
assert_equal expected, actual
|
423
|
+
end
|
424
|
+
|
425
|
+
def test_stringio
|
426
|
+
expected = {"foo" => 5, "utf8" => "żółć"}
|
427
|
+
json = ::StringIO.new('{"foo":5, "utf8":"żółć"}')
|
428
|
+
actual = JrJackson::Json.load_ruby(json)
|
429
|
+
assert_equal expected, actual
|
430
|
+
end
|
431
|
+
|
432
|
+
def test_ruby_io
|
433
|
+
expected = {"foo" => 5, "bar" => 6, "utf8" => "żółć"}
|
434
|
+
json, w = IO.pipe
|
435
|
+
w.write('{"foo":5, "bar":6, "utf8":"żółć"}')
|
436
|
+
w.close
|
437
|
+
actual = JrJackson::Json.load(json)
|
438
|
+
assert_equal expected, actual
|
439
|
+
end
|
440
|
+
|
441
|
+
def test_bad_utf
|
442
|
+
assert_raise JrJackson::ParseError do
|
443
|
+
JrJackson::Json.load("\x82\xAC\xEF")
|
444
|
+
end
|
445
|
+
end
|
446
|
+
|
447
|
+
def test_can_parse_bignum
|
448
|
+
expected = 12345678901234567890123456789
|
449
|
+
json = '{"foo":12345678901234567890123456789}'
|
450
|
+
|
451
|
+
actual = JrJackson::Json.parse(json)['foo']
|
452
|
+
assert_equal expected, actual
|
453
|
+
end
|
454
|
+
|
455
|
+
def test_can_parse_big_decimals
|
456
|
+
expected = BigDecimal.new '0.12345678901234567890123456789'
|
457
|
+
json = '{"foo":0.12345678901234567890123456789}'
|
458
|
+
|
459
|
+
actual = JrJackson::Json.parse(json, :use_bigdecimal => true)['foo']
|
460
|
+
assert_bigdecimal_equal expected, actual
|
461
|
+
|
462
|
+
actual = JrJackson::Json.parse(json, :use_bigdecimal => true, :symbolize_keys => true)[:foo]
|
463
|
+
assert_bigdecimal_equal expected, actual
|
464
|
+
|
465
|
+
actual = JrJackson::Java.parse(json, {})['foo']
|
466
|
+
assert_bigdecimal_similar expected, actual
|
467
|
+
|
468
|
+
actual = JrJackson::Json.parse(json, :use_bigdecimal => true, :raw => true)['foo']
|
469
|
+
assert_bigdecimal_similar expected, actual
|
470
|
+
|
471
|
+
end
|
472
|
+
|
473
|
+
def test_cannot_serialize_object
|
474
|
+
err = assert_raises(JrJackson::ParseError) { JrJackson::Json.dump({"foo" => Object.new}) }
|
475
|
+
assert_match /Cannot serialize instance of: Object/, err.message
|
476
|
+
end
|
477
|
+
|
478
|
+
def test_cannot_serialize_basic_object
|
479
|
+
err = assert_raises(JrJackson::ParseError) { JrJackson::Json.dump({"foo" => BasicObject.new}) }
|
480
|
+
assert_match /Cannot serialize instance of: BasicObject/, err.message
|
481
|
+
end
|
482
|
+
|
483
|
+
def test_cannot_serialize_custom_object
|
484
|
+
err = assert_raises(JrJackson::ParseError) { JrJackson::Json.dump({"foo" => Test::Unit::CustomObj.new}) }
|
485
|
+
assert_match /Cannot serialize instance of: Test::Unit::CustomObj/, err.message
|
486
|
+
end
|
487
|
+
|
488
|
+
def test_supports_pretty_printing
|
489
|
+
object = {"foo" => 5, "utf8" => "żółć"}
|
490
|
+
|
491
|
+
actual = JrJackson::Json.dump(object, :pretty => true)
|
492
|
+
assert_equal "{\n \"foo\" : 5,\n \"utf8\" : \"żółć\"\n}", actual
|
493
|
+
end
|
494
|
+
|
495
|
+
def test_can_serialise_non_string_keys
|
496
|
+
object = {5 => "foo"}
|
497
|
+
actual = JrJackson::Json.dump(object)
|
498
|
+
assert_equal "{\"5\":\"foo\"}", actual
|
499
|
+
end
|
500
|
+
|
501
|
+
def test_can_serialise_regex_match_data
|
502
|
+
re = %r|(foo)(bar)(baz)|
|
503
|
+
m = re.match('foobarbaz')
|
504
|
+
object = {'matched' => m[2]}
|
505
|
+
actual = JrJackson::Json.dump(object)
|
506
|
+
assert_equal "{\"matched\":\"bar\"}", actual
|
507
|
+
end
|
508
|
+
|
509
|
+
def test_can_mix_java_and_ruby_objects
|
510
|
+
json = '{"utf8":"żółć", "moo": "bar", "arr": [2,3,4], "flo": 3.33}'
|
511
|
+
timeobj = Time.new(2015,11,11,11,11,11).utc
|
512
|
+
expected = '{"mixed":{"arr":[2,3,4],"utf8":"żółć","flo":3.33,"zzz":{"one":1.0,"two":2,"six":6.0},"moo":"bar"},"time":"2015-11-11 11:11:11 +0000"}'
|
513
|
+
object = JrJackson::Json.parse_java(json)
|
514
|
+
object["zzz"] = CustomToJson.new(1.0, 2, 6.0)
|
515
|
+
mixed = {"mixed" => object}
|
516
|
+
mixed['time'] = timeobj
|
517
|
+
actual = JrJackson::Json.dump(mixed)
|
518
|
+
assert_equal expected, actual
|
519
|
+
end
|
520
|
+
|
521
|
+
# -----------------------------
|
522
|
+
|
523
|
+
def assert_bigdecimal_equal(expected, actual)
|
524
|
+
assert_equal expected, actual
|
525
|
+
assert_equal expected.class, actual.class
|
526
|
+
assert_equal BigDecimal, actual.class
|
527
|
+
end
|
528
|
+
|
529
|
+
def assert_bigdecimal_similar(expected, actual)
|
530
|
+
assert_equal BigDecimal.new(expected.to_s).round(11), BigDecimal.new(actual.to_s).round(11)
|
531
|
+
assert_equal Java::JavaMath::BigDecimal, actual.class
|
532
|
+
end
|
533
|
+
end
|