26
26
import static software .amazon .lambda .powertools .utilities .jmespath .Base64Function .decode ;
27
27
import static software .amazon .lambda .powertools .utilities .jmespath .Base64GZipFunction .decompress ;
28
28
29
+ /**
30
+ * Class that can be used to extract the meaningful part of an event and deserialize it into a Java object.<br/>
31
+ * For example, extract the body of an API Gateway event, or messages from an SQS event.
32
+ */
29
33
public class EventDeserializer {
30
34
31
35
private static final Logger LOG = LoggerFactory .getLogger (EventDeserializer .class );
32
36
33
- public static EventPart extractDataFrom (Object obj ) {
34
- if (obj instanceof String ) {
35
- return new EventPart ((String ) obj );
36
- } else if (obj instanceof Map ) {
37
- return new EventPart ((Map <String , Object >) obj );
38
- } else if (obj instanceof APIGatewayProxyRequestEvent ) {
39
- APIGatewayProxyRequestEvent event = (APIGatewayProxyRequestEvent ) obj ;
37
+ /**
38
+ * Extract the meaningful part of a Lambda Event object. Main events are built-in:
39
+ * <ul>
40
+ * <li>{@link APIGatewayProxyRequestEvent} -> body</li>
41
+ * <li>{@link APIGatewayV2HTTPEvent} -> body</li>
42
+ * <li>{@link SNSEvent} -> Records[0].Sns.Message</li>
43
+ * <li>{@link SQSEvent} -> Records[*].body <i>(list)</i></li>
44
+ * <li>{@link ScheduledEvent} -> detail</li>
45
+ * <li>{@link ApplicationLoadBalancerRequestEvent} -> body</li>
46
+ * <li>{@link CloudWatchLogsEvent} -> powertools_base64_gzip(data)</li>
47
+ * <li>{@link CloudFormationCustomResourceEvent} -> resourceProperties</li>
48
+ * <li>{@link KinesisEvent} -> Records[*].kinesis.powertools_base64(data) <i>(list)</i></li>
49
+ * <li>{@link KinesisFirehoseEvent} -> Records[*].powertools_base64(data) <i>(list)</i></li>
50
+ * <li>{@link KafkaEvent} -> records[*].values[*].powertools_base64(value) <i>(list)</i></li>
51
+ * <li>{@link ActiveMQEvent} -> messages[*].powertools_base64(data) <i>(list)</i></li>
52
+ * <li>{@link RabbitMQEvent} -> rmqMessagesByQueue[*].values[*].powertools_base64(data) <i>(list)</i></li>
53
+ * <li>{@link KinesisAnalyticsFirehoseInputPreprocessingEvent} -> Records[*].kinesis.powertools_base64(data) <i>(list)</i></li>
54
+ * <li>{@link KinesisAnalyticsStreamsInputPreprocessingEvent} > Records[*].kinesis.powertools_base64(data) <i>(list)</i></li>
55
+ * <li>{@link String}</li>
56
+ * <li>{@link Map}</li>
57
+ * </ul>
58
+ * To be used in conjunction with {@link EventPart#as(Class)} or {@link EventPart#asListOf(Class)}
59
+ * for the deserialization.
60
+ *
61
+ * @param object the event of your Lambda function handler method
62
+ * @return the part of the event which is meaningful (ex: body of the API Gateway).<br/>
63
+ */
64
+ public static EventPart extractDataFrom (Object object ) {
65
+ if (object instanceof String ) {
66
+ return new EventPart ((String ) object );
67
+ } else if (object instanceof Map ) {
68
+ return new EventPart ((Map <String , Object >) object );
69
+ } else if (object instanceof APIGatewayProxyRequestEvent ) {
70
+ APIGatewayProxyRequestEvent event = (APIGatewayProxyRequestEvent ) object ;
40
71
return new EventPart (event .getBody ());
41
- } else if (obj instanceof APIGatewayV2HTTPEvent ) {
42
- APIGatewayV2HTTPEvent event = (APIGatewayV2HTTPEvent ) obj ;
72
+ } else if (object instanceof APIGatewayV2HTTPEvent ) {
73
+ APIGatewayV2HTTPEvent event = (APIGatewayV2HTTPEvent ) object ;
43
74
return new EventPart (event .getBody ());
44
- } else if (obj instanceof SNSEvent ) {
45
- SNSEvent event = (SNSEvent ) obj ;
75
+ } else if (object instanceof SNSEvent ) {
76
+ SNSEvent event = (SNSEvent ) object ;
46
77
return new EventPart (event .getRecords ().get (0 ).getSNS ().getMessage ());
47
- } else if (obj instanceof SQSEvent ) {
48
- SQSEvent event = (SQSEvent ) obj ;
49
- return new EventPart (event .getRecords ().stream ().map (SQSEvent .SQSMessage ::getBody ).collect (Collectors .toList ()));
50
- } else if (obj instanceof ScheduledEvent ) {
51
- ScheduledEvent event = (ScheduledEvent ) obj ;
78
+ } else if (object instanceof SQSEvent ) {
79
+ SQSEvent event = (SQSEvent ) object ;
80
+ return new EventPart (event .getRecords ().stream ()
81
+ .map (SQSEvent .SQSMessage ::getBody )
82
+ .collect (Collectors .toList ()));
83
+ } else if (object instanceof ScheduledEvent ) {
84
+ ScheduledEvent event = (ScheduledEvent ) object ;
52
85
return new EventPart (event .getDetail ());
53
- } else if (obj instanceof ApplicationLoadBalancerRequestEvent ) {
54
- ApplicationLoadBalancerRequestEvent event = (ApplicationLoadBalancerRequestEvent ) obj ;
86
+ } else if (object instanceof ApplicationLoadBalancerRequestEvent ) {
87
+ ApplicationLoadBalancerRequestEvent event = (ApplicationLoadBalancerRequestEvent ) object ;
55
88
return new EventPart (event .getBody ());
56
- } else if (obj instanceof CloudWatchLogsEvent ) {
57
- CloudWatchLogsEvent event = (CloudWatchLogsEvent ) obj ;
89
+ } else if (object instanceof CloudWatchLogsEvent ) {
90
+ CloudWatchLogsEvent event = (CloudWatchLogsEvent ) object ;
58
91
return new EventPart (decompress (decode (event .getAwsLogs ().getData ().getBytes (UTF_8 ))));
59
- } else if (obj instanceof CloudFormationCustomResourceEvent ) {
60
- CloudFormationCustomResourceEvent event = (CloudFormationCustomResourceEvent ) obj ;
92
+ } else if (object instanceof CloudFormationCustomResourceEvent ) {
93
+ CloudFormationCustomResourceEvent event = (CloudFormationCustomResourceEvent ) object ;
61
94
return new EventPart (event .getResourceProperties ());
62
- } else if (obj instanceof KinesisEvent ) {
63
- KinesisEvent event = (KinesisEvent ) obj ;
64
- return new EventPart (event .getRecords ().stream ().map (r -> decode (r .getKinesis ().getData ())).collect (Collectors .toList ()));
65
- } else if (obj instanceof KinesisFirehoseEvent ) {
66
- KinesisFirehoseEvent event = (KinesisFirehoseEvent ) obj ;
67
- return new EventPart (event .getRecords ().stream ().map (r -> decode (r .getData ())).collect (Collectors .toList ()));
68
- } else if (obj instanceof KafkaEvent ) {
69
- KafkaEvent event = (KafkaEvent ) obj ;
70
- return new EventPart (event .getRecords ().values ().stream ().flatMap (List ::stream ).map (r -> decode (r .getValue ())).collect (Collectors .toList ()));
71
- } else if (obj instanceof ActiveMQEvent ) {
72
- ActiveMQEvent event = (ActiveMQEvent ) obj ;
73
- return new EventPart (event .getMessages ().stream ().map (m -> decode (m .getData ())).collect (Collectors .toList ()));
74
- } else if (obj instanceof RabbitMQEvent ) {
75
- RabbitMQEvent event = (RabbitMQEvent ) obj ;
76
- return new EventPart (event .getRmqMessagesByQueue ().values ().stream ().flatMap (List ::stream ).map (r -> decode (r .getData ())).collect (Collectors .toList ()));
77
- } else if (obj instanceof KinesisAnalyticsFirehoseInputPreprocessingEvent ) {
78
- KinesisAnalyticsFirehoseInputPreprocessingEvent event = (KinesisAnalyticsFirehoseInputPreprocessingEvent ) obj ;
79
- return new EventPart (event .getRecords ().stream ().map (r -> decode (r .getData ())).collect (Collectors .toList ()));
80
- } else if (obj instanceof KinesisAnalyticsStreamsInputPreprocessingEvent ) {
81
- KinesisAnalyticsStreamsInputPreprocessingEvent event = (KinesisAnalyticsStreamsInputPreprocessingEvent ) obj ;
82
- return new EventPart (event .getRecords ().stream ().map (r -> decode (r .getData ())).collect (Collectors .toList ()));
95
+ } else if (object instanceof KinesisEvent ) {
96
+ KinesisEvent event = (KinesisEvent ) object ;
97
+ return new EventPart (event .getRecords ().stream ()
98
+ .map (r -> decode (r .getKinesis ().getData ()))
99
+ .collect (Collectors .toList ()));
100
+ } else if (object instanceof KinesisFirehoseEvent ) {
101
+ KinesisFirehoseEvent event = (KinesisFirehoseEvent ) object ;
102
+ return new EventPart (event .getRecords ().stream ()
103
+ .map (r -> decode (r .getData ()))
104
+ .collect (Collectors .toList ()));
105
+ } else if (object instanceof KafkaEvent ) {
106
+ KafkaEvent event = (KafkaEvent ) object ;
107
+ return new EventPart (event .getRecords ().values ().stream ()
108
+ .flatMap (List ::stream )
109
+ .map (r -> decode (r .getValue ()))
110
+ .collect (Collectors .toList ()));
111
+ } else if (object instanceof ActiveMQEvent ) {
112
+ ActiveMQEvent event = (ActiveMQEvent ) object ;
113
+ return new EventPart (event .getMessages ().stream ()
114
+ .map (m -> decode (m .getData ()))
115
+ .collect (Collectors .toList ()));
116
+ } else if (object instanceof RabbitMQEvent ) {
117
+ RabbitMQEvent event = (RabbitMQEvent ) object ;
118
+ return new EventPart (event .getRmqMessagesByQueue ().values ().stream ()
119
+ .flatMap (List ::stream )
120
+ .map (r -> decode (r .getData ()))
121
+ .collect (Collectors .toList ()));
122
+ } else if (object instanceof KinesisAnalyticsFirehoseInputPreprocessingEvent ) {
123
+ KinesisAnalyticsFirehoseInputPreprocessingEvent event = (KinesisAnalyticsFirehoseInputPreprocessingEvent ) object ;
124
+ return new EventPart (event .getRecords ().stream ()
125
+ .map (r -> decode (r .getData ()))
126
+ .collect (Collectors .toList ()));
127
+ } else if (object instanceof KinesisAnalyticsStreamsInputPreprocessingEvent ) {
128
+ KinesisAnalyticsStreamsInputPreprocessingEvent event = (KinesisAnalyticsStreamsInputPreprocessingEvent ) object ;
129
+ return new EventPart (event .getRecords ().stream ()
130
+ .map (r -> decode (r .getData ()))
131
+ .collect (Collectors .toList ()));
83
132
} else {
84
- // does not really make sense to use this EventLoader when you already have a typed object
133
+ // does not really make sense to use this EventDeserializer when you already have a typed object
85
134
// just not to throw an exception
86
135
LOG .warn ("Consider using your object directly instead of using EventDeserializer" );
87
- return new EventPart (obj );
136
+ return new EventPart (object );
88
137
}
89
138
}
90
139
140
+ /**
141
+ * Meaningful part of a Lambda event.<br/>
142
+ * Use {@link #extractDataFrom(Object)} to retrieve an instance of this class.
143
+ */
91
144
public static class EventPart {
92
145
private Map <String , Object > contentMap ;
93
146
private String content ;
94
147
private List <String > contentList ;
95
148
private Object contentObject ;
96
149
97
- public EventPart (List <String > contentList ) {
150
+ private EventPart (List <String > contentList ) {
98
151
this .contentList = contentList ;
99
152
}
100
153
101
- public EventPart (String content ) {
154
+ private EventPart (String content ) {
102
155
this .content = content ;
103
156
}
104
157
105
- public EventPart (Map <String , Object > contentMap ) {
158
+ private EventPart (Map <String , Object > contentMap ) {
106
159
this .contentMap = contentMap ;
107
160
}
108
161
109
- public EventPart (Object content ) {
162
+ private EventPart (Object content ) {
110
163
this .contentObject = content ;
111
164
}
112
165
166
+ /**
167
+ * Deserialize this part of event from JSON to an object of type T
168
+ * @param clazz the target type for deserialization
169
+ * @param <T> type of object to return
170
+ * @return an Object of type T (deserialized from the content)
171
+ */
113
172
public <T > T as (Class <T > clazz ) {
114
173
try {
115
174
if (content != null ) {
@@ -126,21 +185,32 @@ public <T> T as(Class<T> clazz) {
126
185
return (T ) contentObject ;
127
186
}
128
187
if (contentList != null ) {
129
- throw new EventDeserializationException ("The content of this event is a list, consider using 'extractDataAsListOf ' instead" );
188
+ throw new EventDeserializationException ("The content of this event is a list, consider using 'asListOf ' instead" );
130
189
}
131
- throw new EventDeserializationException ("Event content is null" );
190
+ // should not occur, except if the event is malformed (missing fields)
191
+ throw new IllegalStateException ("Event content is null" );
132
192
} catch (IOException e ) {
133
193
throw new EventDeserializationException ("Cannot load the event as " + clazz .getSimpleName (), e );
134
194
}
135
195
}
136
196
197
+ /**
198
+ * Deserialize this part of event from JSON to a list of objects of type T
199
+ * @param clazz the target type for deserialization
200
+ * @param <T> type of object to return
201
+ * @return a list of objects of type T (deserialized from the content)
202
+ */
137
203
public <T > List <T > asListOf (Class <T > clazz ) {
138
204
if (contentList == null ) {
139
- throw new EventDeserializationException ("Event content is null" );
205
+ if (content != null || contentMap != null || contentObject != null ) {
206
+ throw new EventDeserializationException ("The content of this event is not a list, consider using 'as' instead" );
207
+ }
208
+ // should not occur, except if the event is really malformed
209
+ throw new IllegalStateException ("Event content is null" );
140
210
}
141
211
return contentList .stream ().map (s -> {
142
212
try {
143
- return JsonConfig .get ().getObjectMapper ().reader ().readValue (s , clazz );
213
+ return s == null ? null : JsonConfig .get ().getObjectMapper ().reader ().readValue (s , clazz );
144
214
} catch (IOException e ) {
145
215
throw new EventDeserializationException ("Cannot load the event as " + clazz .getSimpleName (), e );
146
216
}
0 commit comments