/* ******************************************************************************* * Copyright (C) 1996-2010, International Business Machines Corporation and * * others. All Rights Reserved. * ******************************************************************************* * */ package com.ibm.icu.dev.tool.serializable; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Modifier; import java.net.URL; import java.util.Arrays; import java.util.Iterator; import java.util.List; import com.ibm.icu.dev.test.serializable.SerializableTest; import com.ibm.icu.impl.URLHandler; /** * This class examines all the classes in a Jar file or a directory * and lists all those classes that implement Serializable. It also checks * to make sure that those classes have the serialVersionUID * field define. * */ public class SerializableChecker implements URLHandler.URLVisitor { private static Class serializable; //private static Class throwable; private String path = null; //private boolean write; public SerializableChecker(String path) { this.path = path; if (path != null) { File dir = new File(path); if (!dir.exists()) { dir.mkdirs(); } } } static { try { serializable = Class.forName("java.io.Serializable"); //throwable = Class.forName("java.lang.Throwable"); } catch (Exception e) { // we're in deep trouble... System.out.println("Woops! Can't get class info for Serializable and Throwable."); } } private void writeFile(String className, byte bytes[]) { File file = new File(path + File.separator + className + ".dat"); FileOutputStream stream; try { stream = new FileOutputStream(file); stream.write(bytes); stream.close(); } catch (Exception e) { System.out.print(" - can't write file!"); } } public void visit(String str) { int ix = str.lastIndexOf(".class"); if (ix >= 0) { String className = "com.ibm.icu" + str.substring(0, ix).replace('/', '.'); // Skip things in com.ibm.icu.dev; they're not relevant. if (className.startsWith("com.ibm.icu.dev.")) { return; } try { Class c = Class.forName(className); int m = c.getModifiers(); if (serializable.isAssignableFrom(c) /*&& (! throwable.isAssignableFrom(c) || c.getDeclaredFields().length > 0)*/) { //Field uid; System.out.print(className + " (" + Modifier.toString(m) + ") - "); if(!Modifier.isInterface(m)){ try { /* uid = */ c.getDeclaredField("serialVersionUID"); } catch (Exception e) { System.out.print("no serialVersionUID - "); } } if (Modifier.isPublic(m)) { SerializableTest.Handler handler = SerializableTest.getHandler(className); if (!Modifier.isInterface(m) && handler != null) { Object objectsOut[] = handler.getTestObjects(); Object objectsIn[]; boolean passed = true; ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(byteOut); try { out.writeObject(objectsOut); out.close(); byteOut.close(); } catch (IOException e) { System.out.println("Eror writing test objects:" + e.toString()); return; } if (path != null) { writeFile(className, byteOut.toByteArray()); } ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray()); ObjectInputStream in = new ObjectInputStream(byteIn); try { objectsIn = (Object[]) in.readObject(); in.close(); byteIn.close(); } catch (Exception e) { System.out.println("Error reading test objects:" + e.toString()); return; } for(int i = 0; i < objectsIn.length; i += 1) { if (! handler.hasSameBehavior(objectsIn[i], objectsOut[i])) { passed = false; System.out.println("Object " + i + " failed behavior test."); } } if (passed) { System.out.print("test passed."); } } else { // it's OK to not have tests for abstract classes... if (! Modifier.isAbstract(m)) { System.out.print("no test."); } } } System.out.println(); } } catch (Exception e) { System.out.println("Error processing " + className + ": " + e.toString()); } } } public static void main(String[] args) { List argList = Arrays.asList(args); String path = null; for (Iterator it = argList.iterator(); it.hasNext(); /*anything?*/) { String arg = (String) it.next(); if (arg.equals("-w")) { if (it.hasNext()) { path = (String) it.next(); } else { System.out.println("Missing directory name on -w command."); } } else { try { //URL jarURL = new URL("jar:file:/dev/eclipse/workspace/icu4j/icu4j.jar!/com/ibm/icu"); //URL fileURL = new URL("file:/dev/eclipse/workspace/icu4j/classes/com/ibm/icu"); URL url = new URL(arg); URLHandler handler = URLHandler.get(url); SerializableChecker checker = new SerializableChecker(path); System.out.println("Checking classes from " + arg + ":"); handler.guide(checker, true, false); } catch (Exception e) { System.out.println("Error processing URL \"" + arg + "\" - " + e.getMessage()); } } } } }