使用构建器模式进行不可变对象的编组和解组的最佳方法

8
我正在开发一个简单的Java RESTful服务。我一直在研究几种JSON编组/解组的选项,如jaxb、jackson等,这些可能是比较新的技术,我试图找到它们的用法。我想知道什么是最好的方法和技术,特别是考虑到我对许多对象感兴趣,并且已经将其实现为不可变对象,并使用构建器模式。因此,没有setter,构造函数是私有的。
我看过了这个之前的问题:Jackson + Builder Pattern?,发布在stackoverflow上。我正在考虑类似这种方法,尽管获得有关使用@JsonDeserialize的更多资源的指针将非常有帮助。
这是一个非常简单的示例,显示了我正在考虑的对象类型。
public class Reading {

private final double xCoord;
private final double yCoord;
private final double diameter;
private final double reliability;
private final String qualityCode;


private Reading(Builder builder){
    xCoord = builder.xCoord;
    yCoord = builder.yCoord;
    diameter = builder.diameter;
    reliability = builder.reliability;
    qualityCode = builder.qualityCode;
}


public static class Builder {
    //required parameters
    private final double diameter;
    //optional parameters
    private double xCoord = 0.0;
    private double yCoord = 0.0;
    private double reliability = 1.0;
    private String qualityCode;


    public Builder (double diameter){
        this.diameter = diameter;
    }

    public Builder reliability(double val){
        reliability = val;
        return this;
    }

    public Builder qualityCode(String qualityCode){
        this.qualityCode = qualityCode;
        return this;
    }

    public Builder coordinates(double xCoord, double yCoord){
        this.xCoord = xCoord;
        this.yCoord = yCoord;
        return this;
    }

    public Reading build(){
        return new Reading(this);
    }

}

public double getXCoord() {return xCoord;}

public double getYCoord() {return yCoord;}

public String getQualityCode() {return qualityCode;}

public double getDiameter() { return diameter;}

public double getReliability() {return reliability; }

这个对象的编组没有问题,但是解组似乎不是很直接。此外,是否支持省略空值对象值的条目?


谢谢大家,我真的很感激所有的回复。我想我可能会考虑使用XmlAdapter来进行JaxB,就像@Blaise建议的那样,或者使用Jackson的@JsonDeserialize等效方法。如果您遇到与不可变对象有关的略微不同的问题,可以在CowTalk博客上讨论一些其他处理Jackson框架中不可变对象的方法,这也值得一看。 - Conor
5个回答

6
你可以这样做:(只实现getters并使用XmlAccessType.FIELD)
@XmlAccessorType(XmlAccessType.FIELD)
public class CreditCardVO implements Serializable {

  private Long ccNumber;
  private String ccName;


  public CreditCardVO(Long ccNumber, String ccName) {
   this.ccNumber = ccNumber;
   this.ccName = ccName;
  }


  private CreditCardVO() {
     // for JAXB's Magic
  }

  public Long getCcNumber() {
    return ccNumber;
  }

  public String getCcName() {
   return ccName;
  }    
}

摘自http://aniketshaligram.blogspot.com/2010/05/jaxb-immutable-objects.html

这篇文章讨论了如何在使用Java Architecture for XML Binding (JAXB)时创建不可变对象。JAXB是一种Java API,用于将XML文档转换为Java对象和将Java对象转换为XML文档。在某些情况下,我们可能希望创建不可变对象来提高代码的安全性和可靠性。本文介绍了如何使用JAXB注释来创建不可变类,并提供了示例代码以帮助您更好地理解。

2

谢谢Blaise,这是一篇非常好的博客文章。我会考虑采用这种方法并看看进展如何。 - Conor

0
简单来说:不要去那里。只有值对象应该由Jersey / Jackson进行序列化/反序列化,并且没有理由使它们不可变,因为它们(应该)没有共享访问。
即每个服务调用应生成一个新的值对象,该对象对其他线程不可用。这样,您就不必担心不可变性,因此可以使用具有getter和setter的标准方式。
如果没有任何好处,不要让生活变得不必要地复杂!
很久以后回来看,我不同意这个观点。 如今,我主要使用Immutables库生成值对象,并且它配备了良好的标准JSON序列化支持

感谢您的快速回复,Sean。我选择了不可变对象,因为我的服务提供对可以以线程形式运行的算法的访问。这些对象也可以作为映射中的键。 - Conor
抱歉,我本意是写以下内容- 谢谢您的快速回复Sean。我选择使用不可变对象,因为我的服务提供对可以以线程形式运行的算法的访问。这些对象也可以作为映射中的键。我认为你是对的,我可能使事情变得不必要地复杂了,至少我应该考虑使用中间对象来编组/解组数据。 - Conor
@Conor,所有这些对于您服务的内部工作都是有意义的。但在Web服务层中,对象不应该被并发访问。您仍然可以将它们用作映射键,因为Web服务框架不会更改它们,但您不能将它们设计为不可变对象。 - Sean Patrick Floyd
或者,如果您绝对想要使用这种用法,请使用@XmlAccessorType(FIELD) - Sean Patrick Floyd
再次感谢你的帮助,Sean。在你和Blaise的建议之间,我认为我应该能够开始解决这个问题了。我想我会尝试使用XmlAdapter来处理编排/解组的问题。 - Conor

0
如果您需要进行一些编组/解组操作,当您需要XML输出时,您可以使用JAXB,否则对于JSON,我会喜欢添加一些Facade,将JSON字符串转换为对象。
这意味着,每个线程都将有自己的Facade实例,因此不会存在不可变性,并且如果您倾向于使Facade成为单例,则也不会有任何问题。
在使用JSON时,您可以编写自己的逻辑来创建对象,即您可以使用构造函数或设置器。补充上述内容,使用Facade还可以支持所有子类和所有外观下的内容。

0

就目前而言,有计划(但没有准备好的代码)支持Builder样式进行反序列化(参见此Jira条目)。它何时得以实现取决于处理该问题的人数(或至少表达兴趣的人数)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接