001 /*
002 * Created on Mar 18, 2012
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
005 * the License. You may obtain a copy of the License at
006 *
007 * http://www.apache.org/licenses/LICENSE-2.0
008 *
009 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
010 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
011 * specific language governing permissions and limitations under the License.
012 *
013 * Copyright @2006-2009 the original author or authors.
014 */
015 package org.fest.reflect.field;
016
017 import java.lang.reflect.Proxy;
018
019 import org.fest.reflect.field.decorator.DecoratorInvocationHandler;
020 import org.fest.reflect.field.decorator.RuntimeExceptionShield;
021
022 /**
023 * A decorated invoker allowing to ignore some exceptions or returning decorator result instead of field result.
024 * @author Ivan Hristov
025 */
026 public final class DecoratedInvoker<T> {
027
028 private final T target;
029 private final T decorator;
030 private final Invoker<T> invoker;
031 private final Class<?> expectedType;
032 private final DecoratorInvocationHandler<T> decoratorInvocationHandler;
033
034 static <T> DecoratedInvoker<T> newInvoker(T target, T decorator, Class<?> expectedType, Invoker<T> invoker,
035 DecoratorInvocationHandler<T> decoratorInvocationHandler) {
036 return new DecoratedInvoker<T>(target, decorator, expectedType, invoker, decoratorInvocationHandler);
037 }
038
039 private DecoratedInvoker(T target, T decorator, Class<?> expectedType, Invoker<T> invoker,
040 DecoratorInvocationHandler<T> decoratorInvocationHandler) {
041 this.target = target;
042 this.decorator = decorator;
043 this.invoker = invoker;
044 this.expectedType = expectedType;
045 this.decoratorInvocationHandler = decoratorInvocationHandler;
046 }
047
048 /**
049 * Ignores any {@link RuntimeException} which comes from the preceding decorator.
050 * @return the DecoratedResultInvoker ignoring exceptions.
051 */
052 public DecoratedInvoker<T> ignoringDecoratorExceptions() {
053 return ignoringDecoratorExceptionsOfType(RuntimeException.class);
054 }
055
056 /**
057 * Ignores any exception of the {@code exceptionClass} type which comes from the preceding decorator.
058 * @param exceptionClass the exception to ignore - usually a checked exception of decorator method
059 * @return the DecoratedResultInvoker ignoring given exception type.
060 */
061 public DecoratedInvoker<T> ignoringDecoratorExceptionsOfType(Class<?> exceptionClass) {
062 RuntimeExceptionShield runtimeExceptionShield = new RuntimeExceptionShield(decorator, exceptionClass);
063 @SuppressWarnings("unchecked")
064 T exceptionSafeDecorator = (T) Proxy.newProxyInstance(decorator.getClass().getClassLoader(),//
065 new Class[] { expectedType }, runtimeExceptionShield);
066
067 decoratorInvocationHandler.setDecorator(exceptionSafeDecorator);
068
069 return newInvoker(target, exceptionSafeDecorator, expectedType, invoker, decoratorInvocationHandler);
070 }
071
072 /**
073 * Specifies that the result from the decorator should be returned.
074 * <p>
075 * If {@link IgnoringDecoratedExceptionInvoker#ignoringDecoratorExceptions() ignoringDecoratorExceptions()} is used in
076 * combination with this method and an exception is thrown, the default value will be returned (as defined by JLS) for
077 * all primitives or null for all non-primitive.
078 * <p>
079 * Example :<br>
080 * If a {@link RuntimeException} is thrown while executing one of the decorated <code>IExampleService</code> field
081 * methods which returns primitive boolean value, the default value <i>false</i> will be returned.
082 *
083 * <pre>
084 * field("fieldName").ofType(IExampleService.class).in(target)
085 * .postDecorateWith(postDecoratorService)
086 * .returningDecoratorResult()
087 * .ignoringDecoratorExceptions();
088 * </pre>
089 * In case of several decorators attached to a field, the result from the latest will be returned.
090 * <p>
091 * Example 1:<br>
092 * The result from the <b>pre</b>DecoratorService will be returned
093 *
094 * <pre>
095 * field("fieldName").ofType(IExampleService.class).in(target)
096 * .preDecorateWith(preDecoratorService)
097 * .returningDecoratorResult();
098 * </pre>
099 * Example 2:<br>
100 * The result from the <b>post</b>DecoratorService will be returned
101 *
102 * <pre>
103 * field("fieldName").ofType(IExampleService.class).in(target)
104 * .postDecorateWith(postDecoratorService)
105 * .returningDecoratorResult();
106 * </pre>
107 * Example 3:<br>
108 * The result from the <b>pre</b>DecoratorService will be returned, since it's the <b>latest</b> attached decorator.
109 *
110 * <pre>
111 * field("fieldName").ofType(IExampleService.class).in(target)
112 * .postDecorateWith(postDecoratorService)
113 * .returningDecoratorResult()
114 * .<b>pre</b>DecorateWith(preDecoratorService)
115 * .returningDecoratorResult();
116 * </pre>
117 */
118 public DecoratedInvoker<T> returningDecoratorResult() {
119 decoratorInvocationHandler.setReturnDecoratorResult(true);
120 return newInvoker(target, decorator, expectedType, invoker, decoratorInvocationHandler);
121 }
122
123 /**
124 * Adds a pre-decorator to an already decorated field.
125 * <p>
126 * Note that if there are more than one pre-decorators assigned to a field they will be executed starting from the
127 * last attached decorator.
128 * @param decorator which methods be called before the same targeted object methods
129 * @return the {@link DecoratedInvoker} pre decorating the target field interface with given decorator.
130 */
131 public DecoratedInvoker<T> preDecorateWith(T decorator) {
132 return invoker.preDecorateWith(decorator);
133 }
134
135 /**
136 * Adds a post-decorator to an already decorated field
137 * <p>
138 * Note that if there are more than one post-decorators assigned to a field they will be executed starting from the
139 * first attached decorator.
140 * @param decorator which methods be called after the same targeted object methods
141 * @return the {@link DecoratedInvoker} post decorating the target field interface with given decorator.
142 */
143 public DecoratedInvoker<T> postDecorateWith(T decorator) {
144 return invoker.postDecorateWith(decorator);
145 }
146 }