Java 避免对未获取的惰性对象进行 Jackson 序列化

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21708339/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 10:12:11  来源:igfitidea点击:

Avoid Hymanson serialization on non fetched lazy objects

javaspringhibernateserializationHymanson

提问by r1ckr

I have a simple controller that return a User object, this user have a attribute coordinates that have the hibernate property FetchType.LAZY.

我有一个简单的控制器,它返回一个用户对象,这个用户有一个属性坐标,它具有休眠属性 FetchType.LAZY。

When I try to get this user, I always have to load all the coordinates to get the user object, otherwise when Hymanson try to serialize the User throws the exception:

当我尝试获取这个用户时,我总是必须加载所有坐标才能获取用户对象,否则当 Hymanson 尝试序列化用户时会抛出异常:

com.fasterxml.Hymanson.databind.JsonMappingException: could not initialize proxy - no Session

com.fasterxml.Hymanson.databind.JsonMappingException:无法初始化代理 - 没有会话

This is due to Hymanson is trying to fetch this unfetched object. Here are the objects:

这是因为 Hymanson 试图获取这个未获取的对象。以下是对象:

public class User{

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
    @JsonManagedReference("user-coordinate")
    private List<Coordinate> coordinates;
}

public class Coordinate {

    @ManyToOne
    @JoinColumn(name = "user_id", nullable = false)
    @JsonBackReference("user-coordinate")
    private User user;
}

And the controller:

和控制器:

@RequestMapping(value = "/user/{username}", method=RequestMethod.GET)
public @ResponseBody User getUser(@PathVariable String username) {

    User user = userService.getUser(username);

    return user;

}

There is a way to tell Hymanson to not serialize the unfetched objects? I've been looking other answers posted 3 years ago implementing Hymanson-hibernate-module. But probably it could be achieved with a new Hymanson feature.

有没有办法告诉Hyman逊不要序列化未提取的对象?我一直在寻找 3 年前发布的其他答案,以实现 Hymanson-hibernate-module。但可能它可以通过一个新的Hyman逊功能来实现。

My versions are:

我的版本是:

  • Spring 3.2.5
  • Hibernate 4.1.7
  • Hymanson 2.2
  • 春天 3.2.5
  • 休眠 4.1.7
  • Hyman逊 2.2

Thanks in advance.

提前致谢。

采纳答案by r1ckr

I finally found the solution! thanks to indybee for giving me a clue.

我终于找到了解决方案!感谢 indybee 给我一个线索。

The tutorial Spring 3.1, Hibernate 4 and Hymanson-Module-Hibernatehave a good solution for Spring 3.1 and earlier versions. But since version 3.1.2 Spring have his own MappingHymanson2HttpMessageConverterwith almost the same functionality as the one in the tutorial, so we don't need to create this custom HTTPMessageConverter.

教程Spring 3.1、Hibernate 4 和 Hymanson-Module-Hibernate为 Spring 3.1 和更早版本提供了很好的解决方案。但是由于 Spring 3.1.2 版本有自己的MappingHymanson2HttpMessageConverter,其功能与教程中的几乎相同,因此我们不需要创建这个自定义 HTTPMessageConverter。

With javaconfig we don't need to create a HibernateAwareObjectMappertoo, we just need to add the Hibernate4Moduleto the default MappingHymanson2HttpMessageConverterthat Spring already have and add it to the HttpMessageConverters of the application, so we need to:

使用 javaconfig 我们也不需要创建HibernateAwareObjectMapper,我们只需要将Hibernate4Module添加到Spring 已有的默认MappingHymanson2HttpMessageConverter并将其添加到应用程序的 HttpMessageConverters 中,因此我们需要:

  1. Extend our spring config class from WebMvcConfigurerAdapterand override the method configureMessageConverters.

  2. On that method add the MappingHymanson2HttpMessageConverterwith the Hibernate4Moduleregistered in a previus method.

  1. WebMvcConfigurerAdapter扩展我们的 spring 配置类并覆盖方法configureMessageConverters

  2. 在该方法上添加MappingHymanson2HttpMessageConverterHibernate4Module在以前的方法中注册。

Our config class should look like this:

我们的配置类应该是这样的:

@Configuration
@EnableWebMvc
public class MyConfigClass extends WebMvcConfigurerAdapter{

    //More configuration....

    /* Here we register the Hibernate4Module into an ObjectMapper, then set this custom-configured ObjectMapper
     * to the MessageConverter and return it to be added to the HttpMessageConverters of our application*/
    public MappingHymanson2HttpMessageConverter HymansonMessageConverter(){
        MappingHymanson2HttpMessageConverter messageConverter = new MappingHymanson2HttpMessageConverter();

        ObjectMapper mapper = new ObjectMapper();
        //Registering Hibernate4Module to support lazy objects
        mapper.registerModule(new Hibernate4Module());

        messageConverter.setObjectMapper(mapper);
        return messageConverter;

    }

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        //Here we add our custom-configured HttpMessageConverter
        converters.add(HymansonMessageConverter());
        super.configureMessageConverters(converters);
    }

    //More configuration....
}

