Introducing Serializable to Existing Code

I think this should be really common, but I canโ€™t find the best practices. Suppose I have the following class:

public class Equation { private Operator operator; private Object leftValue; private Object rightValue; // getters and setters } public enum Operator {...} 

This class has been with us for several years and is well used. Now I need to make serializable. How to do it?

Just add implements Serializable

In this case, the Equation class only works as long as the values โ€‹โ€‹are Serializable . Since the equations really only work on numbers (maybe dates and strings?) That can work. But the values โ€‹โ€‹can be any Object , so there should be a better way.

Make Serializable Values

 public class Equation implements Serializable{ private Operator operator; private Serializable leftValue; private Serializable rightValue; // getters and setters } 

This works anyway, but these changes are an API transition. And no matter what I do, I need to modify all the code with the class, which will lead to a potentially even greater gap in the API. For a large software system that can take age.

Set Serializable values, leave getters and setters as they are

 public void setLeftValue(Object leftValue) { if (!(leftValue instanceof Serializable)) throw new IllegalArgumentException("Value must be Serializable!"); this.leftValue = leftValue; } 

This code does not destroy the existing API, but changes the behavior of the code. But if I assume that all the values โ€‹โ€‹are Serializable anyway, I feel that this might be the way to go. I can even put new setters next to the old ones and condemn them so that future developers understand which objects to use.

Make transient values:

At least what Sonar offers. However, this leads to an unusable class, at least in all cases where we really need Equation be Serializable .

Create an implementation of Serializable :

 public class SerializableEquation extends Equation implements Serializable{ private Serializable leftValue; private Serializable rightValue; // override getters and setters } 

So we have to use a whole class for serialization purposes, which seems ugly, right?

Question:

What is a good way to handle this use case? I ideally do not want to violate the API. And, seeing that Java has not yet broken the API, there must be a way to deal with such cases.

+6
source share
1 answer

In this problem, the correct implementation was to use interfaces to limit the scope of the action.

What is the point of adding UrlConnection to a String ? Well, it should have been something like this:

 public class Equation { Operator operator; Operand leftOp, rightOp; ... } interface Operand { ... } 

And then for a certain data type you would execute certain classes

 public IntegerOperand implements Operand { public Integer value; ... } 

From this, you only need to add Serialiszable to Operator and Operand . This will be a contract that the developer must comply with, so each implementation must be serializable (fully serializable, as the interface asked for it), it will be easy to verify using JUnit.

But

In this case, you cannot update the code because it will break compatibility. So I would put serialization in the test, which means that I checked if both instances of the object are serializable, if not, then you do what you want with it.

You either check this with the method whenever you want (before serialization) so that this action cannot be performed with this data or with the installer of both values โ€‹โ€‹to hold back the possibilities.

 public boolean isSerialisable(){ return Serializable.class.isAssignable(leftValue.class) && Serializable.class.isAssignable(rightValue.class); } 

This will be a call before you need to serialize the instance as a warning or error. (or right in the setters if you want to break everything;))

Last, you serialize yourself with data, you can use some library to generate various types of structures, XML, JSON, .. or maybe in bytes directly (no example)

EDIT:

Here is a quick (and ugly example) serialization with Object

 public class Main implements Serializable{ public Object value; public Main(Object o){ this.value = o; } public static void main(String[] args){ Main m = new Main(new A()); try { FileOutputStream fileOut = new FileOutputStream("test.ser"); ObjectOutputStream out = new ObjectOutputStream(fileOut); out.writeObject(m); out.close(); fileOut.close(); }catch(IOException i) { i.printStackTrace(); } m = null; try { FileInputStream fileIn = new FileInputStream("test.ser"); ObjectInputStream in = new ObjectInputStream(fileIn); m = (Main) in.readObject(); in.close(); fileIn.close(); }catch(Exception i) { i.printStackTrace(); return; } System.out.println(" M : " + m); } @Override public String toString() { return value == null ? "null" : value.toString(); } static class A implements Serializable{ String s = "foo"; @Override public String toString() { return s; } } } 

Removing the implementation if serializable from A will fail. But we see that this works as expected.

+1
source

Source: https://habr.com/ru/post/1012527/


All Articles