Phase 5(b) fix: InvocationMarshaller explicit streaming preserves _invdir
The flatten-mode codegen gave each *Marshaller subclass a self-contained read/writeObject, which overrode InvocationMarshaller.readObject and thus skipped its side-effect of binding the transient _invdir from the stream's client -> null _invdir -> NPE on the first invocation request (hit by ART AND HotSpot clients). Fix: give InvocationMarshaller explicit read/writeObject (GenStreamUtil, deterministic order, byte-identical to the old reflective default) that keeps the _invdir binding; field-free subclasses inherit it. narya 1.22. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HhfHCXYp2ctWi76Z91y9Ut
This commit is contained in:
+1
-1
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.threerings</groupId>
|
<groupId>com.threerings</groupId>
|
||||||
<artifactId>narya-parent</artifactId>
|
<artifactId>narya-parent</artifactId>
|
||||||
<version>1.21</version>
|
<version>1.22</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>narya</artifactId>
|
<artifactId>narya</artifactId>
|
||||||
|
|||||||
@@ -7,7 +7,9 @@ package com.threerings.presents.data;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import com.threerings.io.GenStreamUtil;
|
||||||
import com.threerings.io.ObjectInputStream;
|
import com.threerings.io.ObjectInputStream;
|
||||||
|
import com.threerings.io.ObjectOutputStream;
|
||||||
import com.threerings.io.Streamable;
|
import com.threerings.io.Streamable;
|
||||||
|
|
||||||
import com.threerings.presents.client.Client;
|
import com.threerings.presents.client.Client;
|
||||||
@@ -244,17 +246,37 @@ public class InvocationMarshaller<T extends ClientObject>
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A custom reader method for {@link Streamable}.
|
* A custom reader method for {@link Streamable}. Reads {@code _invOid}/{@code _invCode}
|
||||||
|
* explicitly (by name, in declaration order) rather than via {@code defaultReadObject()} so the
|
||||||
|
* field order is deterministic across ART and HotSpot (Epic A1 Phase 5, approach b) — byte
|
||||||
|
* identical to the old reflective read. Marshaller SUBCLASSES intentionally have NO generated
|
||||||
|
* read/writeObject (they are field-free) so they inherit this method, which also performs the
|
||||||
|
* side-effect the generated flatten-mode streamers would otherwise skip: binding {@link #_invdir}
|
||||||
|
* from the stream's client. That binding is the whole reason this is a hand-written custom
|
||||||
|
* reader; a subclass overriding it would leave {@code _invdir} null and NPE on the first request.
|
||||||
*/
|
*/
|
||||||
public void readObject (ObjectInputStream in)
|
public void readObject (ObjectInputStream in)
|
||||||
throws IOException, ClassNotFoundException
|
throws IOException, ClassNotFoundException
|
||||||
{
|
{
|
||||||
in.defaultReadObject();
|
GenStreamUtil.readField(InvocationMarshaller.class, "_invOid", this, in);
|
||||||
|
GenStreamUtil.readField(InvocationMarshaller.class, "_invCode", this, in);
|
||||||
if (in instanceof ClientObjectInputStream) {
|
if (in instanceof ClientObjectInputStream) {
|
||||||
_invdir = ((ClientObjectInputStream)in).client.getInvocationDirector();
|
_invdir = ((ClientObjectInputStream)in).client.getInvocationDirector();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A custom writer method for {@link Streamable}; mirrors {@link #readObject} (explicit,
|
||||||
|
* deterministic field order) so field-free marshaller subclasses inherit it. Byte identical to
|
||||||
|
* the previous reflective default write.
|
||||||
|
*/
|
||||||
|
public void writeObject (ObjectOutputStream out)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
GenStreamUtil.writeField(InvocationMarshaller.class, "_invOid", this, out);
|
||||||
|
GenStreamUtil.writeField(InvocationMarshaller.class, "_invCode", this, out);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString ()
|
public String toString ()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<groupId>com.threerings</groupId>
|
<groupId>com.threerings</groupId>
|
||||||
<artifactId>narya-parent</artifactId>
|
<artifactId>narya-parent</artifactId>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
<version>1.21</version>
|
<version>1.22</version>
|
||||||
|
|
||||||
<name>Narya Parent</name>
|
<name>Narya Parent</name>
|
||||||
<description>Facilities for making networked multiplayer games.</description>
|
<description>Facilities for making networked multiplayer games.</description>
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.threerings</groupId>
|
<groupId>com.threerings</groupId>
|
||||||
<artifactId>narya-parent</artifactId>
|
<artifactId>narya-parent</artifactId>
|
||||||
<version>1.21</version>
|
<version>1.22</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>narya-tools</artifactId>
|
<artifactId>narya-tools</artifactId>
|
||||||
|
|||||||
Reference in New Issue
Block a user