我有一个类PasswordEncryptor
,它使用org.jasypt.util.password.StrongPasswordEncryptor
作为其中一个字段,因为我试图使应用程序“可群集”所有类都需要序列化以进行会话复制,但每当PasswordEncryptor
访问1}}我遇到以下异常:
Caused by: java.io.NotSerializableException: org.jasypt.util.password.StrongPasswordEncryptor
at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:891)
at org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1063)
at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:1019)
at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:885)
at org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1063)
at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:1019)
at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:885)
at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:680)
at org.jboss.marshalling.AbstractObjectOutput.writeObject(AbstractObjectOutput.java:62)
at org.jboss.marshalling.AbstractMarshaller.writeObject(AbstractMarshaller.java:119)
at org.jboss.as.clustering.SimpleMarshalledValue.getBytes(SimpleMarshalledValue.java:74)
at org.jboss.as.clustering.SimpleMarshalledValue.writeObject(SimpleMarshalledValue.java:172)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [rt.jar:1.6.0_34]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) [rt.jar:1.6.0_34]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) [rt.jar:1.6.0_34]
at java.lang.reflect.Method.invoke(Method.java:622) [rt.jar:1.6.0_34]
at org.jboss.marshalling.reflect.SerializableClass.callWriteObject(SerializableClass.java:175)
at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:1007)
at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:885)
at org.jboss.marshalling.AbstractObjectOutput.writeObject(AbstractObjectOutput.java:62)
at org.jboss.marshalling.AbstractMarshaller.writeObject(AbstractMarshaller.java:119)
at org.infinispan.marshall.MarshallUtil.marshallMap(MarshallUtil.java:60)
at org.infinispan.marshall.exts.MapExternalizer.writeObject(MapExternalizer.java:63)
at org.infinispan.marshall.exts.MapExternalizer.writeObject(MapExternalizer.java:47)
at org.infinispan.marshall.jboss.ExternalizerTable$ExternalizerAdapter.writeObject(ExternalizerTable.java:406)
at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:145)
at org.jboss.marshalling.AbstractObjectOutput.writeObject(AbstractObjectOutput.java:62)
at org.jboss.marshalling.AbstractMarshaller.writeObject(AbstractMarshaller.java:119)
at org.infinispan.atomic.AtomicHashMap$Externalizer.writeObject(AtomicHashMap.java:229)
at org.infinispan.atomic.AtomicHashMap$Externalizer.writeObject(AtomicHashMap.java:226)
at org.infinispan.marshall.jboss.ExternalizerTable$ExternalizerAdapter.writeObject(ExternalizerTable.java:406)
at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:145)
at org.jboss.marshalling.AbstractObjectOutput.writeObject(AbstractObjectOutput.java:62)
at org.jboss.marshalling.AbstractMarshaller.writeObject(AbstractMarshaller.java:119)
at org.infinispan.marshall.jboss.AbstractJBossMarshaller.objectToObjectStream(AbstractJBossMarshaller.java:86)
at org.infinispan.marshall.VersionAwareMarshaller.objectToObjectStream(VersionAwareMarshaller.java:151)
at org.infinispan.marshall.AbstractDelegatingMarshaller.objectToObjectStream(AbstractDelegatingMarshaller.java:44)
at org.infinispan.marshall.MarshalledValue.serialize0(MarshalledValue.java:119)
... 117 more
Caused by: an exception which occurred:
in field spe
in field bean
in object java.util.HashMap@b629b463
in object org.jboss.as.clustering.SimpleMarshalledValue@b629b463
in object org.infinispan.util.FastCopyHashMap@43ad73a2
in object org.infinispan.atomic.AtomicHashMap@4fd181fe
in object org.infinispan.marshall.MarshalledValue@4fd181fe
in object org.infinispan.commands.write.PutKeyValueCommand@ce32d716
in object org.infinispan.commands.tx.PrepareCommand@293098b
我已尝试将字段标记为transient
,如下所示:
import java.io.Serializable;
import org.jasypt.util.password.StrongPasswordEncryptor;
public class PasswordEncryptor implements Serializable {
private static final long serialVersionUID = 1L;
//Need to mark transient as its not serializable
private transient StrongPasswordEncryptor spe = new StrongPasswordEncryptor();
public String encrypt(String password){
return spe.encryptPassword(password);
}
public boolean isPasswordCorrect(String enteredPassword, String passwordHash){
return spe.checkPassword(enteredPassword, passwordHash);
}
}
我不能使用包装器来继承StrongPasswordEncryptor,因为它是最终的
其他任何方法吗? (最好不引入任何其他库)
答案 0 :(得分:5)
从Infinispan的角度来看,控制类序列化的最佳方法,特别是当类是最终的或者您无法修改类时,最好的方法是为要序列化的类提供自己的Infinispan Externalizer。 。 Infinispan的用户指南包含有关how to Plug Infinispan with User-Defined Externalizers的完整章节,解释了它的优点,包括减少有效负载,更快的序列化以及无法修改要序列化的类时的问题。除了文档中的示例之外,Infinispan source code (ASL2)包含大量的Externalizer示例,可以满足您的需求。
更具体地说,PasswordEncryptor的Externalizer不需要在writeObject
和readObject
中编写任何内容,只需要实例化PasswordEncryptor。
答案 1 :(得分:0)
您需要将字段标记为transient
,就像您已经完成的那样。然后,您必须手动序列化该类的单个属性。这将是这样的:
private void writeObject(ObjectOutputStream os){
try{
os.defaultWriteObject();
os.writeChars(spe.encryptPassword("your password"));
}
catch (Exception e){
e.printStackTrace();
}
}
答案 2 :(得分:0)
由于您使用零参数构造函数创建StrongPasswordEncryptor,因此您不需要任何其他数据来创建它。它没有你需要保存的状态,所以根本不需要序列化它。在反序列化后简单地重新创建它是安全的。
标记transient
是正确的做法。
但是,反序列化对象中的瞬态字段为空。
您可以按照the Serializable documentation:
中的说明提供readObject
方法
private transient StrongPasswordEncryptor spe = new StrongPasswordEncryptor();
/**
* Automatically called when this object is deserialized.
*/
private void readObject(ObjectInputStream in)
throws IOException,
ClassNotFoundException {
in.defaultReadObject();
spe = new StrongPasswordEncryptor();
}
另一个选择是使字段瞬态并懒惰地初始化它:
private transient StrongPasswordEncryptor spe;
/**
* Returns this object's StrongPasswordEncryptor, creating it
* if necessary.
*/
private StrongPasswordEncryptor getEncryptor() {
if (spe == null) {
spe = new StrongPasswordEncryptor();
}
return spe;
}
public String encrypt(String password){
return getEncryptor().encryptPassword(password);
}
public boolean isPasswordCorrect(String enteredPassword, String passwordHash){
return getEncryptor().checkPassword(enteredPassword, passwordHash);
}