「Groovy」- 将对象保存到文件,以及读取文件中对象

更新日期:2020年09月18日

问题描述

我们尝试像 Java 那样,将「对象保存到文件中,并从文件中恢复」,但是产生这会产生异常:

Caught: java.lang.ClassNotFoundException: org.openqa.selenium.Cookie
java.lang.ClassNotFoundException: org.openqa.selenium.Cookie
        at java_io_ObjectInput$readObject.call(Unknown Source)
        at org.d3rm.toolbox.wordpress.CsdnSeleniumCommand.cookieReadFromFile(CsdnSeleniumCommand.groovy:238)
        at org.d3rm.toolbox.wordpress.CsdnSeleniumCommand.actionPublishPost(CsdnSeleniumCommand.groovy:112)
        at org.d3rm.toolbox.wordpress.CsdnSeleniumCommand$actionPublishPost$0.call(Unknown Source)
        at org.d3rm.toolbox.wordpress.CsdnSeleniumCommand.main(CsdnSeleniumCommand.groovy:61)

我们场景是在 Jenkins Pipeline 中使用 Groovy 语言调用 Selenium Java 绑定。按照「对象保存到文件中,并从文件中恢复」方法将 Cookie 对象保存到文件,然后下次再将 Cookie 对象恢复,以保存登录状态。但是会出现上述错误。

问题原因

问题的原因和解决在 [GROOVY-1627] Deserialization fails to work - ASF JIRA 中已经给出

after discussion with several other people I must say it is not the fault of groovy. Java uses the last defined ClassLoader to loader the class. In many environments this might mean that the wrong class loader is chosen or that it works one day and the other day not. The only secure way out of this is the solution I already posted on the mailing list

# 调侃 # 混乱才是常态……不好用?造就造一个……还不好用?那就再造一个……最后这些东西盘根错节,相互影响。

解决办法

解决办法自然有很多(我们知道的,我们不知道的),这里只介绍两种我们知道的方法

第一种、使用 Groovy IO 类库

我们的任何问题都可以通过第三方库解决,这次我们使用 Groovy IO 类库,这里只记录核心代码,关键部分建议参考官方文档:
jdereg/groovy-io: Perfect Groovy serialization to and from JSON format.
Maven Repository: com.cedarsoftware » groovy-io » 1.1.1

@Grab(group='com.cedarsoftware', module='groovy-io', version='1.1.1')

// 将对象写入文件
Set<Cookie> cookies = webDriver.manage().getCookies()
String jsonstrFoo = GroovyJsonWriter.objectToJson(cookies) // 转 JSON 字符串
new File("/path/to/cookies.json").write(jsonstrFoo) // 将 JSON 字符串写入文件

// 从文件读取对象
InputStream inputStream = new File("/path/to/cookies.json").newInputStream()
GroovyJsonReader gjr = new GroovyJsonReader(inputStream)
Set<Cookie> cookies = (Set<Cookie>)gjr.readObject()

第二种、搞定类加载器的问题

这种方法属于解决问题的方法,而前者属于寻找替代方案
[GROOVY-1627] Deserialization fails to work - ASF JIRA

// 将对象写入文件
Set<Cookie> cookies = webDriver.manage().getCookies()
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("/path/to/cookies.bin"));
objectOutputStream.writeObject(cookies);

// 从文件中读取
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("/path/to/cookies.bin")) {
    protected Class resolveClass(ObjectStreamClass objectStreamClass) throws IOException, ClassNotFoundException {
		return Class.forName(objectStreamClass.getName(), true, getClass().classLoader);
    }
}
Set<Cookie> cookies = (Set<Cookie>) ois.readObject();

我们的场景决定我们会选择这种解决方法。1)我们的程序运行在 Jenkins Pipeline 中,引入过多的类库需要面临版本冲突问题。2)引入过多的类库还要解决网络问题。当然可以根据自己的场景选择合适的解决方案。

参考文献

java - Groovy serialization without class definition - Stack Overflow
[GROOVY-1627] Deserialization fails to work - ASF JIRA
java - Groovy serialization without class definition - Stack Overflow


ToC

问题描述

问题原因

解决办法

第一种、使用 Groovy IO 类库

第二种、搞定类加载器的问题

参考文献