Java 如何在运行时从类序列化中排除字段?

Java 如何在运行时从类序列化中排除字段?,java,serialization,Java,Serialization,如何在运行时从序列化过程中排除类字段? 编译时间有瞬时修饰符,但运行时呢? 我指的是带有ObjectOutputStream的普通java序列化,不是gson之类的 对不起,我想我解释得不对。这并不完全是关于序列化,而是关于de-序列化。我有一批遗留文件,并按如下方式处理它们: public class Deserialize { /** * @param args * @throws IOException * @throws ClassNotFoundException */

如何在运行时从序列化过程中排除类字段? 编译时间有瞬时修饰符,但运行时呢? 我指的是带有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;
        }

    }
因为退出类的版本不同。新版本有新字段。 当我向新字段添加transient时,错误消失,但另一个文件开始抛出异常(最新文件)

所以,如果我检测到旧的序列化文件,我可以在运行时将瞬态添加到这些新文件中吗? 也许是反射什么的?

上面说:

对象的默认序列化机制写入对象的类、类签名以及所有非瞬态和非静态字段的值。对其他对象的引用(瞬态或静态字段中的引用除外)也会导致写入这些对象

因此,当您将变量声明为瞬态变量时,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)

特定类的序列化表示取决于类本身,您不能在外部对其进行更改,最接近的方法是定义具有自定义序列化行为的子类,但这只影响该子类的对象,而不影响父类型的对象


如果您根本无法修改有问题的类,那么您唯一的选择就是将ObjectOutputStream子类化,并重写
replaceObject
,以在写入时将问题对象替换为仅包含所需数据的其他对象,并在读取时替换镜像进程(子类ObjectInputStream和override
resolveObject
)。

您在这里挖错了洞。与其在运行时决定哪些字段要序列化和重写
readClassDescriptor()
,不如研究重写
readResolve()

您可以使用
瞬态
修饰符:


不太可能。您可以始终使用
writeObject()
writeReplace()
。您需要自己实现
writeObject()
readObject()
,或者使用
Externalizable
而不是
Serializable
,这应该让您完全控制流程:(以及该规范的其他部分)请注意,您可能必须以这种方式正确地反序列化整个类,并且您必须在反序列化时计算出在序列化过程中写入了哪些字段(通过在数据之前写入一组标志或类似的内容)为什么?在另一端会发生什么?看看编辑:我想你的工作已经完成了。如果你想保存数据并改进其模式,内置序列化是一个非常非常笨拙的选择。我用一种简单的方式找到了解决方案。这意味着我必须将两个类都添加到项目中,旧版本和新版本吗r应该重写哪个类readResolve?关于已修改类的反序列化的全部问题(已移动到不同的包并重命名)。示例似乎是错误的。应忽略瞬态字段,而不是非瞬态字段。@BlueM这是我写的:“当您将变量声明为瞬态时,ObjectOutputStream应忽略它”
private transient String foo; // Field gets ignored by ObjectOutputStream
@Transient private String bar; // Treated normally by ObjectOutputStream (might mean something for some other framework)