If you have an xml configuration, you don't need to create your own MappingHymanson2HttpMessageConverter either, but you do need to create the personalized mapper that appears in the tutorial (HibernateAwareObjectMapper), so your xml config should look like this:

如果你有一个 xml 配置,你也不需要创建你自己的 MappingHymanson2HttpMessageConverter,但你需要创建教程中出现的个性化映射器 (HibernateAwareObjectMapper),所以你的 xml 配置应该是这样的:

<mvc:message-converters>
    <bean class="org.springframework.http.converter.json.MappingHymanson2HttpMessageConverter">
        <property name="objectMapper">
            <bean class="com.pastelstudios.json.HibernateAwareObjectMapper" />
        </property>
    </bean>
</mvc:message-converters>

Hope this answer be understandable and helps someone find the solution for this problem, any questions feel free to ask!

希望这个答案是可以理解的,并帮助有人找到这个问题的解决方案,任何问题都可以随时提出!

回答by blackwood

If you use XML config and use <annotation-driven />, I found that you have to nest <message-converters>inside <annotation-driven>as recommended on the Hymanson Github account.

如果您使用 XML 配置并使用<annotation-driven />,我发现您必须按照Hymanson Github 帐户上的建议嵌套<message-converters>在里面。<annotation-driven>

Like so:

像这样:

<annotation-driven>
  <message-converters>
    <beans:bean class="org.springframework.http.converter.json.MappingHymanson2HttpMessageConverter">
      <beans:property name="objectMapper">
        <beans:bean class="com.pastelstudios.json.HibernateAwareObjectMapper" />
      </beans:property>
    </beans:bean> 
  </message-converters>
</annotation-driven>

`

`

回答by Przemek Nowak

You can use the following helper from Spring Data Rest project:

您可以使用 Spring Data Rest 项目中的以下帮助程序:

Hymanson2DatatypeHelper.configureObjectMapper(objectMapper);

回答by Luis Belloch

This is similar to accepted solution by @rick.

这类似于@rick 接受的解决方案。

If you don't want to touch existing message converters configuration you can just declare a Hymanson2ObjectMapperBuilderbean like:

如果你不想接触现有的消息转换器配置,你可以声明一个Hymanson2ObjectMapperBuilderbean,如:

@Bean
public Hymanson2ObjectMapperBuilder configureObjectMapper() {
    return new Hymanson2ObjectMapperBuilder()
        .modulesToInstall(Hibernate4Module.class);
}

Do not forget to add the following dependency to your Gradle file (or Maven):

不要忘记将以下依赖项添加到您的 Gradle 文件(或 Maven):

compile 'com.fasterxml.Hymanson.datatype:Hymanson-datatype-hibernate4:2.4.4'

Useful if you have a spring-bootapplication and you want to keep the ability to modify Hymanson features from application.propertiesfile.

如果您有一个spring-boot应用程序并且希望保留从application.properties文件修改 Hymanson 功能的能力,那么这很有用。

回答by Markus Pscheidt

I tried @rick's useful answer, but ran into the problem that "well-known modules" such as Hymanson-datatype-jsr310weren't automatically registered despite them being on the classpath. (This blog postexplains the auto-registration.)

我尝试了@rick 的有用答案,但遇到了“众所周知的模块”(例如Hymanson-datatype-jsr310)的问题,尽管它们在类路径上,但并未自动注册。(这篇博文解释了自动注册。)

Expanding on @rick's answer, here's a variation using Spring's Hymanson2ObjectMapperBuilderto create the ObjectMapper. This auto-registers the "well-known modules" and sets certain features in addition to installing the Hibernate4Module.

扩展@rick的答案,这是使用 Spring 的Hymanson2ObjectMapperBuilder创建ObjectMapper. 除了安装Hibernate4Module.

@Configuration
@EnableWebMvc
public class MyWebConfig extends WebMvcConfigurerAdapter {

    // get a configured Hibernate4Module
    // here as an example with a disabled USE_TRANSIENT_ANNOTATION feature
    private Hibernate4Module hibernate4Module() {
        return new Hibernate4Module().disable(Hibernate4Module.Feature.USE_TRANSIENT_ANNOTATION);
    }

