File Coverage

blib/lib/Amazon/API/Botocore/Shape/Serializer.pm
Criterion Covered Total %
statement 52 173 30.0
branch 1 40 2.5
condition 0 47 0.0
subroutine 17 41 41.4
pod 1 2 50.0
total 71 303 23.4


line stmt bran cond sub pod time code
1             package Amazon::API::Botocore::Shape::Serializer;
2              
3 3     3   32 use strict;
  3         5  
  3         95  
4 3     3   25 use warnings;
  3         18  
  3         109  
5              
6             BEGIN {
7 3     3   17 use English qw(-no_match_vars);
  3         8  
  3         30  
8              
9 3     3   16 eval { require Log::Log4perl; };
  3         19  
10              
11 3 50       13 if ($EVAL_ERROR) {
12 3     3   1226 no strict qw(refs); ## no critic (ProhibitNoStrict)
  3         13  
  3         267  
13              
14 0         0 *{ __PACKAGE__ . "::$_" } = sub { }
15 0         0 for qw(DEBUG INFO WARN ERROR FATAL);
16             }
17             else {
18 3     3   28 no warnings; ## no critic (ProhibitNoWarnings)
  3         9  
  3         189  
19              
20 3         20 Log::Log4perl->import(qw(:easy));
21             }
22             }
23              
24 3     3   3146 use parent qw(Class::Accessor::Fast);
  3         16  
  3         20  
25              
26 3     3   249 use Amazon::API::Constants qw(:chars :booleans);
  3         8  
  3         622  
27 3     3   35 use Amazon::API::Botocore::Shape::Utils qw(require_shape);
  3         7  
  3         185  
28              
29 3     3   22 use Carp;
  3         6  
  3         164  
30 3     3   27 use Data::Dumper;
  3         15  
  3         165  
31 3     3   137 use English qw(-no_match_vars);
  3         9  
  3         30  
32 3     3   836 use JSON qw(decode_json encode_json);
  3         7  
  3         24  
33 3     3   343 use Scalar::Util qw(reftype);
  3         9  
  3         172  
34 3     3   28 use List::Util qw(any none);
  3         13  
  3         187  
35 3     3   18 use POSIX qw(strftime);
  3         7  
  3         41  
36              
37 3     3   1652 use URL::Encode qw(url_decode_utf8);
  3         20409  
  3         5243  
