/*
 * FindBugs - Find bugs in Java programs
 * Copyright (C) 2003, University of Maryland
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package edu.umd.cs.findbugs;
import org.apache.bcel.classfile.*;
import edu.umd.cs.pugh.visitclass.BetterVisitor;
import edu.umd.cs.pugh.visitclass.Constants2;

public class SerializableIdiom extends BetterVisitor implements Detector, Constants2 {


    boolean sawSerialVersionUID;
    boolean isSerializable;
    int synchronizedMethods;
    boolean writeObjectIsSynchronized;
    private BugReporter bugReporter;

    public SerializableIdiom(BugReporter bugReporter) {
	this.bugReporter = bugReporter;
	}

    public void visitClassContext(ClassContext classContext) {
	classContext.getJavaClass().accept(this);
	}

    public void report() { }

    public void visitJavaClass(JavaClass obj)     {      
sawSerialVersionUID = false;
       super.visitJavaClass(obj);
        constant_pool.accept(this);
    		isSerializable = false;
		String [] interface_names = obj.getInterfaceNames();
		for(int i=0; i < interface_names.length; i++) {
			if (interface_names[i].equals("java.io.Serializable")) {
				isSerializable = true;
			}
		}
        Field[] fields = obj.getFields();
        for(int i = 0; i < fields.length; i++) fields[i].accept(this);
	if (isSerializable && !sawSerialVersionUID)
//		bugReporter.reportBug(BugInstance.inClass("SE_NO_SERIALVERSIONID", UNKNOWN_PRIORITY, this));
		bugReporter.reportBug(new BugInstance("SE_NO_SERIALVERSIONID", NORMAL_PRIORITY).addClass(this));

	synchronizedMethods = 0;
	writeObjectIsSynchronized = false;
        Method[] methods = obj.getMethods();
        for(int i = 0; i < methods.length; i++) methods[i].accept(this);
	if (writeObjectIsSynchronized && synchronizedMethods == 0)
//		bugReporter.reportBug(BugInstance.inClass("WS_WRITEOBJECT_SYNC", UNKNOWN_PRIORITY, this));
		bugReporter.reportBug(new BugInstance("WS_WRITEOBJECT_SYNC", NORMAL_PRIORITY).addClass(this));
        }

    public void visit(Method obj) {
	int accessFlags = obj.getAccessFlags();
        boolean isSynchronized = (accessFlags & ACC_SYNCHRONIZED) != 0;
	// System.out.println(methodName + isSynchronized);
	if (!isSynchronized) return;
	if (methodName.equals("readObject")) 
//		bugReporter.reportBug(BugInstance.inClass("RS_READOBJECT_SYNC", UNKNOWN_PRIORITY, this));
		bugReporter.reportBug(new BugInstance("RS_READOBJECT_SYNC", NORMAL_PRIORITY).addClass(this));
	else if (methodName.equals("writeObject")) 
		writeObjectIsSynchronized = true;
	else synchronizedMethods++;

	}
		
	
    public void visit(Field obj) {
	// System.out.println("Saw " + betterClassName + "." + fieldName);
        super.visit(obj);

	if (!fieldName.equals("serialVersionUID")) return;
	// System.out.println("Saw " + betterClassName + "." + fieldName);
	int flags = obj.getAccessFlags();
	if ((flags & ACC_STATIC) == 0) {
		bugReporter.reportBug(new BugInstance("SE_NONSTATIC_SERIALVERSIONID", NORMAL_PRIORITY)
			.addClass(this)
			.addVisitedField(this));
		return;
		}
	sawSerialVersionUID = true;
	}


}

@@ -859,16 +859,51 @@
 ndbugs;%0A
+import org.apache.bcel.Repository;%0A
 import o
@@ -1511,19 +1511,20 @@
 port() %7B
- %7D%0A
+%0A%09%09%7D
 %0A    pub
@@ -1578,69 +1578,196 @@
    %0A
-sawSerialVersionUID = false;%0A       super.visitJavaClass(obj)
+%09int flags = obj.getAccessFlags();%0A%09boolean isAbstract = (flags & ACC_ABSTRACT) != 0 %0A%09%09%09   %7C%7C (flags & ACC_INTERFACE) != 0;%0A%09super.visitJavaClass(obj);%0A        sawSerialVersionUID = false
 ;%0A  
@@ -1804,18 +1804,27 @@
 s);%0A    
-%09%09
+           
 isSerial
@@ -1839,18 +1839,31 @@
  false;%0A
-%09%09
+               
 String %5B
@@ -1907,18 +1907,31 @@
 ames();%0A
-%09%09
+               
 for(int 
@@ -1970,19 +1970,39 @@
  i++) %7B%0A
-%09%09%09
+                       
 if (inte
@@ -2054,43 +2054,193 @@
 ) %7B%0A
-%09%09%09%09isSerializable = true;%0A%09%09%09%7D%0A%09%09%7D
+                               isSerializable = true;%0A                       %7D%0A               %7D%0A%0A%09isSerializable = isSerializable%0A%09%09%7C%7C Repository.instanceOf(obj,%22java.io.Serializable%22);
 %0A   
@@ -2371,16 +2371,31 @@
 zable &&
+ !isAbstract &&
  !sawSer
@@ -2413,105 +2413,8 @@
 ID)%0A
-//%09%09bugReporter.reportBug(BugInstance.inClass(%22SE_NO_SERIALVERSIONID%22, UNKNOWN_PRIORITY, this));%0A
 %09%09bu
@@ -2753,103 +2753,8 @@
  0)%0A
-//%09%09bugReporter.reportBug(BugInstance.inClass(%22WS_WRITEOBJECT_SYNC%22, UNKNOWN_PRIORITY, this));%0A
 %09%09bu
@@ -3132,102 +3132,8 @@
 )) %0A
-//%09%09bugReporter.reportBug(BugInstance.inClass(%22RS_READOBJECT_SYNC%22, UNKNOWN_PRIORITY, this));%0A
 %09%09bu

Use repository to get more accurate results