jrjackson 0.1.1 → 0.2.0

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.
@@ -1,4 +1,3 @@
1
-
2
1
  module JrJackson
3
- VERSION = '0.1.1'
2
+ VERSION = '0.2.0'
4
3
  end
data/pom.xml CHANGED
@@ -5,10 +5,10 @@
5
5
  <groupId>com.jrjackson.jruby</groupId>
6
6
  <artifactId>jrjackson</artifactId>
7
7
  <packaging>jar</packaging>
8
- <version>1.0</version>
8
+ <version>1.2.2</version>
9
9
  <name>jrjackson</name>
10
10
  <url>http://maven.apache.org</url>
11
-
11
+
12
12
  <properties>
13
13
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
14
14
  </properties>
@@ -28,17 +28,22 @@
28
28
  <dependency>
29
29
  <groupId>com.fasterxml.jackson.core</groupId>
30
30
  <artifactId>jackson-core</artifactId>
31
- <version>2.1.4</version>
31
+ <version>2.2.2</version>
32
32
  </dependency>
33
33
  <dependency>
34
34
  <groupId>com.fasterxml.jackson.core</groupId>
35
35
  <artifactId>jackson-annotations</artifactId>
36
- <version>2.1.4</version>
36
+ <version>2.2.2</version>
37
37
  </dependency>
38
38
  <dependency>
39
39
  <groupId>com.fasterxml.jackson.core</groupId>
40
40
  <artifactId>jackson-databind</artifactId>
41
- <version>2.1.4</version>
41
+ <version>2.2.2</version>
42
+ </dependency>
43
+ <dependency>
44
+ <groupId>com.fasterxml.jackson.module</groupId>
45
+ <artifactId>jackson-module-afterburner</artifactId>
46
+ <version>2.2.2</version>
42
47
  </dependency>
43
48
  </dependencies>
44
49
  <build>
@@ -46,16 +51,16 @@
46
51
  <plugin>
47
52
  <groupId>org.apache.maven.plugins</groupId>
48
53
  <artifactId>maven-compiler-plugin</artifactId>
49
- <version>3.0</version>
54
+ <version>3.1</version>
50
55
  <configuration>
51
- <source>1.6</source>
52
- <target>1.6</target>
56
+ <source>1.7</source>
57
+ <target>1.7</target>
53
58
  </configuration>
54
59
  </plugin>
55
60
  <plugin>
56
61
  <groupId>org.apache.maven.plugins</groupId>
57
62
  <artifactId>maven-surefire-plugin</artifactId>
58
- <version>2.12.2</version>
63
+ <version>2.16</version>
59
64
  <configuration>
60
65
  <parallel>methods</parallel>
61
66
  <threadCount>10</threadCount>
@@ -64,7 +69,7 @@
64
69
  <plugin>
65
70
  <groupId>org.apache.maven.plugins</groupId>
66
71
  <artifactId>maven-shade-plugin</artifactId>
67
- <version>1.6</version>
72
+ <version>2.1</version>
68
73
  <executions>
69
74
  <execution>
70
75
  <phase>package</phase>
@@ -4,51 +4,135 @@ import org.jruby.Ruby;
4
4
  import org.jruby.RubyClass;
5
5
  import org.jruby.RubyObject;
6
6
  import org.jruby.RubyString;
7
+ import org.jruby.RubySymbol;
8
+ import org.jruby.RubyHash;
7
9
  import org.jruby.RubyIO;
8
10
  import org.jruby.anno.JRubyMethod;
9
11
  import org.jruby.anno.JRubyModule;
10
12
  import org.jruby.exceptions.RaiseException;
11
13
  import org.jruby.ext.stringio.RubyStringIO;
12
14
  import org.jruby.java.addons.IOJavaAddons;
13
- import org.jruby.javasupport.JavaUtil;
14
15
  import org.jruby.runtime.ThreadContext;
15
16
  import org.jruby.runtime.builtin.IRubyObject;
