1

A colleague and I are having a disagreement about a particular scenario.

We have a Serializable object that has a toString() method. This toString() is implemented by invoking Apache's ReflectionToStringBuilder. Something like this:

public class Foo implements Serializable {
    // bunch of instance variables, getters and setters ...

    @Override
    public String toString() {
        return ReflectionToStringBuilder.toString(this);
    }
}

We have no control over how these objects are passed around. In our particular application, we might pass them around via RMI calls, HTTP POSTs (after writing as a JSon string), via JMS, or via other protocols.

Now, the JSon string case shouldn't matter because it'll be sent in String form so the implementation details of the toString() method don't matter. But for (some of) the other protocols, we'd expect to serialize the object itself.

Can a method in a Serializable class call a static method and still be (functionally) serializable? It compiles fine, sure -- but can it still be sent across the wire? Will it fail to deserialize if the receiving service does not have the static method's class on its classpath?

Roddy of the Frozen Peas
  • 14,380
  • 9
  • 49
  • 99
  • 3
    How about, you know, testing it? What is serialized when sending an object over the wire, the byte code of the class (that the receiver already has in its classpath), or the state of the object (that the receiver doesn't know)? – JB Nizet May 26 '17 at 16:59
  • 1
    How can the receiving service have the class but not the static method's class? (actually asking). I thought that regardless of how you share the Serializable class between services (whether they all get a library, or whether you've duplicated the class in each service), wouldn't any external library have to be in the class path for the code to even compile? – Ishnark May 26 '17 at 17:15
  • Very good description on this can be found [Java static serialization rules?](https://stackoverflow.com/questions/6429462/java-static-serialization-rules) – Sergey Prokofiev May 26 '17 at 17:18
  • 1
    @Ishnark: yes, during compilation the dependencies need to be present. However, nothing will stop you from putting a jar file into a classpath but not it's dependencies. – Rolf Schäuble May 26 '17 at 17:28
  • @RolfSchäuble good point, I didn't think of that. – Ishnark May 26 '17 at 17:37
  • @RolfSchäuble Sure, but why would you do that? The class wouldn't be very functional without its dependencies. – shmosel May 26 '17 at 17:43
  • @shmosel Well, the question was not about the meaningfulness of doing so, but about what would happen if you did it ;-) – Rolf Schäuble May 26 '17 at 17:54

2 Answers2

1

Yes, this will work. toString() is never called by Java's built-in serialization framework, so it can basically do whatever it wants.

Most of the time, a serialized object is just copied field-by-field, without any methods of the object being invoked. A class can change this default behavior by implementing special methods (see http://www.oracle.com/technetwork/articles/java/javaserial-1536170.html for details), but that's not the case in your example. So whatever your methods are doing (not only toString()), it doesn't matter for serialization.

Now to the second question: what happens if ReflectionToStringBuilder is not in the classpath? That's simple: nothing happens. As long as ReflectionToStringBuilder is not used (i.e. any of its static methods are invoked, or you're creating an instance of it), that class is not loaded (or at least not linked), so it doesn't matter if it's present or not. Only when you try to actually use that class will you get a NoClassDefFoundError. So deserializing your object will work, but if you call toString(), you get an exception.

Rolf Schäuble
  • 690
  • 4
  • 15
1

Your example is totally fine for serialization.

In theory JSON representation of Java object is just another form of serialization. All serialization does it to write object "state" into a stream and be able to read that state from a stream. It does not care about operations the object has or how they are implemented including the toString method. The state of Java object in this case is represented by its instance variables and does not include the objects Class definition. When you read your Foo back, you already should have Foo.class along with Apache's ReflectionToStringBuilder.class in your classpath.

tsolakp
  • 5,858
  • 1
  • 22
  • 28