<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -61,6 +61,8 @@ module JSON
       # * *create_additions*: If set to false, the Parser doesn't create
       #   additions even if a matchin class and create_id was found. This option
       #   defaults to true.
+      # * *object_class*: Defaults to Hash
+      # * *array_class*: Defaults to Array
       def initialize(source, opts = {})
         super
         if !opts.key?(:max_nesting) # defaults to 19
@@ -74,6 +76,8 @@ module JSON
         ca = true
         ca = opts[:create_additions] if opts.key?(:create_additions)
         @create_id = ca ? JSON.create_id : nil
+        @object_class = opts[:object_class] || Hash
+        @array_class = opts[:array_class] || Array
       end
 
       alias source string
@@ -184,7 +188,7 @@ module JSON
       def parse_array
         raise NestingError, &quot;nesting of #@current_nesting is to deep&quot; if
           @max_nesting.nonzero? &amp;&amp; @current_nesting &gt; @max_nesting
-        result = []
+        result = @array_class.new
         delim = false
         until eos?
           case
@@ -216,7 +220,7 @@ module JSON
       def parse_object
         raise NestingError, &quot;nesting of #@current_nesting is to deep&quot; if
           @max_nesting.nonzero? &amp;&amp; @current_nesting &gt; @max_nesting
-        result = {}
+        result = @object_class.new
         delim = false
         until eos?
           case</diff>
      <filename>lib/json/pure/parser.rb</filename>
    </modified>
    <modified>
      <diff>@@ -46,6 +46,8 @@ public class Parser extends RubyObject {
     private RubyString createId;
     private int maxNesting;
     private boolean allowNaN;
+    private RubyClass objectClass;
+    private RubyClass arrayClass;
 
     private static final int DEFAULT_MAX_NESTING = 19;
 
@@ -112,6 +114,12 @@ public class Parser extends RubyObject {
      * &lt;dd&gt;If set to &lt;code&gt;false&lt;/code&gt;, the Parser doesn't create additions
      * even if a matchin class and &lt;code&gt;create_id&lt;/code&gt; was found. This option
      * defaults to &lt;code&gt;true&lt;/code&gt;.
+     * 
+     * &lt;dt&gt;&lt;code&gt;:object_class&lt;/code&gt;
+     * &lt;dd&gt;Defaults to Hash.
+     * 
+     * &lt;dt&gt;&lt;code&gt;:array_class&lt;/code&gt;
+     * &lt;dd&gt;Defaults to Array.
      * &lt;/dl&gt;
      */
     @JRubyMethod(name = &quot;new&quot;, required = 1, optional = 1, meta = true)
@@ -158,11 +166,16 @@ public class Parser extends RubyObject {
             else {
                 this.createId = null;
             }
+
+            this.objectClass = readRubyClassParameter(opts, &quot;object_class&quot;, getRuntime().getHash());
+            this.arrayClass = readRubyClassParameter(opts, &quot;array_class&quot;, getRuntime().getArray());
         }
         else {
             this.maxNesting = DEFAULT_MAX_NESTING;
             this.allowNaN = false;
             this.createId = getCreateId();
+            this.objectClass = getRuntime().getHash();
+            this.arrayClass = getRuntime().getArray();
         }
 
         this.vSource = source;
@@ -202,6 +215,28 @@ public class Parser extends RubyObject {
     }
 
     /**
+     * Reads the setting from the given options hash (using
+     * &lt;code&gt;key&lt;/code&gt; as a Symbol key). If it is &lt;code&gt;nil&lt;/code&gt; or
+     * undefined, returns the default value given.
+     * If not, ensures it is a RubyClass instance and shares the same
+     * allocator as the default value (i.e. for the basic types which have
+     * their specific allocators, this ensures the passed value is
+     * a subclass of them).
+     */
+    private RubyClass readRubyClassParameter(RubyHash opts, String key, RubyClass defaultClass) {
+        IRubyObject value = Utils.fastGetSymItem(opts, key);
+
+        if (value == null || value.isNil()) return defaultClass;
+
+        if (value instanceof RubyClass &amp;&amp;
+            ((RubyClass)value).getAllocator() == defaultClass.getAllocator()) {
+
+            return (RubyClass)value;
+        }
+        throw getRuntime().newTypeError(key + &quot; option must be a subclass of &quot; + defaultClass);
+    }
+
+    /**
      * A string parsing session.
      * 
      * &lt;p&gt;Once a ParserSession is instantiated, the source string should not
@@ -237,11 +272,11 @@ public class Parser extends RubyObject {
         }
 
         
-// line 263 &quot;src/json/ext/Parser.rl&quot;
+// line 298 &quot;src/json/ext/Parser.rl&quot;
 
 
         
-// line 245 &quot;src/json/ext/Parser.java&quot;
+// line 280 &quot;src/json/ext/Parser.java&quot;
 private static byte[] init__JSON_value_actions_0()
 {
 	return new byte [] {
@@ -355,7 +390,7 @@ static final int JSON_value_error = 0;
 static final int JSON_value_en_main = 1;
 
 
-// line 375 &quot;src/json/ext/Parser.rl&quot;
+// line 410 &quot;src/json/ext/Parser.rl&quot;
 
 
         ParserResult parseValue(int p, int pe) {
@@ -363,14 +398,14 @@ static final int JSON_value_en_main = 1;
             IRubyObject result = null;
 
             
-// line 367 &quot;src/json/ext/Parser.java&quot;
+// line 402 &quot;src/json/ext/Parser.java&quot;
 	{
 	cs = JSON_value_start;
 	}
 
-// line 382 &quot;src/json/ext/Parser.rl&quot;
+// line 417 &quot;src/json/ext/Parser.rl&quot;
             
-// line 374 &quot;src/json/ext/Parser.java&quot;
+// line 409 &quot;src/json/ext/Parser.java&quot;
 	{
 	int _klen;
 	int _trans = 0;
@@ -396,13 +431,13 @@ case 1:
 	while ( _nacts-- &gt; 0 ) {
 		switch ( _JSON_value_actions[_acts++] ) {
 	case 9:
-// line 360 &quot;src/json/ext/Parser.rl&quot;
+// line 395 &quot;src/json/ext/Parser.rl&quot;
 	{
                 p--;
                 { p += 1; _goto_targ = 5; if (true)  continue _goto;}
             }
 	break;
-// line 406 &quot;src/json/ext/Parser.java&quot;
+// line 441 &quot;src/json/ext/Parser.java&quot;
 		}
 	}
 
@@ -465,25 +500,25 @@ case 1:
 			switch ( _JSON_value_actions[_acts++] )
 			{
 	case 0:
-// line 271 &quot;src/json/ext/Parser.rl&quot;
+// line 306 &quot;src/json/ext/Parser.rl&quot;
 	{
                 result = runtime.getNil();
             }
 	break;
 	case 1:
-// line 274 &quot;src/json/ext/Parser.rl&quot;
+// line 309 &quot;src/json/ext/Parser.rl&quot;
 	{
                 result = runtime.getFalse();
             }
 	break;
 	case 2:
-// line 277 &quot;src/json/ext/Parser.rl&quot;
+// line 312 &quot;src/json/ext/Parser.rl&quot;
 	{
                 result = runtime.getTrue();
             }
 	break;
 	case 3:
-// line 280 &quot;src/json/ext/Parser.rl&quot;
+// line 315 &quot;src/json/ext/Parser.rl&quot;
 	{
                 if (parser.allowNaN) {
                     result = getConstant(CONST_NAN);
@@ -494,7 +529,7 @@ case 1:
             }
 	break;
 	case 4:
-// line 288 &quot;src/json/ext/Parser.rl&quot;
+// line 323 &quot;src/json/ext/Parser.rl&quot;
 	{
                 if (parser.allowNaN) {
                     result = getConstant(CONST_INFINITY);
@@ -505,7 +540,7 @@ case 1:
             }
 	break;
 	case 5:
-// line 296 &quot;src/json/ext/Parser.rl&quot;
+// line 331 &quot;src/json/ext/Parser.rl&quot;
 	{
                 if (pe &gt; p + 9 &amp;&amp;
                     absSubSequence(p, p + 9).toString().equals(JSON_MINUS_INFINITY)) {
@@ -535,7 +570,7 @@ case 1:
             }
 	break;
 	case 6:
-// line 323 &quot;src/json/ext/Parser.rl&quot;
+// line 358 &quot;src/json/ext/Parser.rl&quot;
 	{
                 ParserResult res = parseString(p, pe);
                 if (res == null) {
@@ -549,7 +584,7 @@ case 1:
             }
 	break;
 	case 7:
-// line 334 &quot;src/json/ext/Parser.rl&quot;
+// line 369 &quot;src/json/ext/Parser.rl&quot;
 	{
                 currentNesting++;
                 ParserResult res = parseArray(p, pe);
@@ -565,7 +600,7 @@ case 1:
             }
 	break;
 	case 8:
-// line 347 &quot;src/json/ext/Parser.rl&quot;
+// line 382 &quot;src/json/ext/Parser.rl&quot;
 	{
                 currentNesting++;
                 ParserResult res = parseObject(p, pe);
@@ -580,7 +615,7 @@ case 1:
                 }
             }
 	break;
-// line 584 &quot;src/json/ext/Parser.java&quot;
+// line 619 &quot;src/json/ext/Parser.java&quot;
 			}
 		}
 	}
@@ -600,7 +635,7 @@ case 5:
 	break; }
 	}
 
-// line 383 &quot;src/json/ext/Parser.rl&quot;
+// line 418 &quot;src/json/ext/Parser.rl&quot;
 
             if (cs &gt;= JSON_value_first_final &amp;&amp; result != null) {
                 return new ParserResult(result, p);
@@ -611,7 +646,7 @@ case 5:
         }
 
         
-// line 615 &quot;src/json/ext/Parser.java&quot;
+// line 650 &quot;src/json/ext/Parser.java&quot;
 private static byte[] init__JSON_integer_actions_0()
 {
 	return new byte [] {
@@ -710,22 +745,22 @@ static final int JSON_integer_error = 0;
 static final int JSON_integer_en_main = 1;
 
 
-// line 403 &quot;src/json/ext/Parser.rl&quot;
+// line 438 &quot;src/json/ext/Parser.rl&quot;
 
 
         ParserResult parseInteger(int p, int pe) {
             int cs = EVIL;
 
             
-// line 721 &quot;src/json/ext/Parser.java&quot;
+// line 756 &quot;src/json/ext/Parser.java&quot;
 	{
 	cs = JSON_integer_start;
 	}
 
-// line 409 &quot;src/json/ext/Parser.rl&quot;
+// line 444 &quot;src/json/ext/Parser.rl&quot;
             int memo = p;
             
-// line 729 &quot;src/json/ext/Parser.java&quot;
+// line 764 &quot;src/json/ext/Parser.java&quot;
 	{
 	int _klen;
 	int _trans = 0;
@@ -806,13 +841,13 @@ case 1:
 			switch ( _JSON_integer_actions[_acts++] )
 			{
 	case 0:
-// line 397 &quot;src/json/ext/Parser.rl&quot;
+// line 432 &quot;src/json/ext/Parser.rl&quot;
 	{
                 p--;
                 { p += 1; _goto_targ = 5; if (true)  continue _goto;}
             }
 	break;
-// line 816 &quot;src/json/ext/Parser.java&quot;
+// line 851 &quot;src/json/ext/Parser.java&quot;
 			}
 		}
 	}
@@ -832,7 +867,7 @@ case 5:
 	break; }
 	}
 
-// line 411 &quot;src/json/ext/Parser.rl&quot;
+// line 446 &quot;src/json/ext/Parser.rl&quot;
 
             if (cs &lt; JSON_integer_first_final) {
                 return null;
@@ -847,7 +882,7 @@ case 5:
         }
 
         
-// line 851 &quot;src/json/ext/Parser.java&quot;
+// line 886 &quot;src/json/ext/Parser.java&quot;
 private static byte[] init__JSON_float_actions_0()
 {
 	return new byte [] {
@@ -949,22 +984,22 @@ static final int JSON_float_error = 0;
 static final int JSON_float_en_main = 1;
 
 
-// line 439 &quot;src/json/ext/Parser.rl&quot;
+// line 474 &quot;src/json/ext/Parser.rl&quot;
 
 
         ParserResult parseFloat(int p, int pe) {
             int cs = EVIL;
 
             
-// line 960 &quot;src/json/ext/Parser.java&quot;
+// line 995 &quot;src/json/ext/Parser.java&quot;
 	{
 	cs = JSON_float_start;
 	}
 
-// line 445 &quot;src/json/ext/Parser.rl&quot;
+// line 480 &quot;src/json/ext/Parser.rl&quot;
             int memo = p;
             
-// line 968 &quot;src/json/ext/Parser.java&quot;
+// line 1003 &quot;src/json/ext/Parser.java&quot;
 	{
 	int _klen;
 	int _trans = 0;
@@ -1045,13 +1080,13 @@ case 1:
 			switch ( _JSON_float_actions[_acts++] )
 			{
 	case 0:
-// line 430 &quot;src/json/ext/Parser.rl&quot;
+// line 465 &quot;src/json/ext/Parser.rl&quot;
 	{
                 p--;
                 { p += 1; _goto_targ = 5; if (true)  continue _goto;}
             }
 	break;
-// line 1055 &quot;src/json/ext/Parser.java&quot;
+// line 1090 &quot;src/json/ext/Parser.java&quot;
 			}
 		}
 	}
@@ -1071,7 +1106,7 @@ case 5:
 	break; }
 	}
 
-// line 447 &quot;src/json/ext/Parser.rl&quot;
+// line 482 &quot;src/json/ext/Parser.rl&quot;
 
             if (cs &lt; JSON_float_first_final) {
                 return null;
@@ -1086,7 +1121,7 @@ case 5:
         }
 
         
-// line 1090 &quot;src/json/ext/Parser.java&quot;
+// line 1125 &quot;src/json/ext/Parser.java&quot;
 private static byte[] init__JSON_string_actions_0()
 {
 	return new byte [] {
@@ -1188,7 +1223,7 @@ static final int JSON_string_error = 0;
 static final int JSON_string_en_main = 1;
 
 
-// line 489 &quot;src/json/ext/Parser.rl&quot;
+// line 524 &quot;src/json/ext/Parser.rl&quot;
 
 
         ParserResult parseString(int p, int pe) {
@@ -1196,15 +1231,15 @@ static final int JSON_string_en_main = 1;
             RubyString result = null;
 
             
-// line 1200 &quot;src/json/ext/Parser.java&quot;
+// line 1235 &quot;src/json/ext/Parser.java&quot;
 	{
 	cs = JSON_string_start;
 	}
 
-// line 496 &quot;src/json/ext/Parser.rl&quot;
+// line 531 &quot;src/json/ext/Parser.rl&quot;
             int memo = p;
             
-// line 1208 &quot;src/json/ext/Parser.java&quot;
+// line 1243 &quot;src/json/ext/Parser.java&quot;
 	{
 	int _klen;
 	int _trans = 0;
@@ -1285,7 +1320,7 @@ case 1:
 			switch ( _JSON_string_actions[_acts++] )
 			{
 	case 0:
-// line 466 &quot;src/json/ext/Parser.rl&quot;
+// line 501 &quot;src/json/ext/Parser.rl&quot;
 	{
                 result = stringUnescape(memo + 1, p);
                 if (result == null) {
@@ -1298,13 +1333,13 @@ case 1:
             }
 	break;
 	case 1:
-// line 477 &quot;src/json/ext/Parser.rl&quot;
+// line 512 &quot;src/json/ext/Parser.rl&quot;
 	{
                 p--;
                 { p += 1; _goto_targ = 5; if (true)  continue _goto;}
             }
 	break;
-// line 1308 &quot;src/json/ext/Parser.java&quot;
+// line 1343 &quot;src/json/ext/Parser.java&quot;
 			}
 		}
 	}
@@ -1324,7 +1359,7 @@ case 5:
 	break; }
 	}
 
-// line 498 &quot;src/json/ext/Parser.rl&quot;
+// line 533 &quot;src/json/ext/Parser.rl&quot;
 
             if (cs &gt;= JSON_string_first_final &amp;&amp; result != null) {
                 return new ParserResult(result, p + 1);
@@ -1466,7 +1501,7 @@ case 5:
         }
 
         
-// line 1470 &quot;src/json/ext/Parser.java&quot;
+// line 1505 &quot;src/json/ext/Parser.java&quot;
 private static byte[] init__JSON_array_actions_0()
 {
 	return new byte [] {
@@ -1579,7 +1614,7 @@ static final int JSON_array_error = 0;
 static final int JSON_array_en_main = 1;
 
 
-// line 672 &quot;src/json/ext/Parser.rl&quot;
+// line 707 &quot;src/json/ext/Parser.rl&quot;
 
 
         ParserResult parseArray(int p, int pe) {
@@ -1590,17 +1625,22 @@ static final int JSON_array_en_main = 1;
                     &quot;nesting of &quot; + currentNesting + &quot; is too deep&quot;);
             }
 
-            RubyArray result = runtime.newArray();
+            // this is guaranteed to be a RubyArray due to the earlier
+            // allocator test at readRubyClassParameter
+            RubyArray result =
+                (RubyArray)parser.arrayClass.newInstance(
+                    runtime.getCurrentContext(), new IRubyObject[0],
+                    Block.NULL_BLOCK);
 
             
-// line 1597 &quot;src/json/ext/Parser.java&quot;
+// line 1637 &quot;src/json/ext/Parser.java&quot;
 	{
 	cs = JSON_array_start;
 	}
 
-// line 685 &quot;src/json/ext/Parser.rl&quot;
+// line 725 &quot;src/json/ext/Parser.rl&quot;
             
-// line 1604 &quot;src/json/ext/Parser.java&quot;
+// line 1644 &quot;src/json/ext/Parser.java&quot;
 	{
 	int _klen;
 	int _trans = 0;
@@ -1681,7 +1721,7 @@ case 1:
 			switch ( _JSON_array_actions[_acts++] )
 			{
 	case 0:
-// line 644 &quot;src/json/ext/Parser.rl&quot;
+// line 679 &quot;src/json/ext/Parser.rl&quot;
 	{
                 ParserResult res = parseValue(p, pe);
                 if (res == null) {
@@ -1695,13 +1735,13 @@ case 1:
             }
 	break;
 	case 1:
-// line 656 &quot;src/json/ext/Parser.rl&quot;
+// line 691 &quot;src/json/ext/Parser.rl&quot;
 	{
                 p--;
                 { p += 1; _goto_targ = 5; if (true)  continue _goto;}
             }
 	break;
-// line 1705 &quot;src/json/ext/Parser.java&quot;
+// line 1745 &quot;src/json/ext/Parser.java&quot;
 			}
 		}
 	}
@@ -1721,7 +1761,7 @@ case 5:
 	break; }
 	}
 
-// line 686 &quot;src/json/ext/Parser.rl&quot;
+// line 726 &quot;src/json/ext/Parser.rl&quot;
 
             if (cs &gt;= JSON_array_first_final) {
                 return new ParserResult(result, p + 1);
@@ -1732,7 +1772,7 @@ case 5:
         }
 
         
-// line 1736 &quot;src/json/ext/Parser.java&quot;
+// line 1776 &quot;src/json/ext/Parser.java&quot;
 private static byte[] init__JSON_object_actions_0()
 {
 	return new byte [] {
@@ -1855,7 +1895,7 @@ static final int JSON_object_error = 0;
 static final int JSON_object_en_main = 1;
 
 
-// line 738 &quot;src/json/ext/Parser.rl&quot;
+// line 778 &quot;src/json/ext/Parser.rl&quot;
 
 
         ParserResult parseObject(int p, int pe) {
@@ -1867,17 +1907,22 @@ static final int JSON_object_en_main = 1;
                     &quot;nesting of &quot; + currentNesting + &quot; is too deep&quot;);
             }
 
-            RubyHash result = RubyHash.newHash(runtime);
+            // this is guaranteed to be a RubyHash due to the earlier
+            // allocator test at readRubyClassParameter
+            RubyHash result =
+                (RubyHash)parser.objectClass.newInstance(
+                    runtime.getCurrentContext(), new IRubyObject[0],
+                    Block.NULL_BLOCK);
 
             
-// line 1874 &quot;src/json/ext/Parser.java&quot;
+// line 1919 &quot;src/json/ext/Parser.java&quot;
 	{
 	cs = JSON_object_start;
 	}
 
-// line 752 &quot;src/json/ext/Parser.rl&quot;
+// line 797 &quot;src/json/ext/Parser.rl&quot;
             
-// line 1881 &quot;src/json/ext/Parser.java&quot;
+// line 1926 &quot;src/json/ext/Parser.java&quot;
 	{
 	int _klen;
 	int _trans = 0;
@@ -1958,7 +2003,7 @@ case 1:
 			switch ( _JSON_object_actions[_acts++] )
 			{
 	case 0:
-// line 701 &quot;src/json/ext/Parser.rl&quot;
+// line 741 &quot;src/json/ext/Parser.rl&quot;
 	{
                 ParserResult res = parseValue(p, pe);
                 if (res == null) {
@@ -1972,7 +2017,7 @@ case 1:
             }
 	break;
 	case 1:
-// line 713 &quot;src/json/ext/Parser.rl&quot;
+// line 753 &quot;src/json/ext/Parser.rl&quot;
 	{
                 ParserResult res = parseString(p, pe);
                 if (res == null) {
@@ -1986,13 +2031,13 @@ case 1:
             }
 	break;
 	case 2:
-// line 725 &quot;src/json/ext/Parser.rl&quot;
+// line 765 &quot;src/json/ext/Parser.rl&quot;
 	{
                 p--;
                 { p += 1; _goto_targ = 5; if (true)  continue _goto;}
             }
 	break;
-// line 1996 &quot;src/json/ext/Parser.java&quot;
+// line 2041 &quot;src/json/ext/Parser.java&quot;
 			}
 		}
 	}
@@ -2012,7 +2057,7 @@ case 5:
 	break; }
 	}
 
-// line 753 &quot;src/json/ext/Parser.rl&quot;
+// line 798 &quot;src/json/ext/Parser.rl&quot;
 
             if (cs &lt; JSON_object_first_final) {
                 return null;
@@ -2051,7 +2096,7 @@ case 5:
         }
 
         
-// line 2055 &quot;src/json/ext/Parser.java&quot;
+// line 2100 &quot;src/json/ext/Parser.java&quot;
 private static byte[] init__JSON_actions_0()
 {
 	return new byte [] {
@@ -2155,7 +2200,7 @@ static final int JSON_error = 0;
 static final int JSON_en_main = 1;
 
 
-// line 826 &quot;src/json/ext/Parser.rl&quot;
+// line 871 &quot;src/json/ext/Parser.rl&quot;
 
 
         public IRubyObject parse() {
@@ -2164,16 +2209,16 @@ static final int JSON_en_main = 1;
             IRubyObject result = null;
 
             
-// line 2168 &quot;src/json/ext/Parser.java&quot;
+// line 2213 &quot;src/json/ext/Parser.java&quot;
 	{
 	cs = JSON_start;
 	}
 
-// line 834 &quot;src/json/ext/Parser.rl&quot;
+// line 879 &quot;src/json/ext/Parser.rl&quot;
             p = byteList.begin();
             pe = p + byteList.length();
             
-// line 2177 &quot;src/json/ext/Parser.java&quot;
+// line 2222 &quot;src/json/ext/Parser.java&quot;
 	{
 	int _klen;
 	int _trans = 0;
@@ -2254,7 +2299,7 @@ case 1:
 			switch ( _JSON_actions[_acts++] )
 			{
 	case 0:
-// line 796 &quot;src/json/ext/Parser.rl&quot;
+// line 841 &quot;src/json/ext/Parser.rl&quot;
 	{
                 currentNesting = 1;
                 ParserResult res = parseObject(p, pe);
@@ -2269,7 +2314,7 @@ case 1:
             }
 	break;
 	case 1:
-// line 809 &quot;src/json/ext/Parser.rl&quot;
+// line 854 &quot;src/json/ext/Parser.rl&quot;
 	{
                 currentNesting = 1;
                 ParserResult res = parseArray(p, pe);
@@ -2283,7 +2328,7 @@ case 1:
                 }
             }
 	break;
-// line 2287 &quot;src/json/ext/Parser.java&quot;
+// line 2332 &quot;src/json/ext/Parser.java&quot;
 			}
 		}
 	}
@@ -2303,7 +2348,7 @@ case 5:
 	break; }
 	}
 
-// line 837 &quot;src/json/ext/Parser.rl&quot;
+// line 882 &quot;src/json/ext/Parser.rl&quot;
 
             if (cs &gt;= JSON_first_final &amp;&amp; p == pe) {
                 return result;</diff>
      <filename>src/json/ext/Parser.java</filename>
    </modified>
    <modified>
      <diff>@@ -44,6 +44,8 @@ public class Parser extends RubyObject {
     private RubyString createId;
     private int maxNesting;
     private boolean allowNaN;
+    private RubyClass objectClass;
+    private RubyClass arrayClass;
 
     private static final int DEFAULT_MAX_NESTING = 19;
 
@@ -110,6 +112,12 @@ public class Parser extends RubyObject {
      * &lt;dd&gt;If set to &lt;code&gt;false&lt;/code&gt;, the Parser doesn't create additions
      * even if a matchin class and &lt;code&gt;create_id&lt;/code&gt; was found. This option
      * defaults to &lt;code&gt;true&lt;/code&gt;.
+     * 
+     * &lt;dt&gt;&lt;code&gt;:object_class&lt;/code&gt;
+     * &lt;dd&gt;Defaults to Hash.
+     * 
+     * &lt;dt&gt;&lt;code&gt;:array_class&lt;/code&gt;
+     * &lt;dd&gt;Defaults to Array.
      * &lt;/dl&gt;
      */
     @JRubyMethod(name = &quot;new&quot;, required = 1, optional = 1, meta = true)
@@ -156,11 +164,16 @@ public class Parser extends RubyObject {
             else {
                 this.createId = null;
             }
+
+            this.objectClass = readRubyClassParameter(opts, &quot;object_class&quot;, getRuntime().getHash());
+            this.arrayClass = readRubyClassParameter(opts, &quot;array_class&quot;, getRuntime().getArray());
         }
         else {
             this.maxNesting = DEFAULT_MAX_NESTING;
             this.allowNaN = false;
             this.createId = getCreateId();
+            this.objectClass = getRuntime().getHash();
+            this.arrayClass = getRuntime().getArray();
         }
 
         this.vSource = source;
@@ -200,6 +213,28 @@ public class Parser extends RubyObject {
     }
 
     /**
+     * Reads the setting from the given options hash (using
+     * &lt;code&gt;key&lt;/code&gt; as a Symbol key). If it is &lt;code&gt;nil&lt;/code&gt; or
+     * undefined, returns the default value given.
+     * If not, ensures it is a RubyClass instance and shares the same
+     * allocator as the default value (i.e. for the basic types which have
+     * their specific allocators, this ensures the passed value is
+     * a subclass of them).
+     */
+    private RubyClass readRubyClassParameter(RubyHash opts, String key, RubyClass defaultClass) {
+        IRubyObject value = Utils.fastGetSymItem(opts, key);
+
+        if (value == null || value.isNil()) return defaultClass;
+
+        if (value instanceof RubyClass &amp;&amp;
+            ((RubyClass)value).getAllocator() == defaultClass.getAllocator()) {
+
+            return (RubyClass)value;
+        }
+        throw getRuntime().newTypeError(key + &quot; option must be a subclass of &quot; + defaultClass);
+    }
+
+    /**
      * A string parsing session.
      * 
      * &lt;p&gt;Once a ParserSession is instantiated, the source string should not
@@ -679,7 +714,12 @@ public class Parser extends RubyObject {
                     &quot;nesting of &quot; + currentNesting + &quot; is too deep&quot;);
             }
 
-            RubyArray result = runtime.newArray();
+            // this is guaranteed to be a RubyArray due to the earlier
+            // allocator test at readRubyClassParameter
+            RubyArray result =
+                (RubyArray)parser.arrayClass.newInstance(
+                    runtime.getCurrentContext(), new IRubyObject[0],
+                    Block.NULL_BLOCK);
 
             %% write init;
             %% write exec;
@@ -746,7 +786,12 @@ public class Parser extends RubyObject {
                     &quot;nesting of &quot; + currentNesting + &quot; is too deep&quot;);
             }
 
-            RubyHash result = RubyHash.newHash(runtime);
+            // this is guaranteed to be a RubyHash due to the earlier
+            // allocator test at readRubyClassParameter
+            RubyHash result =
+                (RubyHash)parser.objectClass.newInstance(
+                    runtime.getCurrentContext(), new IRubyObject[0],
+                    Block.NULL_BLOCK);
 
             %% write init;
             %% write exec;</diff>
      <filename>src/json/ext/Parser.rl</filename>
    </modified>
    <modified>
      <diff>@@ -150,6 +150,14 @@ class TC_JSON &lt; Test::Unit::TestCase
       , [2718.0E-3 ],\r[ null] , [[1, -2, 3 ]], [false ],[ true]\n ]  }))
   end
 
+  class SubArray &lt; Array; end
+
+  def test_parse_array_custom_class
+    res = parse('[]', :array_class =&gt; SubArray)
+    assert_equal([], res)
+    assert_equal(SubArray, res.class)
+  end
+
   def test_parse_object
     assert_equal({}, parse('{}'))
     assert_equal({}, parse('  {  }  '))
@@ -157,6 +165,14 @@ class TC_JSON &lt; Test::Unit::TestCase
     assert_equal({'foo'=&gt;'bar'}, parse('    { &quot;foo&quot;  :   &quot;bar&quot;   }   '))
   end
 
+  class SubHash &lt; Hash; end
+
+  def test_parse_object_custom_class
+    res = parse('{}', :object_class =&gt; SubHash)
+    assert_equal({}, res)
+    assert_equal(SubHash, res.class)
+  end
+
   def test_parser_reset
     parser = Parser.new(@json)
     assert_equal(@hash, parser.parse)</diff>
      <filename>tests/test_json.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>146caaf75f123ad350fc6e90afcfc9c066aff7e1</id>
    </parent>
  </parents>
  <author>
    <name>Daniel Luz</name>
    <email>dev@mernen.com</email>
  </author>
  <url>http://github.com/mernen/json-jruby/commit/5a021ae2324b873da48a1cd6e3991364c91bec16</url>
  <id>5a021ae2324b873da48a1cd6e3991364c91bec16</id>
  <committed-date>2009-05-13T16:56:23-07:00</committed-date>
  <authored-date>2009-05-13T16:56:23-07:00</authored-date>
  <message>Applied commit #302 from json:

    applied object class patch, but do not forget to mark referenced objects</message>
  <tree>9e2635da2b43598b7d9987049409d2408273d305</tree>
  <committer>
    <name>Daniel Luz</name>
    <email>dev@mernen.com</email>
  </committer>
</commit>
