blob: 3a30702bf9af5644dd4bd1b40a7dc3457970bdc4 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.commons.proxy.invoker.recorder;
import org.apache.commons.proxy.Invoker;
import org.apache.commons.proxy.ProxyFactory;
import org.apache.commons.proxy.ProxyUtils;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.LinkedList;
import java.util.List;
/**
* @auothor James Carman
*/
public class InvocationRecorder
{
private final ProxyFactory proxyFactory;
private List<RecordedInvocation> recordedInvocations = new LinkedList<RecordedInvocation>();
public InvocationRecorder( ProxyFactory proxyFactory )
{
this.proxyFactory = proxyFactory;
}
public List<RecordedInvocation> getRecordedInvocations()
{
return recordedInvocations;
}
public <T> T proxy( Class<T> type )
{
return proxy(type, type);
}
public <T> T proxy( Type genericType, Class<T> type )
{
if( proxyFactory.canProxy(type) )
{
return proxyFactory.createInvokerProxy(new InvocationRecorderInvoker(genericType), type);
}
return ProxyUtils.nullValue(type);
}
private class InvocationRecorderInvoker implements Invoker
{
private final Type targetType;
private InvocationRecorderInvoker( Type targetType )
{
this.targetType = targetType;
}
@SuppressWarnings("unchecked")
public Object invoke( Object o, Method method, Object[] args ) throws Throwable
{
recordedInvocations.add(new RecordedInvocation(method, args));
final Class returnType = getReturnType(targetType, method);
return proxy(method.getGenericReturnType(), returnType);
}
}
public void reset()
{
recordedInvocations.clear();
}
public static Class getReturnType( Type enclosingType, Method method ) throws Exception
{
Type returnType = method.getGenericReturnType();
if( returnType instanceof Class )
{
return ( Class ) returnType;
}
else if( returnType instanceof TypeVariable )
{
return resolveVariable(enclosingType, ( TypeVariable ) returnType);
}
else if( returnType instanceof ParameterizedType )
{
return ( Class ) ( ( ParameterizedType ) returnType ).getRawType();
}
return null;
}
public static Class resolveVariable( Type enclosingType, TypeVariable typeVar ) throws Exception
{
if( enclosingType instanceof ParameterizedType )
{
ParameterizedType pt = ( ParameterizedType ) enclosingType;
final Class rawType = ( Class ) pt.getRawType();
TypeVariable[] typeParameters = rawType.getTypeParameters();
for( int i = 0; i < typeParameters.length; i++ )
{
TypeVariable typeParameter = typeParameters[i];
if( typeParameter == typeVar )
{
return ( Class ) pt.getActualTypeArguments()[i];
}
}
}
else if( enclosingType instanceof Class )
{
return resolveVariable(( ( Class ) enclosingType ).getGenericSuperclass(), typeVar);
}
return null;
}
}