001    /*
002     * $Id: ExceptionThrower.java,v 1.5 2011/07/09 21:43:22 oboehm Exp $
003     *
004     * Copyright (c) 2010 by Oliver Boehm
005     *
006     * Licensed under the Apache License, Version 2.0 (the "License");
007     * you may not use this file except in compliance with the License.
008     * You may obtain a copy of the License at
009     *
010     *   http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express orimplied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     *
018     * (c)reated 30.01.2010 by oliver (ob@oasd.de)
019     */
020    
021    package patterntesting.runtime.util;
022    
023    import java.lang.reflect.Constructor;
024    
025    import org.junit.Test;
026    import org.slf4j.*;
027    
028    /**
029     * Because we need the functionality of throwing any exception not only in
030     * PatternTesting Exception but also here this functionality was shifted to
031     * PatternTesting Runtime.
032     * <br/>
033     * This class is not intended for public use. If you do so use it on your own
034     * risk!
035     *
036     * @author oliver
037     * @since 1.0 (30.01.2010)
038     */
039    public final class ExceptionThrower {
040    
041        private static Logger log = LoggerFactory.getLogger(ExceptionThrower.class);
042    
043        /** only a utility class - no need to instantiate it. */
044        private ExceptionThrower() {}
045    
046        /**
047         * Be careful - you can provoke any Exception with the method without the
048         * need to declare it with a throws statement. For example
049         * <pre>provoke(IOException.class)</pre>
050         * would throw an IOException.
051         * <br/>
052         * WARNING: If the desired exception can't be instantiated an
053         * InstantiationException or IllegalAccessException may be thrown.
054         * <br/>
055         * WARNING(2): This method is not synchronized.
056         *
057         * @param type e.g. IOException.class
058         */
059        public static void provoke(final Class<? extends Throwable> type) {
060            Throwable t;
061            try {
062                t = create(type);
063            } catch (Exception ex) {
064                log.debug("can't create " + type, ex);
065                t = ex;
066            }
067            Thrower.provoke(t);
068        }
069    
070        /**
071         * This method throws the expected exception wrapped into the
072         * {@link Test} annotation.
073         *
074         * @param test with the expected exception
075         */
076        public static void provoke(final Test test) {
077            Class<? extends Throwable> expected = test.expected();
078            if ((expected != Test.None.class) && (expected != null)) {
079                ExceptionThrower.provoke(expected);
080            }
081        }
082    
083        /**
084         * Creates any desired exception you want.
085         * If the desired exception can't be instantiated an
086         * InstantiationException or IllegalAccessException may be thrown.
087         *
088         * @param type the exception class you want to be created
089         *
090         * @return the instantiated exception or the caught exception
091         *
092         * @throws IllegalAccessException the illegal access exception
093         * @throws InstantiationException the instantiation exception
094         */
095        public static Throwable create(final Class<? extends Throwable> type)
096                throws InstantiationException, IllegalAccessException {
097            try {
098                Constructor<? extends Throwable> ctor = type
099                        .getConstructor(String.class);
100                return ctor.newInstance("created by ExceptionThrower");
101            } catch (Exception e) {
102                if (log.isTraceEnabled()) {
103                    log.trace("can't call 'new " + type + "(String)'", e);
104                }
105                return type.newInstance();
106            }
107        }
108    
109        /**
110         * The trick here is to use the constructor to throw any desired exception.
111         * So you can throw any exception without the need to have it as throws
112         * clause.
113         *
114         * @author <a href="boehm@javatux.de">oliver</a>
115         */
116        static final class Thrower {
117            private static Throwable throwable;
118    
119            private Thrower() throws Throwable {
120                throw throwable;
121            }
122    
123            /**
124             * Provoke an exception.
125             *
126             * @param t the Throwable which should be used as provoked exception.
127             */
128            public static void provoke(final Throwable t) {
129                throwable = t;
130                try {
131                    Thrower.class.newInstance();
132                } catch (InstantiationException unexpected) {
133                    log.debug("can't instantiate Thrower class", unexpected);
134                } catch (IllegalAccessException unexpected) {
135                    log.debug("can't access Thrower constructor", unexpected);
136                }
137            }
138        }
139    
140    }
141