无法加载常规类

Vaz*_*zid 5 java groovy serialization jenkins

我正在尝试使用詹金斯管道中的以下类序列化和反序列化一个常规对象。

SerializationUtil.groovy

package com.sample;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

/**
 * A simple class with generic serialize and deserialize method implementations
 */
public class SerializationUtil {

    // deserialize to Object from given file
    public static Object deserialize(String fileName) throws IOException,
            ClassNotFoundException {
        FileInputStream fis = new FileInputStream(fileName);
        ObjectInputStream ois = new ObjectInputStream(fis);
        Object obj = ois.readObject();
        ois.close();
        System.out.println(obj);
        return obj;
    }

    // serialize the given object and save it to file
    public static void serialize(Object obj, String fileName)
            throws IOException {
        FileOutputStream fos = new FileOutputStream(fileName);
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(obj);

        fos.close();
    }

}
Run Code Online (Sandbox Code Playgroud)

测试.groovy

package com.sample;

public class Test implements Serializable {
    String key;

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    @Override
    public String toString() {
        return "com.sample.Test{" +
                "key='" + key + '\'' +
                '}';
    }
}
Run Code Online (Sandbox Code Playgroud)

詹金斯管道脚本

Test test = new Test()
test.setKey("sample")
SerializationUtil.serialize(test,"/temp/test.txt")
Test test2 = SerializationUtil.deserialize("/temp/test.txt")
Run Code Online (Sandbox Code Playgroud)

我能够序列化该对象,但无法反序列化。我收到以下异常。

java.lang.ClassNotFoundException: com.sample.Test
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at org.eclipse.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:543)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:348)
    at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:628)
    at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1620)
    at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1521)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1781)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1353)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:373)
    at sun.reflect.GeneratedMethodAccessor8862.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1213)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1022)
    at org.codehaus.groovy.runtime.callsite.PojoMetaClassSite.call(PojoMetaClassSite.java:47)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
    at com.cloudbees.groovy.cps.sandbox.DefaultInvoker.methodCall(DefaultInvoker.java:20)
    at com.sample.SerializationUtil.deserialize(SerializationUtil.groovy:20)
Run Code Online (Sandbox Code Playgroud)

从异常中,我可以看到 GroovyClassLoader 没有被调用,我认为这可能是问题所在。

bla*_*rag 3

问题是,正如您已经确定的那样,没有任何 GroovyClassLoader 参与其中......特别是不知道您当前的类的人。

虽然 ObjectOutputStream 并不真正关心使用 ObjectInputStream 定义的类加载器,但必须在此处做出假设,因为它需要创建一个实例。从跟踪来看,为对象实例创建选择的“最近”类加载器将是包含 groovy 运行时的类加载器。遗憾的是,这是 Groovy 的一个常见问题,因为 Java 中不断引入越来越多的调用者敏感逻辑。

不管怎样,如果你也有这样的东西(ScriptLoaderObjectInputStream.groovy):

class ScriptLoaderObjectInputStream extends ObjectInputStream {
  ScriptLoaderObjectInputStream(InputStream str) { super(str) }

  protected Class resolveClass(ObjectStreamClass desc) {
    return this.class.classLoader.loadClass(desc.getName())
  }
}
Run Code Online (Sandbox Code Playgroud)

并将您对 ObjectInputStream 的使用替换为这个,它应该可以工作。它应该可以工作,因为这也是一个脚本文件,并且生成的类应该具有与其他生成的类相同的类加载器。

为了进一步阅读,我发现这个非常好: https: //rsankarx.wordpress.com/2012/06/08/java-serialization-classloaders/

免责声明:我在这里写了这篇文章,没有 IDE,没有拼写检查,也没有涉及任何测试。