Skip to content
Snippets Groups Projects
Commit 8f7c7ec4 authored by brinn's avatar brinn
Browse files

add: methods checkGettersNotNull(), createProxy()

SVN: 522
parent a84f9bd7
No related branches found
No related tags found
No related merge requests found
...@@ -17,8 +17,13 @@ ...@@ -17,8 +17,13 @@
package ch.systemsx.cisd.common.utilities; package ch.systemsx.cisd.common.utilities;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import ch.systemsx.cisd.common.annotation.Mandatory; import ch.systemsx.cisd.common.annotation.Mandatory;
...@@ -87,11 +92,157 @@ public final class ClassUtils ...@@ -87,11 +92,157 @@ public final class ClassUtils
return method; return method;
} }
} }
// SecurityException, ClassNotFoundException // SecurityException, ClassNotFoundException
} catch (Exception ex) } catch (Exception ex)
{ {
throw CheckedExceptionTunnel.wrapIfNecessary(ex); throw CheckedExceptionTunnel.wrapIfNecessary(ex);
} }
return null; return null;
} }
/**
* The {@link InvocationHandler} for the {@link ClassUtils#createProxy(Object, Class, Class[])} method.
*
* @author Bernd Rinn
*/
private static final class ProxyingInvocationHandler implements InvocationHandler
{
private final Object proxiedObject;
ProxyingInvocationHandler(Object proxiedObject)
{
this.proxiedObject = proxiedObject;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
final Method proxyThroughMethod =
proxiedObject.getClass().getMethod(method.getName(), method.getParameterTypes());
return proxyThroughMethod.invoke(proxiedObject, args);
}
}
private static boolean fitsInterfaces(Class classToCheck, List<Class> interfaces)
{
for (Class ifs : interfaces)
{
if (ifs.isInterface() == false)
{
System.err.println("'" + ifs.getCanonicalName() + "' is not an interface.");
return false;
}
for (Method method : ifs.getMethods())
{
try
{
classToCheck.getMethod(method.getName(), method.getParameterTypes());
} catch (NoSuchMethodException ex)
{
System.err.println("'" + classToCheck.getCanonicalName() + "' does not have a method '" + method
+ "'");
return false;
}
}
}
return true;
}
/**
* Returns a {@link Proxy} for <var>objectToBeProxied</var>. This allows to retroactively fit a class into a couple
* of interfaces.
*
* @param objectToProxy The object to proxy through to.
* @param mainInterfaceToProvideProxyFor The main interface to provide a proxy for and to cast to.
* @param otherInterfacesToProvideProxyFor Other interfaces to provide a proxy for.
*/
// Proxy guarantees that the type cast is OK.
@SuppressWarnings("unchecked")
public final static <T> T createProxy(Object objectToProxy, Class<T> mainInterfaceToProvideProxyFor,
Class... otherInterfacesToProvideProxyFor)
{
final List<Class> interfaces = new ArrayList<Class>();
interfaces.add(mainInterfaceToProvideProxyFor);
interfaces.addAll(Arrays.asList(otherInterfacesToProvideProxyFor));
assert fitsInterfaces(objectToProxy.getClass(), interfaces);
return (T) Proxy.newProxyInstance(ClassUtils.class.getClassLoader(), interfaces.toArray(new Class[interfaces
.size()]), new ProxyingInvocationHandler(objectToProxy));
}
private static boolean isNull(Object objectToCheck)
{
return (objectToCheck instanceof Number) && ((Number) objectToCheck).longValue() == 0;
}
/**
* Checks the list of bean objects item by item for public getters which return <code>null</code> or 0.
*
* @param beanListToCheck The list of beans to check. Can be <code>null</code>.
* @return <var>beanListToCheck</var> (the parameter itself)
* @see #checkGettersNotNull(Object)
* @throws IllegalStateException If at least one of the public getters returns <code>null</code> or 0.
*/
public final static <T> List<T> checkGettersNotNull(List<T> beanListToCheck)
{
if (beanListToCheck == null)
{
return beanListToCheck;
}
for (Object bean : beanListToCheck)
{
checkGettersNotNull(bean);
}
return beanListToCheck;
}
/**
* Checks bean object for public getters which return <code>null</code> or 0.
*
* @param beanToCheck The bean to check. Can be <code>null</code>. Must not be an array type.
* @return <var>beanToCheck</var> (the parameter itself)
* @throws IllegalArgumentException If the <var>beanToCheck</var> is an array type.
* @throws IllegalStateException If at least one of the public getters returns <code>null</code> or 0.
*/
public final static <T> T checkGettersNotNull(T beanToCheck)
{
if (beanToCheck == null)
{
return beanToCheck;
}
if (beanToCheck.getClass().isArray())
{
throw new IllegalArgumentException("Arrays are not supported.");
}
for (Method method : beanToCheck.getClass().getMethods())
{
if (method.getName().startsWith("get") && method.getParameterTypes().length == 0
&& Modifier.isPublic(method.getModifiers()))
{
try
{
final Object result = method.invoke(beanToCheck, new Object[0]);
if (result == null)
{
throw new IllegalStateException("Method '" + method.getName() + "' returns null.");
} else if (isNull(result))
{
throw new IllegalStateException("Method '" + method.getName() + "' returns 0.");
}
} catch (InvocationTargetException ex)
{
final Throwable cause = ex.getCause();
if (cause instanceof Error)
{
throw (Error) cause;
}
throw CheckedExceptionTunnel.wrapIfNecessary((Exception) cause);
} catch (IllegalAccessException ex)
{
// Can't happen since we checked for isAccessible()
throw new Error("Cannot call method '" + method.getName() + "'.");
}
}
}
return beanToCheck;
}
} }
...@@ -17,6 +17,11 @@ ...@@ -17,6 +17,11 @@
package ch.systemsx.cisd.common.utilities; package ch.systemsx.cisd.common.utilities;
import static org.testng.AssertJUnit.*; import static org.testng.AssertJUnit.*;
import java.util.Arrays;
import java.util.List;
import org.testng.AssertJUnit;
import org.testng.annotations.Test; import org.testng.annotations.Test;
/** /**
...@@ -35,5 +40,83 @@ public class ClassUtilsTest ...@@ -35,5 +40,83 @@ public class ClassUtilsTest
{ {
assertEquals("testGetCurrentMethod", ClassUtils.getCurrentMethod().getName()); assertEquals("testGetCurrentMethod", ClassUtils.getCurrentMethod().getName());
} }
private static class SimpleBean
{
private final int number;
private final String string;
SimpleBean(int number, String string)
{
this.number = number;
this.string = string;
}
public int getNumber()
{
return number;
}
public String getString()
{
return string;
}
String getIgnoreThisBecauseItIsNotPublic()
{
AssertJUnit.fail("Should be ignore because not public");
return null;
}
}
@Test
public void testCheckGettersForNullOK()
{
final SimpleBean bean = new SimpleBean(1, "");
assert ClassUtils.checkGettersNotNull(bean) == bean;
}
@Test
public void testCheckGettersForNullOKNullBean()
{
assertNull(ClassUtils.checkGettersNotNull(null));
}
@Test(expectedExceptions = IllegalStateException.class)
public void testCheckGettersForNullStringNull()
{
final SimpleBean bean = new SimpleBean(1, null);
ClassUtils.checkGettersNotNull(bean);
}
@Test(expectedExceptions = IllegalStateException.class)
public void testCheckGettersForNullInt0()
{
final SimpleBean bean = new SimpleBean(0, "test");
ClassUtils.checkGettersNotNull(bean);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testCheckGettersForNullForbiddenArray()
{
ClassUtils.checkGettersNotNull(new Object[0]);
}
@Test
public void testCheckGettersForNullListOK()
{
final SimpleBean bean1 = new SimpleBean(1, "test");
final SimpleBean bean2 = new SimpleBean(5, "test2");
final List<SimpleBean> beanList = Arrays.asList(bean1, bean2);
assert ClassUtils.checkGettersNotNull(beanList) == beanList;
}
@Test(expectedExceptions = IllegalStateException.class)
public void testCheckGettersForNullListInt0()
{
final SimpleBean bean1 = new SimpleBean(1, "test");
final SimpleBean bean2 = new SimpleBean(0, "test2");
ClassUtils.checkGettersNotNull(Arrays.asList(bean1, bean2));
}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment