由ajc和javac生成的类之间的序列化不兼容

时间:2019-04-28 22:02:22

标签: java serialization aspectj javac serialversionuid

最近我发现Java(Java 8)和ajc(v.1.9.2)编译的某些类不兼容 serialization 。所谓序列化兼容性,是指计算出的默认serialVersionUID不相同。

示例:

public class Markup implements Serializable {
    private final MyUnit unit;
    public Markup(MyUnit unit) { this.unit = unit; }

    public enum MyUnit { DOUBLE, STRING }

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Path path = Paths.get("markup.bin");
        if (args.length == 0) {
            try (OutputStream fileOutput = Files.newOutputStream(path);
                 ObjectOutputStream objectOutput = new ObjectOutputStream(fileOutput))
            {
                objectOutput.writeObject(new Markup(MyUnit.STRING));
            }
        } else {
            try (InputStream fileInput = Files.newInputStream(path);
                 ObjectInputStream objectInput = new ObjectInputStream(fileInput))
            {
                System.out.println(objectInput.readObject());
            }
        }
    }

    static String switchType(MyUnit unit) {
        switch (unit) {
            case STRING: return "%";
            case DOUBLE: return "p";
            default: return "Undefined";
        }
    }
}

当我通过ajc编译该类并运行,然后通过javac编译该类并运行时,出现序列化格式不兼容的异常:

Exception in thread "main" java.io.InvalidClassException: Markup; local class incompatible: stream classdesc serialVersionUID = -1905477862550005139, local class serialVersionUID = 793529206923536473

我还发现那是因为ajc开关代码生成器。它在类private static int[] $SWITCH_TABLE$Markup$MyUnit

中创建其他字段

javac生成的字段: enter image description here 由ajc生成的字段: enter image description here

我的问题是:

  1. Java编译器规范是否允许生成未在类中定义的字段?
  2. 为什么AJC会生成其他字段?某种性能优化?
  3. 有什么方法可以使ajc不生成其他字段?
  4. private static影响serialVersionUID生成的原因是什么?
  5. aspectj的开发人员是否知道此行为?如果是这样,为什么他们仍然选择生成字段?
  6. 是否可以保证JLS如何序列化Java类?
  7. 没有此字段,Javac生成的代码如何工作?

1 个答案:

答案 0 :(得分:3)

1。规范允许Java编译器生成类中未定义的字段吗?

是的,尽管应该将它们标记为 synthetic 。合成器包括内部类的访问器(尽管实现方式最近有所变化),lambda表达式方法以及默认的构造函数。

2。为什么AJC会生成其他字段?某种性能优化?

性能优化不佳。也许与有效添加方面有关。

3。有什么方法可以使AJC不生成其他字段?

不知道。您应该期望能够合成合成物。

4。私有静态会影响serialVersionUID生成的原因是什么?

Java序列化是在“ Internet time”中创建的。为了兼容,我们保留了第一个版本要做的任何事情。道德:如果您在互联网时代创造了任何东西,请扔掉它。

5。 Aspectj的开发人员是否知道此行为?如果是这样,为什么他们仍然选择生成字段?

我希望如此。编译器有望成为合成材料。

6。是否可以保证JLS如何序列化Java类?

有一个Java序列化规范(尽管我真的不希望很多人阅读它)。

7。没有此字段,Javac生成的代码如何工作?

比较容易看出如何在不使用数组的情况下编写字符串转换字符串。丑陋的优化版本的确切细节将变得混乱。您可以看到javap -private -c实际发生了什么。

结论

如果期望在类的不同版本之间使用数据,建议添加serialVersionUID。 OTOH,也建议不要使用Java序列化。