Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move away from Jackson #1323

Open
wants to merge 20 commits into
base: 5.0.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 8 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
5 changes: 5 additions & 0 deletions function-aws-api-proxy/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,18 @@ plugins {

dependencies {
annotationProcessor libs.micronaut.graal
annotationProcessor libs.micronaut.serde

compileOnly libs.micronaut.security

implementation libs.micronaut.http.netty

implementation libs.projectreactor

implementation libs.micronaut.serde
implementation libs.micronaut.serde.jackson


api libs.micronaut.http.server
api(libs.managed.aws.serverless.core) {
exclude group:'javax.servlet', module:'javax.servlet-api'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,7 @@

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
import com.fasterxml.jackson.databind.ObjectWriter;
import io.micronaut.json.JsonMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -119,7 +117,7 @@ protected AbstractLambdaContainerHandler(Class<RequestType> requestClass,
*
* @return Return the object mapper.
*/
protected abstract ObjectMapper objectMapper();
protected abstract JsonMapper objectMapper();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a import io.micronaut.serde.ObjectMapper;. Why not return it instead?


/**
* Gets a writer for the given response class.
Expand All @@ -133,7 +131,7 @@ protected AbstractLambdaContainerHandler(Class<RequestType> requestClass,
* @param requestClass The request class
* @return The reader
*/
protected abstract ObjectReader readerFor(Class<RequestType> requestClass);
protected abstract ObjectReader<RequestType> readerFor(Class<RequestType> requestClass);

/**
* Get the container response.
Expand Down Expand Up @@ -258,4 +256,17 @@ public void proxyStream(InputStream input, OutputStream output, Context context)
public static ContainerConfig getContainerConfig() {
return config;
}

@FunctionalInterface
interface ObjectWriter {

void writeValue(OutputStream os, Object value) throws IOException;
}

@FunctionalInterface
interface ObjectReader<T> {

T readValue(InputStream input) throws IOException;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,15 @@
import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
import com.amazonaws.serverless.proxy.model.ErrorModel;
import com.amazonaws.serverless.proxy.model.Headers;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;

/**
* Default {@link ExceptionHandler} implementation.
Expand Down Expand Up @@ -94,11 +95,12 @@ public void handle(Throwable ex, OutputStream stream) throws IOException {
* @return The error json
*/
protected String getErrorJson(String message) {
try {
return environment
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
environment
.getObjectMapper()
.writeValueAsString(new ErrorModel(message));
} catch (JsonProcessingException e) {
.writeValue(baos, new ErrorModel(message));
return baos.toString(StandardCharsets.UTF_8.name());
} catch (IOException e) {
LOG.error("Could not produce error JSON", e);
return "{ \"message\": \"" + message + "\" }";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
*/
package io.micronaut.function.aws.proxy;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.micronaut.context.ApplicationContextProvider;
import io.micronaut.function.aws.MicronautLambdaContext;
import io.micronaut.jackson.codec.JsonMediaTypeCodec;
import io.micronaut.json.JsonMapper;
import io.micronaut.json.codec.JsonMediaTypeCodec;
import io.micronaut.web.router.Router;

/**
Expand All @@ -40,9 +40,9 @@ public interface MicronautLambdaContainerContext extends ApplicationContextProvi
JsonMediaTypeCodec getJsonCodec();

/**
* @return The Jackson's {@link ObjectMapper}
* @return The {@link JsonMapper}
*/
default ObjectMapper getObjectMapper() {
return getJsonCodec().getObjectMapper();
default JsonMapper getObjectMapper() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a import io.micronaut.serde.ObjectMapper; why not use instead of JsonMapper?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JsonCodec returns a JsonMapper, which isn't an ObjectMapper 😔

return getJsonCodec().getJsonMapper();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,18 @@
import com.amazonaws.serverless.proxy.AwsProxySecurityContextWriter;
import com.amazonaws.serverless.proxy.internal.jaxrs.AwsProxySecurityContext;
import com.amazonaws.serverless.proxy.internal.testutils.Timer;
import com.amazonaws.serverless.proxy.model.*;
import com.amazonaws.serverless.proxy.model.AlbContext;
import com.amazonaws.serverless.proxy.model.ApiGatewayAuthorizerContext;
import com.amazonaws.serverless.proxy.model.ApiGatewayRequestIdentity;
import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
import com.amazonaws.serverless.proxy.model.AwsProxyRequestContext;
import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
import com.amazonaws.serverless.proxy.model.CognitoAuthorizerClaims;
import com.amazonaws.serverless.proxy.model.ContainerConfig;
import com.amazonaws.serverless.proxy.model.ErrorModel;
import com.amazonaws.serverless.proxy.model.Headers;
import com.amazonaws.serverless.proxy.model.MultiValuedTreeMap;
import com.amazonaws.services.lambda.runtime.Context;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
import com.fasterxml.jackson.databind.ObjectWriter;
import io.micronaut.context.ApplicationContext;
import io.micronaut.context.ApplicationContextBuilder;
import io.micronaut.context.ApplicationContextProvider;
Expand Down Expand Up @@ -55,8 +61,11 @@
import io.micronaut.http.server.exceptions.response.ErrorContext;
import io.micronaut.http.server.exceptions.response.ErrorResponseProcessor;
import io.micronaut.inject.qualifiers.Qualifiers;
import io.micronaut.jackson.codec.JsonMediaTypeCodec;
import io.micronaut.json.JsonMapper;
import io.micronaut.json.codec.JsonMediaTypeCodec;
import io.micronaut.scheduling.executor.ExecutorSelector;
import io.micronaut.serde.ObjectMapper;
import io.micronaut.serde.annotation.SerdeImport;
import io.micronaut.web.router.MethodBasedRouteMatch;
import io.micronaut.web.router.RouteInfo;
import io.micronaut.web.router.RouteMatch;
Expand All @@ -77,6 +86,7 @@
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
Expand Down Expand Up @@ -107,6 +117,14 @@
AwsProxySecurityContext.class
}
)
@SerdeImport(AwsProxyResponse.class)
@SerdeImport(AwsProxyRequest.class)
@SerdeImport(AwsProxyRequestContext.class)
@SerdeImport(MultiValuedTreeMap.class)
@SerdeImport(Headers.class)
@SerdeImport(ApiGatewayRequestIdentity.class)
@SerdeImport(ApiGatewayAuthorizerContext.class)
@SerdeImport(AlbContext.class)
public final class MicronautLambdaContainerHandler
extends AbstractLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse, MicronautAwsProxyRequest<?>, MicronautAwsProxyResponse<?>> implements ApplicationContextProvider, Closeable, AutoCloseable {

Expand Down Expand Up @@ -202,18 +220,18 @@ public ApplicationContext getApplicationContext() {
}

@Override
protected ObjectMapper objectMapper() {
protected JsonMapper objectMapper() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not use import io.micronaut.serde.ObjectMapper instead?

return lambdaContainerEnvironment.getObjectMapper();
}

@Override
protected ObjectWriter writerFor(Class<AwsProxyResponse> responseClass) {
return objectMapper().writerFor(responseClass);
return (outputStream, value) -> outputStream.write(objectMapper().writeValueAsBytes(value));
}

@Override
protected ObjectReader readerFor(Class<AwsProxyRequest> requestClass) {
return objectMapper().readerFor(requestClass);
protected ObjectReader<AwsProxyRequest> readerFor(Class<AwsProxyRequest> requestClass) {
return input -> objectMapper().readValue(input, Argument.of(requestClass));
}

@Override
Expand Down Expand Up @@ -422,12 +440,10 @@ private void decodeRequestBody(MicronautAwsProxyRequest<?> containerRequest, Rou
bodyArgument = bodyArgument.getFirstTypeVariable().orElse(Argument.OBJECT_ARGUMENT);
}
final Object decoded = lambdaContainerEnvironment.getJsonCodec().decode(bodyArgument, body.get());
((MicronautAwsProxyRequest) containerRequest)
.setDecodedBody(decoded);
((MicronautAwsProxyRequest) containerRequest).setDecodedBody(decoded);
} else {
final JsonNode jsonNode = lambdaContainerEnvironment.getJsonCodec().decode(JsonNode.class, body.get());
((MicronautAwsProxyRequest) containerRequest)
.setDecodedBody(jsonNode);
final Map<?, ?> node = lambdaContainerEnvironment.getJsonCodec().decode(Map.class, body.get());
((MicronautAwsProxyRequest) containerRequest).setDecodedBody(node);
Comment on lines +449 to +450
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't decode to a serde JsonNode here (it fails to create one), so I fell back to a Map. This will break if the body is not a map (ie: a simple json string), but I'm not sure if Lambdas can receive simple strings

}
}
}
Expand Down Expand Up @@ -467,7 +483,7 @@ private void applyRouteConfig(MicronautAwsProxyResponse<?> containerResponse, Ro
if (!containerResponse.getContentType().isPresent()) {
finalRoute.getAnnotationMetadata().getValue(Produces.class, String.class).ifPresent(containerResponse::contentType);
}
finalRoute.getAnnotationMetadata().getValue(Status.class, HttpStatus.class).ifPresent(httpStatus -> containerResponse.status(httpStatus));
finalRoute.getAnnotationMetadata().getValue(Status.class, HttpStatus.class).ifPresent(containerResponse::status);
}

private void handlePossibleErrorStatus(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import io.micronaut.http.annotation.Get
import io.micronaut.http.annotation.Header
import io.micronaut.http.annotation.Post
import io.micronaut.http.annotation.Status
import io.micronaut.serde.annotation.Serdeable
import org.apache.commons.fileupload.FileItem
import org.reactivestreams.Publisher
import spock.lang.AutoCleanup
Expand Down Expand Up @@ -243,6 +244,7 @@ class BodySpec extends Specification {
}

@Canonical
@Serdeable
static class Point {
Integer x,y
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import io.micronaut.http.annotation.Body
import io.micronaut.http.annotation.Consumes
import io.micronaut.http.annotation.Controller
import io.micronaut.http.annotation.Post
import io.micronaut.serde.annotation.Serdeable
import spock.lang.AutoCleanup
import spock.lang.Shared
import spock.lang.Specification
Expand Down Expand Up @@ -53,6 +54,7 @@ class ConsumesSpec extends Specification {
}
}

@Serdeable
static class Pojo {
String name
}
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ projectVersion=3.3.0-SNAPSHOT
projectGroup=io.micronaut.aws

micronautDocsVersion=2.0.0
micronautVersion=3.3.4
micronautVersion=3.4.0
micronautTestVersion=3.0.5

groovyVersion=3.0.10
Expand Down
2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ micronaut-mongo-sync = { module = 'io.micronaut.mongodb:micronaut-mongo-sync' }
micronaut-runtime = { module = 'io.micronaut:micronaut-runtime' }
micronaut-runtime-groovy = { module = 'io.micronaut.groovy:micronaut-runtime-groovy' }
micronaut-security = { module = 'io.micronaut.security:micronaut-security' }
micronaut-serde = { module = 'io.micronaut.serde:micronaut-serde-api' }
micronaut-serde-jackson = { module = 'io.micronaut.serde:micronaut-serde-jackson' }
micronaut-test-junit5 = { module = 'io.micronaut.test:micronaut-test-junit5' }
micronaut-validation = { module = 'io.micronaut:micronaut-validation' }
micronaut-views-handlebars = { module = 'io.micronaut.views:micronaut-views-handlebars' }
Expand Down