From 51c0e4d7982601023340daa127e7f1f01a62cc29 Mon Sep 17 00:00:00 2001 From: Semyon Pupkov Date: Sat, 22 Mar 2025 13:40:59 +0500 Subject: [PATCH] Fix serialize/deserialize circular entries Fixes: #204 --- lib/temporal/json.rb | 1 + .../connection/serializer/failure_spec.rb | 5 ++--- spec/unit/lib/temporal/json.rb | 15 ++++++++++++++- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/lib/temporal/json.rb b/lib/temporal/json.rb index 9784d1ea..9f6d9308 100644 --- a/lib/temporal/json.rb +++ b/lib/temporal/json.rb @@ -5,6 +5,7 @@ module Temporal module JSON OJ_OPTIONS = { mode: :object, + circular: true, # use ruby's built-in serialization. If nil, OJ seems to default to ~15 decimal places of precision float_precision: 0 }.freeze diff --git a/spec/unit/lib/temporal/connection/serializer/failure_spec.rb b/spec/unit/lib/temporal/connection/serializer/failure_spec.rb index 2bde0337..2f1b75b3 100644 --- a/spec/unit/lib/temporal/connection/serializer/failure_spec.rb +++ b/spec/unit/lib/temporal/connection/serializer/failure_spec.rb @@ -80,7 +80,7 @@ def initialize(message) expect(avoids_truncation_error).to eq(old_style_deserialized_error) end - it 'logs a helpful error when the payload is too large' do + it 'logs a helpful error when the payload is too large' do e = MyBigError.new('Uh oh!') allow(Temporal.logger).to receive(:error) @@ -90,10 +90,9 @@ def initialize(message) .to have_received(:error) .with( "Could not serialize exception because it's too large, so we are using a fallback that may not deserialize "\ - "correctly on the client. First #{max_bytes} bytes:\n{\"^o\":\"MyBigError\",\"big_payload\":\"1234567890123456", + "correctly on the client. First #{max_bytes} bytes:\n{\"^o\":\"MyBigError\",\"^i\":1,\"big_payload\":\"123456789", { unserializable_error: 'MyBigError' } ) - end class MyArglessError < RuntimeError diff --git a/spec/unit/lib/temporal/json.rb b/spec/unit/lib/temporal/json.rb index c2d00cd4..5af31300 100644 --- a/spec/unit/lib/temporal/json.rb +++ b/spec/unit/lib/temporal/json.rb @@ -2,12 +2,25 @@ describe Temporal::JSON do let(:hash) { { 'one' => 'one', two: :two, ':three' => ':three' } } - let(:json) { '{"one":"one",":two":":two","\u003athree":"\u003athree"}' } + let(:json) { '{"^i":1,"one":"one",":two":":two","\u003athree":"\u003athree"}' } describe '.serialize' do it 'generates JSON string' do expect(described_class.serialize(hash)).to eq(json) end + + it 'does not raise error on circular entries' do + author = Struct.new('Author', :name, :books) + book = Struct.new('Book', :author) + author_entry = author.new(name: 'David') + book_entry = book.new(title: 'test', author: author) + + author_entry.books = [book_entry] + json = described_class.serialize(author_entry) + + result = described_class.deserialize(json) + expect(result).to eq(author_entry) + end end describe '.deserialize' do