spring-projects / spring-boot

Spring Boot helps you to create Spring-powered, production-grade applications and services with absolute minimum fuss.
https://spring.io/projects/spring-boot
Apache License 2.0
75.27k stars 40.71k forks source link

Auto-configure Hibernate with a JsonFormatMapper that uses the auto-configured Jackson ObjectMapper #33870

Open BernhardPosselt opened 1 year ago

BernhardPosselt commented 1 year ago

After migrating to Spring Boot 3.0.1 and Hibernate 6, I swapped out the Hibernate Types JSON support for the new built in @JdbcTypeCode(SqlTypes.JSON), however my Kotlin data classes failed to deserialize and I had to annotate everything with @JsonCreator and @JsonProperty to fix constructors.

I feel like this should default to the Jackson instance on the Spring context rather than the Jackson library itself, that is pulled in by Hibernate by default. It should be possible to define a custom mapper factory that can be configured via hibernate.type.json_format_mapper and point Hibernate to that instance, see https://github.com/hibernate/hibernate-orm/blob/main/documentation/src/main/asciidoc/userguide/chapters/domain/basic_types.adoc#json-mapping

wilkinsona commented 1 year ago

Thanks for the suggestion. If I have undertood it correctly, you should be able to do this yourself using a HibernatePropertiesCustomizer bean:

@Bean
HibernatePropertiesCustomizer jsonFormatMapperCustomizer(ObjectMapper objectMapper) {
    return (properties) -> properties.put(AvailableSettings.JSON_FORMAT_MAPPER,
            new JacksonJsonFormatMapper(objectMapper));
}

Can you please try this and let us know if it allows you to remove the @JsonCreator and @JsonProperty annotations?

BernhardPosselt commented 1 year ago

Thank you for getting back, can confirm that this does in fact work fine after removing the annotations. Maybe warrants a separate Kotlin compatibility section in the docs unless it's done by default?

wilkinsona commented 1 year ago

Thanks for confirming that it works for you. We should consider making this the default behaviour so I've labelled this issue as enhancement.

When we come to implement this we should consider the effect that Hibernate using the auto-configured ObjectMapper may have on an application. It could be a breaking change so we may want a way to disable the behavior. We should also try to implement it in such a way that if the user is already customizing the JSON format mapper that we do not overwrite that customization.

davidfortin55555 commented 1 year ago

I have implemented the following code but it is nor working with springboot 3.0.1 and hibernate 6

@Bean
HibernatePropertiesCustomizer jsonFormatMapperCustomizer(ObjectMapper objectMapper) {
    return (properties) -> properties.put(AvailableSettings.JSON_FORMAT_MAPPER,
            new JacksonJsonFormatMapper(objectMapper));
}

Do you habe another proposal?

wilkinsona commented 1 year ago

It should work so, without knowing exactly how it isn't working, it's difficult to propose something else. If you'd like some help, please post a question on Stack Overflow that includes a minimal, reproducible example of the problem.

wilkinsona commented 1 month ago

While looking at #42676 and trying to find some inspiration for a property name, a couple of other things came to mind:

  1. We should consider auto-configuring a JsonBJsonFormatMapper when there's a Jsonb bean. This also raises a question about what to do when there's both an ObjectMapper bean and a Jsonb bean. We've got spring.mvc.converters.preferred-json-mapper but its name clearly indicates that it shouldn't apply outside of Spring MVC's message conversion.
  2. The functionality is marked as @Incubating in Hibernate. Are we jumping the gun a bit here and would we be better waiting until its graduated from incubation before we try to offer auto-configuration.