Skip to content

Commit aff8ae7

Browse files
authored
Prevent default message round-trip failures for module-backed payloads (#289)
The default mapper bootstrap only disabled unknown-property failures, so payloads that depend on Jackson module discovery could serialize on enqueue and still fail during dequeue or listener argument mapping. This change enables module auto-discovery in SerializationUtils and adds a regression test that verifies the default GenericMessageConverter round-trip path with a ServiceLoader-discovered Jackson module. Constraint: Must preserve the existing MessageConverterProvider-based extension model Rejected: Prefer Spring-managed ObjectMapper by default | changes the library's default configuration contract Confidence: medium Scope-risk: narrow Directive: If default mapper bootstrap changes again, keep equivalent regression coverage for service-loaded modules Tested: ./gradlew checkFormatJava :rqueue-core:test --tests com.github.sonus21.rqueue.converter.GenericMessageConverterTest --tests com.github.sonus21.rqueue.converter.JsonMessageConverterTest Not-tested: Cross-service producer/consumer environments with different classpaths
1 parent a752acc commit aff8ae7

File tree

3 files changed

+92
-0
lines changed

3 files changed

+92
-0
lines changed

rqueue-core/src/main/java/com/github/sonus21/rqueue/utils/SerializationUtils.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ public static boolean isJson(String data) {
3939
public static ObjectMapper createObjectMapper() {
4040
return JsonMapper.builder()
4141
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
42+
.findAndAddModules()
4243
.build();
4344
}
4445
}

rqueue-core/src/test/java/com/github/sonus21/rqueue/converter/GenericMessageConverterTest.java

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,15 @@
4242
import org.junit.jupiter.api.Test;
4343
import org.springframework.messaging.Message;
4444
import org.springframework.messaging.support.GenericMessage;
45+
import tools.jackson.core.JacksonException;
46+
import tools.jackson.core.JsonGenerator;
47+
import tools.jackson.core.JsonParser;
48+
import tools.jackson.databind.DeserializationContext;
49+
import tools.jackson.databind.JsonNode;
50+
import tools.jackson.databind.SerializationContext;
51+
import tools.jackson.databind.deser.std.StdDeserializer;
52+
import tools.jackson.databind.module.SimpleModule;
53+
import tools.jackson.databind.ser.std.StdSerializer;
4554

4655
@SuppressWarnings("unchecked")
4756
@CoreUnitTest
@@ -115,6 +124,16 @@ void toAndFromMessageList() {
115124
assertEquals(dataList, fromMessage);
116125
}
117126

127+
@Test
128+
void toAndFromMessageUsingServiceLoadedModules() {
129+
ServiceLoadedPayload payload = ServiceLoadedPayload.of("module-backed");
130+
Message<String> message = (Message<String>)
131+
genericMessageConverter.toMessage(payload, RqueueMessageHeaders.emptyMessageHeaders());
132+
ServiceLoadedPayload fromMessage =
133+
(ServiceLoadedPayload) genericMessageConverter.fromMessage(message, null);
134+
assertEquals(payload, fromMessage);
135+
}
136+
118137
@Test
119138
void envelopeEventToAndFromMessage() {
120139
Event<Comment> event = new Event<>("evt-1", comment);
@@ -456,4 +475,75 @@ public Notification(String id, String message, int priority) {
456475
this.priority = priority;
457476
}
458477
}
478+
479+
public static class ServiceLoadedPayload {
480+
481+
private final String value;
482+
483+
private ServiceLoadedPayload(String value) {
484+
this.value = value;
485+
}
486+
487+
public static ServiceLoadedPayload of(String value) {
488+
return new ServiceLoadedPayload(value);
489+
}
490+
491+
String value() {
492+
return value;
493+
}
494+
495+
@Override
496+
public boolean equals(Object o) {
497+
if (!(o instanceof ServiceLoadedPayload)) {
498+
return false;
499+
}
500+
ServiceLoadedPayload that = (ServiceLoadedPayload) o;
501+
return Objects.equals(value, that.value);
502+
}
503+
504+
@Override
505+
public int hashCode() {
506+
return Objects.hash(value);
507+
}
508+
}
509+
510+
public static class ServiceLoadedPayloadModule extends SimpleModule {
511+
512+
public ServiceLoadedPayloadModule() {
513+
addSerializer(ServiceLoadedPayload.class, new ServiceLoadedPayloadSerializer());
514+
addDeserializer(ServiceLoadedPayload.class, new ServiceLoadedPayloadDeserializer());
515+
}
516+
517+
private static class ServiceLoadedPayloadSerializer
518+
extends StdSerializer<ServiceLoadedPayload> {
519+
520+
private ServiceLoadedPayloadSerializer() {
521+
super(ServiceLoadedPayload.class);
522+
}
523+
524+
@Override
525+
public void serialize(
526+
ServiceLoadedPayload value, JsonGenerator jsonGenerator, SerializationContext provider)
527+
throws JacksonException {
528+
jsonGenerator.writeStartObject();
529+
jsonGenerator.writeStringProperty("value", value.value());
530+
jsonGenerator.writeEndObject();
531+
}
532+
}
533+
534+
private static class ServiceLoadedPayloadDeserializer
535+
extends StdDeserializer<ServiceLoadedPayload> {
536+
537+
private ServiceLoadedPayloadDeserializer() {
538+
super(ServiceLoadedPayload.class);
539+
}
540+
541+
@Override
542+
public ServiceLoadedPayload deserialize(JsonParser jsonParser, DeserializationContext context)
543+
throws JacksonException {
544+
JsonNode node = jsonParser.readValueAsTree();
545+
return ServiceLoadedPayload.of(node.get("value").asText());
546+
}
547+
}
548+
}
459549
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
com.github.sonus21.rqueue.converter.GenericMessageConverterTest$ServiceLoadedPayloadModule

0 commit comments

Comments
 (0)