简体   繁体   English

为了避免XMLEncoder的序列化,你如何在Javabean中将属性标记为瞬态?

[英]How do you mark a property as transient in a Javabean in order to avoid serialization by XMLEncoder?

Using the "transient" keyword on a variable declaration or "@Transient" on the getter does not stop the XMLEncoder from serializing properties. 在变量声明上使用“transient”关键字或在getter上使用“@Transient”不会阻止XMLEncoder序列化属性。 The only way I've found to tell the XMLEncoder not to serialize specific properties is with code like: 我发现告诉XMLEncoder不要序列化特定属性的唯一方法是使用以下代码:

BeanInfo info = Introspector.getBeanInfo(MyClass2.class);
PropertyDescriptor[] propertyDescriptors = info.getPropertyDescriptors();
for (int i = 0; i < propertyDescriptors.length; ++i) {
    PropertyDescriptor pd = propertyDescriptors[i];
    if (pd.getName().equals("props")) {
        pd.setValue("transient", Boolean.TRUE);
    }
}

Really??? 真??? Is there an easier way that doesn't require runtime code to loop through all the properties? 是否有一种更简单的方法,不需要运行时代码循环遍历所有属性? Something like the transient modifier would rock! 类似于瞬态修改器的东西会晃动!

Here's a JavaBean that will have all it's properties serialized by XMLEncoder, despite the use of "transient": 这是一个JavaBean,它将具有由XMLEncoder序列化的所有属性,尽管使用了“transient”:

import java.io.Serializable;
import java.beans.XMLEncoder;

public class TestJavaBeanSerialization implements Serializable {
    public TestJavaBeanSerialization() {}
    private transient String myProp1 = null;
    private String myProp2 = null;
    @Transient public String getMyProp1() { return myProp1; }
    public void setMyProp1(String a) { myProp1 = a; }
    public String getMyProp2() { return myProp2; }
    public void setMyProp2(String a) { myProp2 = a; }

    public static void main( String[] args ) {
        TestJavaBeanSerialization myObj = new TestJavaBeanSerialization();
        myObj.setMyProp1("prop 1");
        myObj.setMyProp2("prop 2");
        XMLEncoder encoder = new XMLEncoder(System.out);
        encoder.writeObject(myObj);
        encoder.close();        
    }

}

Here's the output of running this program: 这是运行该程序的输出:

<?xml version="1.0" encoding="UTF-8"?> 
<java version="1.6.0_29" class="java.beans.XMLDecoder"> 
 <object class="TestJavaBeanSerialization"> 
  <void property="myProp1"> 
   <string>prop 1</string> 
  </void> 
  <void property="myProp2"> 
   <string>prop 2</string> 
  </void> 
 </object> 
</java> 

UPDATE UPDATE

I still have not received a definitive answer to the original question. 我还没有收到原始问题的明确答案。 There's this article that people keep referencing, but it's not clear and no one's given a reference to an API or spec that clearly states the only way to mark a property as transient is to loop through all the properties and call "setValue". 这篇文章是人们不断引用的,但是它并不清楚,也没有人给出API或规范的参考,明确指出将属性标记为瞬态的唯一方法是遍历所有属性并调用“setValue”。

You use the wrong @Transient 你使用错误的@Transient

Should use java.beans.Transient for the annotation. 应该使用java.beans.Transient作为注释。 javax.persistence.Transient is only respected in the context of database persistence, not BeanInfo serialization. javax.persistence.Transient仅在数据库持久性的上下文中受到尊重,而不是BeanInfo序列化。

A workaround might be to use JAXB as your XML serializer which is bundled with Java 1.6. 解决方法可能是使用JAXB作为与Java 1.6捆绑在一起的XML序列化程序。 It supports an @XmlTransient annotation. 它支持@XmlTransient注释。

I had a similar problem and I was looking for an easier solution. 我遇到了类似的问题,我正在寻找一个更简单的解决方案。 The way I managed it is by breaking Java Beans conventions. 我管理它的方式是打破Java Beans惯例。

If you don't want to serialize a field, don't set getters setters for it. 如果您不想序列化字段,请不要为其设置getter setter。 Instead of "get" and "set", use other prefixes like "retrieve" and "save". 而不是“获取”和“设置”,使用其他前缀,如“检索”和“保存”。 For example - 例如 -

int x=0;
public int retrieveX() {
    return x;
}
public void saveX(int x) {
    this.x = x;
}

This did the trick for me and I'm sure will help others who don't specifically need Java Beans conventions in the code. 这对我来说很有用,我肯定会帮助那些在代码中没有特别需要Java Beans约定的人。 Using this way makes the variable available throughout your application but at the same time hiding it from XMLEncoder serializer. 使用这种方式可以在整个应用程序中使用该变量,但同时将其隐藏在XMLEncoder序列化程序中。

Hope it helps someone in future. 希望它将来有助于某人。

I was accustomed to use this known solution for several years in my own code but there is a much more simple one since Java 1.7: the java.beans.Transient annotation . 我习惯于在我自己的代码中使用这个已知的解决方案多年,但是自Java 1.7以来有一个更简单的解决方案java.beans.Transient注释 Note that you can use it on the getters and the setters but not on the fields unlike javax.persistence.Transient (JPA). 请注意,您可以在getter和setter上使用它,但不能在javax.persistence.Transient (JPA)上的字段上使用它。

import java.beans.Transient;
import java.beans.XMLEncoder;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Arrays;

public class Test {

public static final void main(String[] args) throws Throwable {
    final Capsule caps = new Capsule();
    caps.setIdentifier("6545346");
    caps.setMe("Julien");
    caps.setSentences(new ArrayList<>(Arrays.asList(new String[]{"I don't like my job","I prefer sleeping"})));
    try (FileOutputStream fOut = new FileOutputStream(new File(System.getProperty("user.home"), "test.xml")); 
         BufferedOutputStream out = new BufferedOutputStream(fOut);
         XMLEncoder encoder = new XMLEncoder(out)) {
        encoder.writeObject(caps);
        encoder.flush();
    }
}

public static final class Capsule {

    private String identifier;

    private transient String me;

    private transient ArrayList<String> sentences;

    public Capsule() {
        super();
    }

    @Transient
    public ArrayList<String> getSentences() {
        return sentences;
    }

    @Transient
    public void setSentences(ArrayList<String> sentences) {
        this.sentences = sentences;
    }

    public String getIdentifier() {
        return identifier;
    }

    public void setIdentifier(String identifier) {
        this.identifier = identifier;
    }

    @Transient
    public String getMe() {
        return me;
    }

    @Transient
    public void setMe(String me) {
        this.me = me;
    }
}}

The result is: 结果是:

<?xml version="1.0" encoding="UTF-8"?>
<java version="1.7.0_76" class="java.beans.XMLDecoder">
 <object class="Test$Capsule">
  <void property="identifier">
   <string>6545346</string>
  </void>
 </object>
</java>

Note the absence of the transient values. 注意没有瞬态值。 I couldn't skip the collections in 2009 but it seems to work now. 我无法在2009年跳过这些收藏,但它现在似乎有效。

this is the only way that declare properties is transient.you can see the article. 这是声明属性是瞬态的唯一方法。您可以看到该文章。 Url is http://www.oracle.com/technetwork/java/persistence4-140124.html?ssSourceSiteId=otncn#transient 网址是http://www.oracle.com/technetwork/java/persistence4-140124.html?ssSourceSiteId=otncn#transient

myProp1字段添加静态,并在getMyProp1方法之前删除'@Transient'关键字,然后运行程序,结果是你想要的?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM