Issue
I'm having an issue doing integration tests with my spring application. I'm using testcontainer to setup a pubsub emulator:
@Container
private static final PubSubEmulatorContainer pubsubEmulator =
new PubSubEmulatorContainer(DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk:317.0.0-emulators"));
@DynamicPropertySource
static void emulatorProperties(DynamicPropertyRegistry registry) {
registry.add("spring.cloud.gcp.pubsub.emulator-host", pubsubEmulator::getEmulatorEndpoint);
}
@Bean
CredentialsProvider googleCredentials() {
return NoCredentialsProvider.create();
}
I'm publishing a message juste like that:
publisherTemplate.publish("My_Topic", "{\"name\": \"test\"}", headers)
Here is my application configuration for pubsub and jackson:
@Configuration
@RequiredArgsConstructor
public class PubSubConsumerConfiguration {
private final ConsumerRepository consumerRepository;
@Bean
public PubSubMessageConverter pubSubMessageConverter(ObjectMapper objectMapper) {
return new JacksonPubSubMessageConverter(objectMapper);
}
@Bean
public ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
return mapper;
}
@Bean
public MessageChannel inputMessageChannel() {
return new PublishSubscribeChannel();
}
@Bean
public PubSubInboundChannelAdapter inboundChannelAdapter(MessageChannel inputMessageChannel, PubSubTemplate pubSubTemplate) {
PubSubInboundChannelAdapter adapter = new
PubSubInboundChannelAdapter(pubSubTemplate, "my_sub");
adapter.setOutputChannel(messageChannel);
adapter.setAckMode(AckMode.MANUAL);
adapter.setPayloadType(Consumer.class);
return adapter;
}
@ServiceActivator(inputChannel = "inputMessageChannel")
public void messageReceiver(
@Payload Consumer payload,
@Header(GcpPubSubHeaders.ORIGINAL_MESSAGE) BasicAcknowledgeablePubsubMessage message
) {
consumerRepository.save(payload);
message.ack();
}
}
I'm defining a bean to setup jackson as the main way to deserialize messsage payload from the pubsub. Everythin works great using pubsub on GCP, the payload i'm sending in the console is correctly deserialized and saved into the database. However in my integration tests with the test container version of the pubsub i'm getting this error during deserialization:
com.google.cloud.spring.pubsub.support.converter.PubSubMessageConversionException:
JSON deserialization of an object of type com.mypackage.model.Consumer failed.;
nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException:
Cannot construct instance of `com.mypackage.model.Consumer` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('{"name": "test"}')
Is something wrong with my way of testing?
EDIT : as asked by @Ilya here is a sample of the content of the class com.mypackage.model.Consumer, I've tried with and without empty constructor etc.. :
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Consumer {
private String name;
private ZonedDateTime deletedOn;
...
}
Solution
I've actually found the answer by looking deeper at this documentation. The issue came from the way I specified the payload when publishing my message to pubsub.
publisherTemplate.publish("My_Topic", ByteString.copyFromUtf8("{\"name\": \"test\"}"), headers)
Answered By - Rlarroque
Answer Checked By - Robin (JavaFixing Admin)