3

I have a class as follows in a .jar file (library file):

class A{
//someimplementation
}

I would like to make it to implements Serializable interface as follows:

class A implements Serializable {
//the same implementation as present in classA
}

I do not want to decompile the jar file, changing the class signature and then archiving it again after compilation.

Is there any way like writing hooks to achieve this? Kindly provide any pointers/suggestions. My ultimate aim is to achieve implementing Serializable interface without modifying the jar file.

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
Arun
  • 2,562
  • 6
  • 25
  • 43
  • 1
    You could use a byte-manipulation framework like javassist to add the interface to the class representation obtained for the bytes you've taken for the class from the jar file if you haven't loaded the class already at start time. You could also create class `B` which extends class `A` and implements `Serializable` if this is also OK (instead of inheritance you could also create a wrapper or DTO for `A`) – Roman Vottner Jun 14 '15 at 04:36

1 Answers1

1

You can probably achieve this using Serialization Proxy Pattern (Effective Java 2nd edition Item 78)

A few links about the Pattern :

http://jtechies.blogspot.com/2012/07/item-78-consider-serialization-proxies.html

http://java.dzone.com/articles/serialization-proxy-pattern

Follow up: instance control in Java without enum

Make a new class that extends A and is Serializable. In order to avoid serialization errors, however, because A isn't serializable, you need to make a SerializationProxy that creates a new instance via constructor or factory method instead of the normal Java Serialization mechanism of explicitly setting the fields outside of any constructor.

public class MySerializableA extends A implements Serializable{
    private final Foo foo;
    private final Bar bar;
   ...

    private Object writeReplace() {
         return new SerializationProxy(this);
    }
    //this forces us to use the SerializationProxy
    private void readObject(ObjectInputStream stream) throws InvalidObjectException {
         throw new InvalidObjectException("Use Serialization Proxy instead.");
    }


   //this private inner class is what actually does our Serialization
   private static class SerializationProxy implements Serializable {
        private final Foo foo;
        private final Bar bar;
   ...

    public SerializationProxy(MySerializableA myA) {
        this.foo = myA.getFoo();
        this.bar = myA.getBar();
        ...//etc
    }

    private Object readResolve() {
        return new MySerializableA(foo, bar,...);
    }

}
} 

The only downside is when you want to serialize an A, you will have to wrap it in a MyA. but when deserializing, the cast to A will work fine.

Community
  • 1
  • 1
dkatzel
  • 31,188
  • 3
  • 63
  • 67
  • 2
    If some class in the jar file calls `new A()`, how do you change it to `new MySerializableA()`? –  Jun 14 '15 at 04:55
  • 1
    @saka1029 you could use either [AspectJ](http://www.eclipse.org/aspectj/) ([Sample](http://stackoverflow.com/questions/12372165/intercepting-method-calls)) or [Spring AOP](http://docs.spring.io/spring/docs/2.5.x/reference/aop.html) ([Sample](http://stackoverflow.com/questions/576918/how-do-i-intercept-a-method-invocation-with-standard-java-features-no-aspectj-e)) to intercept each method-invocation of A and redirect it to your class. As A is not an interface you sadly cannot use dynamic proxis. – Roman Vottner Jun 14 '15 at 06:01
  • @RomanVottner, Do you know that Apache Commons BCEL can intercept the ClassLoader and change the class signature on the fly? –  Jun 14 '15 at 06:25
  • @Dkatzel: thanks for your answer. I have the same doubt as saka1029. Can you please let me know your thoughts if an instance like new A() inside the jar file itself. Cuz your answer cannot be used in this case. – Arun Jun 14 '15 at 08:27
  • @dkatzel haven't worked with Apache Commons BCEL yet, but based on what I've read it is quite similar to ASM, javassist or CGLIB in that you can alter the bytes of an existing class and add/remove code fragments or even create a new class from scratch before sending the bytes to the classloader. However, all of these concepts have to use a custom classloading mechanism as far as I know. Not sure if Java Agent (included in the JDK) is able to alter classes loaded by the application or bootstrap CL directly, at least it supports the before-mentioned byte-manipulation frameworks, to my knowledge – Roman Vottner Jun 14 '15 at 11:36
  • @Arun that is correct, without using Aspect oriented programing to intercept calls to `new A()` and redirect them to `new SerializedA()` you can't change anything inside the jar itself. However, since `A` wasn't serializable before you can't serialize any code from the jar anyway. So I think the point is moot. If you are trying to actually serialize a different class that has a field `A` then you can probably just use a SerializationProxy for that too. – dkatzel Jun 14 '15 at 18:34