Rather helpful code for testing Externalizable classes

Karl Wettin <[email protected]>
Newsgroups gmane.comp.java.prevayler
Message-ID <[email protected]>
This is what I use to make sure my readExternal and writeExternal work  
as they should. I've found lots of human errors in my code using this.

Ihe code does not yet handle arrays. There are two todos that needs to  
be handled.

         // todo String[].getClass().what() == String.class?
       // todo should really make sure that the default value is not  
the same as the value we set it to!

There is a method in there that sets the id of my domain objects. You  
might want to remove or modify that.

      karl




   public void test() throws Exception {
     assertSerializationMatches(MyClass.class);
     assertSerializationMatches(MyOtherClass.class);

     if (manuallyRequiredChecks.size() > 0) {
       System.out.println("Manual checking of serialization is  
required for the following fields:");
       for (Field field : manuallyRequiredChecks) {
         System.out.println(field.getDeclaringClass().getName() + "#"  
+ field.getName());
       }
     }

   }

   private static List<Field> manuallyRequiredChecks = new  
ArrayList<Field>();

   /**
    * sets the id of my entity domain objects.
    */
   public void setNonNullableField(Object object) {
     if (object instanceof EntityDomainObject) {
       ((EntityDomainObject)  
object).setId(UUID.randomUUID().toString());
     }
   }

   public void assertSerializationMatches(Class _class) throws  
Exception {

     System.out.println("Testing " + _class.getName());

     Object object = _class.newInstance();
     setNonNullableField(object);

     List<Field> allFields = getAllFields(_class);
     for (int i = 0; i < allFields.size(); i++) {
       Field field = allFields.get(i);

       System.out.println("Setting " + _class.getName() + "#" +  
field.getName());

       // todo should really make sure that the default value is not  
the same as the value we set it to!


       Method setter = getSetter(field);
       Method getter = getGetter(field);
       if (field.getType().isArray()) {
         // todo String[].getClass().what() == String.class?
//        setter.invoke(Array.newInstance(field.getType(), i));
         manuallyRequiredChecks.add(field);
       } else if (field.getType() == java.lang.Boolean.class ||  
field.getType() == boolean.class) {
         setter.invoke(object, !((Boolean) getter.invoke(object))); //  
set to the !default
       } else if (field.getType() == java.lang.Short.class |  
field.getType() == short.class) {
         setter.invoke(object, (short) i);
       } else if (field.getType() == java.lang.Integer.class ||  
field.getType() == int.class) {
         setter.invoke(object, Integer.valueOf(i));
       } else if (field.getType() == java.lang.Long.class ||  
field.getType() == long.class) {
         setter.invoke(object, Long.valueOf(i));
       } else if (field.getType() == java.lang.Float.class ||  
field.getType() == float.class) {
         setter.invoke(object, Float.valueOf(i));
       } else if (field.getType() == java.lang.Double.class ||  
field.getType() == double.class) {
         setter.invoke(object, Double.valueOf(i));
       } else if (field.getType() == java.lang.String.class) {
         setter.invoke(object, String.valueOf(i));
       } else if (field.getType() == java.util.List.class) {
         List list = (List) getter.invoke(object);
         if (list == null) {
           setter.invoke(object, new ArrayList());
         } else {
           setter.invoke(object, list.getClass().newInstance());
         }
       } else if (field.getType() == java.util.Set.class) {
         Set set = (Set) getter.invoke(object);
         if (set == null) {
           setter.invoke(object, new HashSet());
         } else {
           setter.invoke(object, set.getClass().newInstance());
         }
       } else if (field.getType() == java.util.Map.class) {
         Map map = (Map) getter.invoke(object);
         if (map == null) {
           setter.invoke(object, new HashMap());
         } else {
           setter.invoke(object, map.getClass().newInstance());
         }
       } else if (field.getType().isEnum()) {
         // set value to something different than default value.
         Object value = getter.invoke(object);
         if (value != field.getType().getEnumConstants()[0]) {
           setter.invoke(object, field.getType().getEnumConstants()[0]);
         } else {
           setter.invoke(object, field.getType().getEnumConstants()[1]);
         }
       } else {
         Object instance = null;
         if (Modifier.isAbstract(field.getType().getModifiers())) {
           // todo i have no clue how to handle this. need to set one  
of the implementations.
         } else {
           instance = field.getType().newInstance();
         }
         setNonNullableField(instance);
         setter.invoke(object, instance);
       }
     }

     ByteArrayOutputStream baos = new ByteArrayOutputStream();
     ObjectOutputStream oos = new ObjectOutputStream(baos);
     oos.writeObject(object);
     oos.close();
     baos.close();
     ObjectInputStream os = new ObjectInputStream(new  
ByteArrayInputStream(baos.toByteArray()));

     Object clone = os.readObject();

     for (Field field : getAllFields(object.getClass())) {

       System.out.println("Testing " + _class.getName() + "#" +  
field.getName());

       Method getter = getGetter(field);
       assertEquals("Field " + field.getName() + " in class " +  
object.getClass().getName() + " does not match.",  
getter.invoke(object), getter.invoke(clone));

     }

     System.out.println();

   }

   private Method getGetter(Field field) throws Exception {
     StringBuilder getterName = new  
StringBuilder(field.getName().length() + 3);
     if (field.getType() == java.lang.Boolean.class || field.getType()  
== boolean.class) {
       getterName.append("is");
     } else {
       getterName.append("get");
     }
     getterName.append(field.getName().substring(0, 1).toUpperCase());
     getterName.append(field.getName().substring(1));
     return field.getDeclaringClass().getMethod(getterName.toString());
   }

   private Method getSetter(Field field) throws Exception {
     StringBuilder setterName = new  
StringBuilder(field.getName().length() + 3);
     setterName.append("set");
     setterName.append(field.getName().substring(0, 1).toUpperCase());
     setterName.append(field.getName().substring(1));
     return field.getDeclaringClass().getMethod(setterName.toString(),  
field.getType());
   }

   private List<Field> getAllFields(Class serializable) {

     // search super classes
     Set<Class> allClasses = new HashSet<Class>();
     findSuperClasses(allClasses, serializable);

     List<Field> allFields = new ArrayList<Field>();

     for (Class _class : allClasses) {
       for (Field field : Arrays.asList(_class.getDeclaredFields())) {
         if (!Modifier.isFinal(field.getModifiers())
             && !Modifier.isStatic(field.getModifiers())) {
           allFields.add(field);
         }
       }
     }


     return allFields;
   }

   private void findSuperClasses(Set<Class> classes, Class current) {
     classes.add(current);
     if (current.getSuperclass() != null &&  
classes.add(current.getSuperclass())) {
       findSuperClasses(classes, current.getSuperclass());
     }
     for (Class _class : current.getInterfaces()) {
       if (classes.add(_class)) {
         findSuperClasses(classes, _class);
       }
     }
   }


------------------------------------------------------------------------------
This SF.Net email is sponsored by the Verizon Developer Community
Take advantage of Verizon's best-in-class app development support
A streamlined, 14 day to market process makes app distribution fast and easy
Join now and get one step closer to millions of Verizon customers
http://p.sf.net/sfu/verizon-dev2dev 
_______________________________________________
To unsubscribe go to the end of this page: http://lists.sourceforge.net/lists/listinfo/prevayler-discussion
_______________________________________________
"Databases in Memoriam" -- http://www.prevayler.org
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.