【问题标题】:Java DTO class design for partial persistance and serialization?用于部分持久性和序列化的 Java DTO 类设计?
【发布时间】:2018-04-24 20:45:14
【问题描述】:

我有一个具有数百个属性的复杂 Java DTO(数据传输对象模式)类。为了便于说明,只考虑两个

class PointlessExample {
    private int x;
    private int y;
    public ... // getters/setters
}

将其重构为两个类的最佳方法是什么,以便属性的某些子集(“x”)可以与完整类分开保存,并单独或与完整类一起序列化?

我的简单想法是:

@Entity 
class PointlessBase {
    private int x;
    ...
}
class PointlessExample extends PointlessBase {
    private int y;
    ...
}

然而,问题是对象可以作为完整类 (PointlessExample) 开始其生命周期,尽管它们将始终作为 PointlessBase 持久化,但我有用例来序列化和反序列化为完整或部分对象(包括从完整序列化对象反序列化部分对象)。没有简单的方法可以仅序列化(通过 Jackson)或持久化(通过 Hibernate)属于 PointlessExample 对象的 PointlessBase 字段。或者有吗?

【问题讨论】:

  • 也许@Transient@JsonIgnore 可以胜任这项工作>?否则将需要 DTO(不是持久实体)或自定义属性包装器
  • @AntJavaDev 这不起作用,一旦我开始添加 JsonIgnore,我就失去了序列化整个类的能力。此外,这是我正在尝试设计的 DTO,因此第二部分是循环推荐 :-)
  • 嗯,是的,没有看到后面的编辑,但是,您仍然没有创建一个分割的 DTO 或创建它的助手/构建器,但是您正在创建一个实体(表)并且您想要将它作为 JSON 重用.....所以要么创建一个从 DTO/JSON Wrapper 或 Opposite 提供的适当实体。陷阱是您需要维护两个对象(重构)并分隔字段
  • 另外,我想避免将@Transient 添加到派生类的每个成员(在重构示例中)>
  • @AntJavaDev 我不介意根据预期的持久性/可序列化性来分离字段,但我真的不想要的一件事是必须在两个单独的类上重复一些大型字段定义.

标签: java hibernate jackson


【解决方案1】:

DTO 一般是painful concept
您使用继承分离属性的想法听起来不错。
如果我了解您的要求,您需要这样的东西:

-------------------------------------- |班级 | JSON |休眠 | -------------------------------------- |无意义的基础 |是 |是 | -------------------------------------- |无意义示例 |是 |否 | --------------------------------------

Jackson 中,您可以自定义反序列化的序列化过程,并且通常忽略来自给定类型或其他过滤器的属性。例如看我的简单类过滤器:

class ClassIgnoranceIntrospector extends JacksonAnnotationIntrospector {

    private final Class<?> clazz;

    ClassIgnoranceIntrospector(Class<?> clazz) {
        this.clazz = clazz;
    }

    public boolean hasIgnoreMarker(AnnotatedMember m) {
        return m.getDeclaringClass() != clazz;
    }
}

您可以在下面找到如何使用它:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.introspect.AnnotatedMember;
import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector;

import java.util.Arrays;
import java.util.List;

public class Main {

    public static void main(String[] args) throws Exception {
        ObjectMapper baseMapper = new ObjectMapper();
        baseMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
        baseMapper.setAnnotationIntrospector(new ClassIgnoranceIntrospector(PointlessBase.class));

        ObjectMapper extendedMapper = new ObjectMapper();
        extendedMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
        extendedMapper.setAnnotationIntrospector(new ClassIgnoranceIntrospector(PointlessExample.class));

        List<PointlessBase> list = Arrays.asList(new PointlessBase(), new PointlessExample());
        for (PointlessBase item : list) {
            System.out.println("Base only mapper for class " + item.getClass().getSimpleName() + " " + baseMapper.writeValueAsString(item));
            System.out.println("Extended only mapper for class " + item.getClass().getSimpleName() + " " + extendedMapper.writeValueAsString(item));
        }
    }
}

上图:

Base only mapper for class PointlessBase {"x":10}
Extended only mapper for class PointlessBase {}
Base only mapper for class PointlessExample {"x":10}
Extended only mapper for class PointlessExample {"y":11}

您可以使用ObjectMapper 的不同实例来序列化特定的属性集。如果您不想序列化/反序列化所有属性,请使用默认 ObjectMapper

另一个想法是使用Jackson JSON Views。有关如何使用Jackson 正确处理继承的更多信息,请阅读Inheritance with Jackson

【讨论】:

  • 这个ClassIgnoranceIntrospector 似乎是个好主意,让我试一试。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-17
  • 1970-01-01
相关资源
最近更新 更多