Home | History | Annotate | Download | only in defaultanswers
      1 /*
      2  * Copyright (c) 2007 Mockito contributors
      3  * This program is made available under the terms of the MIT License.
      4  */
      5 package org.mockito.internal.stubbing.defaultanswers;
      6 
      7 import static org.mockito.internal.exceptions.Reporter.smartNullPointerException;
      8 import static org.mockito.internal.util.ObjectMethodsGuru.isToStringMethod;
      9 
     10 import java.io.Serializable;
     11 import java.lang.reflect.Modifier;
     12 
     13 import org.mockito.Mockito;
     14 import org.mockito.internal.debugging.LocationImpl;
     15 import org.mockito.invocation.InvocationOnMock;
     16 import org.mockito.invocation.Location;
     17 import org.mockito.stubbing.Answer;
     18 
     19 /**
     20  * Optional Answer that can be used with
     21  * {@link Mockito#mock(Class, Answer)}
     22  * <p>
     23  * This implementation can be helpful when working with legacy code. Unstubbed
     24  * methods often return null. If your code uses the object returned by an
     25  * unstubbed call you get a NullPointerException. This implementation of
     26  * Answer returns SmartNulls instead of nulls.
     27  * SmartNull gives nicer exception message than NPE because it points out the
     28  * line where unstubbed method was called. You just click on the stack trace.
     29  * <p>
     30  * ReturnsSmartNulls first tries to return ordinary return values (see
     31  * {@link ReturnsMoreEmptyValues}) then it tries to return SmartNull. If the
     32  * return type is not mockable (e.g. final) then ordinary null is returned.
     33  * <p>
     34  * ReturnsSmartNulls will be probably the default return values strategy in
     35  * Mockito 2.1.0
     36  */
     37 public class ReturnsSmartNulls implements Answer<Object>, Serializable {
     38 
     39     private static final long serialVersionUID = 7618312406617949441L;
     40 
     41     private final Answer<Object> delegate = new ReturnsMoreEmptyValues();
     42 
     43     public Object answer(final InvocationOnMock invocation) throws Throwable {
     44         Object defaultReturnValue = delegate.answer(invocation);
     45         if (defaultReturnValue != null) {
     46             return defaultReturnValue;
     47         }
     48         Class<?> type = invocation.getMethod().getReturnType();
     49         if (!type.isPrimitive() && !Modifier.isFinal(type.getModifiers())) {
     50             final Location location = new LocationImpl();
     51             return Mockito.mock(type, new ThrowsSmartNullPointer(invocation, location));
     52         }
     53         return null;
     54     }
     55 
     56     private static class ThrowsSmartNullPointer implements Answer {
     57         private final InvocationOnMock unstubbedInvocation;
     58         private final Location location;
     59 
     60         public ThrowsSmartNullPointer(InvocationOnMock unstubbedInvocation, Location location) {
     61             this.unstubbedInvocation = unstubbedInvocation;
     62             this.location = location;
     63         }
     64 
     65         public Object answer(InvocationOnMock currentInvocation) throws Throwable {
     66             if (isToStringMethod(currentInvocation.getMethod())) {
     67                 return "SmartNull returned by this unstubbed method call on a mock:\n" +
     68                         unstubbedInvocation.toString();
     69             }
     70 
     71             throw smartNullPointerException(unstubbedInvocation.toString(), location);
     72         }
     73     }
     74 }
     75