38              
39             our $VERSION = '2.0.10'; ## no critic (RequireInterpolationOfMetachars)
40              
41             __PACKAGE__->follow_best_practice;
42              
43             __PACKAGE__->mk_accessors(qw( service delete_empty_members debug logger ));
44              
45             ########################################################################
46             sub new {
47             ########################################################################
48 0     0 1   my ( $class, @args ) = @_;
49              
50 0 0         my %options = ref $args[0] ? %{ $args[0] } : @args;
  0            
51              
52 0           my $self = $class->SUPER::new( \%options );
53              
54 0           return $self;
55             }
56              
57             ########################################################################
58             sub _serialize_structure {
59             ########################################################################
60 0     0     my ( $self, $this, $data, $service ) = @_;
61              
62 0   0       $service ||= $self->get_service;
63              
64 0           TRACE( Dumper [ 'serialize_structure', $this, $data ] );
65              
66 0           my $members = $this->get_members;
67              
68 0           my $result = {};
69              
70 0           foreach my $m ( keys %{$members} ) {
  0            
71 0           my $member = $members->{$m};
72 0   0       my $location_name = $member->{locationName} || $m;
73 0           my $has_location = exists $member->{locationName};
74              
75 0           my $shape = $member->{shape};
76 0           my $serialized_data;
77              
78             DEBUG(
79             sub {
80 0     0     return Dumper(
81             [ 'member name:', $m,
82             'member:', $member,
83             'shape:', $shape,
84             'location:', $location_name,
85             'has location:', $has_location
86             ]
87             );
88             }
89 0           );
90              
91 0           my $member_data;
92              
93             DEBUG(
94             sub {
95 0     0     return Dumper(
96             [ 'data', $data, 'location', $location_name,
97             'member_data', $member_data
98             ]
99             );
100             }
101 0           );
102              
103 0           $member_data = $data->{$location_name};
104              
105             # because we may have serialized an XML object...
106 0 0 0       if ( $member_data && ref($member_data) && $shape eq 'String' ) {
      0        
107 0   0       $member_data = $member_data->{content} // $EMPTY;
108             }
109              
110             DEBUG(
111             sub {
112 0     0     return Dumper(
113             [ 'serializing structure member',
114             $m, $shape, $data, $member_data, $has_location
115             ]
116             );
117             }
118 0           );
119              
120 0   0       $serialized_data = $self->serialize(
121             shape => $shape,
122             data => $member_data || $data,
123             service => $service
124             );
125              
126             DEBUG(
127             sub {
128 0     0     return Dumper(
129             [ "back from serializing $shape",
130             'data', $serialized_data, 'location_name', $location_name, 'm',
131             $m
132             ]
133             );
134             }
135 0           );
136              
137             # skip empty members
138 0 0 0       next if !exists $data->{$location_name} && !defined $serialized_data;
139              
140 0           $result->{$m} = $serialized_data;
141              
142 0     0     DEBUG( sub { return Dumper( [ 'result', $result ] ) } );
  0            
143             }
144              
145 0           return $result;
146             }
147              
148             ########################################################################
149             sub _serialize_list {
150             ########################################################################
151 0     0     my ( $self, $this, $data, $service ) = @_;
152              
153 0   0       $service ||= $self->get_service;
154              
155 0           DEBUG( Dumper( [ 'serialize_list', $this, $data, $service ] ) );
156              
157 0           my $member = $this->get_member;
158 0           my $location_name = $member->{locationName};
159              
160 0 0         if ( !$location_name ) {
161 0 0 0       if ( ref $data && reftype($data) eq 'HASH' && exists $data->{member} ) {
      0        
162 0           $location_name = 'member';
163             }
164             }
165              
166 0 0         my $list = $location_name ? $data->{$location_name} : $data;
167              
168 0           my $member_shape = $member->{shape};
169              
170 0           DEBUG(
171             Dumper(
172             [ 'serialize_list', 'member:',
173             $member, 'location_name:',
174             $location_name, 'list',
175             $list, 'member shape:',
176             $member_shape
177             ]
178             )
179             );
180              
181 0           my $result = [];
182              
183 0 0 0       if ( $list && !ref $list ) {
    0 0        
184 0           $list = [$list];
185             }
186             elsif ( $list && reftype($list) eq 'HASH' ) {
187              
188 0           my @key_values;
189 0           DEBUG( Dumper( [ 'pre-pre-marker', $list ] ) );
190 0           if (0) {
191             foreach my $key ( keys %{$list} ) {
192             push @key_values, { $key => $list->{$key} };
193             next;
194              
195             DEBUG( Dumper( [ 'pre-marker', $key ] ) );
196              
197             if ( ref $list->{$key} && exists $list->{$key}->{value} ) {
198             push @key_values,
199             {
200             value => $list->{$key}->{value},
201             key => $key
202             };
203             }
204             else {
205             push @key_values, { $key => $list->{$key} };
206             }
207             }
208             }
209             else {
210 0           $list = [$list];
211             }
212              
213 0           DEBUG( Dumper( [ 'key_values', $member_shape, \@key_values ] ) );
214              
215 0           my %result;
216              
217 0           foreach my $p ( @{$list} ) {
  0            
218              
219 0           DEBUG( Dumper( [ 'post-marker', $p, $member_shape ] ) );
220              
221 0           my $serialized_data = $self->serialize(
222             shape => $member_shape,
223             data => $p,
224             service => $service,
225             );
226              
227 0           push @{$result}, $serialized_data;
  0            
228             }
229              
230 0           local $LIST_SEPARATOR = ",";
231              
232 0           DEBUG( 'list:' . Dumper( [ ref($self), ref($this), $result, $list ] ) );
233             }
234             else {
235 0           foreach my $elem ( @{$list} ) {
  0            
236              
237             DEBUG(
238 0     0     sub { return Dumper( [ 'populate list', $member->{shape}, $elem ] ) }
239 0           );
240              
241 0           push @{$result},
242             $self->serialize(
243             shape => $member->{shape},
244 0           data => $elem,
245             service => $service,
246             );
247             }
248             }
249              
250 0           return $result;
251             }
252              
253             ########################################################################
254             sub serialize {
255             ########################################################################
256 0     0 0   my ( $self, %args ) = @_;
257              
258 0           my ( $shape, $service, $data ) = @args{qw(shape service data)};
259              
260 0   0       $service ||= $self->get_service;
261              
262             DEBUG(
263             sub {
264 0     0     return Dumper( [ 'serialize', $shape, $data, $service ] );
265             }
266 0           );
267              
268 0           my $class = require_shape( $shape, $service );
269              
270 0 0         croak "unable to require class for $shape: $EVAL_ERROR\n"
271             if !$class;
272              
273 0           my $this = $class->new;
274              
275 0           my $type = $this->get_type;
276              
277             DEBUG(
278             sub {
279 0     0     return Dumper(
280             [ 'serialize', 'class', $class, 'type',
281             $type, 'data', $data, $service
282             ]
283             );
284             }
285 0           );
286              
287             my %serializers = (
288             structure => sub {
289 0     0     return $self->_serialize_structure( $this, $data, $service );
290             },
291             list => sub {
292 0     0     return $self->_serialize_list( $this, $data, $service );
293             },
294             string => sub {
295 0 0   0     return if !defined $data;
296              
297 0 0         if ( $shape eq 'policyDocumentType' ) {
298 0           return decode_json( url_decode_utf8($data) );
299             }
300              
301 0 0 0       $data = ref $data ? $data->{content} // $EMPTY : $data;
302              
303 0           return $data;
304             },
305             boolean => sub {
306 0 0   0     $data = ref $data ? $data->{content} : $data;
307              
308 0   0       $data //= 0;
309              
310 0 0         if ( any { $data eq $_ } qw( 0 1 true false) ) {
  0            
311             return {
312             0 => JSON::false,
313             1 => JSON::true,
314             true => JSON::true,
315             false => JSON::false,
316 0           }->{$data};
317             }
318              
319 0           return $data;
320             },
321             integer => sub {
322 0 0   0     return ref $data ? $data->{content} : $data;
323             },
324             long => sub {
325 0 0   0     return ref $data ? $data->{content} : $data;
326             },
327             map => sub {
328 0     0     return $data;
329             },
330             blob => sub {
331 0     0     return $data;
332             },
333             timestamp => sub {
334 0 0   0     $data = ref $data ? $data->{content} : $data;
335 0   0       $data //= $EMPTY;
336              
337 0           $data =~ s/^(.*)[.]000Z$/$1\+00:00/xsm;
338              
339 0 0         if ( $data =~ /^[\d.]+$/xsm ) {
340 0           my $epoch = $data;
341 0           my ( undef, $nanoseconds ) = split /[.]/xsm, $epoch;
342              
343 0           $data = strftime( '%Y-%m-%dT%H:%M:%S.%%d%z', gmtime $epoch );
344 0           $data = sprintf $data, ".$nanoseconds" * 1_000_000;
345             }
346              
347 0           return $data;
348             },
349 0           );
350              
351 0           my $result;
352              
353 0 0         if ( $serializers{$type} ) {
354             DEBUG(
355             sub {
356 0     0     return Dumper(
357             [ 'serializing object of type', $type, 'data', $data ] );
358             }
359 0           );
360              
361 0           $result = $serializers{$type}->();
362              
363 0     0     DEBUG( sub { return Dumper( [ 'result', $result ] ) } );
  0            
364             }
365             else {
366             DEBUG(
367             sub {
368 0     0     return Dumper( [ 'serializing unknown object', $this, $data ] );
369             }
370 0           );
371              
372             $result = $self->serialize(
373             shape => $this->{shape},
374 0           data => $data,
375             service => $service,
376             );
377             }
378              
379 0           return $result;
380             }
381              
382             1;