【问题标题】:Jackson @JsonView for long chain of associations on JPA/Hibernate entity graphJackson @JsonView 用于 JPA/Hibernate 实体图上的长链关联
【发布时间】:2017-07-12 07:44:37
【问题描述】:

我有以下代码:

public interface JSONInvoiceView {

    public interface JSONInvoiceBasicView {

    }

    public interface JSONInvoiceWithLinesView extends JSONInvoiceBasicView {

    }
}

@PersistenceUnit(unitName="ERP_PU")
@Entity 
@Table(name="INVOICE")
public class Invoice extends FrameworkEntity {

    @Id
    @SequenceGenerator(name = "PK_INVOICE_GEN", sequenceName = "PK_INVOICE_GEN", allocationSize=1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "PK_INVOICE_GEN")
    @Column(name = "ID")
    @JsonView(JSONInvoiceView.JSONInvoiceBasicView.class)
    private Long id;

    @OneToMany(mappedBy="invoiceLine", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JsonView(JSONInvoiceView.JSONInvoiceWithLinesView.class)
    @JsonManagedReference
    private List<InvoiceLine> lines = new ArrayList<InvoiceLine>();

    @Temporal(TemporalType.DATE)
    @Column(name = "DATE")
    @JsonView(JSONInvoiceView.JSONInvoiceBasicView.class)
    private Date startDate;

    //...
}

@PersistenceUnit(unitName="ERP_PU")
@Entity 
@Table(name="INVOICE_LINE")
public class InvoiceLine extends FrameworkEntity {

    @Id
    @Column(name = "ID")
    @JsonView(JSONInvoiceView.JSONInvoiceWithLinesView.class)
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
    @JoinColumn(name="FK_INVOICE")
    @JsonBackReference
    private Invoice invoice;

    @Column(name = "AMOUNT")
    @JsonView(JSONInvoiceView.JSONInvoiceWithLinesView.class)
    private BigDecimal amount;

    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
    @JoinColumn(name="FK_GOOD")
    private Good good;

    //...
}
@PersistenceUnit(unitName="ERP_PU")
@Entity 
@Table(name="GOOD")
public class Good extends FrameworkEntity {

    @Id
    @Column(name = "ID")
    private Long id;

    @Column(name = "DESCRIPTION", length=200)
    private String description;

//...
}

所以 – 一张 Invoice 可以有多个 InvoiceLines,并且每一行都引用 Good。我需要获得两个 JSON 视图:仅限 Inovice 视图和仅限 Invoice+InvoiceLine 视图。我的领域远比这 3 个类丰富——整个实体图包含数十个类,我需要仔细控制我在实体中加载的这个图的多少。但我还需要控制 JSON 序列化工具应该尝试序列化多少加载的图形。我对第二个控件有疑问。

entityList 是已加载 InvoiceLines 的 Invoices 列表(带有触摸,例如 invoiceLines.size();),但 InvoiceLines 没有进一步加载货物(在延迟加载期间未触摸 invoiceLine.good)。所以,entityList if Invoice+InvoiceLines。

我将以下代码用于仅发票视图,并且此代码有效:

jsonString = objectMapper.writerWithView(JSONInvoiceView.JSONInvoiceBasicView.class).writeValueAsString(entityList);

使用仅 Invoice+InvoiceLine 数据检索 JSON 视图的代码:

jsonString = objectMapper.writerWithView(JSONInvoiceView.JSONInvoiceWithLinesView.class).writeValueAsString(entityList);

此代码不起作用,它会引发错误消息:

org.codehaus.jackson.map.JsonMappingException: could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->mycom.entities.Invoice["invoiceLines"]->org.hibernate.collection.internal.PersistentBag[0]-> mycom.entities.Good["good"]-> mycom.entities.Good_$$_jvst4f9_c["id"])
    at org.codehaus.jackson.map.JsonMappingException.wrapWithPath(JsonMappingException.java:218)
    at org.codehaus.jackson.map.JsonMappingException.wrapWithPath(JsonMappingException.java:183)
    at org.codehaus.jackson.map.ser.std.SerializerBase.wrapAndThrow(SerializerBase.java:140)
    at org.codehaus.jackson.map.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:158)
    at org.codehaus.jackson.map.ser.BeanSerializer.serialize(BeanSerializer.java:112)
Caused by: org.hibernate.LazyInitializationException: could not initialize proxy - no Session
    at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:165)
    at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:286)

所以,问题是——我应该对仅加载 Invoice+InvoiceLine 数据的实体图的序列化 Invoice+InvoiceLine 部分应用什么 Jackson 视图/注释?我应该如何表明 Jackson 不应该尝试沿着关联链走得更远,Jackson 不应该尝试序列化 3rd、4th 等顺序关联,Jackson 不应该尝试序列化好的实体?

附言忽略注释(或实体上的任何类似全局注释)不适用于我的情况,因为在某些情况下我只需要 Invoice 数据,然后在某些情况下我需要 Invoice+InvoiceLine+Good 数据,而且我还需要数据Invoice+InvoiceLine+Good+GoodSupplier等

【问题讨论】:

    标签: java json hibernate jpa jackson


    【解决方案1】:

    我找到了解决方案 - Jackson 将没有 @JsonView 注释的字段视为属于每个视图的字段。因此我应该引入额外的观点:

    公共接口 JSONInvoiceView {

        public interface JSONInvoiceBasicView {
    
        }
    
        public interface JSONInvoiceWithLinesView extends JSONInvoiceBasicView {
    
        }
    
        public interface JSONInvoiceWithLinesViewExt extends JSONInvoiceWithLinesView { 
        }
    
    }
    

    并将新的交互应用于 Good 字段:

    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
    @JoinColumn(name="FK_GOOD")
    @JsonView(JSONInvoiceView.JSONInvoiceWithLinesExtView.class)
    private Good good;
    

    所以 - 我应该为我的实体的每个关联级别定义新的 JSON 视图接口。应用 @JsonView 后,一切都像魅力一样。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-07-19
      • 1970-01-01
      • 2015-08-10
      • 2012-11-02
      • 1970-01-01
      • 1970-01-01
      • 2018-01-31
      相关资源
      最近更新 更多