bounty还有6天到期。回答此问题可获得+150声望奖励。MatWein希望引起更多的注意这个问题。
问题:
我们目前正在使用Caucho Hessian 3.2.0与Java 8和Java 11应用程序结合使用。这工作正常,但我们想迁移到Java 17,我们得到以下systen.out消息:
java.lang.reflect.InaccessibleObjectException: Unable to make field private java.lang.String java.lang.StackTraceElement.classLoaderName accessible: module java.base does not "opens java.lang" to unnamed module @78e03bb5
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354)
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)
at java.base/java.lang.reflect.Field.checkCanSetAccessible(Field.java:178)
at java.base/java.lang.reflect.Field.setAccessible(Field.java:172)
at com.caucho.hessian.io.JavaDeserializer.getFieldMap(JavaDeserializer.java:299)
at com.caucho.hessian.io.JavaDeserializer.<init>(JavaDeserializer.java:77)
at com.caucho.hessian.io.StackTraceElementDeserializer.<init>(StackTraceElementDeserializer.java:60)
at com.caucho.hessian.io.SerializerFactory.<clinit>(SerializerFactory.java:627)
at com.caucho.hessian.io.AbstractHessianOutput.findSerializerFactory(AbstractHessianOutput.java:95)
at com.caucho.hessian.io.Hessian2Output.writeObject(Hessian2Output.java:486)
at Main.serializeWithHessian(Main.java:23)
at Main.main(Main.java:13)
有一种解决方法,即添加以下JVM参数:
--add-opens java.base/java.lang=ALL-UNNAMED
我们不想在所有生产应用程序中使用此标志,因此我们尝试将Hessian升级到最新版本4.0.66。基本上,这适用于最常见的用例,但当我们多次序列化具有相同对象示例的数据时,这不起作用。
我创建了一个小的示例应用程序:https://github.com/MatWein/hessian-test
这个应用程序从它的类路径中读取一些Java序列化的测试数据,并尝试用Hessian序列化和反序列化它。如果您使用Hessian 3.2.0运行此应用程序,则它适用于运行和调试模式下的所有Java版本(8,11和17,如果您设置了上面的JVM标志)。但我不能让它与Hessian 4.0.66工作,因为以下错误发生:
Exception in thread "main" com.caucho.hessian.io.HessianFieldException: de.test.TestData.field29: de.test.PaymentType cannot be assigned from null
at com.caucho.hessian.io.FieldDeserializer2FactoryUnsafe.logDeserializeError(FieldDeserializer2FactoryUnsafe.java:538)
at com.caucho.hessian.io.FieldDeserializer2FactoryUnsafe$ObjectFieldDeserializer.deserialize(FieldDeserializer2FactoryUnsafe.java:169)
at com.caucho.hessian.io.UnsafeDeserializer.readObject(UnsafeDeserializer.java:237)
at com.caucho.hessian.io.UnsafeDeserializer.readObject(UnsafeDeserializer.java:148)
at com.caucho.hessian.io.Hessian2Input.readObjectInstance(Hessian2Input.java:2202)
at com.caucho.hessian.io.Hessian2Input.readObject(Hessian2Input.java:2123)
at com.caucho.hessian.io.CollectionDeserializer.readLengthList(CollectionDeserializer.java:93)
at com.caucho.hessian.io.Hessian2Input.readObject(Hessian2Input.java:2050)
at Main.deserializeWithHessian(Main.java:32)
at Main.main(Main.java:15)
Caused by: java.lang.IndexOutOfBoundsException: Index 13 out of bounds for length 13
at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64)
at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:70)
at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:266)
at java.base/java.util.Objects.checkIndex(Objects.java:361)
at java.base/java.util.ArrayList.get(ArrayList.java:427)
at com.caucho.hessian.io.Hessian2Input.readObject(Hessian2Input.java:1810)
at com.caucho.hessian.io.FieldDeserializer2FactoryUnsafe$ObjectFieldDeserializer.deserialize(FieldDeserializer2FactoryUnsafe.java:165)
... 8 more
注意:我们在运行和调试应用程序之间有不同的运行时行为(不知道为什么,但Hessian似乎使用了Unsafe类,Weak&Soft引用等)。
对我来说,这看起来像是黑森州的内部bug。它在序列化站点上使用类com.caucho.hessian.util.IdentityIntMap,但是在序列化时客户端找不到对象引用索引。
**问题:**有没有办法让Hessian 4.0.66与Java 8、11和17(或至少与Java 11和17)一起工作?
1条答案
按热度按时间wecizke31#
最后,经过大量的调试,发现了问题。问题是枚举字段具有
null
值。在Hessian
3.x.x
中,默认情况下允许对选中的Enum类型的null
值进行反序列化。但是在Hessian
4.x.x
中,他们改变了计算枚举值的方法,并且不允许对检查的枚举类型的null
值进行反序列化。注:我用的是4.0.66黑森。它将与所有版本的(JDK 8,11,17)(已测试)
修复:
1.**第一个解决方案:**使用
transient
关键字PaymentType
,GenderType
和ActivationState
,因为它们带有null
值,应该避免成为反序列化的一部分。**注意:**在为Enum字段放置
transient
之前,请确保选择您认为不需要作为序列化一部分的字段,并且确保在反序列化发生时,这些Enum字段的数据将在那里。JDK 11输出:
JDK 8输出:
JDK 17输出:
1.**第二种解决方案:**请确保在相应的Enum字段中发送非空值,以避免出现以下错误。