16
- import org.jruby.util.RubyDateFormat;
17
17
 
18
18
  import java.io.InputStream;
19
19
  import java.io.IOException;
20
- import java.text.DateFormat;
21
20
  import java.util.*;
22
21
 
23
22
  import com.fasterxml.jackson.databind.ObjectMapper;
23
+ import com.fasterxml.jackson.databind.DeserializationFeature;
24
24
  import com.fasterxml.jackson.core.JsonProcessingException;
25
25
 
26
26
  @JRubyModule(name = "JrJacksonRaw")
27
27
  public class JrJacksonRaw extends RubyObject {
28
- protected static final ObjectMapper mapper = new ObjectMapper();
28
+ private static final HashMap<String, ObjectMapper> mappers = new HashMap<String, ObjectMapper>(3);
29
+ private static final HashMap<String, RubySymbol> symbols = new HashMap<String, RubySymbol>(3);
30
+
31
+ private static final Ruby _ruby = Ruby.getGlobalRuntime();
29
32
 
30
33
  static {
31
- mapper.setDateFormat(new RubyDateFormat("yyyy-MM-dd HH:mm:ss z", Locale.US, true));
34
+ mappers.put("str",
35
+ RubyJacksonModule.mappedAs("str")
36
+ );
37
+ mappers.put("sym",
38
+ RubyJacksonModule.mappedAs("sym")
39
+ );
40
+ mappers.put("raw",
41
+ RubyJacksonModule.mappedAs("raw")
42
+ );
43
+ symbols.put("sym",
44
+ RubyUtils.rubySymbol(_ruby, "symbolize_keys")
45
+ );
46
+ symbols.put("raw",
47
+ RubyUtils.rubySymbol(_ruby, "raw")
48
+ );
49
+ symbols.put("bigdecimal",
50
+ RubyUtils.rubySymbol(_ruby, "use_bigdecimal")
51
+ );
32
52
  }
33
53
 
34
54
  public JrJacksonRaw(Ruby ruby, RubyClass metaclass) {
35
55
  super(ruby, metaclass);
36
56
  }
37
57
 
38
- @JRubyMethod(module = true, name = {"parse", "load"}, required = 1)
39
- public static IRubyObject parse(ThreadContext context, IRubyObject self, IRubyObject arg) {
58
+ private static boolean flagged(RubyHash opts, String key) {
59
+ Object val = opts.get(symbols.get(key));
60
+ if (val == null) {
61
+ return false;
62
+ }
63
+ return (Boolean) val;
64
+ }
65
+
66
+ // deserialize
67
+ @JRubyMethod(module = true, name = {"parse", "load"}, required = 2)
68
+ public static IRubyObject parse(ThreadContext context, IRubyObject self, IRubyObject arg, IRubyObject opts)
69
+ throws IOException
70
+ {
71
+ RubyHash options = null;
72
+ String key = "str";
73
+ ObjectMapper local;
74
+
75
+ if (opts != context.nil) {
76
+ options = opts.convertToHash();
77
+ if (flagged(options, "sym")) {
78
+ key = "sym";
79
+ }
80
+ if (flagged(options, "raw")) {
81
+ key = "raw";
82
+ }
83
+ local = mappers.get(key).copy();
84
+ if (flagged(options, "bigdecimal")) {
85
+ local.enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS);
86
+ }
87
+ else {
88
+ local.disable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS);
89
+ }
90
+ }
91
+ else {
92
+ local = mappers.get(key).copy();
93
+ }
94
+ return _parse(context, arg, local);
95
+ }
96
+
97
+ @JRubyMethod(module = true, name = {"parse_raw", "load_raw"}, required = 1)
98
+ public static IRubyObject parse_raw(ThreadContext context, IRubyObject self, IRubyObject arg)
99
+ throws IOException
100
+ {
101
+ return _parse(context, arg, mappers.get("raw"));
102
+ }
103
+
104
+ @JRubyMethod(module = true, name = {"parse_sym", "load_sym"}, required = 1)
105
+ public static IRubyObject parse_sym(ThreadContext context, IRubyObject self, IRubyObject arg)
106
+ throws IOException
107
+ {
108
+ return _parse(context, arg, mappers.get("sym"));
109
+ }
110
+
111
+ @JRubyMethod(module = true, name = {"parse_str", "load_str"}, required = 1)
112
+ public static IRubyObject parse_str(ThreadContext context, IRubyObject self, IRubyObject arg)
113
+ throws IOException
114
+ {
115
+ return _parse(context, arg, mappers.get("str"));
116
+ }
117
+
118
+ public static IRubyObject _parse(ThreadContext context, IRubyObject arg, ObjectMapper mapper)
119
+ throws IOException
120
+ {
40
121
  Ruby ruby = context.getRuntime();
122
+
41
123
  try {
42
124
  Object o;
43
125
  if (arg instanceof RubyString) {
44
- o = mapper.readValue(arg.toString(), Object.class);
126
+ o = mapper.readValue(
127
+ arg.toString(), Object.class
128
+ );
45
129
  } else if ((arg instanceof RubyIO) || (arg instanceof RubyStringIO)) {
46
130
  IRubyObject stream = IOJavaAddons.AnyIO.any_to_inputstream(context, arg);
47
- o = mapper.readValue((InputStream)stream.toJava(InputStream.class), Object.class);
131
+ o = mapper.readValue((InputStream)stream.toJava(InputStream.class), Object.class);
48
132
  } else {
49
133
  throw ruby.newArgumentError("Unsupported source. This method accepts String or IO");
50
134
  }
51
- return (RubyObject)JavaUtil.convertJavaToRuby(ruby, o);
135
+ return RubyUtils.rubyObject(ruby, o);
52
136
  }
53
137
  catch (JsonProcessingException e) {
54
138
  throw ParseError.newParseError(ruby, e.getLocalizedMessage());
@@ -58,13 +142,14 @@ public class JrJacksonRaw extends RubyObject {
58
142
  }
59
143
  }
60
144
 
145
+ // serialize
61
146
  @JRubyMethod(module = true, name = {"generate", "dump"}, required = 1)
62
147
  public static IRubyObject generate(ThreadContext context, IRubyObject self, IRubyObject arg) {
63
148
  Ruby ruby = context.getRuntime();
64
149
  Object obj = arg.toJava(Object.class);
65
150
  try {
66
- String s = mapper.writeValueAsString(obj);
67
- return ruby.newString(s);
151
+ String s = mappers.get("raw").writeValueAsString(obj);
152
+ return RubyUtils.rubyString(ruby, s);
68
153
  }
69
154
  catch (JsonProcessingException e) {
70
155
  throw ParseError.newParseError(ruby, e.getLocalizedMessage());
@@ -13,15 +13,9 @@ public class JrJacksonService implements BasicLibraryService {
13
13
  public boolean basicLoad(final Ruby ruby) throws IOException {
14
14
  RubyModule jr_jackson = ruby.defineModule("JrJackson");
15
15
 
16
- RubyModule jr_jackson_str = ruby.defineModuleUnder("Str", jr_jackson);
17
- jr_jackson_str.defineAnnotatedMethods(JrJacksonStr.class);
18
-
19
16
  RubyModule jr_jackson_raw = ruby.defineModuleUnder("Raw", jr_jackson);
20
17
  jr_jackson_raw.defineAnnotatedMethods(JrJacksonRaw.class);
21
18
 
22
- RubyModule jr_jackson_sym = ruby.defineModuleUnder("Sym", jr_jackson);
23
- jr_jackson_sym.defineAnnotatedMethods(JrJacksonSym.class);
24
-
25
19
  RubyClass runtimeError = ruby.getRuntimeError();
26
20
  RubyClass parseError = jr_jackson.defineClassUnder("ParseError", runtimeError, runtimeError.getAllocator());
27
21
  return true;
@@ -0,0 +1,74 @@
1
+ package com.jrjackson;
2
+
3
+ import java.util.*;
4
+
5
+ import org.jruby.*;
6
+ import org.jruby.util.RubyDateFormat;
7
+
8
+ import com.fasterxml.jackson.databind.ObjectMapper;
9
+ import com.fasterxml.jackson.databind.module.SimpleModule;
10
+ import com.fasterxml.jackson.core.util.VersionUtil;
11
+ import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
12
+
13
+ import com.fasterxml.jackson.module.afterburner.AfterburnerModule;
14
+
15
+ public class RubyJacksonModule extends SimpleModule
16
+ {
17
+
18
+ private RubyJacksonModule()
19
+ {
20
+ super("JrJacksonStrModule", VersionUtil.versionFor(RubyJacksonModule.class));
21
+ }
22
+
23
+ public static ObjectMapper mappedAs(String key)
24
+ {
25
+ ObjectMapper mapper = new ObjectMapper();
26
+
27
+ mapper.registerModule(
28
+ new AfterburnerModule()
29
+ );
30
+
31
+ if (key == "sym") {
32
+ mapper.registerModule(
33
+ asSym()
34
+ );
35
+ }
36
+ else if (key == "raw") {
37
+ mapper.registerModule(
38
+ asRaw()
39
+ );
40
+ }
41
+ else {
42
+ mapper.registerModule(
43
+ asStr()
44
+ );
45
+ }
46
+ mapper.setDateFormat(new RubyDateFormat("yyyy-MM-dd HH:mm:ss z", Locale.US, true));
47
+ return mapper;
48
+ }
49
+
50
+ public static SimpleModule asRaw()
51
+ {
52
+ return new RubyJacksonModule().addSerializer(
53
+ RubySymbol.class, ToStringSerializer.instance
54
+ );
55
+ }
56
+
57
+ public static SimpleModule asSym()
58
+ {
59
+ return new RubyJacksonModule().addSerializer(
60
+ RubySymbol.class, ToStringSerializer.instance
61
+ ).addDeserializer(
62
+ Object.class, RubyObjectSymDeserializer.instance
63
+ );
64
+ }
65
+
66
+ public static SimpleModule asStr()
67
+ {
68
+ return new RubyJacksonModule().addSerializer(
69
+ RubySymbol.class, ToStringSerializer.instance
70
+ ).addDeserializer(
71
+ Object.class, RubyObjectStrDeserializer.instance
72
+ );
73
+ }
74
+ }
@@ -7,8 +7,6 @@ import com.fasterxml.jackson.core.*;
7
7
 
8
8
  import com.fasterxml.jackson.databind.DeserializationContext;
9
9
  import com.fasterxml.jackson.databind.DeserializationFeature;
10
- import com.fasterxml.jackson.databind.annotation.JacksonStdImpl;
11
- import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
12
10
  import com.fasterxml.jackson.databind.util.ObjectBuffer;
13
11
  import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
14
12
 
@@ -16,242 +14,160 @@ import org.jruby.Ruby;
16
14
  import org.jruby.RubyObject;
17
15
  import org.jruby.RubyArray;
18
16
  import org.jruby.RubyHash;
19
- import org.jruby.RubyString;
20
- import org.jruby.runtime.builtin.IRubyObject;
21
- import org.jruby.javasupport.JavaUtil;
22
17
  import org.jruby.javasupport.util.RuntimeHelpers;
23
18
 
24
19
 
25
- public class RubyObjectDeserializer
26
- extends StdDeserializer<RubyObject>
20
+ public abstract class RubyObjectDeserializer
21
+ extends StdDeserializer<RubyObject>
27
22
  {
28
- private static final long serialVersionUID = 1L;
29
-
30
- private final static RubyObject[] NO_OBJECTS = new RubyObject[0];
31
-
32
- protected final static Ruby __ruby__ = Ruby.getGlobalRuntime();
33
-
34
- /**
35
- * @since 2.2
36
- */
37
- public final static RubyObjectDeserializer instance = new RubyObjectDeserializer();
38
-
39
- public RubyObjectDeserializer() { super(RubyObject.class); }
40
-
41
- /*
42
- /**********************************************************
43
- /* Deserializer API
44
- /**********************************************************
45
- */
46
-
47
- @Override
48
- public RubyObject deserialize(JsonParser jp, DeserializationContext ctxt)
49
- throws IOException, JsonProcessingException
50
- {
51
- switch (jp.getCurrentToken()) {
52
- case START_OBJECT:
53
- return mapObject(jp, ctxt);
54
- case START_ARRAY:
55
- return mapArray(jp, ctxt);
56
- case FIELD_NAME:
57
- return mapObject(jp, ctxt);
58
- case VALUE_EMBEDDED_OBJECT:
59
- return toRuby(jp.getEmbeddedObject());
60
- case VALUE_STRING:
61
- return rubyString(jp);
62
-
63
- case VALUE_NUMBER_INT:
64
- /* [JACKSON-100]: caller may want to get all integral values
65
- * returned as BigInteger, for consistency
66
- */
67
- if (ctxt.isEnabled(DeserializationFeature.USE_BIG_INTEGER_FOR_INTS)) {
68
- return toRuby(jp.getBigIntegerValue()); // should be optimal, whatever it is
69
- }
70
- return toRuby(jp.getNumberValue()); // should be optimal, whatever it is
71
-
72
- case VALUE_NUMBER_FLOAT:
73
- /* [JACKSON-72]: need to allow overriding the behavior regarding
74
- * which type to use
75
- */
76
- if (ctxt.isEnabled(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS)) {
77
- return toRuby(jp.getDecimalValue());
78
- }
79
- return toRuby(Double.valueOf(jp.getDoubleValue()));
80
-
81
- case VALUE_TRUE:
82
- return __ruby__.newBoolean(Boolean.TRUE);
83
- case VALUE_FALSE:
84
- return __ruby__.newBoolean(Boolean.FALSE);
85
-
86
- case VALUE_NULL: // should not get this but...
87
- return null;
88
-
89
- case END_ARRAY: // invalid
90
- case END_OBJECT: // invalid
91
- default:
92
- throw ctxt.mappingException(Object.class);
93
- }
94
- }
95
-
96
- @Override
97
- public RubyObject deserializeWithType(JsonParser jp, DeserializationContext ctxt,
98
- TypeDeserializer typeDeserializer)
99
- throws IOException, JsonProcessingException
100
- {
101
- JsonToken t = jp.getCurrentToken();
102
- switch (t) {
103
- // First: does it look like we had type id wrapping of some kind?
104
- case START_ARRAY:
105
- case START_OBJECT:
106
- case FIELD_NAME:
107
- /* Output can be as JSON Object, Array or scalar: no way to know
108
- * a this point:
109
- */
110
- return toRuby(typeDeserializer.deserializeTypedFromAny(jp, ctxt));
111
-
112
- /* Otherwise we probably got a "native" type (ones that map
113
- * naturally and thus do not need or use type ids)
23
+ private static final long serialVersionUID = 1L;
24
+
25
+ private final static RubyObject[] NO_OBJECTS = new RubyObject[0];
26
+
27
+ protected final static Ruby __ruby__ = Ruby.getGlobalRuntime();
28
+
29
+ /**
30
+ * @since 2.2
31
+ */
32
+
33
+ public RubyObjectDeserializer() { super(RubyObject.class); }
34
+
35
+ protected abstract RubyObject convertKey(JsonParser jp)
36
+ throws IOException;
37
+
38
+ /**
39
+ /**********************************************************
40
+ /* Deserializer API
41
+ /**********************************************************
42
+ */
43
+
44
+ @Override
45
+ public RubyObject deserialize(JsonParser jp, DeserializationContext ctxt)
46
+ throws IOException, JsonProcessingException
47
+ {
48
+ switch (jp.getCurrentToken()) {
49
+ case START_OBJECT:
50
+ return mapObject(jp, ctxt);
51
+
52
+ case START_ARRAY:
53
+ return mapArray(jp, ctxt);
54
+
55
+ case FIELD_NAME:
56
+ return convertKey(jp);
57
+
58
+ case VALUE_EMBEDDED_OBJECT:
59
+ return RubyUtils.rubyObject(__ruby__, jp.getEmbeddedObject());
60
+
61
+ case VALUE_STRING:
62
+ return RubyUtils.rubyString(__ruby__, jp.getText());
63
+
64
+ case VALUE_NUMBER_INT:
65
+ /* [JACKSON-100]: caller may want to get all integral values
66
+ * returned as BigInteger, for consistency
114
67
  */
115
- case VALUE_STRING:
116
- return rubyString(jp);
68
+ if (ctxt.isEnabled(DeserializationFeature.USE_BIG_INTEGER_FOR_INTS)) {
69
+ return RubyUtils.rubyBignum(__ruby__, jp.getBigIntegerValue());
70
+ }
71
+ return RubyUtils.rubyFixnum(__ruby__, jp.getLongValue());
72
+
73
+ case VALUE_NUMBER_FLOAT:
74
+ if (ctxt.isEnabled(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS)) {
75
+ return RubyUtils.rubyBigDecimal(__ruby__, jp.getDecimalValue());
76
+ }
77
+ return RubyUtils.rubyFloat(__ruby__, jp.getDoubleValue());
117
78
 
118
- case VALUE_NUMBER_INT:
119
- // For [JACKSON-100], see above:
120
- if (ctxt.isEnabled(DeserializationFeature.USE_BIG_INTEGER_FOR_INTS)) {
121
- return toRuby(jp.getBigIntegerValue());
122
- }
123
- /* and as per [JACKSON-839], allow "upgrade" to bigger types: out-of-range
124
- * entries can not be produced without type, so this should "just work",
125
- * even if it is bit unclean
126
- */
127
- return toRuby(jp.getNumberValue());
79
+ case VALUE_TRUE:
80
+ return __ruby__.newBoolean(Boolean.TRUE);
128
81
 
129
- case VALUE_NUMBER_FLOAT:
130
- // For [JACKSON-72], see above
131
- if (ctxt.isEnabled(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS)) {
132
- return toRuby(jp.getDecimalValue());
133
- }
134
- return __ruby__.newFloat(Double.valueOf(jp.getDoubleValue()));
82
+ case VALUE_FALSE:
83
+ return __ruby__.newBoolean(Boolean.FALSE);
135
84
 
136
- case VALUE_TRUE:
137
- return __ruby__.newBoolean(Boolean.TRUE);
138
- case VALUE_FALSE:
139
- return __ruby__.newBoolean(Boolean.FALSE);
140
- case VALUE_EMBEDDED_OBJECT:
141
- return toRuby(jp.getEmbeddedObject());
85
+ case VALUE_NULL: // should not get this but...
86
+ return null;
142
87
 
143
- case VALUE_NULL: // should not get this far really but...
144
- return null;
145
- default:
146
- throw ctxt.mappingException(Object.class);
147
- }
88
+ case END_ARRAY: // invalid
89
+ case END_OBJECT: // invalid
90
+ default:
91
+ throw ctxt.mappingException(Object.class);
148
92
  }
149
-
150
- /*
151
- /**********************************************************
152
- /* Internal methods
153
- /**********************************************************
154
- */
155
-
156
- protected RubyObject toRuby(Object o) {
157
- return (RubyObject)JavaUtil.convertJavaToRuby(__ruby__, o);
93
+ }
94
+
95
+ /**
96
+ /**********************************************************
97
+ /* Internal methods
98
+ /**********************************************************
99
+ */
100
+
101
+ /**
102
+ * Method called to map a JSON Array into a Java value.
103
+ */
104
+ protected RubyObject mapArray(JsonParser jp, DeserializationContext ctxt)
105
+ throws IOException, JsonProcessingException
106
+ {
107
+ // if (ctxt.isEnabled(DeserializationFeature.USE_JAVA_ARRAY_FOR_JSON_ARRAY)) {
108
+ // return mapArrayToArray(jp, ctxt);
109
+ // }
110
+ // Minor optimization to handle small lists (default size for ArrayList is 10)
111
+ if (jp.nextToken() == JsonToken.END_ARRAY) {
112
+ return RubyArray.newArray(__ruby__);
158
113
  }
159
-
160
- protected RubyString rubyString(JsonParser jp) throws IOException {
161
- return __ruby__.newString(jp.getText());
114
+ ObjectBuffer buffer = ctxt.leaseObjectBuffer();
115
+ Object[] values = buffer.resetAndStart();
116
+ int ptr = 0;
117
+ long totalSize = 0;
118
+ do {
119
+ Object value = deserialize(jp, ctxt);
120
+ ++totalSize;
121
+ if (ptr >= values.length) {
122
+ values = buffer.appendCompletedChunk(values);
123
+ ptr = 0;
124
+ }
125
+ values[ptr++] = value;
126
+ } while (jp.nextToken() != JsonToken.END_ARRAY);
127
+ // let's create almost full array, with 1/8 slack
128
+ RubyArray result = RubyArray.newArray(__ruby__, (totalSize + (totalSize >> 3) + 1));
129
+ buffer.completeAndClearBuffer(values, ptr, result);
130
+ return result;
131
+ }
132
+
133
+ /**
134
+ * Method called to map a JSON Object into a Java value.
135
+ */
136
+ protected RubyObject mapObject(JsonParser jp, DeserializationContext ctxt)
137
+ throws IOException, JsonProcessingException
138
+ {
139
+ JsonToken t = jp.getCurrentToken();
140
+ if (t == JsonToken.START_OBJECT) {
141
+ t = jp.nextToken();
142
+ }
143
+ // 1.6: minor optimization; let's handle 1 and 2 entry cases separately
144
+ if (t != JsonToken.FIELD_NAME) { // and empty one too
145
+ // empty map might work; but caller may want to modify... so better just give small modifiable
146
+ return RubyHash.newHash(__ruby__);
162
147
  }
163
148
 
164
- /**
165
- * Method called to map a JSON Array into a Java value.
166
- */
167
- protected RubyObject mapArray(JsonParser jp, DeserializationContext ctxt)
168
- throws IOException, JsonProcessingException
169
- {
170
- // if (ctxt.isEnabled(DeserializationFeature.USE_JAVA_ARRAY_FOR_JSON_ARRAY)) {
171
- // return mapArrayToArray(jp, ctxt);
172
- // }
173
- // Minor optimization to handle small lists (default size for ArrayList is 10)
174
- if (jp.nextToken() == JsonToken.END_ARRAY) {
175
- return RubyArray.newArray(__ruby__);
176
- }
177
- ObjectBuffer buffer = ctxt.leaseObjectBuffer();
178
- Object[] values = buffer.resetAndStart();
179
- int ptr = 0;
180
- long totalSize = 0;
181
- do {
182
- Object value = deserialize(jp, ctxt);
183
- ++totalSize;
184
- if (ptr >= values.length) {
185
- values = buffer.appendCompletedChunk(values);
186
- ptr = 0;
187
- }
188
- values[ptr++] = value;
189
- } while (jp.nextToken() != JsonToken.END_ARRAY);
190
- // let's create almost full array, with 1/8 slack
191
- RubyArray result = RubyArray.newArray(__ruby__, (totalSize + (totalSize >> 3) + 1));
192
- buffer.completeAndClearBuffer(values, ptr, result);
193
- return result;
149
+ RubyObject field1 = convertKey(jp);
150
+ jp.nextToken();
151
+ RubyObject value1 = deserialize(jp, ctxt);
152
+ if (jp.nextToken() != JsonToken.FIELD_NAME) { // single entry; but we want modifiable
153
+ return RuntimeHelpers.constructHash(__ruby__, field1, value1);
194
154
  }
195
155
 
196
- /**
197
- * Method called to map a JSON Object into a Java value.
198
- */
199
- protected RubyObject mapObject(JsonParser jp, DeserializationContext ctxt)
200
- throws IOException, JsonProcessingException
201
- {
202
- JsonToken t = jp.getCurrentToken();
203
- if (t == JsonToken.START_OBJECT) {
204
- t = jp.nextToken();
205
- }
206
- // 1.6: minor optimization; let's handle 1 and 2 entry cases separately
207
- if (t != JsonToken.FIELD_NAME) { // and empty one too
208
- // empty map might work; but caller may want to modify... so better just give small modifiable
209
- return RubyHash.newHash(__ruby__);
210
- }
211
- RubyString field1 = rubyString(jp);
212
- jp.nextToken();
213
- RubyObject value1 = deserialize(jp, ctxt);
214
- if (jp.nextToken() != JsonToken.FIELD_NAME) { // single entry; but we want modifiable
215
- return RuntimeHelpers.constructHash(__ruby__, field1, value1);
216
- }
217
- RubyString field2 = rubyString(jp);
218
- jp.nextToken();
219
- RubyObject value2 = deserialize(jp, ctxt);
220
- if (jp.nextToken() != JsonToken.FIELD_NAME) {
221
- return RuntimeHelpers.constructHash(__ruby__, field1, value1, field2, value2);
222
- }
223
- // And then the general case; default map size is 16
224
- RubyHash result = RuntimeHelpers.constructHash(__ruby__, field1, value1, field2, value2);
225
- do {
226
- RubyString fieldName = rubyString(jp);
227
- jp.nextToken();
228
- result.fastASet(fieldName, deserialize(jp, ctxt));
229
- } while (jp.nextToken() != JsonToken.END_OBJECT);
230
- return result;
156
+ RubyObject field2 = convertKey(jp);
157
+ jp.nextToken();
158
+ RubyObject value2 = deserialize(jp, ctxt);
159
+ if (jp.nextToken() != JsonToken.FIELD_NAME) {
160
+ return RuntimeHelpers.constructHash(__ruby__, field1, value1, field2, value2);
231
161
  }
232
162
 
233
- /**
234
- * Method called to map a JSON Array into a Java Object array (Object[]).
235
- */
236
- // protected Object[] mapArrayToArray(JsonParser jp, DeserializationContext ctxt)
237
- // throws IOException, JsonProcessingException
238
- // {
239
- // // Minor optimization to handle small lists (default size for ArrayList is 10)
240
- // if (jp.nextToken() == JsonToken.END_ARRAY) {
241
- // return NO_OBJECTS;
242
- // }
243
- // ObjectBuffer buffer = ctxt.leaseObjectBuffer();
244
- // Object[] values = buffer.resetAndStart();
245
- // int ptr = 0;
246
- // do {
247
- // Object value = deserialize(jp, ctxt);
248
- // if (ptr >= values.length) {
249
- // values = buffer.appendCompletedChunk(values);
250
- // ptr = 0;
251
- // }
252
- // values[ptr++] = value;
253
- // } while (jp.nextToken() != JsonToken.END_ARRAY);
254
- // return buffer.completeAndClearBuffer(values, ptr);
255
- // }
163
+ // And then the general case; default map size is 16
164
+ RubyHash result = RuntimeHelpers.constructHash(__ruby__, field1, value1, field2, value2);
165
+ do {
166
+ RubyObject fieldName = convertKey(jp);
167
+ jp.nextToken();
168
+ result.fastASet(fieldName, deserialize(jp, ctxt));
169
+ } while (jp.nextToken() != JsonToken.END_OBJECT);
170
+ return result;
171
+ }
256
172
  }
257
173