/**
* Copyright (c) 2014 - 2017 Frank Appel
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Frank Appel - initial API and implementation
*/
package com.codeaffine.eclipse.swt.util;
import static java.util.Arrays.asList;
import static java.util.stream.Collectors.toList;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.ProtectionDomain;
import java.util.List;
import org.eclipse.swt.widgets.Widget;
public class ControlReflectionUtil {
public static final String SCROLL_BAR = "scrollBar";
public static final String PARENT = "parent";
public static final String DISPLAY = "display";
public static final String CREATE_WIDGET = "createWidget";
public static final String STYLE = "style";
private final Unsafe unsafe;
public static class Parameter<T> {
private final Class<T> type;
private final T instance;
Parameter( T instance, Class<T> type ) {
this.instance = instance;
this.type = type;
}
}
interface Operator<T> {
T execute() throws Exception;
}
public ControlReflectionUtil() {
unsafe = new Unsafe();
}
public Class<? extends Widget> defineWidgetClass( String name ) {
return execute( () -> defineClass( name ) );
}
public <T extends Widget> T newInstance( Class<T> type ) {
return execute( () -> createNewIewInstance( type ) );
}
public void invoke( Widget receiver, String methodName, Parameter<?> ... parameters ) {
execute( () -> invokeMethod( receiver, methodName, parameters ) );
}
public void setField( Widget receiver, String fieldName, Object value ) {
execute( () -> setFieldValue( receiver, fieldName, value ) );
}
public <T> T getField( Widget receiver, String fieldName, Class<T> type ) {
return execute( () -> getFieldValue( receiver, fieldName, type ) );
}
public static <T> Parameter<T> $( T instance, Class<T> type ) {
return new Parameter<T>( instance, type );
}
@SuppressWarnings("unchecked")
private Class<? extends Widget> defineClass( String name ) {
String path = name.replaceAll( "\\.", "/" ) + ".class";
byte[] bytes = new ResourceLoader().load( path );
ClassLoader loader = getClass().getClassLoader();
ProtectionDomain domain = getClass().getProtectionDomain();
return ( Class<? extends Widget> )unsafe.defineClass( name, bytes, 0, bytes.length, loader, domain );
}
private <T extends Widget> T createNewIewInstance( Class<T> type ) throws Exception {
return unsafe.newInstance( type );
}
private static Object invokeMethod( Widget receiver, String methodName, Parameter<?> ... parameters )
throws Exception
{
Method method = getMethod( receiver, methodName, parameters );
method.setAccessible( true );
return invokeMethodInternal( receiver, method, parameters );
}
private static Object invokeMethodInternal( Widget receiver, Method method, Parameter<?>... parameters )
throws Exception
{
try {
return method.invoke( receiver );
} catch( Exception exception ) {
return method.invoke( receiver, calculateParameterValues( parameters ) );
}
}
private static Method getMethod( Widget receiver, String methodName, Parameter<?> ... parameters )
throws NoSuchMethodException
{
try {
return getMethodInternal( receiver, methodName );
} catch( NoSuchMethodException noReceiverMethod ) {
return getMethodInternal( receiver, methodName, calculateParameterTypes( parameters ) );
}
}
private static Method getMethodInternal( Widget receiver, String methodName, Class<?> ... parameterTypes )
throws NoSuchMethodException
{
Class<? extends Object> type = receiver.getClass();
do {
try {
return type.getDeclaredMethod( methodName, parameterTypes );
} catch( NoSuchMethodException noReceiverMethod ) {
if( type == Widget.class ) {
throw noReceiverMethod;
}
type = type.getSuperclass();
}
} while( true );
}
private static Object setFieldValue( Object receiver, String fieldName, Object value ) throws Exception {
Field field = getField( receiver, fieldName );
field.setAccessible( true );
field.set( receiver, value );
return null;
}
private static <T> T getFieldValue( Widget receiver, String fieldName, Class<T> type ) throws Exception {
Field field = getField( receiver, fieldName );
field.setAccessible( true );
return type.cast( field.get( receiver ) );
}
private static Field getField( Object receiver, String fieldName ) throws NoSuchFieldException {
Class<? extends Object> type = receiver.getClass();
do {
try {
return type.getDeclaredField( fieldName );
} catch( NoSuchFieldException noReceiverField ) {
if( type == Widget.class ) {
throw noReceiverField;
}
type = type.getSuperclass();
}
} while( true );
}
private static <T> T execute( Operator<T> operator ) {
try {
return operator.execute();
} catch( RuntimeException rte ) {
throw rte;
} catch( InvocationTargetException ite ) {
if( ite.getCause() instanceof RuntimeException ) {
throw ( RuntimeException )ite.getCause();
}
throw new RuntimeException( ite.getCause() );
} catch( Exception e ) {
throw new RuntimeException( e );
}
}
private static Class<?>[] calculateParameterTypes( Parameter<?>[] parameters ) {
List<Class<?>> classes = asList( parameters ).stream().map( parameter -> parameter.type ).collect( toList() );
return classes.toArray( new Class[ classes.size() ] );
}
private static Object[] calculateParameterValues( Parameter<?>[] parameters ) {
return asList( parameters ).stream().map( parameter -> parameter.instance ).collect( toList() ).toArray();
}
}