如何在 Java 中以编程方式生成 serialVersionUID?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18294326/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 00:10:58  来源:igfitidea点击:

How to generate serialVersionUID programmatically in Java?

javaserializationserialversionuid

提问by bn.

I am working on a project that generates Javafiles. I'd like to be able to optionally add the serialVersionUIDas you would with the serialvertool.

我正在开发一个生成Java文件的项目。我希望能够像serialVersionUID使用serialver工具一样选择性地添加。

Is there a way to do this when I generate the Javacode, or will I need to ask the user of the tool to provide UIDs manually? To be clear, I'm not looking to do this automatically through Eclipse or the serialvertool, but to do it via Javaitself.

当我生成Java代码时,有没有办法做到这一点,或者我是否需要要求该工具的用户手动提供 UID?需要明确的是,我不希望通过 Eclipse 或serialver工具自动执行此操作,而是希望通过Java本身执行此操作。

采纳答案by c.s.

There is a version of the serialvertool source available from OpenJDK. It all comes down to this call:

OpenJDKserialver提供了一个工具源版本。这一切都归结为这个电话:

ObjectStreamClass c = ObjectStreamClass.lookup(MyClass.class);
long serialID = c.getSerialVersionUID();
System.out.println(serialID);

In JDK 6 at least it returns the same number with serialvertool.

至少在 JDK 6 中它返回与serialver工具相同的数字。

回答by William Morrison

Try the hashcode of the class name of the class being generated.

尝试生成的类的类名的哈希码。

There could be collisions as a hashcode is not unique, but those collisions are statistically unlikely.

由于哈希码不是唯一的,因此可能会发生冲突,但这些冲突在统计上是不可能的。

Here's documentationon how serialVersionUID values are generated. Its much more complex than I'd have guessed.

这是有关如何生成 serialVersionUID 值的文档。它比我想象的要复杂得多。

Because of its complexity, I'd either have the user type in the UID themselves, or just use a simple hash of the full classname.

由于它的复杂性,我要么让用户自己输入 UID,要么只使用完整类名的简单散列。

回答by Jeffrey

From ObjectStreamClass:

来自ObjectStreamClass

/**
 * Computes the default serial version UID value for the given class.
 */
