Skip to content

Commit 4dccf5b

Browse files
committed
Allow JSON::Fragment to be used even in strict mode
1 parent 1607273 commit 4dccf5b

File tree

3 files changed

+36
-6
lines changed

3 files changed

+36
-6
lines changed

java/src/json/ext/Generator.java

Lines changed: 29 additions & 0 deletions
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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -412,10 +412,10 @@ def to_json(state = nil, *)
412412
state = State.from_state(state) if state
413413
if state&.strict?
414414
value = self
415-
if state.strict? && !(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value)
415+
if state.strict? && !(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value)
416416
if state.as_json
417417
value = state.as_json.call(value)
418-
unless false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value
418+
unless false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value
419419
raise GeneratorError.new("#{value.class} returned by #{state.as_json} not allowed in JSON", value)
420420
end
421421
value.to_json(state)
@@ -472,10 +472,10 @@ def json_transform(state)
472472
end
473473

474474
result = +"#{result}#{key_json}#{state.space_before}:#{state.space}"
475-
if state.strict? && !(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value)
475+
if state.strict? && !(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value)
476476
if state.as_json
477477
value = state.as_json.call(value)
478-
unless false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value
478+
unless false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value
479479
raise GeneratorError.new("#{value.class} returned by #{state.as_json} not allowed in JSON", value)
480480
end
481481
result << value.to_json(state)
@@ -533,10 +533,10 @@ def json_transform(state)
533533
each { |value|
534534
result << delim unless first
535535
result << state.indent * depth if indent
536-
if state.strict? && !(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value)
536+
if state.strict? && !(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value)
537537
if state.as_json
538538
value = state.as_json.call(value)
539-
unless false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value
539+
unless false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value
540540
raise GeneratorError.new("#{value.class} returned by #{state.as_json} not allowed in JSON", value)
541541
end
542542
result << value.to_json(state)

test/json/json_generator_test.rb

Lines changed: 1 addition & 0 deletions
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)