-
Bug
-
Resolution: Unresolved
-
P3
-
9, 10, 11
FULL PRODUCT VERSION :
java version "9.0.4"
Java(TM) SE Runtime Environment (build 9.0.4+11)
Java HotSpot(TM) 64-Bit Server VM (build 9.0.4+11, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Linux prod-wgba-005.oslo-no0030.xxx.xxx 3.10.0-693.21.1.el7.x86_64 #1 SMP Wed Mar 7 19:03:37 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
Microsoft Windows [Version 6.1.76.01]
EXTRA RELEVANT SYSTEM CONFIGURATION :
Seems to be independent of operating system.
A DESCRIPTION OF THE PROBLEM :
Seems to be similar to the 1.4.2 bug described here
https://bugs.java.com/bugdatabase/view_bug.do?bug_id=6208166#
1) Create an object graph (for example object tree) with cyclic dependencies:
- Node class with an Long field and a hashCode() method depending on this field.
- A parent reference.
- A set of children (represented by a HashSet) and a parent reference.
2)
- Create some Node instances and chain them together so that they represent a tree (with cyclic dependencies).
3)
- Serialize and de-serialize the object graph from 2)
This works with JDK8 but fails with JDK9.
REGRESSION. Last worked in version 8u172
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the attached code with JDK9.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
No output.
ACTUAL -
Exception in thread "main" java.lang.RuntimeException: java.lang.NullPointerException
at wg.crewmanager.scrapbook.ReproduceHashSetSerializationBug.deSerialize(ReproduceHashSetSerializationBug.java:127)
at wg.crewmanager.scrapbook.ReproduceHashSetSerializationBug.test(ReproduceHashSetSerializationBug.java:89)
at wg.crewmanager.scrapbook.ReproduceHashSetSerializationBug.main(ReproduceHashSetSerializationBug.java:73)
Caused by: java.lang.NullPointerException
at wg.crewmanager.scrapbook.ReproduceHashSetSerializationBug$Superclass.hashCode(ReproduceHashSetSerializationBug.java:38)
at java.base/java.util.HashMap.hash(HashMap.java:339)
at java.base/java.util.HashMap.put(HashMap.java:612)
at java.base/java.util.HashSet.readObject(HashSet.java:342)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at java.base/java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1160)
at java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2207)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2078)
at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1585)
at java.base/java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2346)
at java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2240)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2078)
at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1585)
at java.base/java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2346)
at java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2240)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2078)
at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1585)
at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:422)
at java.base/java.util.ArrayList.readObject(ArrayList.java:825)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at java.base/java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1160)
at java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2207)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2078)
at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1585)
at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:422)
at wg.crewmanager.scrapbook.ReproduceHashSetSerializationBug.deSerialize(ReproduceHashSetSerializationBug.java:123)
... 2 more
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
package wg.crewmanager.scrapbook;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
/**
* Test serialization of {@link HashSet}.
*
*/
public class ReproduceHashSetSerializationBug
{
private static final Random RANDOM = new Random();
public static class Superclass implements Serializable
{
private final Long id;
public Superclass()
{
this.id = RANDOM.nextLong();
}
public int hashCode()
{
return this.id.hashCode();
}
/*
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException
{
in.defaultReadObject();
}
*/
}
public static class Node extends Superclass implements Serializable
{
private final String name;
private final Node parent;
private final Set<Node> children = new HashSet<>();
public Node(String name, Node parent)
{
this.name = name;
this.parent = parent;
if (parent != null)
{
parent.children.add(this);
}
}
}
public static void main(String[] args)
{
new ReproduceHashSetSerializationBug().test();
}
@SuppressWarnings("unchecked")
private void test()
{
Node a = new Node("a", null);
Node b = new Node("b", a);
List<Node> elements = new ArrayList<>();
elements.add(b);
elements.add(a);
byte[] bytes = serialize((Serializable) elements);
List<Node> deserialized = (List<Node>) deSerialize(bytes);
}
/**
* Serializes the given object into a byte array.
*
* @param serializable not null
* @return a byte array, not null
*/
private static byte[] serialize(Serializable serializable)
{
try
{
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(out);
objectOutputStream.writeObject(serializable);
return out.toByteArray();
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
/**
* De-serializes the given byte array into an object.
*
* @param bytes the byte array to de-serializes, not null
* @return the de-serialized object
*/
private static Serializable deSerialize(byte[] bytes)
{
try
{
return (Serializable) new ObjectInputStream(new ByteArrayInputStream(bytes)).readObject();
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Explicit readObject in super class (remove comments and run again).
Not sure why this makes it work.
java version "9.0.4"
Java(TM) SE Runtime Environment (build 9.0.4+11)
Java HotSpot(TM) 64-Bit Server VM (build 9.0.4+11, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Linux prod-wgba-005.oslo-no0030.xxx.xxx 3.10.0-693.21.1.el7.x86_64 #1 SMP Wed Mar 7 19:03:37 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
Microsoft Windows [Version 6.1.76.01]
EXTRA RELEVANT SYSTEM CONFIGURATION :
Seems to be independent of operating system.
A DESCRIPTION OF THE PROBLEM :
Seems to be similar to the 1.4.2 bug described here
https://bugs.java.com/bugdatabase/view_bug.do?bug_id=6208166#
1) Create an object graph (for example object tree) with cyclic dependencies:
- Node class with an Long field and a hashCode() method depending on this field.
- A parent reference.
- A set of children (represented by a HashSet) and a parent reference.
2)
- Create some Node instances and chain them together so that they represent a tree (with cyclic dependencies).
3)
- Serialize and de-serialize the object graph from 2)
This works with JDK8 but fails with JDK9.
REGRESSION. Last worked in version 8u172
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the attached code with JDK9.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
No output.
ACTUAL -
Exception in thread "main" java.lang.RuntimeException: java.lang.NullPointerException
at wg.crewmanager.scrapbook.ReproduceHashSetSerializationBug.deSerialize(ReproduceHashSetSerializationBug.java:127)
at wg.crewmanager.scrapbook.ReproduceHashSetSerializationBug.test(ReproduceHashSetSerializationBug.java:89)
at wg.crewmanager.scrapbook.ReproduceHashSetSerializationBug.main(ReproduceHashSetSerializationBug.java:73)
Caused by: java.lang.NullPointerException
at wg.crewmanager.scrapbook.ReproduceHashSetSerializationBug$Superclass.hashCode(ReproduceHashSetSerializationBug.java:38)
at java.base/java.util.HashMap.hash(HashMap.java:339)
at java.base/java.util.HashMap.put(HashMap.java:612)
at java.base/java.util.HashSet.readObject(HashSet.java:342)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at java.base/java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1160)
at java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2207)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2078)
at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1585)
at java.base/java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2346)
at java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2240)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2078)
at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1585)
at java.base/java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2346)
at java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2240)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2078)
at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1585)
at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:422)
at java.base/java.util.ArrayList.readObject(ArrayList.java:825)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at java.base/java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1160)
at java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2207)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2078)
at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1585)
at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:422)
at wg.crewmanager.scrapbook.ReproduceHashSetSerializationBug.deSerialize(ReproduceHashSetSerializationBug.java:123)
... 2 more
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
package wg.crewmanager.scrapbook;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
/**
* Test serialization of {@link HashSet}.
*
*/
public class ReproduceHashSetSerializationBug
{
private static final Random RANDOM = new Random();
public static class Superclass implements Serializable
{
private final Long id;
public Superclass()
{
this.id = RANDOM.nextLong();
}
public int hashCode()
{
return this.id.hashCode();
}
/*
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException
{
in.defaultReadObject();
}
*/
}
public static class Node extends Superclass implements Serializable
{
private final String name;
private final Node parent;
private final Set<Node> children = new HashSet<>();
public Node(String name, Node parent)
{
this.name = name;
this.parent = parent;
if (parent != null)
{
parent.children.add(this);
}
}
}
public static void main(String[] args)
{
new ReproduceHashSetSerializationBug().test();
}
@SuppressWarnings("unchecked")
private void test()
{
Node a = new Node("a", null);
Node b = new Node("b", a);
List<Node> elements = new ArrayList<>();
elements.add(b);
elements.add(a);
byte[] bytes = serialize((Serializable) elements);
List<Node> deserialized = (List<Node>) deSerialize(bytes);
}
/**
* Serializes the given object into a byte array.
*
* @param serializable not null
* @return a byte array, not null
*/
private static byte[] serialize(Serializable serializable)
{
try
{
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(out);
objectOutputStream.writeObject(serializable);
return out.toByteArray();
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
/**
* De-serializes the given byte array into an object.
*
* @param bytes the byte array to de-serializes, not null
* @return the de-serialized object
*/
private static Serializable deSerialize(byte[] bytes)
{
try
{
return (Serializable) new ObjectInputStream(new ByteArrayInputStream(bytes)).readObject();
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Explicit readObject in super class (remove comments and run again).
Not sure why this makes it work.
- duplicates
-
JDK-8199664 Deserialization fails when subclass contains reference to self in field of hash container type
-
- Closed
-
- relates to
-
JDK-8071474 Better failure atomicity for default read object
-
- Resolved
-
-
JDK-6208166 Deserialization fails with cyclic object graph using HashSet
-
- Open
-