Deserialization and classloading in Akka - NoClassDefFoundError

226 Views Asked by At

I am trying to setup an Akka system where deserialization errors trigger a protocol in which missing classes are exchanged. I use a custom de/serializer for the purpose, which returns a certain message to the application actor once it catches an exception related to missing classes.

In simple terms, remote system B sends an object to system A; if, during deserialization, system A gets a ClassNotFoundError or NoClassDefFoundError, then system A asks to system B the bytecode for the undefined class. When A receives the response from B (which is a pair of classname plus an object of type Array[Byte]), then it can register the class, so that the next time system B sends the object to system A, A can deserialize it correctly.

Now, there are two approaches

1) System B also sends all the classes related to the requested class

2) System B only sends the bytecode for the requested class (without its dependencies)

Now, let's focus on approach 2 and consider the following scenario

  • 1) B ===obj:X==> A (B sends object of class X to A)
  • 2) Let's suppose that X depends on Y,Z
  • 3) B <====X?==== A (A asks class X to B)
  • 4) B =====X====> B (B provides class X to A; A registers class X)
  • 5) B ===obj:X==> A (A gets error due to missing dependency Y)
  • 6) B <====Y?==== A
  • 7) B =====Y====> A (A registers class Y)
  • 8) B ===obj:X==> A
  • 9) B <====Z?==== A
  • 10) B =====Z====> A (A registers class Z)
  • 10) B ===obj:X==> A (OK, finally A can deserialize object of class X)

I think that such a protocol should work, but in practice I get a loop in steps 5-7, due to the following

NoClassDefFoundError: Lexamples/DemoDecentralizedAkkaPlatformCmdLineMain2$AggregateProgram$$anonfun$main$3$$anonfun$apply$5;

I get to register the following class: examples.DemoDecentralizedAkkaPlatformCmdLineMain2$AggregateProgram$$anonfun$main$3$$anonfun$apply$5

however I keep getting the NoClassDefFoundError.

Note that I strip the initial "L" and the trailing ";" from the class name, as well as replacing "/" with ".". Otherwise, I would get an error on system B.

I am sorry for a such complicated formulation of the question.

1

There are 1 best solutions below

0
On

From the abstract overview:

Once you got the 'NoClassDefFound Y' error for loading class 'X', did you ensure throw away the classloader of 'X', and load 'A' in a new class loader, which includes the byte code of 'Y'. If a class get's loaded, but fails to load, the JVM remembers the error and just re-throws it. At least for some class initialization errors. So you'll need to try the reloading in a new class loader.

Honest recommendation: If you try to create a reliable distributed system, avoid relying on exact byte shared byte code or sending you're byte code around. It will make the system very brittle. At best bizarre class loader errors, method not found errors, serialization errors. At worst you're system runs invisible, unexpected code: Like you deployed a new version, but it loaded old code from a still running other instance. Use some solid, byte code independent serialization. Pick one of the many serialization formats out there. Akka brings already a protobuf serializer included. And it's easy to include another one.