-
-
Notifications
You must be signed in to change notification settings - Fork 358
Introduce jackson 3 support #1539
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
base: main
Are you sure you want to change the base?
Conversation
spring-cloud-aws-sns/src/main/java/io/awspring/cloud/sns/core/JsonStringEncoderDelegator.java
Outdated
Show resolved
Hide resolved
|
In general great job @MatejNedic! Left two comments plus all new public classes need proper Javadocs |
tomazfernandes
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @MatejNedic , overall this looks good on the SQS side. I left a couple of questions, mostly around simplifying version detection.
I also think we could prefix the previous classes "Jackson2" rather than Legacy so it's more precise, but that's just a nit.
Let me know what you think.
|
|
||
| import org.springframework.messaging.converter.MessageConverter; | ||
|
|
||
| public abstract class AbstractMessageConverterFactory { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’m curious: could we use direct instantiation based on classpath detection instead of introducing this factory abstraction?
For instance, Spring Kafka’s MessagingMessageConverter handles Jackson version selection via classpath detection:
Since we already have JacksonPresent too, could we apply the same pattern here so version selection is automatic and users don’t have to manually choose? If there’s a downside or constraint in our case, what is it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking that people can extend AbstractMessageConverterFactory and do their own implementation of MessageConverter. Also, it is much more readable when I refactored to this way considering deletions and so on.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @MatejNedic, I understand what you're aiming at, and we already support users providing their own MessageConverters through the SqsListenerConfigurer.
As far as I can tell, the only place we're using the create() method from AbstractMessageConverterFactory is in AbstractListenerAnnotationBeanPostProcessor.java:345.
I think we could just detect the Jackson version on the classpath there and decide what converter to use automatically.
This might eliminate the need for AbstractMessageConverterFactory, JacksonJsonMessageConverterFactory, and LegacyJackson2MessageConverterFactory, and make overall converter configuration simpler, while still preserving the customization options for users.
What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @tomazfernandes , I was thinking about it but I came up with following scenario.
What if you have Jackson 3 and Jackson 2 on classpath. Since this is messaging I want to keep Jackson 2 for SQS integration. currently if we put JacksonPresent users are not able to change this behaviour.
Notice inside of SqsListenerAnnotationBeanPostProcessor we are also based on instace getting ObjectMapper or JsonMapper. I want to allow users to control this. I don't also want to polute EndpointRegistar with ObjectMapper and JsonMapper (we had objectMapper there). So for me best way was to do a wrapper and then extract either Jackson 2 or Jackson 3 based on whichever Bean users defined. This allows users themselves to have on Classpath Jackson 3 and 2 and opt in for 2.
if (wrapper instanceof JacksonJsonMessageConverterFactory) {
argumentResolvers.add(new NotificationMessageArgumentResolver(messageConverter,
((JacksonJsonMessageConverterFactory) wrapper).getJsonMapperWrapper().getJsonMapper()));
argumentResolvers.add(new NotificationSubjectArgumentResolver(
((JacksonJsonMessageConverterFactory) wrapper).getJsonMapperWrapper().getJsonMapper()));
argumentResolvers.add(new SnsNotificationArgumentResolver(messageConverter,
((JacksonJsonMessageConverterFactory) wrapper).getJsonMapperWrapper().getJsonMapper()));
}
else if (wrapper instanceof LegacyJackson2MessageConverterFactory) {
argumentResolvers.add(new LegacyJackson2NotificationMessageArgumentResolver(messageConverter,
((LegacyJackson2MessageConverterFactory) wrapper).getObjectMapper()));
argumentResolvers.add(new LegacyJackson2NotificationSubjectArgumentResolver(
((LegacyJackson2MessageConverterFactory) wrapper).getObjectMapper()));
argumentResolvers.add(new LegacyJackson2SnsNotificationArgumentResolver(messageConverter,
((LegacyJackson2MessageConverterFactory) wrapper).getObjectMapper()));
}
@tomazfernandes Wdyt?
| @ConditionalOnMissingBean | ||
| @Bean | ||
| public MessagingMessageConverter<Message> messageConverter() { | ||
| return new SqsMessagingMessageConverter(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if this could be simpler if we detect which Jackson version is on the classpath and just return the appropriate converter directly, while still auto-wiring any user-provided mapper. Something like:
@Bean
@ConditionalOnMissingBean
public MessagingMessageConverter<Message> messageConverter(
ObjectProvider<JsonMapper> jsonMapper,
ObjectProvider<ObjectMapper> objectMapper) {
if (JacksonPresent.isJackson3Present()) {
SqsMessagingMessageConverter c = new SqsMessagingMessageConverter();
jsonMapper.ifAvailable(c::setJsonMapper);
return c;
}
else if (JacksonPresent.isJackson2Present()) {
LegacySqsMessagingMessageConverter c = new LegacySqsMessagingMessageConverter();
objectMapper.ifAvailable(c::setObjectMapper);
return c;
}
}There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will refactor with static classes. Sadly this can lead to ClassNotFoundException if I am not wrong so I will have to add more code.
📢 Type of change
📜 Description
💡 Motivation and Context
💚 How did you test it?
📝 Checklist
🔮 Next steps