/*
*
* * Copyright 2010, Unitils.org
* *
* * Licensed under the Apache License, Version 2.0 (the "License");
* * you may not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* *
* * http://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the License for the specific language governing permissions and
* * limitations under the License.
*
*/
package org.unitils.mock.core.proxy;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Factory;
import org.unitils.core.UnitilsException;
import org.unitils.mock.core.MockObject;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Utility class to create and work with proxy objects.
*
* @author Kenny Claes
* @author Filip Neven
* @author Tim Ducheyne
*/
public class ProxyUtils {
/**
* @param object The object to check
* @return The proxied type, null if the object is not a proxy
*/
public static Class<?> getProxiedTypeIfProxy(Object object) {
if (object == null) {
return null;
}
if (object instanceof Factory) {
Callback[] callbacks = ((Factory) object).getCallbacks();
if (callbacks == null || callbacks.length == 0) {
return null;
}
if (callbacks[0] instanceof CglibProxyMethodInterceptor) {
return ((CglibProxyMethodInterceptor) callbacks[0]).getProxiedType();
}
}
return null;
}
/**
* @param instance The instance to check, not null
* @return True if the given instance is a jdk or cglib proxy
*/
public static boolean isProxy(Object instance) {
if (instance == null) {
return false;
}
Class<?> clazz = instance.getClass();
return isProxyClassName(clazz.getName()) || Proxy.isProxyClass(clazz);
}
/**
* @param className The class name to check, not null
* @return True if the given class name is cglib proxy class name
*/
public static boolean isProxyClassName(String className) {
return className.contains("$$EnhancerByCGLIB$$");
}
/**
* note: don't remove, used through reflection from {@link org.unitils.core.util.ObjectFormatter}
*
* @param object The object to check
* @return The proxied type, null if the object is not a proxy or mock
*/
@SuppressWarnings({"UnusedDeclaration"})
public static String getMockName(Object object) {
if (object == null) {
return null;
}
if (object instanceof MockObject) {
return ((MockObject) object).getName();
}
if (object instanceof Factory) {
Callback callback = ((Factory) object).getCallback(0);
if (callback instanceof CglibProxyMethodInterceptor) {
return ((CglibProxyMethodInterceptor) callback).getMockName();
}
}
return null;
}
/**
* First finds a trace element in which a cglib proxy method was invoked. Then it returns the rest of the stack trace following that
* element. The stack trace starts with the element rh r is the method call that was proxied by the proxy method.
*
* @return The proxied method trace, not null
*/
public static StackTraceElement[] getProxiedMethodStackTrace() {
List<StackTraceElement> stackTrace = new ArrayList<StackTraceElement>();
boolean foundProxyMethod = false;
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
for (StackTraceElement stackTraceElement : stackTraceElements) {
if (foundProxyMethod) {
stackTrace.add(stackTraceElement);
} else if (isProxyClassName(stackTraceElement.getClassName())) {
// found the proxy method element, the next element is the proxied method element
foundProxyMethod = true;
}
}
if (stackTrace.isEmpty()) {
throw new UnitilsException("No invocation of a cglib proxy method found in stacktrace: " + Arrays.toString(stackTraceElements));
}
return stackTrace.toArray(new StackTraceElement[stackTrace.size()]);
}
}