Skip to content

Commit 99040e6

Browse files
committed
Allow JSON::Fragment to be used even in strict mode
1 parent 524b949 commit 99040e6

File tree

3 files changed

+36
-6
lines changed

3 files changed

+36
-6
lines changed

java/src/json/ext/Generator.java

+29
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
*/
66
package json.ext;
77

8+
import json.ext.RuntimeInfo;
9+
810
import org.jcodings.Encoding;
911
import org.jcodings.specific.ASCIIEncoding;
1012
import org.jcodings.specific.USASCIIEncoding;
@@ -115,6 +117,11 @@ private static <T extends IRubyObject> Handler<? super T> getHandlerFor(Ruby run
115117
case HASH :
116118
if (Helpers.metaclass(object) != runtime.getHash()) break;
117119
return (Handler<T>) HASH_HANDLER;
120+
case STRUCT :
121+
RuntimeInfo info = RuntimeInfo.forRuntime(runtime);
122+
RubyClass fragmentClass = info.jsonModule.get().getClass("Fragment");
123+
if (Helpers.metaclass(object) != fragmentClass) break;
124+
return (Handler<T>) FRAGMENT_HANDLER;
118125
}
119126
return GENERIC_HANDLER;
120127
}
@@ -481,6 +488,28 @@ static RubyString ensureValidEncoding(ThreadContext context, RubyString str) {
481488
static final Handler<IRubyObject> NIL_HANDLER =
482489
new KeywordHandler<>("null");
483490

491+
/**
492+
* The default handler (<code>Object#to_json</code>): coerces the object
493+
* to string using <code>#to_s</code>, and serializes that string.
494+
*/
495+
static final Handler<IRubyObject> FRAGMENT_HANDLER =
496+
new Handler<IRubyObject>() {
497+
@Override
498+
RubyString generateNew(ThreadContext context, Session session, IRubyObject object) {
499+
GeneratorState state = session.getState(context);
500+
IRubyObject result = object.callMethod(context, "to_json", state);
501+
if (result instanceof RubyString) return (RubyString)result;
502+
throw context.runtime.newTypeError("to_json must return a String");
503+
}
504+
505+
@Override
506+
void generate(ThreadContext context, Session session, IRubyObject object, OutputStream buffer) throws IOException {
507+
RubyString result = generateNew(context, session, object);
508+
ByteList bytes = result.getByteList();
509+
buffer.write(bytes.unsafeBytes(), bytes.begin(), bytes.length());
510+
}
511+
};
512+
484513
/**
485514
* The default handler (<code>Object#to_json</code>): coerces the object
486515
* to string using <code>#to_s</code>, and serializes that string.

lib/json/truffle_ruby/generator.rb

+6-6
Original file line numberDiff line numberDiff line change
@@ -416,10 +416,10 @@ def to_json(state = nil, *)
416416
state = State.from_state(state) if state
417417
if state&.strict?
418418
value = self
419-
if state.strict? && !(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value)
419+
if state.strict? && !(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value)
420420
if state.as_json
421421
value = state.as_json.call(value)
422-
unless false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value
422+
unless false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value
423423
raise GeneratorError.new("#{value.class} returned by #{state.as_json} not allowed in JSON", value)
424424
end
425425
value.to_json(state)
@@ -476,10 +476,10 @@ def json_transform(state)
476476
end
477477

478478
result = +"#{result}#{key_json}#{state.space_before}:#{state.space}"
479-
if state.strict? && !(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value)
479+
if state.strict? && !(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value)
480480
if state.as_json
481481
value = state.as_json.call(value)
482-
unless false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value
482+
unless false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value
483483
raise GeneratorError.new("#{value.class} returned by #{state.as_json} not allowed in JSON", value)
484484
end
485485
result << value.to_json(state)
@@ -537,10 +537,10 @@ def json_transform(state)
537537
each { |value|
538538
result << delim unless first
539539
result << state.indent * depth if indent
540-
if state.strict? && !(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value)
540+
if state.strict? && !(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value)
541541
if state.as_json
542542
value = state.as_json.call(value)
543-
unless false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value
543+
unless false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value
544544
raise GeneratorError.new("#{value.class} returned by #{state.as_json} not allowed in JSON", value)
545545
end
546546
result << value.to_json(state)

test/json/json_generator_test.rb

+1
Original file line numberDiff line numberDiff line change
@@ -668,6 +668,7 @@ def test_nonutf8_encoding
668668
def test_fragment
669669
fragment = JSON::Fragment.new(" 42")
670670
assert_equal '{"number": 42}', JSON.generate({ number: fragment })
671+
assert_equal '{"number": 42}', JSON.generate({ number: fragment }, strict: true)
671672
end
672673

673674
def test_json_generate_as_json_convert_to_proc

0 commit comments

Comments
 (0)