Why HSF’s Hessian2 Serialization Fails with Java 9 Immutable Collections
The article explains that HSF’s default Hessian2 serializer cannot handle Java 9 immutable collections like Set.of() because it only serializes the writeReplace proxy object and skips the actual elements, leading to a null‑array InvalidObjectException during deserialization.
Problem Overview
When calling an HSF service with a parameter built by Set.of(), the server throws a serialization error: InvalidObjectException: null array. The root cause is that HSF’s default Hessian2 serializer does not support Java 9 immutable collection types.
Java Default Serialization
Java objects that implement java.io.Serializable can define writeReplace and readResolve methods. During serialization, writeReplace can replace the object with another one, and during deserialization, readResolve can replace the deserialized object with a final result.
Immutable Collections in Java 9
Java 9 introduced factory methods such as List.of(), Set.of(), and Map.of(). Their implementations reside in java.util.ImmutableCollections. For example, Set.of() creates an instance of ImmutableCollections$SetN (or Set12 for small sizes) which implements writeReplace to return a java.util.CollSer proxy that holds a
transient arrayfield containing the elements.
HSF Hessian2 Serialization Process
HSF uses the Hessian2Serializer. When writeObject is called, it finds a serializer for the object. For custom types it uses UnsafeSerializer. If the object defines writeReplace, the serializer invokes it and then serializes the returned proxy object.
During serialization of an immutable collection, WriteReplaceSerializer replaces the collection with a CollSer instance. UnsafeSerializer then serializes only the non‑transient fields of CollSer, i.e., the tag field, while the array field (which holds the actual elements) is transient and therefore omitted.
Why Deserialization Fails
When deserializing, HSF reconstructs the CollSer object, reads the tag (e.g., IMM_SET) and finds that the array field is null. The CollSer.readResolve() method then throws InvalidObjectException: null array, causing the whole request to fail.
Solution
Do not use Java 9 immutable collection factories as RPC parameters. Replace them with mutable collections such as HashSet, ArrayList, or HashMap. This ensures that all elements are serialized correctly by Hessian2.
Example Code
package com.taotian.mikan;
import java.io.Serializable;
import java.util.List;
import lombok.Data;
@Data
public class TestParam implements Serializable {
private static final long serialVersionUID = -1331672346095938095L;
private List<Integer> idList;
} @Test
void should_serialize_java9_unmodifiable_list_success_but_deserialize_failed() throws Exception {
TestParam testParam = new TestParam();
testParam.setIdList(List.of(1001, 2002));
Hessian2Serializer hessian2Serializer = new Hessian2Serializer();
byte[] serializedResult = hessian2Serializer.serialize(testParam, null);
assertThat(serializedResult).isNotEmpty();
Exception exception = catchException(() -> hessian2Serializer.deserialize(serializedResult, null));
assertThat(exception).isInstanceOf(Exception.class)
.hasRootCauseMessage("null array");
}Conclusion
HSF’s Hessian2 serializer only supports writeReplace / readResolve and ignores custom writeObject / readObject. Because Java 9 immutable collections rely on a transient array field, the elements are not serialized, leading to a null‑array error on the server. Switching to mutable collections resolves the issue.
Cognitive Technology Team
Cognitive Technology Team regularly delivers the latest IT news, original content, programming tutorials and experience sharing, with daily perks awaiting you.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