    // create the ObjectMapper with Spring's Hymanson2ObjectMapperBuilder
    // and passing the hibernate4Module to modulesToInstall()
    private MappingHymanson2HttpMessageConverter HymansonMessageConverter(){
        Hymanson2ObjectMapperBuilder builder = new Hymanson2ObjectMapperBuilder()
                            .modulesToInstall(hibernate4Module());
        return new MappingHymanson2HttpMessageConverter(builder.build());
  }

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(HymansonMessageConverter());
        super.configureMessageConverters(converters);
    }
}

回答by nevster

Although this question is slightly different to this one : Strange Hymanson exception being thrown when serializing Hibernate object, the underlying problem can be fixed in the same way with this code:

虽然这个问题与这个问题略有不同:在序列化 Hibernate 对象时抛出奇怪的Hyman逊异常,但可以使用以下代码以相同的方式修复底层问题:

@Provider
public class MyHymansonJsonProvider extends HymansonJsonProvider {
    public MyHymansonJsonProvider() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
        setMapper(mapper);
    }
}

回答by user2968675

For those who came here looking to find the solution for Apache CXF-based RESTful service, the configuration that fixes it is below:

对于那些来这里寻找基于 Apache CXF 的 RESTful 服务的解决方案的人,修复它的配置如下:

<jaxrs:providers>
    <bean class="com.fasterxml.Hymanson.jaxrs.json.HymansonJsonProvider">
        <property name="mapper" ref="objectMapper"/>
    </bean>
</jaxrs:providers>

<bean id="objectMapper" class="path.to.your.HibernateAwareObjectMapper"/>

Where HibernateAwareObjectMapper is defined as:

其中 HibernateAwareObjectMapper 定义为:

public class HibernateAwareObjectMapper extends ObjectMapper {
    public HibernateAwareObjectMapper() {
        registerModule(new Hibernate5Module());
    }
}

The following dependency is required as of June 2016 (provided you're using Hibernate5):

截至 2016 年 6 月,需要以下依赖项(前提是您使用的是 Hibernate5):

<dependency>
    <groupId>com.fasterxml.Hymanson.datatype</groupId>
    <artifactId>Hymanson-datatype-hibernate5</artifactId>
    <version>2.7.4</version>
</dependency>  

回答by chrismarx

As of Spring 4.2 and using Spring Boot and javaconfig, registering the Hibernate4Module is now as simple as adding this to your configuration:

从 Spring 4.2 开始,使用 Spring Boot 和 javaconfig,注册 Hibernate4Module 现在就像将其添加到您的配置中一样简单:

@Bean
public Module datatypeHibernateModule() {
  return new Hibernate4Module();
}

ref: https://spring.io/blog/2014/12/02/latest-Hymanson-integration-improvements-in-spring

参考:https: //spring.io/blog/2014/12/02/latest-Hymanson-integration-improvements-in-spring

回答by ahll

I tried this, and worked:

我试过这个,并工作:

// custom configuration for lazy loading

// 延迟加载的自定义配置

public static class HibernateLazyInitializerSerializer extends JsonSerializer<JavassistLazyInitializer> {

    @Override
    public void serialize(JavassistLazyInitializer initializer, JsonGenerator jsonGenerator,
            SerializerProvider serializerProvider)
            throws IOException, JsonProcessingException {
        jsonGenerator.writeNull();
    }
}

and configure mapper:

并配置映射器:

    mapper = new HymansonMapper();
    SimpleModule simpleModule = new SimpleModule(
            "SimpleModule", new Version(1,0,0,null)
    );
    simpleModule.addSerializer(
            JavassistLazyInitializer.class,
            new HibernateLazyInitializerSerializer()
    );
    mapper.registerModule(simpleModule);

回答by Alan Hay

In the case of Spring Data Rest then, while the solution posted by @r1ckr works, all that is required is to add one of the following dependencies depending on your Hibernate version:

在 Spring Data Rest 的情况下,虽然@r1ckr 发布的解决方案有效,但所需要做的就是根据您的 Hibernate 版本添加以下依赖项之一:

<dependency>
    <groupId>com.fasterxml.Hymanson.datatype</groupId>
    <artifactId>Hymanson-datatype-hibernate4</artifactId>
    <version>${Hymanson.version}</version>
</dependency>

or

或者

<dependency>
    <groupId>com.fasterxml.Hymanson.datatype</groupId>
    <artifactId>Hymanson-datatype-hibernate5</artifactId>
    <version>${Hymanson.version}</version>
</dependency>

Within Spring Data Rest there is a class:

在 Spring Data Rest 中有一个类:

org.springframework.data.rest.webmvc.json.Hymanson2DatatypeHelper

org.springframework.data.rest.webmvc.json.Hymanson2DatatypeHelper

which will auto-detect and register the Module on application start-up.

这将在应用程序启动时自动检测和注册模块。

There is however an issue:

不过有一个问题:

Issue Serializing Lazy @ManyToOne

问题序列化 Lazy @ManyToOne