0

I am writing a spring cloud function (latest build) to deploy into AWS. I understand that the AWS lambda handler uses its own Jackson configuration. I wrote a custom serializer. But, how do I override or configure the default AWS lambda one?

package com.ttp.api;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import org.bson.types.ObjectId;
import org.springframework.stereotype.Component;

import java.io.IOException;

@Component
public class ObjectIdJsonConverter {

    public static class ObjectIdSerializer extends JsonSerializer<ObjectId> {
        @Override
        public void serialize(ObjectId objectId, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
            if (objectId == null) {
                jsonGenerator.writeNull();
            } else {
                jsonGenerator.writeString(objectId.toHexString());
            }
        }
    }

    public static class ObjectIdDeserializer extends JsonDeserializer<ObjectId> {
        @Override
        public ObjectId deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
            String objectIdString = jsonParser.readValueAs(String.class);
            return new ObjectId(objectIdString);
        }
    }


}

I tried this in my main application, but either get the bean can't be overridden (I tried the spring boot property). If I take that I get the error below.

    @Bean
    @Primary
    public ObjectMapper objectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.registerModule(new JavaTimeModule());
        SimpleModule objectIdModule = new SimpleModule("ObjectIdModule");
        objectIdModule.addSerializer(ObjectId.class, new ObjectIdJsonConverter.ObjectIdSerializer());
        objectIdModule.addDeserializer(ObjectId.class, new ObjectIdJsonConverter.ObjectIdDeserializer());

        objectMapper.registerModule(objectIdModule);

        return objectMapper;
    }
{"errorMessage":"Failed to convert. Possible bug as the conversion probably shouldn't have been attempted here","errorType":"java.lang.IllegalStateException","stackTrace":["org.springframework.cloud.function.json.JacksonMapper.doFromJson(JacksonMapper.java:65)","org.springframework.cloud.function.json.JsonMapper.fromJson(JsonMapper.java:66)","org.springframework.cloud.function.adapter.aws.AWSLambdaUtils.generateMessage(AWSLambdaUtils.java:90)","org.springframework.cloud.function.adapter.aws.FunctionInvoker.handleRequest(FunctionInvoker.java:83)","java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)","java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)","java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)","java.base/java.lang.reflect.Method.invoke(Unknown Source)"],"cause":{"errorMessage":"No content to map due to end-of-input\n at [Source: (byte[])\"\"; line: 1, column: 0]","errorType":"com.fasterxml.jackson.databind.exc.MismatchedInputException","stackTrace":["com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59)","com.fasterxml.jackson.databind.ObjectMapper._initForReading(ObjectMapper.java:4821)","com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4723)","com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3771)","org.springframework.cloud.function.json.JacksonMapper.doFromJson(JacksonMapper.java:55)","org.springframework.cloud.function.json.JsonMapper.fromJson(JsonMapper.java:66)","org.springframework.cloud.function.adapter.aws.AWSLambdaUtils.generateMessage(AWSLambdaUtils.java:90)","org.springframework.cloud.function.adapter.aws.FunctionInvoker.handleRequest(FunctionInvoker.java:83)","java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)","java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)","java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)","java.base/java.lang.reflect.Method.invoke(Unknown Source)"]}}

Here is my function

@Component
public class ListCustomers implements Supplier<Flux<Subscriber>> {

    public static final Logger LOGGER = LoggerFactory.getLogger(AddCustomer.class);

    @Autowired
    private CustomerRepository customerRepository;

    @Override
    public Flux<Subscriber> get() {
        Flux<Subscriber> customers = this.customerRepository
                .findAll()
                .log();
        return customers;
    }
}
Here is my Pojo

@NoArgsConstructor
@Data
@Setter
@Getter
@AllArgsConstructor
@Document("subscriber")
public class Subscriber {

    @Id
    //@JsonSerialize(using = ObjectIdJsonConverter.ObjectIdSerializer.class)
    //@JsonDeserialize(using = ObjectIdJsonConverter.ObjectIdDeserializer.class)
    private ObjectId _id;
    private String firstName;
    private String lastName;
    private String emailAddress;
}

user521990
  • 669
  • 1
  • 5
  • 21

2 Answers2

0

Turns out when using Postman doing a GET request with no body causes this error

{"errorMessage":"Failed to convert. Possible bug as the conversion probably shouldn't have been attempted here","errorType":"java.lang.IllegalStateException","stackTrace":["org.springframework.cloud.function.json.JacksonMapper.doFromJson(JacksonMapper.java:65)","org.springframework.cloud.function.json.JsonMapper.fromJson(JsonMapper.java:66)","org.springframework.cloud.function.adapter.aws.AWSLambdaUtils.generateMessage(AWSLambdaUtils.java:90)","org.springframework.cloud.function.adapter.aws.FunctionInvoker.handleRequest(FunctionInvoker.java:83)","java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)","java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)","java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)","java.base/java.lang.reflect.Method.invoke(Unknown Source)"],"cause":{"errorMessage":"No content to map due to end-of-input\n at [Source: (byte[])\"\"; line: 1, column: 0]","errorType":"com.fasterxml.jackson.databind.exc.MismatchedInputException","stackTrace":["com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59)","com.fasterxml.jackson.databind.ObjectMapper._initForReading(ObjectMapper.java:4821)","com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4723)","com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3771)","org.springframework.cloud.function.json.JacksonMapper.doFromJson(JacksonMapper.java:55)","org.springframework.cloud.function.json.JsonMapper.fromJson(JsonMapper.java:66)","org.springframework.cloud.function.adapter.aws.AWSLambdaUtils.generateMessage(AWSLambdaUtils.java:90)","org.springframework.cloud.function.adapter.aws.FunctionInvoker.handleRequest(FunctionInvoker.java:83)","java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)","java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)","java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)","java.base/java.lang.reflect.Method.invoke(Unknown Source)"]}}

If a just put "" as part of the GET request in Postman this works.

user521990
  • 669
  • 1
  • 5
  • 21
0

Yes we do provide default set of MessageConverters with org.springframework.cloud.function.context.config.JsonMessageConverter being one of them.

However, if you need something custom you can define your own MessageConverter as described here - https://docs.spring.io/spring-cloud-function/docs/3.2.10-SNAPSHOT/reference/html/spring-cloud-function.html#user-defined-message-converters

Let us know if you have any issue

Oleg Zhurakousky
  • 5,820
  • 16
  • 17