From 910433e916d703fad39bbd02dc97591e43b4caa2 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Wed, 17 Jun 2015 21:49:45 +0200 Subject: [PATCH] IDEA-141475 (serialVersionUID generated by IDEA differs from one generated by JDK) --- .../com/siyeh/ig/fixes/MemberSignature.java | 9 +- .../ig/fixes/SerialVersionUIDBuilder.java | 98 ++++--------------- .../serialVersionUID/ClassAccess.after.java | 15 +++ .../serialVersionUID/ClassAccess.java | 14 +++ .../AddSerialVersionUIDFixTest.java | 36 +++++++ 5 files changed, 83 insertions(+), 89 deletions(-) create mode 100644 plugins/InspectionGadgets/test/com/siyeh/igfixes/serialization/serialVersionUID/ClassAccess.after.java create mode 100644 plugins/InspectionGadgets/test/com/siyeh/igfixes/serialization/serialVersionUID/ClassAccess.java create mode 100644 plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/serialization/AddSerialVersionUIDFixTest.java diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/fixes/MemberSignature.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/fixes/MemberSignature.java index d77df3120b63..e71d532ef739 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/fixes/MemberSignature.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/fixes/MemberSignature.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2010 Bas Leijdekkers + * Copyright 2003-2015 Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,8 +25,6 @@ public class MemberSignature implements Comparable { @NonNls private static final String INITIALIZER_SIGNATURE = "()V"; @NonNls private static final MemberSignature ASSERTIONS_DISABLED_FIELD = new MemberSignature("$assertionsDisabled", Modifier.STATIC | Modifier.FINAL, "Z"); - @NonNls private static final MemberSignature CLASS_ACCESS_METHOD = - new MemberSignature("class$", Modifier.STATIC, "(Ljava.lang.String;)Ljava.lang.Class;"); @NonNls private static final MemberSignature PACKAGE_PRIVATE_CONSTRUCTOR = new MemberSignature(CONSTRUCTOR_NAME, 0, INITIALIZER_SIGNATURE); @NonNls private static final MemberSignature PUBLIC_CONSTRUCTOR = @@ -235,11 +233,6 @@ public class MemberSignature implements Comparable { return ASSERTIONS_DISABLED_FIELD; } - public static MemberSignature getClassAccessMethodMemberSignature() { - return CLASS_ACCESS_METHOD; - } - - public int getModifiers() { return modifiers; } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/fixes/SerialVersionUIDBuilder.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/fixes/SerialVersionUIDBuilder.java index 23811567380c..d2e50461b586 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/fixes/SerialVersionUIDBuilder.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/fixes/SerialVersionUIDBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2012 Bas Leijdekkers + * Copyright 2003-2015 Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -45,9 +45,7 @@ public class SerialVersionUIDBuilder extends JavaRecursiveElementVisitor { private final Set nonPrivateFields; private final List staticInitializers; private boolean assertStatement = false; - private boolean classObjectAccessExpression = false; - private final Map memberMap = - new HashMap(); + private final Map memberMap = new HashMap(); private static final Comparator INTERFACE_COMPARATOR = new Comparator() { @@ -76,7 +74,6 @@ public class SerialVersionUIDBuilder extends JavaRecursiveElementVisitor { return name1.compareTo(name2); } }; - @NonNls private static final String CLASS_ACCESS_METHOD_PREFIX = "class$"; private SerialVersionUIDBuilder(PsiClass clazz) { super(); @@ -103,7 +100,7 @@ public class SerialVersionUIDBuilder extends JavaRecursiveElementVisitor { } } - staticInitializers = new ArrayList(); + staticInitializers = new ArrayList(1); final PsiClassInitializer[] initializers = clazz.getInitializers(); if (initializers.length > 0) { for (final PsiClassInitializer initializer : initializers) { @@ -130,8 +127,8 @@ public class SerialVersionUIDBuilder extends JavaRecursiveElementVisitor { } } - nonPrivateConstructors = new HashSet(); final PsiMethod[] constructors = clazz.getConstructors(); + nonPrivateConstructors = new HashSet(constructors.length); if (constructors.length == 0 && !clazz.isInterface()) { // generated empty constructor if no constructor is defined in the source final MemberSignature constructorSignature; @@ -152,6 +149,9 @@ public class SerialVersionUIDBuilder extends JavaRecursiveElementVisitor { } } + /** + * @see java.io.ObjectStreamClass#computeDefaultSUID(java.lang.Class) + */ public static long computeDefaultSUID(PsiClass psiClass) { final Project project = psiClass.getProject(); final GlobalSearchScope scope = GlobalSearchScope.allScope(project); @@ -197,34 +197,15 @@ public class SerialVersionUIDBuilder extends JavaRecursiveElementVisitor { } final MemberSignature[] fields = serialVersionUIDBuilder.getNonPrivateFields(); - Arrays.sort(fields); - for (final MemberSignature field : fields) { - dataOutputStream.writeUTF(field.getName()); - dataOutputStream.writeInt(field.getModifiers()); - dataOutputStream.writeUTF(field.getSignature()); - } + writeSignatures(fields, dataOutputStream); final MemberSignature[] staticInitializers = serialVersionUIDBuilder.getStaticInitializers(); - for (final MemberSignature staticInitializer : staticInitializers) { - dataOutputStream.writeUTF(staticInitializer.getName()); - dataOutputStream.writeInt(staticInitializer.getModifiers()); - dataOutputStream.writeUTF(staticInitializer.getSignature()); - } + writeSignatures(staticInitializers, dataOutputStream); final MemberSignature[] constructors = serialVersionUIDBuilder.getNonPrivateConstructors(); - Arrays.sort(constructors); - for (final MemberSignature constructor : constructors) { - dataOutputStream.writeUTF(constructor.getName()); - dataOutputStream.writeInt(constructor.getModifiers()); - dataOutputStream.writeUTF(constructor.getSignature()); - } + writeSignatures(constructors, dataOutputStream); - Arrays.sort(methodSignatures); - for (final MemberSignature methodSignature : methodSignatures) { - dataOutputStream.writeUTF(methodSignature.getName()); - dataOutputStream.writeInt(methodSignature.getModifiers()); - dataOutputStream.writeUTF(methodSignature.getSignature()); - } + writeSignatures(methodSignatures, dataOutputStream); dataOutputStream.flush(); @NonNls final String algorithm = "SHA"; @@ -248,43 +229,13 @@ public class SerialVersionUIDBuilder extends JavaRecursiveElementVisitor { } } - private void createClassObjectAccessSynthetics(PsiType type) { - if (!classObjectAccessExpression) { - final MemberSignature syntheticMethod = - MemberSignature.getClassAccessMethodMemberSignature(); - nonPrivateMethods.add(syntheticMethod); + private static void writeSignatures(MemberSignature[] signatures, DataOutputStream dataOutputStream) throws IOException { + Arrays.sort(signatures); + for (final MemberSignature field : signatures) { + dataOutputStream.writeUTF(field.getName()); + dataOutputStream.writeInt(field.getModifiers()); + dataOutputStream.writeUTF(field.getSignature()); } - PsiType unwrappedType = type; - @NonNls final StringBuffer fieldNameBuffer; - if (type instanceof PsiArrayType) { - fieldNameBuffer = new StringBuffer(); - fieldNameBuffer.append("array"); - while (unwrappedType instanceof PsiArrayType) { - final PsiArrayType arrayType = (PsiArrayType)unwrappedType; - unwrappedType = arrayType.getComponentType(); - fieldNameBuffer.append('$'); - } - } - else { - fieldNameBuffer = new StringBuffer(CLASS_ACCESS_METHOD_PREFIX); - } - if (unwrappedType instanceof PsiPrimitiveType) { - final PsiPrimitiveType primitiveType = (PsiPrimitiveType)unwrappedType; - fieldNameBuffer.append(MemberSignature.createPrimitiveType(primitiveType)); - } - else { - final String text = unwrappedType.getCanonicalText().replace('.', - '$'); - fieldNameBuffer.append(text); - } - final String fieldName = fieldNameBuffer.toString(); - final MemberSignature memberSignature = - new MemberSignature(fieldName, Modifier.STATIC, - "Ljava/lang/Class;"); - if (!nonPrivateFields.contains(memberSignature)) { - nonPrivateFields.add(memberSignature); - } - classObjectAccessExpression = true; } private String getAccessMethodIndex(PsiElement element) { @@ -351,10 +302,6 @@ public class SerialVersionUIDBuilder extends JavaRecursiveElementVisitor { final MemberSignature memberSignature = MemberSignature.getAssertionsDisabledFieldMemberSignature(); nonPrivateFields.add(memberSignature); - final PsiManager manager = clazz.getManager(); - final PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory(); - final PsiClassType classType = factory.createType(clazz); - createClassObjectAccessSynthetics(classType); if (staticInitializers.isEmpty()) { final MemberSignature initializerSignature = MemberSignature.getStaticInitializerMemberSignature(); @@ -363,17 +310,6 @@ public class SerialVersionUIDBuilder extends JavaRecursiveElementVisitor { assertStatement = true; } - @Override - public void visitClassObjectAccessExpression( - PsiClassObjectAccessExpression expression) { - final PsiTypeElement operand = expression.getOperand(); - final PsiType type = operand.getType(); - if (!(type instanceof PsiPrimitiveType)) { - createClassObjectAccessSynthetics(type); - } - super.visitClassObjectAccessExpression(expression); - } - @Override public void visitMethodCallExpression( @NotNull PsiMethodCallExpression methodCallExpression) { diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/serialization/serialVersionUID/ClassAccess.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/serialization/serialVersionUID/ClassAccess.after.java new file mode 100644 index 000000000000..f84120dbf9fe --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/serialization/serialVersionUID/ClassAccess.after.java @@ -0,0 +1,15 @@ +import java.io.Serializable; +import java.util.EnumMap; +import java.util.Map; +import java.util.Set; + +public class ClassAccess implements Serializable { + + private static final long serialVersionUID = 2269507042140353173L; + + enum TestEnum {} + + Map> testField = new EnumMap>(TestEnum.class); + // Map> testField = new HashMap<>(); + +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/serialization/serialVersionUID/ClassAccess.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/serialization/serialVersionUID/ClassAccess.java new file mode 100644 index 000000000000..e444acfa5150 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/serialization/serialVersionUID/ClassAccess.java @@ -0,0 +1,14 @@ +import java.io.Serializable; +import java.util.EnumMap; +import java.util.Map; +import java.util.Set; + +public class ClassAccess implements Serializable { + + enum TestEnum {} + + // at one point javac generated a synthetic field for .class accesses with a name starting with the string "class$" + Map> testField = new EnumMap>(TestEnum.class); + // Map> testField = new HashMap<>(); + +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/serialization/AddSerialVersionUIDFixTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/serialization/AddSerialVersionUIDFixTest.java new file mode 100644 index 000000000000..e88bb7e23529 --- /dev/null +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/serialization/AddSerialVersionUIDFixTest.java @@ -0,0 +1,36 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.siyeh.ig.fixes.serialization; + +import com.siyeh.InspectionGadgetsBundle; +import com.siyeh.ig.IGQuickFixesTestCase; +import com.siyeh.ig.serialization.SerializableHasSerialVersionUIDFieldInspection; + +/** + * @author Bas Leijdekkers + */ +public class AddSerialVersionUIDFixTest extends IGQuickFixesTestCase { + + @Override + public void setUp() throws Exception { + super.setUp(); + myFixture.enableInspections(new SerializableHasSerialVersionUIDFieldInspection()); + myRelativePath = "serialization/serialVersionUID"; + myDefaultHint = InspectionGadgetsBundle.message("add.serialversionuidfield.quickfix"); + } + + public void testClassAccess() { doTest(); } +}