Jackson/Hibernate,元获取方法和序列化 [英] Jackson/Hibernate, meta get methods and serialization

查看:151
本文介绍了Jackson/Hibernate,元获取方法和序列化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们有很多具有嵌套关系的休眠实体类.我正在尝试找到将给定实体转换为等效json格式的最佳方法.

We have lot of hibernate entity classes with nested relationships. I'm trying to find best way to convert given entity to equivalent json format.

我了解JsonIgnore,Jackson mixins和JsonFilters,并且已经在尝试使用它们.

I know about JsonIgnore, Jackson mixins and JsonFilters and have been experimenting with those.

我们面临的挑战如下

  1. 使用OneToMany/JoinColumn或类似注释彼此关联的对象-创建无限递归.

  1. Objects related to each other using OneToMany/JoinColumn or similar annotations - creates infinite recursion.

实用程序或元方法.杰克逊似乎是用吸气剂而不是田地去.其中一些方法是不与任何列关联的元"方法.示例getTotal方法可以是几个实际字段的值之和,而没有实际的总字段.对于类似getIncomeAccounts之类的其他情况,情况类似,它会根据某些条件过滤帐户.

Utility or meta methods. Jackson seems to be going by getter methods and not by fields. Some of the methods are "meta" method that is not associated with any columns. Example getTotal method can be summing of values of couple of actual fields without having actual total field. Similar case for other cases like getIncomeAccounts which filters accounts based on some criteria.

我写的杰克逊过滤器有一点帮助-它根据杰克逊的属性名称检查类字段是否存在.它还会检查是否存在诸如JoinColumn注释之类的注释,以避免在该字段存在的情况下递归.

Jackson Filter I wrote helps a little - it checks if the class field exists based on Jackson property name. It also checks if there annotations such as JoinColumn annotation to avoid recursion if the field exists.

有什么办法可以从休眠中获取元数据并在过滤器中使用它?基本上对于给定的实体对象,我想知道杰克逊想要序列化的属性是否将映射到列,并且仅当存在与之关联的列值时才进行序列化. Hibernate当然知道属性和列映射.

Is there any way I can get metadata from hibernate and use it in my filters? Basically for given entity object, I am interested in knowing if the property Jackson wants to serialize will be mapped to a column and serialize only if there is column value associated with it. Hibernate is certainly aware of properties and column mappings.

Mixins和jsonignore选项是可行的,但是我们依赖于各个开发人员记住将注释放在适当位置的情况.通常,当我们真正想要获取导出的数据以分析某些问题并在本地创建测试用例时,发现被遗忘的注释为时已晚.

Mixins and jsonignore options are workable, but then we depend upon individual developer remembering about putting annotations at appropriate place. Usually forgotten annotations are discovered too late when we really want to get the exported data to analyze some problem and create test case locally.

推荐答案

如果您不想创建新的POJO模型来表示REST API级别的JSON,则需要先准备ORM模型,然后再传递给Jackson层.

If you do not want to create new POJO model for representing JSON on REST API level you need to prepare ORM model before passing to Jackson layer.

您应该先启用最适合您的 Hibernate模块 Hibernate版本.它解决了lazy-loadings和内部数据类型的许多问题.

You should start from enabling Hibernate module which fits the best to your Hibernate version. It solves many problem with lazy-loadings and internal data types.

了解Jackson具有的选项解决序列化过程中的循环问题.主要注释是:

Read about options which Jackson have for solving cycles problem during serialisation. Main annotations are:

  • JsonManagedReference
  • JsonBackReference
  • JsonIdentityInfo

您可以在ObjectMapper如何指定杰克逊只使用字段-最好是全局使用,并根据需要使用

You can define global visibility on ObjectMapper, how to specify jackson to only use fields - preferably globally and customise it if needed for given class using JsonAutoDetect annotation.

可能在大多数情况下,您将能够重复使用为ORM创建的POJO模型.如果很难对带有注释的JSON输出进行自定义,则可以随时创建自定义类,并在额外的映射/业务层中手动将ORM模型映射到该模型.

Probably for most cases you will be able to reuse POJO model created for ORM. In cases where customising JSON output with annotation will be to hard you can always create custom class and map ORM model to this one manually in extra mapping/business layer.

如果您需要以一般方式处理一些自定义注释或某些字段,则可以使用 Jackson自定义序列化和反序列化.

In case you need to handle some custom annotations or some fields in general way you can use BeanSerializerModifier and BeanPropertyWriter. It is not easy to implement but it is very powerful. See example usage here: Jackson custom serialization and deserialization.

一个简单的示例,如何实现双向关系和可见性配置:

Simple example how it could be done for bidirectional relations and visibility configuration:

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.File;
import java.util.Arrays;
import java.util.List;

public class JsonApp {

    public static void main(String[] args) throws Exception {
        File jsonFile = new File("./resource/test.json").getAbsoluteFile();

        Item item0 = new Item();
        item0.setId(1);
        item0.setItemName("Item 0");

        Item item1 = new Item();
        item1.setId(2);
        item1.setItemName("Item 1");

        List<Item> items = Arrays.asList(item0, item1);
        User user = new User();
        user.setId(123);
        user.setName("Rick");
        user.setUserItems(items);
        items.forEach(item -> item.setOwner(user));

        ObjectMapper mapper = new ObjectMapper();
        mapper.setVisibility(mapper.getSerializationConfig().getDefaultVisibilityChecker()
                .withFieldVisibility(JsonAutoDetect.Visibility.ANY)
                .withGetterVisibility(JsonAutoDetect.Visibility.NONE)
                .withSetterVisibility(JsonAutoDetect.Visibility.NONE)
                .withCreatorVisibility(JsonAutoDetect.Visibility.NONE));

        System.out.println(mapper.writeValueAsString(user));
    }
}

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
class User {

    private int id;
    private String name;
    private List<Item> userItems;

    // getters, setters
}

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
class Item {

    private int id;
    private String itemName;
    private User owner;

    // getters, setters
}

上面的代码显示:

{"id":123,"name":"Rick","userItems":[{"id":1,"itemName":"Item 0","owner":123},{"id":2,"itemName":"Item 1","owner":123}]}

这篇关于Jackson/Hibernate,元获取方法和序列化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