1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
|
# frozen_string_literal: true
require 'base64'
require 'time'
module Aws
module Json
class Parser
include Seahorse::Model::Shapes
# @param [Seahorse::Model::ShapeRef] rules
def initialize(rules, query_compatible: false)
@rules = rules
@query_compatible = query_compatible
end
# @param [String<JSON>] json
def parse(json, target = nil)
json = '{}' if json.empty?
parse_ref(@rules, Json.load(json), target)
end
private
def structure(ref, values, target = nil)
shape = ref.shape
target = ref.shape.struct_class.new if target.nil?
values.each do |key, value|
member_name, member_ref = shape.member_by_location_name(key)
if member_ref
target[member_name] = parse_ref(member_ref, value)
elsif shape.union && key != '__type'
target[:unknown] = { 'name' => key, 'value' => value }
end
end
# In services that were previously Query/XML, members that were
# "flattened" defaulted to empty lists. In JSON, these values are nil,
# which is backwards incompatible. To preserve backwards compatibility,
# we set a default value of [] for these members.
if @query_compatible
ref.shape.members.each do |member_name, member_target|
next unless target[member_name].nil?
if flattened_list?(member_target.shape)
target[member_name] = []
elsif flattened_map?(member_target.shape)
target[member_name] = {}
end
end
end
if shape.union
# convert to subclass
member_subclass = shape.member_subclass(target.member).new
member_subclass[target.member] = target.value
target = member_subclass
end
target
end
def list(ref, values, target = nil)
target = [] if target.nil?
values.each do |value|
target << parse_ref(ref.shape.member, value)
end
target
end
def map(ref, values, target = nil)
target = {} if target.nil?
values.each do |key, value|
next if value.nil?
target[key] = parse_ref(ref.shape.value, value)
end
target
end
def parse_ref(ref, value, target = nil)
if value.nil?
nil
else
case ref.shape
when StructureShape then structure(ref, value, target)
when ListShape then list(ref, value, target)
when MapShape then map(ref, value, target)
when TimestampShape then time(value)
when BlobShape then Base64.decode64(value)
when BooleanShape then value.to_s == 'true'
when FloatShape then Util.deserialize_number(value)
else value
end
end
end
# @param [String, Integer] value
# @return [Time]
def time(value)
value.is_a?(Numeric) ? Time.at(value) : Aws::Util.deserialize_time(value)
end
def flattened_list?(shape)
shape.is_a?(ListShape) && shape.flattened
end
def flattened_map?(shape)
shape.is_a?(MapShape) && shape.flattened
end
end
end
end
|