簡體   English   中英

使用 Jackson Objectmapper 配置的 Spring boot in Hibernate

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM