【问题标题】:Overriding class signature in java在java中覆盖类签名
【发布时间】:2015-06-14 04:27:03
【问题描述】:

我在.jar 文件(库文件)中有一个如下类:

class A{
//someimplementation
}

我想把implements Serializable界面改成如下:

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

我不想反编译 jar 文件,更改类签名,然后在编译后再次归档。

有没有办法像编写钩子来实现这一点?请提供任何指示/建议。 我的最终目标是在不修改jar文件的情况下实现Serializable接口。

【问题讨论】:

  • 如果您尚未加载类,您可以使用 javassist 之类的字节操作框架将接口添加到从 jar 文件中为类获取的字节所获得的类表示中在开始时间。您还可以创建类 B,它扩展类 A 并实现 Serializable,如果这也可以(您还可以为 A 创建包装器或 DTO,而不是继承)

标签: java serialization hook


【解决方案1】:

您可能可以使用序列化代理模式(Effective Java 2nd edition Item 78)实现此目的

一些关于模式的链接:

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

创建一个扩展A 并且是Serializable 的新类。然而,为了避免序列化错误,因为A 不可序列化,您需要创建一个通过构造函数或工厂方法创建新实例的 SerializationProxy,而不是在任何构造函数之外显式设置字段的常规 Java 序列化机制.

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,...);
    }

}
} 

唯一的缺点是当您想要序列化 ​​A 时,您必须将其包装在 MyA 中。但是在反序列化时,转换为 A 会正常工作。

【讨论】:

  • 如果jar文件中的某个类调用new A(),怎么改成new MySerializableA()
  • @saka1029 您可以使用AspectJ (Sample) 或Spring AOP (Sample) 来拦截 A 的每个方法调用并将其重定向到您的类。由于 A 不是一个接口,因此很遗憾您不能使用动态代理。
  • @RomanVottner,你知道 Apache Commons BCEL 可以拦截 ClassLoader 并即时更改类签名吗?
  • @Dkatzel:感谢您的回答。我和saka1029有同样的疑问。如果 jar 文件本身中有像 new A() 这样的实例,请告诉我你的想法。因为在这种情况下不能使用您的答案。
  • @dkatzel 尚未与 Apache Commons BCEL 合作,但根据我所读到的内容,它与 ASM、javassist 或 CGLIB 非常相似,因为您可以更改现有类的字节和添加/删除代码片段,甚至在将字节发送到类加载器之前从头开始创建一个新类。但是,据我所知,所有这些概念都必须使用自定义类加载机制。不确定 Java 代理(包含在 JDK 中)是否能够直接更改应用程序加载的类或引导 CL,据我所知,至少它支持前面提到的字节操作框架
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-02-16
  • 2016-12-09
  • 2021-02-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多