Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.networknt.aws.lambda;

import com.networknt.jackson.JacksonDefaults;
import tools.jackson.databind.DeserializationFeature;
import tools.jackson.databind.ObjectMapper;

/**
* Shared immutable mapper exclusively for AWS Lambda event payloads in the JVM and native runtimes.
* Intentionally accepts unknown event properties, making it more permissive than the framework mapper.
* Do not use it for configuration binding or validation.
*/
public final class LambdaRuntimeMappers {
private static final ObjectMapper MAPPER = JacksonDefaults.builder()
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES).build();

private LambdaRuntimeMappers() { }

/** Returns the event-only mapper, accepting future AWS event properties. */
public static ObjectMapper mapper() {
return MAPPER;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,19 @@
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;
import com.networknt.jackson.JacksonDefaults;
import com.networknt.utility.NioUtils;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.net.HttpURLConnection;
import tools.jackson.databind.DeserializationFeature;
import tools.jackson.databind.ObjectMapper;

public class Runtime {
private static final String REQUEST_ID_HEADER = "lambda-runtime-aws-request-id";

private static final ObjectMapper OBJECT_MAPPER = JacksonDefaults.builder()
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES).build();
private static final ObjectMapper OBJECT_MAPPER = LambdaRuntimeMappers.mapper();

public static void main(String[] args) throws IOException {
while(true) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;
import com.networknt.jackson.JacksonDefaults;
import org.junit.jupiter.api.Test;
import tools.jackson.databind.ObjectMapper;
import tools.jackson.databind.DeserializationFeature;

import java.util.List;
import java.util.Map;
Expand All @@ -14,15 +15,17 @@
import static org.junit.jupiter.api.Assertions.assertTrue;

class Jackson3RuntimeCompatibilityTest {
private ObjectMapper runtimeMapper() throws Exception {
var field = Runtime.class.getDeclaredField("OBJECT_MAPPER");
field.setAccessible(true);
return (ObjectMapper) field.get(null);
@Test
void runtimeAndFrameworkMappersHaveSeparateUnknownPropertyPolicies() {
var runtimeMapper = LambdaRuntimeMappers.mapper();
var frameworkMapper = JacksonDefaults.builder().build();
assertFalse(runtimeMapper.isEnabled(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES));
assertTrue(frameworkMapper.isEnabled(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES));
}

@Test
void bindsAwsGatewayEventsWithoutJackson2Types() throws Exception {
var mapper = runtimeMapper();
var mapper = LambdaRuntimeMappers.mapper();
var request = mapper.readValue("{\"path\":\"/pets\",\"httpMethod\":\"POST\","
+ "\"body\":\"雪\",\"isBase64Encoded\":true,\"requestContext\":{\"requestId\":\"fixture\"},"
+ "\"multiValueHeaders\":{\"X-Test\":[\"one\",\"two\"]}}", APIGatewayProxyRequestEvent.class);
Expand All @@ -40,12 +43,12 @@ void preservesTheMeasuredResponseWireShape() throws Exception {
.withMultiValueHeaders(Map.of("Set-Cookie", List.of("a=1", "b=2")));
assertEquals("{\"statusCode\":201,\"headers\":{\"Content-Type\":\"application/json\"},"
+ "\"multiValueHeaders\":{\"Set-Cookie\":[\"a=1\",\"b=2\"]},\"body\":\"雪\\nbody\","
+ "\"isBase64Encoded\":true}", runtimeMapper().writeValueAsString(response));
+ "\"isBase64Encoded\":true}", LambdaRuntimeMappers.mapper().writeValueAsString(response));
}

@Test
void retainsBuilderBindingAndNullPrimitiveHandling() throws Exception {
var mapper = runtimeMapper();
var mapper = LambdaRuntimeMappers.mapper();
var response = mapper.readValue("{\"code\":null,\"message\":\"fixture error\"}", DefaultResponse.class);
assertEquals(0, response.getCode());
assertEquals("{\"code\":0,\"message\":\"fixture error\"}", mapper.writeValueAsString(response));
Expand All @@ -56,7 +59,7 @@ void retainsBuilderBindingAndNullPrimitiveHandling() throws Exception {

@Test
void retainsPermissiveRuntimeBinding() throws Exception {
var mapper = runtimeMapper();
var mapper = LambdaRuntimeMappers.mapper();
var request = mapper.readValue("{\"futureField\":1,\"isBase64Encoded\":false} {}", APIGatewayProxyRequestEvent.class);
assertNull(request.getPath());
assertFalse(request.getIsBase64Encoded());
Expand Down
Loading