1.9.0.0.9743; it also occurred in a few other prerelease versions nearby (97xx stuff), but I don' recall exactly whihc ones.
the bugs do not occur if I revert to using the most recent stable .7621
windows 10 home
version 1709
OS build 16299.248
the error text from below came when using WW2 global 1940 2nd edition; the bug was first encountered in Big World 2: balance of power. it does not occur on some other maps.
just did some more testing: the bug does not occur in Big World 1942; but it does occur in Big World 1942 v3 rules
I haven't yet done an exhaustive test of which maps are affected.
Just testin gsome more maps now while I write this up (edit adding in the ones above just for ease of reading):
affected by the bug:
ww2 global 1940 2nd edition
big world 1942 v3 rules
big world 2: balance of power
civil war: a house divided
world war 2 v3 1941
pact of steel 2
unaffected by the bug:
domination 1914 nml
battle of aventurica
lords of the rings middle earth
world at war
world war 2 v3 1942
world war 2 v6 1941
world war 2 v4
world war 2 classic third edition
world war 2 classic
new world order
napoleonic empires
pact of steel
big world 1942
the bug seems to occur whenever the game tries to show the game history. If I start a new game, then select the "show history" command it causes the issue.
the bug when first encountered happened on starting the map with the hard ai set for the first nation; bbut based on our prior debugging assessments, it appears that this was simply because the game automatically tries to show the history during ai turns.
At least some other people weren't getting the error themselves, though it happens with perfect consistency on my computer.
did a little more testing just now: the behavior when I do it via an ai causes the game to then stop progressing, not a true crash, but its' like the ai or some other part is stuck. but the screen remains responsive and I can go around, look at tooltips, load the battle calculator. If I start the game with all humans; and trigger the bug via using show history, then it generates the error, but I can still issues command (such as telling unist to move if in a movement phase) until I end the phase, then the game does no tprogress anymore (it doesn't force-close, but it's like it's not loading the next phase or something).
Loading map: world_war_ii_global, from: C:\Users\Tom\triplea\downloadedMaps\world_war_ii_global-master.zip
Loading resources from the following paths: [C:\Users\Tom\triplea\downloadedMaps\world_war_ii_global-master.zip, C:\Program Files\TripleA\assets]
Loading map: world_war_ii_global, from: C:\Users\Tom\triplea\downloadedMaps\world_war_ii_global-master.zip
Loading resources from the following paths: [C:\Users\Tom\triplea\downloadedMaps\world_war_ii_global-master.zip, C:\Program Files\TripleA\assets]
Warning: serialization de-serialization error, m_name in DefaultNamed.java is null.
Warning: serialization de-serialization error, m_name in DefaultNamed.java is null.
Warning: serialization de-serialization error, m_name in DefaultNamed.java is null.
Error: java.lang.NullPointerException
java.lang.NullPointerException
at games.strategy.engine.data.DefaultNamed.equals(DefaultNamed.java:33)
at java.base/java.util.HashMap.putVal(Unknown Source)
at java.base/java.util.HashMap.put(Unknown Source)
at java.base/java.util.HashSet.readObject(Unknown Source)
at java.base/jdk.internal.reflect.GeneratedMethodAccessor29.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/java.io.ObjectStreamClass.invokeReadObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.defaultReadFields(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject(Unknown Source)
at java.base/java.util.HashMap.readObject(Unknown Source)
at java.base/jdk.internal.reflect.GeneratedMethodAccessor22.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/java.io.ObjectStreamClass.invokeReadObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.defaultReadFields(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject(Unknown Source)
at java.base/java.util.ArrayList.readObject(Unknown Source)
at java.base/jdk.internal.reflect.GeneratedMethodAccessor20.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/java.io.ObjectStreamClass.invokeReadObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.defaultReadFields(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject(Unknown Source)
at java.base/java.util.HashMap.readObject(Unknown Source)
at java.base/jdk.internal.reflect.GeneratedMethodAccessor22.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/java.io.ObjectStreamClass.invokeReadObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.defaultReadFields(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.defaultReadFields(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject(Unknown Source)
at java.base/java.util.ArrayList.readObject(Unknown Source)
at java.base/jdk.internal.reflect.GeneratedMethodAccessor20.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/java.io.ObjectStreamClass.invokeReadObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.defaultReadFields(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.defaultReadFields(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject(Unknown Source)
at java.base/java.util.HashMap.readObject(Unknown Source)
at java.base/jdk.internal.reflect.GeneratedMethodAccessor22.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/java.io.ObjectStreamClass.invokeReadObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.defaultReadFields(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject(Unknown Source)
at java.base/java.util.HashMap.readObject(Unknown Source)
at java.base/jdk.internal.reflect.GeneratedMethodAccessor22.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/java.io.ObjectStreamClass.invokeReadObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.defaultReadFields(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject(Unknown Source)
at java.base/java.util.ArrayList.readObject(Unknown Source)
at java.base/jdk.internal.reflect.GeneratedMethodAccessor20.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/java.io.ObjectStreamClass.invokeReadObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.defaultReadFields(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject(Unknown Source)
at java.base/java.util.HashMap.readObject(Unknown Source)
at java.base/jdk.internal.reflect.GeneratedMethodAccessor22.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/java.io.ObjectStreamClass.invokeReadObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.defaultReadFields(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.defaultReadFields(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject(Unknown Source)
at java.base/java.util.ArrayList.readObject(Unknown Source)
at java.base/jdk.internal.reflect.GeneratedMethodAccessor20.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/java.io.ObjectStreamClass.invokeReadObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.defaultReadFields(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.defaultReadFields(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject(Unknown Source)
at java.base/java.util.ArrayList.readObject(Unknown Source)
at java.base/jdk.internal.reflect.GeneratedMethodAccessor20.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/java.io.ObjectStreamClass.invokeReadObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.defaultReadFields(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject(Unknown Source)
at java.base/java.util.HashMap.readObject(Unknown Source)
at java.base/jdk.internal.reflect.GeneratedMethodAccessor22.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/java.io.ObjectStreamClass.invokeReadObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.defaultReadFields(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject(Unknown Source)
at java.base/java.util.HashSet.readObject(Unknown Source)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/java.io.ObjectStreamClass.invokeReadObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.defaultReadFields(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject(Unknown Source)
at java.base/java.util.HashMap.readObject(Unknown Source)
at java.base/jdk.internal.reflect.GeneratedMethodAccessor22.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/java.io.ObjectStreamClass.invokeReadObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.defaultReadFields(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject(Unknown Source)
at java.base/java.util.ArrayList.readObject(Unknown Source)
at java.base/jdk.internal.reflect.GeneratedMethodAccessor20.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/java.io.ObjectStreamClass.invokeReadObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.defaultReadFields(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject(Unknown Source)
at java.base/java.util.HashMap.readObject(Unknown Source)
at java.base/jdk.internal.reflect.GeneratedMethodAccessor22.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/java.io.ObjectStreamClass.invokeReadObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.defaultReadFields(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.defaultReadFields(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject(Unknown Source)
at java.base/java.util.HashMap.readObject(Unknown Source)
at java.base/jdk.internal.reflect.GeneratedMethodAccessor22.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/java.io.ObjectStreamClass.invokeReadObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.defaultReadFields(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject(Unknown Source)
at java.base/java.util.ArrayList.readObject(Unknown Source)
at java.base/jdk.internal.reflect.GeneratedMethodAccessor20.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/java.io.ObjectStreamClass.invokeReadObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.defaultReadFields(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject(Unknown Source)
at java.base/java.util.HashMap.readObject(Unknown Source)
at java.base/jdk.internal.reflect.GeneratedMethodAccessor22.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/java.io.ObjectStreamClass.invokeReadObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.defaultReadFields(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject(Unknown Source)
at java.base/java.util.ArrayList.readObject(Unknown Source)
at java.base/jdk.internal.reflect.GeneratedMethodAccessor20.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/java.io.ObjectStreamClass.invokeReadObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.defaultReadFields(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject(Unknown Source)
at java.base/java.util.HashMap.readObject(Unknown Source)
at java.base/jdk.internal.reflect.GeneratedMethodAccessor22.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/java.io.ObjectStreamClass.invokeReadObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.defaultReadFields(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject(Unknown Source)
at java.base/java.util.ArrayList.readObject(Unknown Source)
at java.base/jdk.internal.reflect.GeneratedMethodAccessor20.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/java.io.ObjectStreamClass.invokeReadObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.defaultReadFields(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject(Unknown Source)
at java.base/java.util.HashMap.readObject(Unknown Source)
at java.base/jdk.internal.reflect.GeneratedMethodAccessor22.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/java.io.ObjectStreamClass.invokeReadObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.defaultReadFields(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject(Unknown Source)
at com.google.common.collect.ImmutableListMultimap.readObject(ImmutableListMultimap.java:486)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/java.io.ObjectStreamClass.invokeReadObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.defaultReadFields(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.defaultReadFields(Unknown Source)
at java.base/java.io.ObjectInputStream.defaultReadObject(Unknown Source)
at games.strategy.engine.data.GameData.readObject(GameData.java:122)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/java.io.ObjectStreamClass.invokeReadObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source)
at java.base/java.io.ObjectInputStream.readObject(Unknown Source)
at games.strategy.engine.framework.GameDataManager.loadGame(GameDataManager.java:108)
at games.strategy.io.IoUtils.readFromMemory(IoUtils.java:60)
at games.strategy.engine.framework.GameDataUtils.cloneGameData(GameDataUtils.java:29)
at games.strategy.engine.framework.GameDataUtils.cloneGameData(GameDataUtils.java:19)
at games.strategy.triplea.ui.TripleAFrame.showHistory(TripleAFrame.java:1657)
at games.strategy.triplea.ui.TripleAFrame.lambda$new$39(TripleAFrame.java:1955)
at games.strategy.ui.SwingAction$1.actionPerformed(SwingAction.java:65)
at java.desktop/javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
at java.desktop/javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
at java.desktop/javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
at java.desktop/javax.swing.DefaultButtonModel.setPressed(Unknown Source)
at java.desktop/javax.swing.AbstractButton.doClick(Unknown Source)
at java.desktop/javax.swing.plaf.basic.BasicMenuItemUI.doClick(Unknown Source)
at java.desktop/javax.swing.plaf.basic.BasicMenuItemUI$Handler.mouseReleased(Unknown Source)
at java.desktop/java.awt.AWTEventMulticaster.mouseReleased(Unknown Source)
at java.desktop/java.awt.Component.processMouseEvent(Unknown Source)
at java.desktop/javax.swing.JComponent.processMouseEvent(Unknown Source)
at java.desktop/java.awt.Component.processEvent(Unknown Source)
at java.desktop/java.awt.Container.processEvent(Unknown Source)
at java.desktop/java.awt.Component.dispatchEventImpl(Unknown Source)
at java.desktop/java.awt.Container.dispatchEventImpl(Unknown Source)
at java.desktop/java.awt.Component.dispatchEvent(Unknown Source)
at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
at java.desktop/java.awt.Container.dispatchEventImpl(Unknown Source)
at java.desktop/java.awt.Window.dispatchEventImpl(Unknown Source)
at java.desktop/java.awt.Component.dispatchEvent(Unknown Source)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.desktop/java.awt.EventQueue.access$500(Unknown Source)
at java.desktop/java.awt.EventQueue$3.run(Unknown Source)
at java.desktop/java.awt.EventQueue$3.run(Unknown Source)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
at java.desktop/java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.run(Unknown Source)
the game history should've been shown; and the game run without crashing
I already did a fresh reinstall of triplea; uninstalling all my old versions, removing the maps/saves folder; and using a fresh download of the engine and the maps.
I also removed an older java version which was still on the computer; and there can't be many more of those cuz the computer is fairly new.
and the bug continues to occur just as it did before I did those things.
Seems like you're using java 9.
Downgrading to java 8 should temporarily fix this issue.
(You need to uninstall java 9 to make the engine use java 8)
We really need to fix this problem...
@RoiEXLab What change in Java 9 causes that error?
I don't know, but the java 9 travis build spams a lot of deserialization error warnings because some field is null
For anyone who's interested, the unit tests that seem to exhibit this deserialization warning in the Java 9 build are in OddsCalculatorTest (not surprisingly, where GameDataUtils#cloneGameData() is used, just as with the history view).
Yeah, from the stacktrace it appears that for some reason some of the fields deserialize to null. Probably happens anywhere game data is cloned. Just no idea why that is.
Hmm, every DefaultNamed instance with a null name (from OddsCalculatorTest) is of type Resource. And even better, adding a readObject() method in DefaultNamed that simply calls in.defaultReadObject() to probe this causes the problem to go away. Yay for Heisenbergs!
Umm. That's interesting. Maybe some sort of race condition?
Ok, I think I tracked down the issue. It's late, so I'm just writing this to record it while it's fresh in my mind. I'll try to dig deeper tomorrow.
There was a change in the implementation of ObjectInputStream#readSerialData() between Java 8 and 9. Here are the Java 8 and Java 9 implementations for reference.
The specific change is in how ObjectInputStream#defaultReadFields() works. In Java 8, when this method is called, the field values in the target object are set immediately before moving on. However, in Java 9, the field values are read from the stream, but setting the field values in the target object is delayed. These comments from the Java 9 implementation kind of sums it up:
// Best effort Failure Atomicity; slotValues will be non-null if field
// values can be set after reading all field data in the hierarchy.
// Field values can only be set after reading all data if there are no
// user observable methods in the hierarchy, readObject(NoData). The
// top most Serializable class in the hierarchy can be skipped.
FieldValues[] slotValues = null;
and
// No special read methods, can store values and defer setting.
if (!hasSpecialReadMethod)
The first comment suggests this was done to ensure atomicity in the case of a failure midway through deserialization. You'll note they also refer to the case when a readObject() method is present. In Java 9, just as in Java 8, if a readObject() method is present, setting the field values is _not_ deferred. This explains why when I added a readObject() method to DefaultNamed that simply called in.defaultReadObject(), m_name was set immediately and was not null when its hashCode() method was called.
In a nutshell, Java 9's deferment of setting field values is allowing some logic to run in a descendant object being deserialized. I suspect that descendant is an IntegerMap<Resource> (probably from PlayerID) which contains a back-reference to the Resource in question. It could be that where the Java 8 implementation was friendly towards circular references like this, the Java 9 implementation can't handle it...?
I did verify that after the entire GameData is deserialized, the Resources that originally triggered that warning message do indeed have a non-null m_name field at this point. So that confirms that the Java 9 serialization framework is eventually setting the field values correctly, just not when we apparently need them to be set. :disappointed:
I was able to create an MCVE that demonstrates the issue:
public final class DeserializationTest {
@Test
public void shouldBeAbleToDeserializeWithCircularReferenceInDerivedClass() throws Exception {
final FooDerived foo1 = new FooDerived("foo_1");
final FooDerived foo2 = new FooDerived("foo_2");
final Bar bar = new Bar();
bar.valuesByFoo.put(foo1, 1);
bar.valuesByFoo.put(foo2, 2);
foo1.bars.add(bar);
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
oos.writeObject(foo1);
}
final ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
final FooDerived actualFoo1;
try (ObjectInputStream ois = new ObjectInputStream(bais)) {
actualFoo1 = (FooDerived) ois.readObject();
}
assertEquals("foo_1", actualFoo1.name);
assertEquals(1, actualFoo1.bars.size());
final Bar actualBar = actualFoo1.bars.get(0);
assertTrue(actualBar.valuesByFoo.containsKey(new FooDerived("foo_1")));
assertTrue(actualBar.valuesByFoo.containsKey(new FooDerived("foo_2")));
}
private static class FooBase implements Serializable {
private static final long serialVersionUID = 6716343853564480063L;
final String name;
FooBase(final String name) {
this.name = name;
}
@Override
public boolean equals(final Object obj) {
if (obj == this) {
return true;
} else if (!(obj instanceof FooBase)) {
return false;
}
final FooBase other = (FooBase) obj;
return name.equals(other.name);
}
@Override
public int hashCode() {
return name.hashCode();
}
}
private static final class FooDerived extends FooBase {
private static final long serialVersionUID = 9182581686880080478L;
final List<Bar> bars = new ArrayList<>();
FooDerived(final String name) {
super(name);
}
}
private static final class Bar implements Serializable {
private static final long serialVersionUID = -7436641641281651051L;
final Map<FooBase, Integer> valuesByFoo = new HashMap<>();
}
}
On Java 8, the test passes. On Java 9, an NPE is thrown from FooBase#hashCode() due to FooBase#name being null during deserialization of Bar#valuesByFoo. Even if I were to change the implementation of FooBase#hashCode() to use Objects#hash() to avoid the NPE, the test would still fail because the value associated with the FooBase key will have been placed in the wrong bucket due to the key generating the wrong hash code (or put another way, the key's hash code changes after it is inserted into the map).
The key to getting this example to work is the fact that the circular reference is in a _subclass_ of the class that hosts the field used in hashCode(). If, for example, the FooBase and FooDerived classes were merged, the test would fail on Java 8 with an NPE, as well. (This is because the Java 8 ObjectInputStream#defaultReadFields() method deserializes _all_ field values for a given class before actually assigning those values to the fields themselves. In a sense, it's a limited form of "deferred field setting" described above with the Java 9 implementation.)
So, I guess I can open a bug report with Oracle because I'm not sure this backwards-incompatible change was intentional. However, we may have to be prepared to use the readObject() workaround described above.
In reality, we need to get a handle on these circular references. In this particular case, I'm wondering if it would have been better to have Resource simply store a collection of player _names_ rather than the PlayerIDs themselves?
@ssoloff Yeah, I'd say let's open a bug report with Oracle and see if we get a response after a few days. If they don't plan to change it or we don't get much of a response then we should probably look to add in the workaround at least in the short term. We can then always evaluate the game data model and see if its feasible to remove circular references.
@ron-murhammer Will do. I'll try to get the bug report submitted tomorrow.
I did some searching through the Java bug tracker and found a similar issue. It's basically the case I described earlier with FooBase and FooDerived being merged. Apparently that circular reference scenario used to work pre-1.4 and broke in 1.4 due to a similar "performance optimization":
Note that the particular test case, as is, works with Sun's implementations of ObjectInputStream prior to 1.4 (i.e. it does not cause a NullPointerException), because pre-1.4 implementations, when deserializing the values of the non-primitive serializable fields of a class, would set each individual field's value after reading it (before deserializing the next value). 1.4's and later implementations set the values of all non-primitive serializable fields in a single batch, after they have all been deserialized, for improved performance.
That issue has been open for over 13 years, which may not be a good sign for us.
Bug report submitted to Oracle and assigned a provisional ID of 9052987. Not sure how long it takes them to review these things before they make them public.
Cool. Seems like they at least acknowledged it.
@DanVanAtta @ron-murhammer @ssoloff
Looks like this issue is not going to get fixed as part of the initial JDK-11 release.
So in order to support the "LTS" Java release for the next couple of years, we need to give this issue a higher priority
Reopening as this is _the_ Java 9+ blocker. As @RoiEXLab noted above, we'll probably just have to go with the in.defaultReadObject() workaround in all GameDataComponent classes since JDK-8199664 will not be fixed upon the initial release of Java 11.
Closing as this should be fixed by #4032.
I suspect migrating to Java 11 will become high priority for us in early 2019 as Java 8 will hit EOL. We can reopen this issue or create a new issue if the same problem is discovered during Java 11 testing.