Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java序列化错误,当遇到具有集合的循环依赖项时_Java_Hibernate_Serialization - Fatal编程技术网

Java序列化错误,当遇到具有集合的循环依赖项时

Java序列化错误,当遇到具有集合的循环依赖项时,java,hibernate,serialization,Java,Hibernate,Serialization,我的项目是一个java项目,在EJB3上使用Hibernate和Weblogic服务器 为了方便起见(据我所知,这是典型的hibernate),一些实体包含循环依赖项(父知道子,子知道父)。此外,对于某些子类,hashCode()和equals()方法依赖于它们的父类(因为它是唯一的键) 在工作时,我看到了一种奇怪的行为——一些从服务器返回到客户机的集合,虽然包含正确的元素,但它们的行为却好像不包含任何元素。例如,这样一个简单的测试:set.contains(set.toArray()[0])返

我的项目是一个
java
项目,在
EJB3
上使用Hibernate和
Weblogic
服务器

为了方便起见(据我所知,这是典型的
hibernate
),一些实体包含循环依赖项(父知道子,子知道父)。此外,对于某些子类,
hashCode()
equals()
方法依赖于它们的父类(因为它是唯一的键)

在工作时,我看到了一种奇怪的行为——一些从服务器返回到客户机的集合,虽然包含正确的元素,但它们的行为却好像不包含任何元素。例如,这样一个简单的测试:
set.contains(set.toArray()[0])
返回了
false
,尽管
hashCode()
方法是一个好方法

经过大量调试后,我能够生成两个简单的类来重现问题(我可以向您保证两个类中的
hashCode()
函数都是自反、传递和对称的):


equals方法必须是自反的、传递的和对称的

hashCode方法必须具有:

hashCode的总合同为:

在Java应用程序的执行过程中,每当在同一对象上多次调用hashCode方法时,只要没有修改对象上的equals比较中使用的信息,hashCode方法必须始终返回相同的整数。从应用程序的一次执行到同一应用程序的另一次执行,该整数不必保持一致

如果根据equals(Object)方法两个对象相等,那么对两个对象中的每一个调用hashCode方法必须产生相同的整数结果

根据equals(java.lang.Object)方法,如果两个对象不相等,则对这两个对象中的每一个调用hashCode方法都必须产生不同的整数结果,这不是必需的。但是,程序员应该知道,为不相等的对象生成不同的整数结果可能会提高哈希表的性能

在这里,在反序列化期间用于将条目放入集合中的哈希代码似乎与在contains()期间计算的哈希代码不同。顺便说一句,您注意到条目在集合中,您无法通过其哈希代码访问它,如果您循环集合的内容,您将找到元素

可能的解决办法:

  • 具有不依赖父对象的哈希代码
  • 使用不使用哈希代码的数据结构(列表、树集…)
  • 不要对集合使用contains方法
  • 实现ReadResolve以在理想化后重新创建集合

[编辑]:似乎不止您一人

反序列化将两个字段(
mHashCodeField
mSomeSet
)的值读取到临时数组中,并在两个值反序列化后将字段设置为存储值

由于HashSet在反序列化期间重新计算其元素的哈希代码,因此当它仍然为空时,它将使用
mHashCodeField

可能的解决方案是将
mSomeSet
标记为瞬态,并在writeObject/readObject中写入/读取它

@SuppressWarnings("unchecked")
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException
{
    System.out.println("Just started deserializing");
    in.defaultReadObject();
    mSomeSet=(Set<FieldOfSerializableClass>)in.readObject();
    System.out.println("Just finished deserializing");        
}
private void writeObject(java.io.ObjectOutputStream out) throws IOException
{
    System.out.println("Just started serializing");
    out.defaultWriteObject();
    out.writeObject(mSomeSet);
    System.out.println("Just finished serializing");        
}
@SuppressWarnings(“未选中”)
私有void readObject(java.io.ObjectInputStream in)引发IOException、ClassNotFoundException
{
System.out.println(“刚刚开始反序列化”);
in.defaultReadObject();
mSomeSet=(Set)in.readObject();
System.out.println(“刚刚完成反序列化”);
}
私有void writeObject(java.io.ObjectOutputStream out)抛出IOException
{
System.out.println(“刚刚开始序列化”);
out.defaultWriteObject();
out.writeObject(mSomeSet);
System.out.println(“刚刚完成序列化”);
}

事实上,Hibernate说不要将id用作哈希代码,但我认为他们对它太严格了。只有当id由Hibernate自动生成/自动递增时,这才有意义。在这种情况下,您可能有一个bean,它只有在Hibernate决定实际将其持久化到数据库时才接收其id值,因此在这种情况下,您可能会从使用id的hashcode和/或equals方法中获得不可预测的行为。但是,如果手动设置id,也就是说,您的应用程序处理填充这个值,那么我相信在hashcode/equals方法中使用它是完全可以的。你就是这样吗

