Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright (c) 2016 Mockito contributors
      3  * This program is made available under the terms of the MIT License.
      4  */
      5 package org.mockito.internal.util;
      6 
      7 import org.mockito.internal.creation.instance.InstantiationException;
      8 
      9 import java.lang.reflect.Method;
     10 
     11 /**
     12  * Helper class to work with features that were introduced in Java versions after 1.5.
     13  * This class uses reflection in most places to avoid coupling with a newer JDK.
     14  */
     15 public final class JavaEightUtil {
     16 
     17     // No need for volatile, these optionals are already safe singletons.
     18     private static Object emptyOptional;
     19     private static Object emptyOptionalDouble;
     20     private static Object emptyOptionalInt;
     21     private static Object emptyOptionalLong;
     22 
     23     private JavaEightUtil() {
     24         // utility class
     25     }
     26 
     27     /**
     28      * Creates an empty Optional using reflection to stay backwards-compatible with older JDKs.
     29      *
     30      * @return an empty Optional.
     31      */
     32     public static Object emptyOptional() {
     33         // no need for double-checked locking
     34         if (emptyOptional != null) {
     35             return emptyOptional;
     36         }
     37 
     38         return emptyOptional = invokeNullaryFactoryMethod("java.util.Optional", "empty");
     39     }
     40 
     41 
     42     /**
     43      * Creates an empty OptionalDouble using reflection to stay backwards-compatible with older JDKs.
     44      *
     45      * @return an empty OptionalDouble.
     46      */
     47     public static Object emptyOptionalDouble() {
     48         // no need for double-checked locking
     49         if (emptyOptionalDouble != null) {
     50             return emptyOptionalDouble;
     51         }
     52 
     53         return emptyOptionalDouble = invokeNullaryFactoryMethod("java.util.OptionalDouble", "empty");
     54     }
     55 
     56     /**
     57      * Creates an empty OptionalInt using reflection to stay backwards-compatible with older JDKs.
     58      *
     59      * @return an empty OptionalInt.
     60      */
     61     public static Object emptyOptionalInt() {
     62         // no need for double-checked locking
     63         if (emptyOptionalInt != null) {
     64             return emptyOptionalInt;
     65         }
     66 
     67         return emptyOptionalInt = invokeNullaryFactoryMethod("java.util.OptionalInt", "empty");
     68     }
     69 
     70     /**
     71      * Creates an empty OptionalLong using reflection to stay backwards-compatible with older JDKs.
     72      *
     73      * @return an empty OptionalLong.
     74      */
     75     public static Object emptyOptionalLong() {
     76         // no need for double-checked locking
     77         if (emptyOptionalLong != null) {
     78             return emptyOptionalLong;
     79         }
     80 
     81         return emptyOptionalLong = invokeNullaryFactoryMethod("java.util.OptionalLong", "empty");
     82     }
     83 
     84     /**
     85      * Creates an empty Stream using reflection to stay backwards-compatible with older JDKs.
     86      *
     87      * @return an empty Stream.
     88      */
     89     public static Object emptyStream() {
     90         // note: the empty stream can not be stored as a singleton.
     91         return invokeNullaryFactoryMethod("java.util.stream.Stream", "empty");
     92     }
     93 
     94     /**
     95      * Creates an empty DoubleStream using reflection to stay backwards-compatible with older JDKs.
     96      *
     97      * @return an empty DoubleStream.
     98      */
     99     public static Object emptyDoubleStream() {
    100         // note: the empty stream can not be stored as a singleton.
    101         return invokeNullaryFactoryMethod("java.util.stream.DoubleStream", "empty");
    102     }
    103 
    104     /**
    105      * Creates an empty IntStream using reflection to stay backwards-compatible with older JDKs.
    106      *
    107      * @return an empty IntStream.
    108      */
    109     public static Object emptyIntStream() {
    110         // note: the empty stream can not be stored as a singleton.
    111         return invokeNullaryFactoryMethod("java.util.stream.IntStream", "empty");
    112     }
    113 
    114     /**
    115      * Creates an empty LongStream using reflection to stay backwards-compatible with older JDKs.
    116      *
    117      * @return an empty LongStream.
    118      */
    119     public static Object emptyLongStream() {
    120         // note: the empty stream can not be stored as a singleton.
    121         return invokeNullaryFactoryMethod("java.util.stream.LongStream", "empty");
    122     }
    123 
    124     /**
    125      * Invokes a nullary static factory method using reflection to stay backwards-compatible with older JDKs.
    126      *
    127      * @param fqcn The fully qualified class name of the type to be produced.
    128      * @param methodName The name of the factory method.
    129      * @return the object produced.
    130      */
    131     private static Object invokeNullaryFactoryMethod(final String fqcn, final String methodName) {
    132         try {
    133             final Class<?> type = Class.forName(fqcn);
    134             final Method method = type.getMethod(methodName);
    135 
    136             return method.invoke(null);
    137             // any exception is really unexpected since the type name has
    138             // already been verified
    139         } catch (final Exception e) {
    140             throw new InstantiationException(
    141                     String.format("Could not create %s#%s(): %s", fqcn, methodName, e), e);
    142         }
    143     }
    144 }
    145