📄 serializableidiom.java
字号:
implementsSerializableDirectly|| seenTransientField ? HIGH_PRIORITY : ( sawSerialVersionUID ? NORMAL_PRIORITY : LOW_PRIORITY)) .addClass(getThisClass().getClassName())); // Downgrade class-level warnings if it's a GUI class. int priority = false && isGUIClass ? LOW_PRIORITY : NORMAL_PRIORITY; if (obj.getClassName().endsWith("_Stub")) priority++; if (isExternalizable && !hasPublicVoidConstructor && !isAbstract) bugReporter.reportBug(new BugInstance(this, "SE_NO_SUITABLE_CONSTRUCTOR_FOR_EXTERNALIZATION", directlyImplementsExternalizable ? HIGH_PRIORITY : NORMAL_PRIORITY) .addClass(getThisClass().getClassName())); if (!foundSynthetic) priority++; if (seenTransientField) priority--; if (!isAnonymousInnerClass && !isExternalizable && !isGUIClass && !obj.isAbstract() && isSerializable && !isAbstract && !sawSerialVersionUID) bugReporter.reportBug(new BugInstance(this, "SE_NO_SERIALVERSIONID", priority).addClass(this)); if (writeObjectIsSynchronized && !foundSynchronizedMethods) bugReporter.reportBug(new BugInstance(this, "WS_WRITEOBJECT_SYNC", LOW_PRIORITY).addClass(this)); } @Override public void visit(Method obj) { int accessFlags = obj.getAccessFlags(); boolean isSynchronized = (accessFlags & ACC_SYNCHRONIZED) != 0; if (getMethodName().equals("<init>") && getMethodSig().equals("()V") && (accessFlags & ACC_PUBLIC) != 0 ) hasPublicVoidConstructor = true; if (!getMethodName().equals("<init>") && isSynthetic(obj)) foundSynthetic = true; // System.out.println(methodName + isSynchronized); if (getMethodName().equals("readExternal") && getMethodSig().equals("(Ljava/io/ObjectInput;)V")) { sawReadExternal = true; if (false && !obj.isPrivate()) System.out.println("Non-private readExternal method in: " + getDottedClassName()); } else if (getMethodName().equals("writeExternal") && getMethodSig().equals("(Ljava/io/Objectoutput;)V")) { sawWriteExternal = true; if (false && !obj.isPrivate()) System.out.println("Non-private writeExternal method in: " + getDottedClassName()); } else if (getMethodName().equals("readResolve") && getMethodSig().startsWith("()") && isSerializable) { sawReadResolve = true; if (!getMethodSig().equals("()Ljava/lang/Object;")) bugReporter.reportBug(new BugInstance(this, "SE_READ_RESOLVE_MUST_RETURN_OBJECT", HIGH_PRIORITY) .addClassAndMethod(this)); }else if (getMethodName().equals("readObject") && getMethodSig().equals("(Ljava/io/ObjectInputStream;)V") && isSerializable) { sawReadObject = true; if (!obj.isPrivate()) bugReporter.reportBug(new BugInstance(this, "SE_METHOD_MUST_BE_PRIVATE", HIGH_PRIORITY) .addClassAndMethod(this)); } else if (getMethodName().equals("readObjectNoData") && getMethodSig().equals("()V") && isSerializable) { if (!obj.isPrivate()) bugReporter.reportBug(new BugInstance(this, "SE_METHOD_MUST_BE_PRIVATE", HIGH_PRIORITY) .addClassAndMethod(this)); }else if (getMethodName().equals("writeObject") && getMethodSig().equals("(Ljava/io/ObjectOutputStream;)V") && isSerializable) { sawReadObject = true; if (!obj.isPrivate()) bugReporter.reportBug(new BugInstance(this, "SE_METHOD_MUST_BE_PRIVATE", HIGH_PRIORITY) .addClassAndMethod(this)); } if (isSynchronized) { if (getMethodName().equals("readObject") && getMethodSig().equals("(Ljava/io/ObjectInputStream;)V") && isSerializable) bugReporter.reportBug(new BugInstance(this, "RS_READOBJECT_SYNC", NORMAL_PRIORITY).addClass(this)); else if (getMethodName().equals("writeObject") && getMethodSig().equals("(Ljava/io/ObjectOutputStream;)V") && isSerializable) writeObjectIsSynchronized = true; else foundSynchronizedMethods = true; } super.visit(obj); } boolean isSynthetic(FieldOrMethod obj) { Attribute[] a = obj.getAttributes(); for (Attribute aA : a) if (aA instanceof Synthetic) return true; return false; } @Override public void visit(Code obj) { if (isSerializable) { stack.resetForMethodEntry(this); super.visit(obj); } } @Override public void sawOpcode(int seen) { stack.mergeJumps(this); if (seen == PUTFIELD) { String nameOfClass = getClassConstantOperand(); if ( getClassName().equals(nameOfClass)) { Item first = stack.getStackItem(0); boolean isPutOfDefaultValue = first.isNull() || first.isInitialParameter(); if (!isPutOfDefaultValue && first.getConstant() != null) { Object constant = first.getConstant(); if (constant instanceof Number && ((Number)constant).intValue() == 0 || constant.equals(Boolean.FALSE)) isPutOfDefaultValue = true; } if (!isPutOfDefaultValue) { String nameOfField = getNameConstantOperand(); if (transientFieldsUpdates.containsKey(nameOfField) ) { if (getMethodName().equals("<init>")) transientFieldsSetInConstructor.add(nameOfField); else transientFieldsUpdates.put(nameOfField, transientFieldsUpdates.get(nameOfField)+1); } else if (fieldsThatMightBeAProblem.containsKey(nameOfField)) { try { JavaClass classStored = first.getJavaClass(); double isSerializable = DeepSubtypeAnalysis .isDeepSerializable(classStored); if (isSerializable <= 0.2) { XField f = fieldsThatMightBeAProblem.get(nameOfField); String sig = f.getSignature(); // System.out.println("Field signature: " + sig); // System.out.println("Class stored: " + // classStored.getClassName()); String genSig = "L" + classStored.getClassName().replace('.', '/') + ";"; if (!sig.equals(genSig)) { double bias = 0.0; if (!getMethodName().equals("<init>")) bias = 1.0; int priority = computePriority(isSerializable, bias); fieldWarningList.add(new BugInstance(this, "SE_BAD_FIELD_STORE", priority).addClass( getThisClass().getClassName()).addField(f) .addType(genSig).describe("TYPE_FOUND").addSourceLine(this)); } } } catch (Exception e) { // ignore it } } } } } stack.sawOpcode(this,seen); } private OpcodeStack stack = new OpcodeStack(); @Override public void visit(Field obj) { int flags = obj.getAccessFlags(); if (obj.isTransient()) { if (isSerializable) { seenTransientField = true; transientFields.put(obj.getName(), XFactory.createXField(this)); transientFieldsUpdates.put(obj.getName(), 0); } else if (reportTransientFieldOfNonSerializableClass) { bugReporter.reportBug(new BugInstance(this, "SE_TRANSIENT_FIELD_OF_NONSERIALIZABLE_CLASS", NORMAL_PRIORITY) .addClass(this) .addVisitedField(this)); } } else if (getClassName().indexOf("ObjectStreamClass") == -1 && isSerializable && !isExternalizable && getFieldSig().indexOf("L") >= 0 && !obj.isTransient() && !obj.isStatic()) { try { double isSerializable = DeepSubtypeAnalysis.isDeepSerializable(getFieldSig()); if (isSerializable < 1.0) fieldsThatMightBeAProblem.put(obj.getName(), XFactory.createXField(this)); if (isSerializable < 0.9) { // Priority is LOW for GUI classes (unless explicitly marked Serializable), // HIGH if the class directly implements Serializable, // NORMAL otherwise. int priority = computePriority(isSerializable, 0); if (priority > NORMAL_PRIORITY && obj.getName().startsWith("this$")) priority = NORMAL_PRIORITY; else if (innerClassHasOuterInstance) { if (isAnonymousInnerClass) priority+=2; else priority+=1; } if (false) System.out.println("SE_BAD_FIELD: " + getThisClass().getClassName() +" " + obj.getName() +" " + isSerializable +" " + implementsSerializableDirectly +" " + sawSerialVersionUID +" " + isGUIClass); // Report is queued until after the entire class has been seen. if (obj.getName().equals("this$0")) fieldWarningList.add(new BugInstance(this, "SE_BAD_FIELD_INNER_CLASS", priority) .addClass(getThisClass().getClassName())); else if (isSerializable < 0.9) fieldWarningList.add(new BugInstance(this, "SE_BAD_FIELD", priority) .addClass(getThisClass().getClassName()) .addField(getDottedClassName(), obj.getName(), getFieldSig(), false)); } else if (false && obj.getName().equals("this$0")) fieldWarningList.add(new BugInstance(this, "SE_INNER_CLASS", implementsSerializableDirectly ? NORMAL_PRIORITY : LOW_PRIORITY) .addClass(getThisClass().getClassName())); } catch (ClassNotFoundException e) { bugReporter.reportMissingClass(e); } } if (!getFieldName().startsWith("this") && isSynthetic(obj)) foundSynthetic = true; if (!getFieldName().equals("serialVersionUID")) return; int mask = ACC_STATIC | ACC_FINAL; if (!getFieldSig().equals("I") && !getFieldSig().equals("J")) return; if ((flags & mask) == mask && getFieldSig().equals("I")) { bugReporter.reportBug(new BugInstance(this, "SE_NONLONG_SERIALVERSIONID", LOW_PRIORITY) .addClass(this) .addVisitedField(this)); sawSerialVersionUID = true; return; } else if ((flags & ACC_STATIC) == 0) { bugReporter.reportBug(new BugInstance(this, "SE_NONSTATIC_SERIALVERSIONID", NORMAL_PRIORITY) .addClass(this) .addVisitedField(this)); return; } else if ((flags & ACC_FINAL) == 0) { bugReporter.reportBug(new BugInstance(this, "SE_NONFINAL_SERIALVERSIONID", NORMAL_PRIORITY) .addClass(this) .addVisitedField(this)); return; } sawSerialVersionUID = true; } private int computePriority(double isSerializable, double bias) { int priority = (int)(1.9+isSerializable*3 + bias); if (implementsSerializableDirectly || sawSerialVersionUID || sawReadObject) priority--; if (!implementsSerializableDirectly && priority == HIGH_PRIORITY) priority = NORMAL_PRIORITY; return priority; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -