Blazebit / blaze-persistence

Rich Criteria API for JPA providers
https://persistence.blazebit.com
Apache License 2.0
741 stars 90 forks source link

Property naming strategy for Jackson integration does not work #1900

Open billysoderlund opened 6 months ago

billysoderlund commented 6 months ago

Description

I am trying to deserialize json with snake case json properties to entity views with lower camel case properties. I have tried to add the strategy to both the jackson object mapper builder and the entity view aware object mapper without success. It works for regular classes and interfaces but not entity views. Am I missing something here or is this a bug?

Expected behavior

Properties like "created_at" should deserialize to "createdAt".

Actual behavior

Properties does not get set and end up being null.

Steps to reproduce

    @Bean
    fun jsonCustomizer(): Jackson2ObjectMapperBuilderCustomizer =
        Jackson2ObjectMapperBuilderCustomizer { it
            .serializers(LifeCycleStatusSerializer())
            .propertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE)
        }

    @Bean
    fun evaObjectMapper(evm: EntityViewManager, mapper: ObjectMapper): EntityViewAwareObjectMapper {
        mapper.propertyNamingStrategy = PropertyNamingStrategies.SNAKE_CASE
        return EntityViewAwareObjectMapper(evm, mapper)
    }

Environment

Version: 1.6.11 JPA-Provider: Spring Data JPA DBMS: MySQL Application Server: Spring Boot

beikov commented 6 months ago

This should work. Blaze-Persistence delegates the serialization process to Jackson after it created the object. Can you please share the exception that you're getting and an example?

billysoderlund commented 6 months ago

The serialization part works, but "de"-serialization does not. I don't get an error, the properties just deserializes to null.

This also goes when adding custom to the object mapper builder. If I do something like this, the serializers works but the overridden function for deserializers is never called.

@Bean
fun jsonCustomizer(): Jackson2ObjectMapperBuilderCustomizer =
    Jackson2ObjectMapperBuilderCustomizer { it
        .serializers(LifeCycleStatusSerializer())
        .deserializers(LifeCycleStatusDeserializer())
        .propertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE)
    }

internal class LifeCycleStatusSerializer : StdSerializer<LifeCycleStatus>(LifeCycleStatus::class.java) {
    override fun serialize(status: LifeCycleStatus, generator: JsonGenerator, provider: SerializerProvider) {
        generator.writeNumber(status.value)
    }
}

internal class LifeCycleStatusDeserializer : StdDeserializer<LifeCycleStatus>(LifeCycleStatus::class.java) {
    override fun deserialize(jsonParser: JsonParser, context: DeserializationContext): LifeCycleStatus {
        val node: JsonNode = jsonParser.codec.readTree(jsonParser)
        return LifeCycleStatus.valueOf(node["life_cycle_status_id"].asInt())
    }
}
beikov commented 6 months ago

Ok, let me correct this

Blaze-Persistence delegates the serialization and deserialization process to Jackson after it created the object.

Can you maybe provide a reproducer for this in this test class? https://github.com/Blazebit/blaze-persistence/blob/main/integration/jackson/src/test/java/com/blazebit/persistence/integration/jackson/EntityViewAwareObjectMapperTest.java