lib/active_job/arguments.rb in activejob-5.2.8.1 vs lib/active_job/arguments.rb in activejob-6.0.0.beta1

- old
+ new

@@ -12,51 +12,65 @@ set_backtrace $!.backtrace end end # Raised when an unsupported argument type is set as a job argument. We - # currently support NilClass, Integer, Fixnum, Float, String, TrueClass, FalseClass, - # Bignum, BigDecimal, and objects that can be represented as GlobalIDs (ex: Active Record). + # currently support String, Integer, Float, NilClass, TrueClass, FalseClass, + # BigDecimal, Symbol, Date, Time, DateTime, ActiveSupport::TimeWithZone, + # ActiveSupport::Duration, Hash, ActiveSupport::HashWithIndifferentAccess, + # Array or GlobalID::Identification instances, although this can be extended + # by adding custom serializers. # Raised if you set the key for a Hash something else than a string or # a symbol. Also raised when trying to serialize an object which can't be - # identified with a Global ID - such as an unpersisted Active Record model. + # identified with a GlobalID - such as an unpersisted Active Record model. class SerializationError < ArgumentError; end module Arguments extend self - # :nodoc: - TYPE_WHITELIST = [ NilClass, String, Integer, Float, BigDecimal, TrueClass, FalseClass ] - TYPE_WHITELIST.push(Fixnum, Bignum) unless 1.class == Integer - - # Serializes a set of arguments. Whitelisted types are returned - # as-is. Arrays/Hashes are serialized element by element. - # All other types are serialized using GlobalID. + # Serializes a set of arguments. Intrinsic types that can safely be + # serialized without mutation are returned as-is. Arrays/Hashes are + # serialized element by element. All other types are serialized using + # GlobalID. def serialize(arguments) arguments.map { |argument| serialize_argument(argument) } end - # Deserializes a set of arguments. Whitelisted types are returned - # as-is. Arrays/Hashes are deserialized element by element. - # All other types are deserialized using GlobalID. + # Deserializes a set of arguments. Intrinsic types that can safely be + # deserialized without mutation are returned as-is. Arrays/Hashes are + # deserialized element by element. All other types are deserialized using + # GlobalID. def deserialize(arguments) arguments.map { |argument| deserialize_argument(argument) } rescue raise DeserializationError end private + # :nodoc: - GLOBALID_KEY = "_aj_globalid".freeze + PERMITTED_TYPES = [ NilClass, String, Integer, Float, BigDecimal, TrueClass, FalseClass ] # :nodoc: - SYMBOL_KEYS_KEY = "_aj_symbol_keys".freeze + GLOBALID_KEY = "_aj_globalid" # :nodoc: - WITH_INDIFFERENT_ACCESS_KEY = "_aj_hash_with_indifferent_access".freeze - private_constant :GLOBALID_KEY, :SYMBOL_KEYS_KEY, :WITH_INDIFFERENT_ACCESS_KEY + SYMBOL_KEYS_KEY = "_aj_symbol_keys" + # :nodoc: + WITH_INDIFFERENT_ACCESS_KEY = "_aj_hash_with_indifferent_access" + # :nodoc: + OBJECT_SERIALIZER_KEY = "_aj_serialized" + # :nodoc: + RESERVED_KEYS = [ + GLOBALID_KEY, GLOBALID_KEY.to_sym, + SYMBOL_KEYS_KEY, SYMBOL_KEYS_KEY.to_sym, + OBJECT_SERIALIZER_KEY, OBJECT_SERIALIZER_KEY.to_sym, + WITH_INDIFFERENT_ACCESS_KEY, WITH_INDIFFERENT_ACCESS_KEY.to_sym, + ] + private_constant :PERMITTED_TYPES, :RESERVED_KEYS, :GLOBALID_KEY, :SYMBOL_KEYS_KEY, :WITH_INDIFFERENT_ACCESS_KEY + def serialize_argument(argument) case argument - when *TYPE_WHITELIST + when *PERMITTED_TYPES argument when GlobalID::Identification convert_to_global_id_hash(argument) when Array argument.map { |arg| serialize_argument(arg) } @@ -68,25 +82,27 @@ result[SYMBOL_KEYS_KEY] = symbol_keys result when -> (arg) { arg.respond_to?(:permitted?) } serialize_indifferent_hash(argument.to_h) else - raise SerializationError.new("Unsupported argument type: #{argument.class.name}") + Serializers.serialize(argument) end end def deserialize_argument(argument) case argument when String argument - when *TYPE_WHITELIST + when *PERMITTED_TYPES argument when Array argument.map { |arg| deserialize_argument(arg) } when Hash if serialized_global_id?(argument) deserialize_global_id argument + elsif custom_serialized?(argument) + Serializers.deserialize(argument) else deserialize_hash(argument) end else raise ArgumentError, "Can only deserialize primitive arguments: #{argument.inspect}" @@ -99,10 +115,14 @@ def deserialize_global_id(hash) GlobalID::Locator.locate hash[GLOBALID_KEY] end + def custom_serialized?(hash) + hash.key?(OBJECT_SERIALIZER_KEY) + end + def serialize_hash(argument) argument.each_with_object({}) do |(key, value), hash| hash[serialize_hash_key(key)] = serialize_argument(value) end end @@ -114,17 +134,9 @@ elsif symbol_keys = result.delete(SYMBOL_KEYS_KEY) result = transform_symbol_keys(result, symbol_keys) end result end - - # :nodoc: - RESERVED_KEYS = [ - GLOBALID_KEY, GLOBALID_KEY.to_sym, - SYMBOL_KEYS_KEY, SYMBOL_KEYS_KEY.to_sym, - WITH_INDIFFERENT_ACCESS_KEY, WITH_INDIFFERENT_ACCESS_KEY.to_sym, - ] - private_constant :RESERVED_KEYS def serialize_hash_key(key) case key when *RESERVED_KEYS raise SerializationError.new("Can't serialize a Hash with reserved key #{key.inspect}")