001    /*  Copyright (c) 2000-2006 hamcrest.org
002     */
003    package org.hamcrest.core;
004    
005    import org.hamcrest.Description;
006    import org.hamcrest.DiagnosingMatcher;
007    import org.hamcrest.Factory;
008    import org.hamcrest.Matcher;
009    
010    
011    /**
012     * Tests whether the value is an instance of a class.
013     * Classes of basic types will be converted to the relevant "Object" classes
014     */
015    public class IsInstanceOf extends DiagnosingMatcher<Object> {
016        private final Class<?> expectedClass;
017        private final Class<?> matchableClass;
018    
019        /**
020         * Creates a new instance of IsInstanceOf
021         *
022         * @param expectedClass The predicate evaluates to true for instances of this class
023         *                 or one of its subclasses.
024         */
025        public IsInstanceOf(Class<?> expectedClass) {
026            this.expectedClass = expectedClass;
027            this.matchableClass = matchableClass(expectedClass);
028        }
029    
030        private static Class<?> matchableClass(Class<?> expectedClass) {
031          if (boolean.class.equals(expectedClass)) return Boolean.class; 
032          if (byte.class.equals(expectedClass)) return Byte.class; 
033          if (char.class.equals(expectedClass)) return Character.class; 
034          if (double.class.equals(expectedClass)) return Double.class; 
035          if (float.class.equals(expectedClass)) return Float.class; 
036          if (int.class.equals(expectedClass)) return Integer.class; 
037          if (long.class.equals(expectedClass)) return Long.class; 
038          if (short.class.equals(expectedClass)) return Short.class; 
039          return expectedClass;
040        }
041    
042        @Override
043        protected boolean matches(Object item, Description mismatch) {
044          if (null == item) {
045            mismatch.appendText("null");
046            return false;
047          }
048          
049          if (!matchableClass.isInstance(item)) {
050            mismatch.appendValue(item).appendText(" is a " + item.getClass().getName());
051            return false;
052          }
053          
054          return true;
055        }
056    
057        @Override
058        public void describeTo(Description description) {
059            description.appendText("an instance of ").appendText(expectedClass.getName());
060        }
061    
062        /**
063         * Creates a matcher that matches when the examined object is an instance of the specified <code>type</code>,
064         * as determined by calling the {@link java.lang.Class#isInstance(Object)} method on that type, passing the
065         * the examined object.
066         * 
067         * <p>The created matcher assumes no relationship between specified type and the examined object.</p>
068         * <p/>
069         * For example: 
070         * <pre>assertThat(new Canoe(), instanceOf(Paddlable.class));</pre>
071         * 
072         */
073        @SuppressWarnings("unchecked")
074        @Factory
075        public static <T> Matcher<T> instanceOf(Class<?> type) {
076            return (Matcher<T>) new IsInstanceOf(type);
077        }
078        
079        /**
080         * Creates a matcher that matches when the examined object is an instance of the specified <code>type</code>,
081         * as determined by calling the {@link java.lang.Class#isInstance(Object)} method on that type, passing the
082         * the examined object.
083         * 
084         * <p>The created matcher forces a relationship between specified type and the examined object, and should be
085         * used when it is necessary to make generics conform, for example in the JMock clause
086         * <code>with(any(Thing.class))</code></p>
087         * <p/>
088         * For example: 
089         * <pre>assertThat(new Canoe(), instanceOf(Canoe.class));</pre>
090         *
091         */
092        @SuppressWarnings("unchecked")
093        @Factory
094        public static <T> Matcher<T> any(Class<T> type) {
095            return (Matcher<T>) new IsInstanceOf(type);
096        }
097    
098    }