我添加了另一个答案,因为它与我的第一个答案非常不同:

这是一个没有瞬态场的实现,我在这里找到了必要的信息:和

顺便说一下,我还尝试使用
serialPersistentFields
属性强制先序列化mHashCodeFields,但没有帮助

    public static class SerializableClass implements Serializable {

    // this tells the serialization mechanism to serialize only mHasCodeField...
    private final static ObjectStreamField[]
            serialPersistentFields = {
              new ObjectStreamField(
              "mHashCodeField", String.class)
            };


    private String mHashCodeField;
    private Set<FieldOfSerializableClass> mSomeSet;


    public void setSomeSet(Set<FieldOfSerializableClass> pSomeSet) {
        mSomeSet = pSomeSet;
    }

    public Set<FieldOfSerializableClass> getSomeSet() {
        return mSomeSet;
    }

    public void setHashCodeField(String pHashCodeField) {
        mHashCodeField = pHashCodeField;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;

        System.out.println("In hashCode - value of mHashCodeField: "
                + mHashCodeField);

        result = prime
                * result
                + ((mHashCodeField == null) ? 0 : mHashCodeField.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        SerializableClass other = (SerializableClass) obj;

        if (mHashCodeField == null) {
            if (other.mHashCodeField != null) {
                return false;
            }
        } else if (!mHashCodeField.equals(other.mHashCodeField))
            return false;
        return true;
    }

    private void writeObject(java.io.ObjectOutputStream out)
            throws IOException, ClassNotFoundException {
        System.out.println("Just started serializing");
        out.defaultWriteObject();
        out.writeObject(mSomeSet);


        System.out.println("In writeObject - value of mHashCodeField: "
                + mHashCodeField);
        System.out.println("Just finished serializing");
    }

    private void readObject(java.io.ObjectInputStream in)
            throws IOException, ClassNotFoundException {
        System.out.println("Just started deserializing");
        in.defaultReadObject();
        mSomeSet=(Set<FieldOfSerializableClass>)in.readObject();

        System.out.println("In readObject - value of mHashCodeField: "
                + mHashCodeField);
        System.out.println("Just finished deserializing");
    }
}
公共静态类SerializableClass实现可序列化{
//这告诉序列化机制只序列化mHasCodeField。。。
私有最终静态ObjectStreamField[]
serialPersistentFields={
新ObjectStreamField(
“mHashCodeField”,String.class)
};
私有字符串字段;
私有集mSomeSet;
公共无效集合集合(集合pSomeSet){
mSomeSet=pSomeSet;
}
公共集getSomeSet(){
返回mSomeSet;
}
public void setHashCodeField(String pHashCodeField){
mHashCodeField=相码字段;
}
@凌驾
公共int hashCode(){
最终整数素数=31;
int结果=1;
System.out.println(“在hashCode中-mHashCodeField的值:”
+mHashCodeField);
结果=素数
*结果
+((mHashCodeField==null)?0:mHashCodeField.hashCode());
返回结果;
}
@凌驾
公共布尔等于(对象obj){
if(this==obj)
返回true;
如果
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;

public class Test implements Serializable
{
    public static void main(String[] args) throws Exception
    {
        ClassA aClass = new ClassA();
        aClass.setId(Long.valueOf(321));

        ClassB bClass = new ClassB();
        bClass.setId(Long.valueOf(921));

        Set<ClassA> set = new HashSet<ClassA>();
        set.add(aClass);

        bClass.setSetfield(set);
        aClass.setBField(bClass);

        Set<ClassA> goodClassA = aClass.getBField().getSetfield();
        Set<ClassA> badClassA = serializeAndDeserialize(aClass).getBField().getSetfield();

        System.out.println("Does it contain its member? (should return true!) " + goodClassA.contains(goodClassA.toArray()[0]));
        System.out.println("Does it contain its member? (should return true!) " + badClassA.contains(badClassA.toArray()[0]));
    }

    public static ClassA serializeAndDeserialize(ClassA s) throws Exception
    {
        new ObjectOutputStream(new FileOutputStream(new File("temp"))).writeObject(s);
        return (ClassA) new ObjectInputStream(new FileInputStream(new File("temp"))).readObject();
    }

    public static class ClassB implements Serializable
    {
        private Long mId;
        private Set<ClassA> mSetfield = new HashSet<ClassA>();
        public Long getmId() {
            return mId;
        }
        public void setId(Long mId) {
            this.mId = mId;
        }
        public Set<ClassA> getSetfield() {
            return mSetfield;
        }
        public void setSetfield(Set<ClassA> mSetfield) {
            this.mSetfield = mSetfield;
        }
        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + ((mId == null) ? 0 : mId.hashCode());
            return result;
        }
        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            ClassB other = (ClassB) obj;
            if (mId == null) {
                if (other.mId != null)
                    return false;
            } else if (!mId.equals(other.mId))
                return false;
            return true;
        }       
    }

    public static class ClassA implements Serializable
    {
        private Long mId;
        private ClassB mBField;
        public Long getmId() {
            return mId;
        }
        public void setId(Long mId) {
            this.mId = mId;
        }
        public ClassB getBField() {
            return mBField;
        }
        public void setBField(ClassB mBField) {
            this.mBField = mBField;
        }
        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + ((mId == null) ? 0 : mId.hashCode());
            return result;
        }
        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            ClassA other = (ClassA) obj;
            if (mId == null) {
                if (other.mId != null)
                    return false;
            } else if (!mId.equals(other.mId))
                return false;
            return true;
        }
    }
}
@SuppressWarnings("unchecked")
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException
{
    System.out.println("Just started deserializing");
    in.defaultReadObject();
    mSomeSet=(Set<FieldOfSerializableClass>)in.readObject();
    System.out.println("Just finished deserializing");        
}
private void writeObject(java.io.ObjectOutputStream out) throws IOException
{
    System.out.println("Just started serializing");
    out.defaultWriteObject();
    out.writeObject(mSomeSet);
    System.out.println("Just finished serializing");        
}
    public static class SerializableClass implements Serializable {

    // this tells the serialization mechanism to serialize only mHasCodeField...
    private final static ObjectStreamField[]
            serialPersistentFields = {
              new ObjectStreamField(
              "mHashCodeField", String.class)
            };


    private String mHashCodeField;
    private Set<FieldOfSerializableClass> mSomeSet;


    public void setSomeSet(Set<FieldOfSerializableClass> pSomeSet) {
        mSomeSet = pSomeSet;
    }

    public Set<FieldOfSerializableClass> getSomeSet() {
        return mSomeSet;
    }

    public void setHashCodeField(String pHashCodeField) {
        mHashCodeField = pHashCodeField;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;

        System.out.println("In hashCode - value of mHashCodeField: "
                + mHashCodeField);

        result = prime
                * result
                + ((mHashCodeField == null) ? 0 : mHashCodeField.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        SerializableClass other = (SerializableClass) obj;

        if (mHashCodeField == null) {
            if (other.mHashCodeField != null) {
                return false;
            }
        } else if (!mHashCodeField.equals(other.mHashCodeField))
            return false;
        return true;
    }

    private void writeObject(java.io.ObjectOutputStream out)
            throws IOException, ClassNotFoundException {
        System.out.println("Just started serializing");
        out.defaultWriteObject();
        out.writeObject(mSomeSet);


        System.out.println("In writeObject - value of mHashCodeField: "
                + mHashCodeField);
        System.out.println("Just finished serializing");
    }

    private void readObject(java.io.ObjectInputStream in)
            throws IOException, ClassNotFoundException {
        System.out.println("Just started deserializing");
        in.defaultReadObject();
        mSomeSet=(Set<FieldOfSerializableClass>)in.readObject();

        System.out.println("In readObject - value of mHashCodeField: "
                + mHashCodeField);
        System.out.println("Just finished deserializing");
    }
}
public void setParentLink(SerializableClass pParentLink) {
    this.mHashCodeField = pParentLink.mHashCodeField;
    mParentLink = pParentLink;
}
@Override
public int hashCode() {
    return ((mHashCodeField == null) ? 0 : mHashCodeField.hashCode());
}
public class Test {

    static class Thing implements Serializable {
        String name;
        Set<Thing> others = new HashSet<Thing>();

        @Override
        public int hashCode() {
            if (name == null) {
                System.out.println("hashcode called with null name!");
            }
            return name == null ? 0 : name.hashCode();
        }

        @Override
        public boolean equals(Object o) {
            return o instanceof Thing && ((Thing) o).name == name;
        }
    }

    @org.junit.Test
    public void testHashSetCircularDependencySerialization() throws Exception {
        Thing thing = new Thing();
        thing.name = "thing";
        Thing thing2 = new Thing();
        thing2.name = "thing2";
        thing.others.add(thing2);
        thing2.others.add(thing);
        assertTrue(thing2.others.contains(thing));
        Thing thingCopy = (Thing) serializeAndDeserialize(thing);
        Thing thing2Copy = thingCopy.others.iterator().next();
        assertTrue(thing2Copy.others.contains(thingCopy));
    }

    public static Object serializeAndDeserialize(Object other) throws Exception {
        ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
        new ObjectOutputStream(byteOutputStream).writeObject(other);
        ByteArrayInputStream byteInputStream = new ByteArrayInputStream(byteOutputStream.toByteArray());
        return new ObjectInputStream(byteInputStream).readObject();
    }
}
hashcode called with null name!
    int hashcode;

    @Override
    public int hashCode() {
        if (hashcode != 0) {
            return hashcode;
        }
        hashcode = name == null ? 0 : name.hashCode();
        return hashcode;
    }