private static long computeDefaultSUID(Class<?> cl) {
    if (!Serializable.class.isAssignableFrom(cl) || Proxy.isProxyClass(cl))
    {
        return 0L;
    }

    try {
        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        DataOutputStream dout = new DataOutputStream(bout);

        dout.writeUTF(cl.getName());

        int classMods = cl.getModifiers() &
            (Modifier.PUBLIC | Modifier.FINAL |
             Modifier.INTERFACE | Modifier.ABSTRACT);

        /*
         * compensate for javac bug in which ABSTRACT bit was set for an
         * interface only if the interface declared methods
         */
        Method[] methods = cl.getDeclaredMethods();
        if ((classMods & Modifier.INTERFACE) != 0) {
            classMods = (methods.length > 0) ?
                (classMods | Modifier.ABSTRACT) :
                (classMods & ~Modifier.ABSTRACT);
        }
        dout.writeInt(classMods);

        if (!cl.isArray()) {
            /*
             * compensate for change in 1.2FCS in which
             * Class.getInterfaces() was modified to return Cloneable and
             * Serializable for array classes.
             */
            Class<?>[] interfaces = cl.getInterfaces();
            String[] ifaceNames = new String[interfaces.length];
            for (int i = 0; i < interfaces.length; i++) {
                ifaceNames[i] = interfaces[i].getName();
            }
            Arrays.sort(ifaceNames);
            for (int i = 0; i < ifaceNames.length; i++) {
                dout.writeUTF(ifaceNames[i]);
            }
        }

        Field[] fields = cl.getDeclaredFields();
        MemberSignature[] fieldSigs = new MemberSignature[fields.length];
        for (int i = 0; i < fields.length; i++) {
            fieldSigs[i] = new MemberSignature(fields[i]);
        }
        Arrays.sort(fieldSigs, new Comparator<MemberSignature>() {
            public int compare(MemberSignature ms1, MemberSignature ms2) {
                return ms1.name.compareTo(ms2.name);
            }
        });
        for (int i = 0; i < fieldSigs.length; i++) {
            MemberSignature sig = fieldSigs[i];
            int mods = sig.member.getModifiers() &
                (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED |
                 Modifier.STATIC | Modifier.FINAL | Modifier.VOLATILE |
                 Modifier.TRANSIENT);
            if (((mods & Modifier.PRIVATE) == 0) ||
                ((mods & (Modifier.STATIC | Modifier.TRANSIENT)) == 0))
            {
                dout.writeUTF(sig.name);
                dout.writeInt(mods);
                dout.writeUTF(sig.signature);
            }
        }

        if (hasStaticInitializer(cl)) {
            dout.writeUTF("<clinit>");
            dout.writeInt(Modifier.STATIC);
            dout.writeUTF("()V");
        }

        Constructor[] cons = cl.getDeclaredConstructors();
        MemberSignature[] consSigs = new MemberSignature[cons.length];
        for (int i = 0; i < cons.length; i++) {
            consSigs[i] = new MemberSignature(cons[i]);
        }
        Arrays.sort(consSigs, new Comparator<MemberSignature>() {
            public int compare(MemberSignature ms1, MemberSignature ms2) {
                return ms1.signature.compareTo(ms2.signature);
            }
        });
        for (int i = 0; i < consSigs.length; i++) {
            MemberSignature sig = consSigs[i];
            int mods = sig.member.getModifiers() &
                (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED |
                 Modifier.STATIC | Modifier.FINAL |
                 Modifier.SYNCHRONIZED | Modifier.NATIVE |
                 Modifier.ABSTRACT | Modifier.STRICT);
            if ((mods & Modifier.PRIVATE) == 0) {
                dout.writeUTF("<init>");
                dout.writeInt(mods);
                dout.writeUTF(sig.signature.replace('/', '.'));
            }
        }

        MemberSignature[] methSigs = new MemberSignature[methods.length];
        for (int i = 0; i < methods.length; i++) {
            methSigs[i] = new MemberSignature(methods[i]);
        }
        Arrays.sort(methSigs, new Comparator<MemberSignature>() {
            public int compare(MemberSignature ms1, MemberSignature ms2) {
                int comp = ms1.name.compareTo(ms2.name);
                if (comp == 0) {
                    comp = ms1.signature.compareTo(ms2.signature);
                }
                return comp;
            }
        });
        for (int i = 0; i < methSigs.length; i++) {
            MemberSignature sig = methSigs[i];
            int mods = sig.member.getModifiers() &
                (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED |
                 Modifier.STATIC | Modifier.FINAL |
                 Modifier.SYNCHRONIZED | Modifier.NATIVE |
                 Modifier.ABSTRACT | Modifier.STRICT);
            if ((mods & Modifier.PRIVATE) == 0) {
                dout.writeUTF(sig.name);
                dout.writeInt(mods);
                dout.writeUTF(sig.signature.replace('/', '.'));
            }
        }

        dout.flush();

        MessageDigest md = MessageDigest.getInstance("SHA");
        byte[] hashBytes = md.digest(bout.toByteArray());
        long hash = 0;
        for (int i = Math.min(hashBytes.length, 8) - 1; i >= 0; i--) {
            hash = (hash << 8) | (hashBytes[i] & 0xFF);
        }
        return hash;
    } catch (IOException ex) {
        throw new InternalError();
    } catch (NoSuchAlgorithmException ex) {
        throw new SecurityException(ex.getMessage());
    }
}

回答by user207421

If your tool is generating brand new code you don't have any need to compute it the way serialverdoes. Just use 1, or -1, or whatever you like.

如果您的工具正在生成全新的代码,则您无需像这样计算它serialver。只需使用 1 或 -1 或任何您喜欢的值。

回答by kizanlik

This is an old thread but, I guess, serialVersionUIDis still one of the hot topics.

这是一个旧线程,但我想,serialVersionUID仍然是热门话题之一。

When I started to write Java codes, it was too hard to find and assign a unique value to serlialVersionUIDvariable for me. After a while, simple date time format (yyyy-MM-ddTHH:mm:ss) gave me the idea: Why don't I generate a value from current date and time?

当我开始编写 Java 代码时,很难为我找到并为serlialVersionUID变量分配一个唯一值。过了一会儿,简单的日期时间格式 (yyyy-MM-ddTHH:mm:ss) 给了我一个想法:为什么我不从当前日期和时间生成一个值?

So, I started to generate (of course manually) values according to current date and time.

因此,我开始根据当前日期和时间生成(当然是手动)值。

Let's say current date and time is 01/09/2015 11:00pm. I would assign 201601091100L value to serialVersionUID.

假设当前日期和时间是 01/09/2015 晚上 11:00。我会将 201601091100L 值分配给 serialVersionUID。

I hope this idea helps you for further improvements in your projects.

我希望这个想法可以帮助您进一步改进您的项目。