![](/img/trans.png)
[英]Spring Boot auto-configured Jackson ObjectMapper not used for WebFlux WebClient by default
[英]Use Jackson Objectmapper configured by Spring boot in Hibernate
我想將 Hibernate 配置為使用由 Spring 到Objectmapper
創建的傑克遜 Objectmapper 在 Z466DEEC76ECDF6324FCA6D3857DF 之間。 在我正在進行的項目中,我已經將 Jooq 配置為使用 Spring 的ObjectMapper
,但我在如何配置 Hibernate 以使用它時遇到了麻煩。 最終的目標是 Jooq 和 Hibernate 都將使用相同的ObjectMapper
。
我查看了 Vlad 的這篇文章。 不幸的是,本文中給出的所有技巧都不適用於我正在從事的項目。
這是我嘗試的示例配置
@Configuration
public class HibernateConfiguration implements HibernatePropertiesCustomizer {
//Autowire Objectmapper created by Spring
@Autowired
ObjectMapper objectMapper;
@Override
public void customize(Map<String, Object> hibernateProperties) {
ObjectMapperSupplier objectMapperSupplier = () -> objectMapper;
// Below config doesn't work since Hibernate types creates it's own mapper
hibernateProperties.put("hibernate.types.jackson.object.mapper", objectMapperSupplier);
}
還通過將 Objectmapper 添加到 hibernate-types.properties 來嘗試相同的方法。
#Used by Hibernate but cannot get reference of Spring managed ObjectMapper since this is class is called outside of Spring's context.
hibernate.types.jackson.object.mapper=path.to.ObjectMapperSupplier
我使用的另一種方法,但是當從 JSON 轉換為 JsonTypeDescriptor class 中的實體時,它失敗並JsonTypeDescriptor
NullpointerException
。
@Configuration
public class HibernateConfiguration implements HibernatePropertiesCustomizer{
@Autowired
ObjectMapper objectMapper;
@Override
public void customize(Map<String, Object> hibernateProperties) {
// Underlying implementation needs some JavaType or propertyClass, otherwise when converting
// from JSON we get a nullpointer.
var jsonBinaryType = new JsonBinaryType(objectMapper);
hibernateProperties.put("hibernate.type_contributors", (TypeContributorList) () ->
Collections.singletonList((typeContributions, serviceRegistry) ->
typeContributions.contributeType(jsonBinaryType)));
}
下面是實體 super class 的類型聲明。
// This makes Hibernate types create it's own mapper.
@TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)
@MappedSuperclass
public abstract class Entity{
}
那么,有什么可能的解決方案可以將 Spring 托管 ObjectMapper 連接到 Hibernate 嗎?
我終於想通了,但這是一種創造性的解決方案......
TLDR:我有一個 bean,它將 Spring 配置的objectMapper
存儲在 static 字段中。 BeanFactoryPostProcessor 確保在 Hibernate(類型)嘗試加載/獲取 ObjectMapper 之前初始化此 bean。
hibernate.properties
hibernate.types.jackson.object.mapper=com.github.lion7.example.HibernateObjectMapperSupplier
HibernateObjectMapperSupplier.kt
package com.github.lion7.example
import com.fasterxml.jackson.databind.ObjectMapper
import com.vladmihalcea.hibernate.type.util.ObjectMapperSupplier
import org.springframework.beans.factory.config.BeanFactoryPostProcessor
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory
import org.springframework.stereotype.Component
class HibernateObjectMapperSupplier : ObjectMapperSupplier {
override fun get(): ObjectMapper =
ObjectMapperHolder.objectMapper
}
@Component
class ObjectMapperHolder(objectMapper: ObjectMapper) {
companion object {
lateinit var objectMapper: ObjectMapper
}
init {
Companion.objectMapper = objectMapper
}
}
@Component
class ObjectMapperDependencyFixer : BeanFactoryPostProcessor {
override fun postProcessBeanFactory(beanFactory: ConfigurableListableBeanFactory) {
val beanDefinition = beanFactory.getBeanDefinition("entityManagerFactory")
val oldDependsOn = beanDefinition.dependsOn ?: emptyArray()
val newDependsOn = oldDependsOn + "objectMapperHolder"
beanDefinition.setDependsOn(*newDependsOn)
}
}
與 gist 相同的代碼: https://gist.github.com/lion7/c8006b69a309e38183deb69124b888b5
Java 實現。
@Component
public class HibernateObjectMapperSupplier implements Supplier<ObjectMapper> {
private static ObjectMapper objectMapper;
@Autowired
public void setObjectMapper(ObjectMapper objectMapper) {
HibernateObjectMapperSupplier.objectMapper = objectMapper;
}
@Override
public ObjectMapper get() {
return objectMapper;
}
}
如果您定義自己的 JPA bean,只需將@DependsOn("hibernateObjectMapper")
添加到他們的配置中。 否則,您需要一個BeanPostProcessor
將依賴項添加到自動配置的 bean:
@Component
class HibernateBeanDependencyProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) {
BeanDefinition beanDefinition = factory.getBeanDefinition("entityManagerFactory");
String[] dependsOn = beanDefinition.getDependsOn();
dependsOn = dependsOn == null ? new String[]{} : dependsOn;
String[] newDependsOn = new String[dependsOn.length];
System.arraycopy(dependsOn, 0, newDependsOn, 1, dependsOn.length);
newDependsOn[0] = "hibernateObjectMapperSupplier";
beanDefinition.setDependsOn(newDependsOn);
}
}
要將 Vlads 解決方案與 Spring 一起使用,您只需設置系統屬性,例如通過System.setProperty()
:
static {
System.setProperty("hibernate.types.jackson.object.mapper", CustomObjectMapperSupplier.class.getName());
}
(其中CustomObjectMapperSupplier
是您的 class ,它實現了來自 Vlads 庫的ObjectMapperSupplier
)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.