如何在运行时从序列化过程中排除类字段? 编译时有瞬态修饰符,但运行时呢? 我指的是使用ObjectOutputStream的常见java序列化,而不是gson或其他东西。
对不起,我想我没解释得对。这不完全是关于序列化,而是关于 de - 序列化。我有一批遗留文件并像这样处理它们:
public class Deserialize {
/**
* @param args
* @throws IOException
* @throws ClassNotFoundException
*/
public static void main(String[] args) throws ClassNotFoundException, IOException {
File file = new File("/home/developer/workspace/DDFS/some.ddf");
HackedObjectInputStream in = new HackedObjectInputStream(new GZIPInputStream(new FileInputStream(file)));
System.out.println("Attempt to open " + file.getAbsolutePath());
Object obj = in.readObject();
in.close();
}
static class HackedObjectInputStream extends ObjectInputStream
{
/**
* Migration table. Holds old to new classes representation.
*/
private static final Map<String, Class<?>> MIGRATION_MAP = new HashMap<String, Class<?>>();
static
{
MIGRATION_MAP.put("DBOBExit", Exit.class);
}
/**
* Constructor.
* @param stream input stream
* @throws IOException if io error
*/
public HackedObjectInputStream(final InputStream stream) throws IOException
{
super(stream);
}
@Override
protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException
{
ObjectStreamClass resultClassDescriptor = super.readClassDescriptor();
for (final String oldName : MIGRATION_MAP.keySet())
{
if (resultClassDescriptor.getName().equals(oldName))
{
resultClassDescriptor = ObjectStreamClass.lookup(MIGRATION_MAP.get(oldName));
}
}
return resultClassDescriptor;
}
}
}
此代码适用于大多数文件,但某些文件会抛出
Exception in thread "main" java.lang.ClassCastException: cannot assign instance of java.awt.Polygon to field Exit.msgbackPt of type java.awt.Point in instance of Exit
at java.io.ObjectStreamClass$FieldReflector.setObjFieldValues(ObjectStreamClass.java:2053)
因为Exit类的版本不同。新版本有新字段。 向新字段添加瞬态时错误消失,但另一个文件开始抛出异常(最新文件)。
如果我检测到遗留的加强文件,我可以在运行时向这些新文件添加瞬态吗? 也许反思或其他什么?
答案 0 :(得分:42)
documentation of ObjectOutputStream说:
对象的默认序列化机制会写入对象的类,类签名以及所有非瞬态和非静态字段的值。对其他对象的引用(瞬态或静态字段除外)也会导致这些对象被写入。
因此,当您将变量声明为瞬态时,ObjectOutputStream应该忽略它。确保使用transient
关键字而不是@Transient
注释。某些ORM框架使用此类注释来标记不应保存在数据库中的字段。它们对于buildin序列化框架毫无意义。
private transient String foo; // Field gets ignored by ObjectOutputStream
@Transient private String bar; // Treated normally by ObjectOutputStream (might mean something for some other framework)
答案 1 :(得分:2)
您可以使用'transient'修饰符:
http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.3.1.3
答案 2 :(得分:1)
特定类的序列化表示取决于类本身,你不能在外部更改它,你可以得到的最近的是定义一个具有自定义序列化行为的子类但只影响该子类的对象,而不是对象父类型。
如果您根本无法修改有问题的类,那么您唯一的选择是继承ObjectOutputStream并覆盖replaceObject
以在写入时将问题对象替换为仅包含您想要的数据的另一个问题对象,和读取时的镜像处理(子类ObjectInputStream并覆盖resolveObject
)。
答案 3 :(得分:0)
你在这里挖错了洞。您应该考虑覆盖readResolve(),而不是通过运行时决定传递有关哪些字段要序列化并覆盖readClassDescriptor()的信息。