Coverage Report - biz.xsoftware.impl.mock.MockObjectImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
MockObjectImpl
77%
63/82
81%
17/21
0
 
 1  
 package biz.xsoftware.impl.mock;
 2  
 
 3  
 import java.lang.reflect.InvocationHandler;
 4  
 import java.lang.reflect.InvocationTargetException;
 5  
 import java.lang.reflect.Method;
 6  
 import java.lang.reflect.Type;
 7  
 import java.util.HashMap;
 8  
 import java.util.HashSet;
 9  
 import java.util.Map;
 10  
 import java.util.Set;
 11  
 import java.util.logging.Level;
 12  
 import java.util.logging.Logger;
 13  
 
 14  
 import biz.xsoftware.mock.MockObject;
 15  
 
 16  
 /**
 17  
  * This is the implementation of the MockObject interface and the default object
 18  
  * returned by the {@link biz.xsoftware.mock.MockObjectFactory}.  This implements the invoke method
 19  
  * used by the Java Reflection {@link java.lang.reflect.Proxy}
 20  
  * 
 21  
  * @author Dean Hiller
 22  
  * @author Brian Freeman
 23  
  */
 24  
 public final class MockObjectImpl extends MockSuperclass implements InvocationHandler {
 25  
 
 26  14
     private static final Logger log =
 27  
             Logger.getLogger(MockObjectImpl.class.getName());
 28  
 
 29  14
     private static Set<Method> isMethodInSuper = new HashSet<Method>();
 30  
 
 31  14
     private static Map<Type, Class<?>> primitiveToClass =
 32  
             new HashMap<Type, Class<?>>();
 33  
 
 34  
     private Class<?>[] classes;
 35  
 
 36  
     static {
 37  
         // reflect and find all the methods of the superclass.
 38  14
         Class<?> c = MockObject.class;
 39  14
         Method[] m = c.getMethods();
 40  518
         for (int i = 0; i < m.length; i++) {
 41  504
             isMethodInSuper.add(m[i]);
 42  
         }
 43  14
         c = Object.class;
 44  14
         m = c.getMethods();
 45  140
         for (int i = 0; i < m.length; i++) {
 46  126
             isMethodInSuper.add(m[i]);
 47  
         }
 48  
 
 49  14
         primitiveToClass.put(Integer.TYPE, Integer.class);
 50  14
         primitiveToClass.put(Double.TYPE, Double.class);
 51  14
         primitiveToClass.put(Float.TYPE, Float.class);
 52  14
         primitiveToClass.put(Boolean.TYPE, Boolean.class);
 53  14
         primitiveToClass.put(Character.TYPE, Character.class);
 54  14
         primitiveToClass.put(Byte.TYPE, Byte.class);
 55  14
         primitiveToClass.put(Short.TYPE, Short.class);
 56  14
         primitiveToClass.put(Long.TYPE, Long.class);
 57  14
     }
 58  
 
 59  
     public MockObjectImpl(String id, Class<?>[] interfaces) {
 60  98
         super(id);
 61  
         // copy the array of interface classes
 62  98
         classes = new Class<?>[interfaces.length];
 63  98
         System.arraycopy(interfaces, 0, classes, 0, interfaces.length);
 64  98
     }
 65  
 
 66  
     /*
 67  
      * (non-Javadoc)
 68  
      * 
 69  
      * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object,
 70  
      *      java.lang.reflect.Method, java.lang.Object[])
 71  
      */
 72  
     public Object invoke(Object proxy, Method method, Object[] args)
 73  
             throws Throwable {
 74  467
         if (log.isLoggable(Level.FINEST)) {
 75  0
             StringBuilder sb = new StringBuilder();
 76  0
             sb.append(proxy.getClass().getSimpleName()).append("> ");
 77  0
             sb.append(method.getName()).append("(");
 78  0
             if (args != null) {
 79  0
                 int i = 0;
 80  0
                 for (; i < args.length - 1; i++) {
 81  0
                     if (args[i] != null)
 82  0
                         sb.append(args[i].getClass().getSimpleName()).append(
 83  
                                 ", ");
 84  
                     else
 85  0
                         sb.append("null, ");
 86  
                 }
 87  0
                 if (args[i] != null)
 88  0
                     sb.append(args[i].getClass().getSimpleName());
 89  
                 else
 90  0
                     sb.append("null");
 91  
             }
 92  0
             sb.append(")");
 93  0
             log.finest(sb.toString());
 94  
         }
 95  
 
 96  467
         if (shouldCallSuperMethod(method)) {
 97  157
             return callSuperMethod(proxy, method, args);
 98  
         }
 99  
 
 100  310
         Object o = methodCalledImpl(method, args);
 101  302
         Class<?> returnType = method.getReturnType();
 102  
 
 103  302
         if (returnType == null)
 104  0
             throw new RuntimeException("This is a bug or something");
 105  
 
 106  302
         String methodString = getCleanMethodString(method);
 107  302
         if (returnType.equals(void.class)) {
 108  
             // The return type is void
 109  151
             if (o != null)
 110  0
                 throw new IllegalArgumentException(
 111  
                         "You are trying to return something on a method that returns void.\n"
 112  
                                 + "Method=" + methodString
 113  
                                 + " value you tried to return=" + o);
 114  
         } else {
 115  
             // Return type is not void...(could be primitive or Object)
 116  
 
 117  151
             if (o == null) {
 118  2
                 if (returnType.isPrimitive()) {
 119  1
                     throw new IllegalArgumentException(
 120  
                             "Must call addReturnValue and "
 121  
                                     + "specify a non-null value as method="
 122  
                                     + methodString
 123  
                                     + " returns a primitive value");
 124  
                 }
 125  149
             } else if (returnType.isPrimitive()) {
 126  
                 // TODO: this is not working correctly no matter what I do
 127  
                 // here.....
 128  17
                 Class<?> primitiveClass = primitiveToClass.get(returnType);
 129  17
                 if (!primitiveClass.isInstance(o)) {
 130  1
                     throw new IllegalArgumentException(
 131  
                             "You specified an incorrect return type on method\n="
 132  
                                     + methodString + "\n"
 133  
                                     + "You specified a return type of="
 134  
                                     + o.getClass()
 135  
                                     + " which needs to be or extend type="
 136  
                                     + returnType);
 137  
                 }
 138  16
             } else if (!returnType.isInstance(o)) {
 139  
                 // if not a primitive, make sure is assignable....
 140  0
                 throw new IllegalArgumentException(
 141  
                         "You specified an incorrect return type on method\n="
 142  
                                 + methodString + "\n"
 143  
                                 + "You specified a return type of="
 144  
                                 + o.getClass()
 145  
                                 + " which needs to be or extend type="
 146  
                                 + returnType);
 147  
             }
 148  
         }
 149  
 
 150  300
         return o;
 151  
     }
 152  
 
 153  
     private boolean shouldCallSuperMethod(Method method) {
 154  467
         return isMethodInSuper.contains(method)
 155  
                 && !methodToReturnVal.containsKey(method)
 156  
                 && !methodToDefaultRetVal.containsKey(method);
 157  
     }
 158  
 
 159  
     /**
 160  
      * @param method
 161  
      * @return
 162  
      */
 163  
     private String getCleanMethodString(Method method) {
 164  302
         String retType = method.getReturnType().getName();
 165  302
         String methodArgs = retType + " " + method.getName() + "(";
 166  302
         Class<?>[] parameterTypes = method.getParameterTypes();
 167  473
         for (int ii = 0; ii < parameterTypes.length; ii++) {
 168  171
             Class<?> arg = method.getParameterTypes()[ii];
 169  171
             methodArgs += arg.getName();
 170  171
             if (ii < parameterTypes.length - 1)
 171  13
                 methodArgs += ", ";
 172  
         }
 173  302
         return methodArgs + ")";
 174  
     }
 175  
 
 176  
     /**
 177  
      * 
 178  
      * @param proxy The method was invoked on this object. This is the dynamicly
 179  
      *            created class
 180  
      * @param m This is the method that was invoked
 181  
      * @param args These are the arguments that were passed to the method
 182  
      * @throws Throwable
 183  
      */
 184  
     private Object callSuperMethod(Object proxy, Method m, Object[] args)
 185  
             throws Throwable {
 186  
         try {
 187  157
             if ("equals".equals(m.getName()))
 188  4
                 return Boolean.valueOf(proxy == args[0]);
 189  153
             else if ("toString".equals(m.getName()))
 190  1
                 return "" + this;
 191  
 
 192  152
             return m.invoke(this, args);
 193  11
         } catch (InvocationTargetException e) {
 194  11
             if (e.getCause() != null)
 195  11
                 throw e.getCause();
 196  0
             throw e;
 197  
         }
 198  
     }
 199  
 
 200  
     /*
 201  
      * (non-Javadoc)
 202  
      * 
 203  
      * @see biz.xsoftware.mock.MockSuperclass#getClasses()
 204  
      */
 205  
     @Override
 206  
     public Class<?>[] getClasses() {
 207  
         // copy the array of interface classes
 208  149
         Class<?>[] result = new Class<?>[classes.length];
 209  149
         System.arraycopy(classes, 0, result, 0, classes.length);
 210  149
         return result;
 211  
     }
 212  
 
 213  
     public Object inst() {
 214  
         // TODO Auto-generated method stub
 215  0
         return null;
 216  
     }
 217  
 
 218  
 }