@@ -520,6 +520,23 @@ static void generateHash(ThreadContext context, Session session, RubyHash object
520520 buffer .write ('}' );
521521 }
522522
523+ private static IRubyObject castKey (ThreadContext context , IRubyObject key ) {
524+ RubyClass keyClass = key .getType ();
525+ Ruby runtime = context .runtime ;
526+
527+ if (key instanceof RubyString ) {
528+ if (keyClass == runtime .getString ()) {
529+ return key ;
530+ } else {
531+ return key .callMethod (context , "to_s" );
532+ }
533+ } else if (keyClass == runtime .getSymbol ()) {
534+ return ((RubySymbol ) key ).id2name (context );
535+ } else {
536+ return null ;
537+ }
538+ }
539+
523540 private static void processEntry (ThreadContext context , Session session , OutputStream buffer , RubyHash .RubyHashEntry entry , boolean firstPair , ByteList objectNl , byte [] indent , ByteList spaceBefore , ByteList space ) {
524541 IRubyObject key = (IRubyObject ) entry .getKey ();
525542 IRubyObject value = (IRubyObject ) entry .getValue ();
@@ -533,21 +550,22 @@ private static void processEntry(ThreadContext context, Session session, OutputS
533550
534551 Ruby runtime = context .runtime ;
535552
536- IRubyObject keyStr ;
537- RubyClass keyClass = key .getType ();
538- if (key instanceof RubyString ) {
539- if (keyClass == runtime .getString ()) {
540- keyStr = key ;
541- } else {
542- keyStr = key .callMethod (context , "to_s" );
553+ IRubyObject keyStr = castKey (context , key );
554+ if (keyStr == null || !(keyStr instanceof RubyString )) {
555+ GeneratorState state = session .getState (context );
556+ if (state .strict ()) {
557+ if (state .getAsJSON () != null ) {
558+ key = state .getAsJSON ().call (context , key );
559+ keyStr = castKey (context , key );
560+ }
561+
562+ if (keyStr == null ) {
563+ throw Utils .buildGeneratorError (context , key , key .getType ().name (context ) + " not allowed as object key in JSON" ).toThrowable ();
564+ }
543565 }
544- } else if (keyClass == runtime .getSymbol ()) {
545- keyStr = ((RubySymbol ) key ).id2name (context );
546- } else {
547- if (session .getState (context ).strict ()) {
548- throw Utils .buildGeneratorError (context , key , key + " not allowed in JSON" ).toThrowable ();
566+ else {
567+ keyStr = TypeConverter .convertToType (key , runtime .getString (), "to_s" );
549568 }
550- keyStr = TypeConverter .convertToType (key , runtime .getString (), "to_s" );
551569 }
552570
553571 if (keyStr .getMetaClass () == runtime .getString ()) {
@@ -673,7 +691,7 @@ void generate(ThreadContext context, Session session, IRubyObject object, Output
673691 static RubyString generateGenericNew (ThreadContext context , Session session , IRubyObject object ) {
674692 GeneratorState state = session .getState (context );
675693 if (state .strict ()) {
676- if (state .getAsJSON () != null ) {
694+ if (state .getAsJSON () != null ) {
677695 IRubyObject value = state .getAsJSON ().call (context , object );
678696 Handler handler = getHandlerFor (context .runtime , value );
679697 if (handler == GENERIC_HANDLER ) {
0 commit comments