diff --git a/common/source/java/ch/systemsx/cisd/common/annotation/BeanNameMapping.java b/common/source/java/ch/systemsx/cisd/common/annotation/BeanNameMapping.java new file mode 100644 index 0000000000000000000000000000000000000000..c31459ab9c5a7dcd286e3f5ae5a3fc0c46a82505 --- /dev/null +++ b/common/source/java/ch/systemsx/cisd/common/annotation/BeanNameMapping.java @@ -0,0 +1,41 @@ +/* + * Copyright 2007 ETH Zuerich, CISD + * + * 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 ch.systemsx.cisd.common.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * An annotation that allows to override the name mapping of beans, i.e. that a setter requires a getter on the source + * bean with same name. + * + * @author Bernd Rinn + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +@Inherited +public @interface BeanNameMapping +{ + + /** + * The names to look for among the getters instead of the setter name. + */ + String[] names(); +} diff --git a/common/source/java/ch/systemsx/cisd/common/annotation/CollectionMapping.java b/common/source/java/ch/systemsx/cisd/common/annotation/CollectionMapping.java new file mode 100644 index 0000000000000000000000000000000000000000..1792e6091f5a08e672943bed80564a57d7db0669 --- /dev/null +++ b/common/source/java/ch/systemsx/cisd/common/annotation/CollectionMapping.java @@ -0,0 +1,46 @@ +/* + * Copyright 2007 ETH Zuerich, CISD + * + * 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 ch.systemsx.cisd.common.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.Collection; + +/** + * An annotation that defines the type of collection and the type of elements to use when creating the collection in a + * bean context. + * + * @author Bernd Rinn + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +@Inherited +public @interface CollectionMapping +{ + /** + * The concrete class to use as a collection. + */ + Class<? extends Collection> collectionClass(); + + /** + * The class to use as the elements of the collection (since the generics type isn't known at run time). + */ + Class<?> elementClass(); +} diff --git a/common/source/java/ch/systemsx/cisd/common/utilities/BeanUtils.java b/common/source/java/ch/systemsx/cisd/common/utilities/BeanUtils.java index 583c71a2b8758b72e3cc697df0e320f3631a4eea..b9e2e8002fd88b6cadb374e2b3740290dcec1e03 100644 --- a/common/source/java/ch/systemsx/cisd/common/utilities/BeanUtils.java +++ b/common/source/java/ch/systemsx/cisd/common/utilities/BeanUtils.java @@ -22,11 +22,32 @@ import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.lang.annotation.Annotation; +import java.lang.reflect.Array; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Arrays; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.lang.StringUtils; + +import ch.systemsx.cisd.common.annotation.BeanNameMapping; +import ch.systemsx.cisd.common.annotation.CollectionMapping; +import ch.systemsx.cisd.common.exceptions.CheckedExceptionTunnel; /** * Some utilities around <i>Java Bean</i>s. * * @author Christian Ribeaud + * @author Bernd Rinn */ public final class BeanUtils { @@ -68,4 +89,632 @@ public final class BeanUtils encoder.close(); return result; } + + /** + * 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 isPublic() + throw new Error("Cannot call method '" + method.getName() + "'."); + } + } + } + return beanToCheck; + } + + private static boolean isNull(Object objectToCheck) + { + return (objectToCheck instanceof Number) && ((Number) objectToCheck).longValue() == 0; + } + + /** + * A map that provides annotations for given annotation classes. + */ + public interface AnnotationMap + { + /** + * Returns the name of the entity that this annotation stems from. + */ + public String getAnnotatedEntity(); + + /** + * Returns the annotation for <var>annotationClazz</var>. + */ + public <T extends Annotation> T getAnnotation(Class<T> annotationClazz); + } + + /** + * An empty {@link AnnotationMap} (to be used when there are no annotations). + */ + private static class EmptyAnnotationMap implements AnnotationMap + { + + public String getAnnotatedEntity() + { + return "GENERIC"; + } + + public <T extends Annotation> T getAnnotation(Class<T> annotationClazz) + { + return null; + } + + } + + /** + * An {@link AnnotationMap} that gets its annotation from a (setter) method. + */ + private static class SetterAnnotationMap implements AnnotationMap + { + + private final Method setterMethod; + + SetterAnnotationMap(Method setterMethod) + { + assert setterMethod != null; + + this.setterMethod = setterMethod; + } + + public String getAnnotatedEntity() + { + return setterMethod.toGenericString(); + } + + public <T extends Annotation> T getAnnotation(Class<T> annotationClazz) + { + return setterMethod.getAnnotation(annotationClazz); + } + + } + + /** + * Marker interface for converter classes. The real method are determined via reflection. A converter needs to match + * both the source and the destination bean. If the destination bean has a setter <code>setFoo(FooClass foo)</code> + * and the converter has a method <code>FooClass convertToFoo(SourceBeanClass sourceBean)</code>, then this will + * be called instead of any getter of the <var>sourceBean</var>. Note that if there is a matching method + * <code>convertToFoo()</code>, it needs to have an appropriate return type or else an + * {@link IllegalArgumentException} will be thrown. + */ + public interface Converter + { + } + + private static final AnnotationMap emptyAnnotationMap = new EmptyAnnotationMap(); + + private static final Converter nullConverter = new Converter() + { + }; + + @SuppressWarnings("unchecked") + private static final Set<Class> immutableTypes = + new HashSet<Class>(Arrays.asList(boolean.class, Boolean.class, byte.class, Byte.class, short.class, + Short.class, int.class, Integer.class, long.class, Long.class, float.class, Float.class, + double.class, Double.class, String.class, Date.class)); + + /** + * Creates a new bean of type <var>beanClass</var> and fills it with values from <var>sourceBean</var>. + */ + public static <T> T fillBean(Class<T> beanClass, Object sourceBean) + { + return fillBean(beanClass, sourceBean, emptyAnnotationMap, nullConverter); + } + + /** + * Creates a new bean of type <var>beanClass</var> and fills it with values from <var>sourceBean</var>, using the + * <var>converter</var> where appropriate. + */ + public static <T> T fillBean(Class<T> beanClass, Object sourceBean, Converter converter) + { + return fillBean(beanClass, sourceBean, emptyAnnotationMap, converter); + } + + /** + * Creates a new bean of type <var>beanClass</var> and fills it with values from <var>beanToFill</var>. + * + * @param beanClass The class to create a new instance from. + * @param sourceBean The bean to get the values from. + * @param setterAnnotations The annotations attached to the setter that can be used to determine how the result + * should be created. + */ + private static <T> T fillBean(Class<T> beanClass, Object sourceBean, AnnotationMap setterAnnotations, + Converter converter) + { + assert beanClass != null; + assert sourceBean != null; + assert setterAnnotations != null; + assert converter != null; + + try + { + final T destinationBean = instantiateBean(beanClass, sourceBean, setterAnnotations); + if (isArray(destinationBean)) + { + if (isArray(sourceBean)) + { + copyArrayToArray(destinationBean, sourceBean, converter); + } else if (isCollection(sourceBean)) + { + copyCollectionToArray(destinationBean, (Collection) sourceBean, converter); + } + } else if (isCollection(destinationBean)) + { + if (isArray(sourceBean)) + { + copyArrayToCollection((Collection) destinationBean, sourceBean, setterAnnotations, converter); + } else if (isCollection(sourceBean)) + { + copyCollectionToCollection((Collection) destinationBean, (Collection) sourceBean, + setterAnnotations, converter); + } + } else + { + copyBean(destinationBean, sourceBean, converter); + } + return destinationBean; + } catch (InvocationTargetException ex) + { + final Throwable cause = ex.getCause(); + if (cause instanceof Error) + { + throw (Error) cause; + } + throw CheckedExceptionTunnel.wrapIfNecessary((Exception) cause); + } catch (Exception ex) + { + throw CheckedExceptionTunnel.wrapIfNecessary(ex); + } + } + + private static boolean isCollection(Object o) + { + return o instanceof Collection<?>; + } + + private static boolean isCollection(Class<?> clazz) + { + return Collection.class.isAssignableFrom(clazz); + } + + private static boolean isArray(Object o) + { + return o.getClass().isArray(); + } + + private static boolean isArray(final Class<?> clazz) + { + return clazz.isArray(); + } + + private static <T> T instantiateBean(Class<T> beanClass, Object sourceBean, AnnotationMap setterAnnotations) + throws InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException + { + if (sourceBean == null) + { + return null; + } + final boolean beanIsArray = isArray(beanClass); + final boolean beanIsCollection = isCollection(beanClass); + if (beanIsArray || beanIsCollection) + { + final Integer size = getSize(sourceBean); + if (size == null) + { + return null; + } + if (beanIsArray) + { + return createArray(beanClass, size); + } + if (beanIsCollection) + { + return createCollection(beanClass, size, setterAnnotations); + } + } + return beanClass.newInstance(); + } + + private static Integer getSize(Object o) + { + if (isArray(o)) + { + return Array.getLength(o); + } else if (isCollection(o)) + { + return ((Collection) o).size(); + } else + { // Don't know how to get the size of o. + return null; + } + } + + @SuppressWarnings("unchecked") + private static <T> T createArray(Class<T> beanClass, int length) throws NegativeArraySizeException + { + return (T) Array.newInstance(beanClass.getComponentType(), length); + } + + private static <T> T createCollection(Class<T> beanClass, int size, AnnotationMap setterAnnotations) + throws InstantiationException, IllegalAccessException, SecurityException, NoSuchMethodException, + IllegalArgumentException, InvocationTargetException + { + final CollectionMapping mapping = setterAnnotations.getAnnotation(CollectionMapping.class); + if (mapping == null) + { + throw new IllegalArgumentException("No collection mapping specified for '" + + setterAnnotations.getAnnotatedEntity() + "'."); + } + try + { + final Constructor<? extends Collection> constructorWithSize = + mapping.collectionClass().getConstructor(new Class[] + { int.class }); + return constructCollection(constructorWithSize, size); + } catch (NoSuchMethodException ex) + { // Happens e.g. for a LinkedList + return constructCollection(mapping.collectionClass()); + } + } + + @SuppressWarnings("unchecked") + private static <T> T constructCollection(final Constructor<? extends Collection> constructorWithSize, int size) + throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException + { + // This conversion _can_ go wrong if the concrete collection class doesn't implement the right sub-interface of + // collection, e.g. when using a HashSet as concrete collection class where a List is required. + return (T) constructorWithSize.newInstance(new Object[] + { size }); + } + + @SuppressWarnings("unchecked") + private static <T> T constructCollection(final Class<? extends Collection> collectionClazz) + throws InstantiationException, IllegalAccessException + { + // This conversion _can_ go wrong if the concrete collection class doesn't implement the right sub-interface of + // collection, e.g. when using a HashSet as concrete collection class where a List is required. + return (T) collectionClazz.newInstance(); + } + + private static void copyArrayToArray(Object destination, Object source, Converter converter) + throws IllegalAccessException, InvocationTargetException + { + if (destination == null) + { + return; + } + final Class<?> componentType = destination.getClass().getComponentType(); + final int length = Array.getLength(destination); + if (immutableTypes.contains(componentType)) + { + if (componentType == source.getClass().getComponentType()) + { + System.arraycopy(source, 0, destination, 0, length); + } else + { + for (int index = 0; index < length; ++index) + { + final Object sourceElement = Array.get(source, index); + Array.set(destination, index, sourceElement); + } + } + } else + { + for (int index = 0; index < length; ++index) + { + final Object sourceElement = Array.get(source, index); + final Object destinationElement = fillBean(componentType, sourceElement, converter); + Array.set(destination, index, destinationElement); + } + } + } + + private static void copyCollectionToArray(Object destination, Collection source, Converter converter) + throws IllegalAccessException, InvocationTargetException + { + if (destination == null) + { + return; + } + assert Array.getLength(destination) == source.size(); + final Class<?> componentType = destination.getClass().getComponentType(); + if (immutableTypes.contains(componentType)) + { + int index = 0; + for (Object sourceElement : source) + { + Array.set(destination, index++, sourceElement); + } + } else + { + int index = 0; + for (Object sourceElement : source) + { + final Object destinationElement = fillBean(componentType, sourceElement, converter); + Array.set(destination, index++, destinationElement); + } + } + } + + private static void copyArrayToCollection(Collection destination, Object source, AnnotationMap setterAnnotations, + Converter converter) + { + if (destination == null) + { + return; + } + final Class<?> componentType = getCollectionComponentType(setterAnnotations); + final int length = getSize(source); + if (immutableTypes.contains(componentType)) + { + for (int index = 0; index < length; ++index) + { + final Object sourceElement = Array.get(source, index); + addToUntypedCollection(destination, sourceElement); + } + } else + { + for (int index = 0; index < length; ++index) + { + final Object sourceElement = Array.get(source, index); + final Object destinationElement = fillBean(componentType, sourceElement, converter); + addToUntypedCollection(destination, destinationElement); + } + } + } + + private static void copyCollectionToCollection(Collection destination, Collection source, + AnnotationMap setterAnnotations, Converter converter) + { + if (destination == null) + { + return; + } + final Class<?> componentType = getCollectionComponentType(setterAnnotations); + if (immutableTypes.contains(componentType)) + { + for (Object sourceElement : source) + { + addToUntypedCollection(destination, sourceElement); + } + } else + { + for (Object sourceElement : source) + { + final Object destinationElement = fillBean(componentType, sourceElement, converter); + addToUntypedCollection(destination, destinationElement); + } + } + } + + @SuppressWarnings("unchecked") + private static void addToUntypedCollection(Collection destination, Object element) + { + destination.add(element); + } + + private static Class<?> getCollectionComponentType(AnnotationMap setterAnnotations) + { + final CollectionMapping mapping = setterAnnotations.getAnnotation(CollectionMapping.class); + if (mapping == null) + { + throw new IllegalArgumentException("No collection mapping specified for '" + + setterAnnotations.getAnnotatedEntity() + "'."); + } + return mapping.elementClass(); + } + + private static void copyBean(Object destination, Object source, Converter converter) throws IllegalAccessException, + InvocationTargetException + { + if (destination == null) + { + return; + } + final Collection<Method> destinationSetters = scanForPublicMethods(destination, "set", 1).values(); + final Map<String, Method> sourceGetters = scanForPublicMethods(source, "get", 0); + scanForPublicMethods(source, sourceGetters, "is", 0, boolean.class, Boolean.class); + for (Method setter : destinationSetters) + { + final Object newBean = emergeNewBean(setter, source, sourceGetters, converter); + if (newBean != null) + { + try + { + setter.invoke(destination, new Object[] + { newBean }); + } catch (IllegalArgumentException ex) + { + final String defaultJavaArgumentTypeMismatchMessage = "argument type mismatch"; + if (defaultJavaArgumentTypeMismatchMessage.equals(ex.getMessage())) + { + throw new IllegalArgumentException(defaultJavaArgumentTypeMismatchMessage + ": method '" + + setter.toGenericString() + "': cannot assign from '" + + newBean.getClass().getCanonicalName() + "'."); + } else + { + throw ex; + } + } + } + } + } + + private static Object emergeNewBean(Method setter, Object source, Map<String, Method> sourceGetters, + Converter converter) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException + { + final AnnotationMap annotationMap = new SetterAnnotationMap(setter); + final Method converterMethod = getConverterMethod(setter, source, converter); + if (converterMethod != null) + { + return converterMethod.invoke(converter, new Object[] + { source }); + } + final Method getter = getGetter(setter, sourceGetters, annotationMap); + if (getter == null) + { + return null; + } + final Object oldBean = getter.invoke(source, new Object[0]); + final Class<?> parameterType = setter.getParameterTypes()[0]; + if (parameterType.isPrimitive() || immutableTypes.contains(parameterType)) + { + return oldBean; + } else + { + return fillBean(parameterType, oldBean, annotationMap, converter); + } + } + + private static Method getConverterMethod(Method setter, Object sourceBean, Converter converter) + { + if (converter != nullConverter) + { + try + { + final Method converterMethod = + converter.getClass().getMethod("convertTo" + setter.getName().substring("set".length()), + new Class[] + { sourceBean.getClass() }); + if (converterMethod.isAccessible() == false) + { + converterMethod.setAccessible(true); + } + return converterMethod; + } catch (NoSuchMethodException ex) + { + // Nothing to do here - there just isn't any converter method for this setter. + } + } + return null; + } + + private static Method getGetter(Method setter, Map<String, Method> sourceGetters, AnnotationMap annotationMap) + { + final BeanNameMapping mapping = annotationMap.getAnnotation(BeanNameMapping.class); + if (mapping != null) + { + return getGetter(sourceGetters, getGetterPrefix(setter), mapping.names()); + } + final String getterName = getGetterPrefix(setter) + setter.getName().substring("set".length()); + final Method getter = sourceGetters.get(getterName); + return getter; + } + + private static Method getGetter(Map<String, Method> sourceGetters, String prefix, String... attributeNames) + { + for (String attributeName : attributeNames) + { + final String getterName = prefix + StringUtils.capitalize(attributeName); + final Method getter = sourceGetters.get(getterName); + if (getter != null) + { + return getter; + } + } + return null; + } + + private static String getGetterPrefix(final Method setter) + { + final Class<?> type = setter.getParameterTypes()[0]; + if (type == boolean.class || type == Boolean.class) + { + return "is"; + } else + { + return "get"; + } + } + + private static Map<String, Method> scanForPublicMethods(Object bean, String prefix, int numberOfParameters) + { + final Map<String, Method> methodMap = new HashMap<String, Method>(); + scanForPublicMethods(bean, methodMap, prefix, numberOfParameters, (Set<Class<?>>) null); + return methodMap; + } + + private static void scanForPublicMethods(Object bean, Map<String, Method> methodMap, String prefix, + int numberOfParameters, Class<?>... returnValueTypes) + { + scanForPublicMethods(bean, methodMap, prefix, numberOfParameters, new HashSet<Class<?>>(Arrays + .asList(returnValueTypes))); + } + + private static void scanForPublicMethods(Object bean, Map<String, Method> methodMap, String prefix, + int numberOfParameters, Set<Class<?>> returnValueTypes) + { + for (Method method : bean.getClass().getMethods()) + { + final String methodName = method.getName(); + if (methodName.startsWith(prefix) && method.getParameterTypes().length == numberOfParameters + && Modifier.isPublic(method.getModifiers())) + { + if (returnValueTypes == null || returnValueTypes.contains(method.getReturnType())) + { + methodMap.put(methodName, method); + } + } + } + } + } diff --git a/common/source/java/ch/systemsx/cisd/common/utilities/ClassUtils.java b/common/source/java/ch/systemsx/cisd/common/utilities/ClassUtils.java index 1dc886c0e430bda91f7811a3701053236298e9dd..52c49a45bed355d9e0c93f45d68c9d4a3a5c968c 100644 --- a/common/source/java/ch/systemsx/cisd/common/utilities/ClassUtils.java +++ b/common/source/java/ch/systemsx/cisd/common/utilities/ClassUtils.java @@ -18,9 +18,7 @@ package ch.systemsx.cisd.common.utilities; import java.lang.reflect.Field; import java.lang.reflect.InvocationHandler; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.lang.reflect.Modifier; import java.lang.reflect.Proxy; import java.util.ArrayList; import java.util.Arrays; @@ -186,81 +184,4 @@ public final class ClassUtils .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; - } - } diff --git a/common/sourceTest/java/ch/systemsx/cisd/common/utilities/BeanUtilsTest.java b/common/sourceTest/java/ch/systemsx/cisd/common/utilities/BeanUtilsTest.java index b2a2f7ee13c033abd5f0df5084bc83bd6ce8264d..a89f99c71adcb67cc23c671c68c31054a095274d 100644 --- a/common/sourceTest/java/ch/systemsx/cisd/common/utilities/BeanUtilsTest.java +++ b/common/sourceTest/java/ch/systemsx/cisd/common/utilities/BeanUtilsTest.java @@ -16,16 +16,30 @@ package ch.systemsx.cisd.common.utilities; +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertNotNull; +import static org.testng.AssertJUnit.assertNull; + import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.LinkedList; import java.util.List; -import static org.testng.AssertJUnit.*; +import org.apache.commons.lang.StringUtils; +import org.testng.AssertJUnit; import org.testng.annotations.Test; +import ch.systemsx.cisd.common.annotation.BeanNameMapping; +import ch.systemsx.cisd.common.annotation.CollectionMapping; + /** * Test cases for the {@link BeanUtils} class. * * @author Christian Ribeaud + * @author Bernd Rinn */ public final class BeanUtilsTest { @@ -48,8 +62,8 @@ public final class BeanUtilsTest String xml = BeanUtils.xmlEncode(list); List newList = (List) BeanUtils.xmlDecode(xml); assert newList.size() == 2; - assertEquals(((SimpleBean)newList.get(0)).getFirstName(), "Tanja"); - assertEquals(((SimpleBean)newList.get(1)).getLastName(), "Ribeaud"); + assertEquals(((SimpleBean) newList.get(0)).getFirstName(), "Tanja"); + assertEquals(((SimpleBean) newList.get(1)).getLastName(), "Ribeaud"); } // This MUST be public. @@ -83,4 +97,896 @@ public final class BeanUtilsTest this.lastName = lastName; } } + + private static class SimpleBean2 + { + private final int number; + + private final String string; + + SimpleBean2(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 SimpleBean2 bean = new SimpleBean2(1, ""); + assert BeanUtils.checkGettersNotNull(bean) == bean; + } + + @Test + public void testCheckGettersForNullOKNullBean() + { + assertNull(BeanUtils.checkGettersNotNull(null)); + } + + @Test(expectedExceptions = IllegalStateException.class) + public void testCheckGettersForNullStringNull() + { + final SimpleBean2 bean = new SimpleBean2(1, null); + BeanUtils.checkGettersNotNull(bean); + } + + @Test(expectedExceptions = IllegalStateException.class) + public void testCheckGettersForNullInt0() + { + final SimpleBean2 bean = new SimpleBean2(0, "test"); + BeanUtils.checkGettersNotNull(bean); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testCheckGettersForNullForbiddenArray() + { + BeanUtils.checkGettersNotNull(new Object[0]); + } + + @Test + public void testCheckGettersForNullListOK() + { + final SimpleBean2 bean1 = new SimpleBean2(1, "test"); + final SimpleBean2 bean2 = new SimpleBean2(5, "test2"); + final List<SimpleBean2> beanList = Arrays.asList(bean1, bean2); + assert BeanUtils.checkGettersNotNull(beanList) == beanList; + } + + @Test(expectedExceptions = IllegalStateException.class) + public void testCheckGettersForNullListInt0() + { + final SimpleBean2 bean1 = new SimpleBean2(1, "test"); + final SimpleBean2 bean2 = new SimpleBean2(0, "test2"); + BeanUtils.checkGettersNotNull(Arrays.asList(bean1, bean2)); + } + + public static class Bean1a + { + private int i; + + private String s; + + private boolean b; + + private float f; + + public boolean isB() + { + return b; + } + + public void setB(boolean b) + { + this.b = b; + } + + public float getF() + { + return f; + } + + public void setF(float f) + { + this.f = f; + } + + public int getI() + { + return i; + } + + public void setI(int i) + { + this.i = i; + } + + public String getS() + { + return s; + } + + public void setS(String s) + { + this.s = s; + } + } + + public static class Bean1b + { + private Integer i; + + private String s; + + private Boolean b; + + private Float f; + + public Boolean isB() + { + return b; + } + + public void setB(Boolean b) + { + this.b = b; + } + + public Float getF() + { + return f; + } + + public void setF(Float f) + { + this.f = f; + } + + public Integer getI() + { + return i; + } + + public void setI(Integer i) + { + this.i = i; + } + + public String getS() + { + return s; + } + + public void setS(String s) + { + this.s = s; + } + } + + public static class Bean2a + { + private int i; + + private String s; + + private boolean b; + + private float f; + + public boolean isB() + { + return b; + } + + public void setB(boolean b) + { + this.b = b; + } + + public float getF() + { + return f; + } + + public void setF(float f) + { + this.f = f; + } + + public int getI() + { + return i; + } + + public void setI(int i) + { + this.i = i; + } + + public String getS() + { + return s; + } + + public void setS(String s) + { + this.s = s; + } + } + + public static class Bean2b + { + private Integer i; + + private String s; + + private Boolean b; + + private Float f; + + public Boolean isB() + { + return b; + } + + public void setB(Boolean b) + { + this.b = b; + } + + public Float getF() + { + return f; + } + + public void setF(Float f) + { + this.f = f; + } + + public Integer getI() + { + return i; + } + + public void setI(Integer i) + { + this.i = i; + } + + public String getS() + { + return s; + } + + public void setS(String s) + { + this.s = s; + } + } + + @Test + public void testFillSimpleBean() + { + final Bean1a b1 = new Bean1a(); + b1.setB(true); + b1.setF(0.2f); + b1.setI(17); + b1.setS("test"); + final Bean2a b2 = BeanUtils.fillBean(Bean2a.class, b1); + assertBeansAreEqual("Beans are not equal", b1, b2); + } + + @Test + public void testFillSimpleBeanWithNativeWrapper1() + { + final Bean1b b1 = new Bean1b(); + b1.setB(true); + b1.setF(0.2f); + b1.setI(17); + b1.setS("test"); + final Bean2a b2 = BeanUtils.fillBean(Bean2a.class, b1); + assertEquals(b1.isB().booleanValue(), b2.isB()); + assertEquals(b1.getF().floatValue(), b2.getF()); + assertEquals(b1.getI().intValue(), b2.getI()); + assertEquals(b1.getS(), b2.getS()); + } + + @Test + public void testFillSimpleBeanWithNativeWrapper2() + { + final Bean1a b1 = new Bean1a(); + b1.setB(true); + b1.setF(0.2f); + b1.setI(17); + b1.setS("test"); + final Bean2b b2 = BeanUtils.fillBean(Bean2b.class, b1); + assertEquals(b1.isB(), b2.isB().booleanValue()); + assertEquals(b1.getF(), b2.getF().floatValue()); + assertEquals(b1.getI(), b2.getI().intValue()); + assertEquals(b1.getS(), b2.getS()); + } + + @Test + public void testFillSimpleBeanWithNativeWrapper3() + { + final Bean1b b1 = new Bean1b(); + b1.setB(true); + b1.setF(0.2f); + b1.setI(17); + b1.setS("test"); + final Bean2b b2 = BeanUtils.fillBean(Bean2b.class, b1); + assertEquals(b1.isB().booleanValue(), b2.isB().booleanValue()); + assertEquals(b1.getF().floatValue(), b2.getF().floatValue()); + assertEquals(b1.getI().intValue(), b2.getI().intValue()); + assertEquals(b1.getS(), b2.getS()); + } + + @Test + public void testFillSimpleBeanArray() + { + final Bean1a b1a = new Bean1a(); + b1a.setB(true); + b1a.setF(0.2f); + b1a.setI(17); + b1a.setS("test"); + final Bean1a b1b = new Bean1a(); + b1b.setB(false); + b1b.setF(0.3f); + b1b.setI(42); + b1b.setS("ttt"); + final Bean1a[] b1Array = new Bean1a[] + { b1a, b1b }; + final Bean2a[] b2Array = BeanUtils.fillBean(Bean2a[].class, b1Array); + assertEquals(b1Array.length, b2Array.length); + for (int i = 0; i < b1Array.length; ++i) + { + final Bean1a b1 = b1Array[i]; + final Bean2a b2 = b2Array[i]; + assertNotNull("Element " + i, b2); + assertEquals("Element " + i, b1.isB(), b2.isB()); + assertEquals("Element " + i, b1.getF(), b2.getF()); + assertEquals("Element " + i, b1.getI(), b2.getI()); + assertEquals("Element " + i, b1.getS(), b2.getS()); + } + } + + @Test + public void testFillPrimitiveArray() + { + final int[] array = new int[] + { -5, 17, 0, 88 }; + final int[] array2 = BeanUtils.fillBean(int[].class, array); + assert Arrays.equals(array, array2); + } + + @Test + public void testFillPrimitiveArrayToWrapper() + { + final int[] array = new int[] + { -5, 17, 0, 88 }; + final Integer[] array2 = BeanUtils.fillBean(Integer[].class, array); + for (int i = 0; i < array.length; ++i) + { + assertEquals("Element " + i, array[i], array2[i].intValue()); + } + } + + @Test + public void testFillPrimitiveArrayFromWrapper() + { + final Integer[] array = new Integer[] + { -5, 17, 0, 88 }; + final int[] array2 = BeanUtils.fillBean(int[].class, array); + for (int i = 0; i < array.length; ++i) + { + assertEquals("Element " + i, array[i].intValue(), array2[i]); + } + } + + @Test + public void testFillImmutableArray() + { + final String[] array = new String[] + { "apple", "orange", "banana" }; + final String[] array2 = BeanUtils.fillBean(String[].class, array); + for (int i = 0; i < array.length; ++i) + { + assertEquals("Element " + i, array[i], array2[i]); + } + } + + public static class ArrayWrapper1 + { + private byte[] array; + + public byte[] getArray() + { + return array; + } + + public void setArray(byte[] array) + { + this.array = array; + } + } + + public static class ArrayWrapper2 + { + private Byte[] array; + + public Byte[] getArray() + { + return array; + } + + public void setArray(Byte[] array) + { + this.array = array; + } + } + + public static class ArrayWrapper3 + { + private String[] array; + + public String[] getArray() + { + return array; + } + + public void setArray(String[] array) + { + this.array = array; + } + } + + @Test + public void testFillBeanWithPrimitiveArray() + { + final ArrayWrapper1 awrapper = new ArrayWrapper1(); + awrapper.setArray(new byte[] + { -1, 0, 100, -88 }); + final ArrayWrapper1 awrapper2 = BeanUtils.fillBean(ArrayWrapper1.class, awrapper); + final byte[] array = awrapper.getArray(); + final byte[] array2 = awrapper2.getArray(); + assertNotNull(array2); + assertEquals(array.length, array.length); + for (int i = 0; i < array.length; ++i) + { + assertEquals("Element " + i, array[i], array2[i]); + } + } + + @Test + public void testFillBeanWithPrimitiveWrapperArray() + { + final ArrayWrapper1 awrapper = new ArrayWrapper1(); + awrapper.setArray(new byte[] + { -1, 0, 100, -88 }); + final ArrayWrapper2 awrapper2 = BeanUtils.fillBean(ArrayWrapper2.class, awrapper); + final byte[] array = awrapper.getArray(); + final Byte[] array2 = awrapper2.getArray(); + assertNotNull(array2); + assertEquals(array.length, array.length); + for (int i = 0; i < array.length; ++i) + { + assertEquals("Element " + i, array[i], array2[i].byteValue()); + } + } + + public static class CollectionWrapper1 + { + private List<String> array; + + public List<String> getArray() + { + return array; + } + + @CollectionMapping(collectionClass = ArrayList.class, elementClass = String.class) + public void setArray(List<String> array) + { + this.array = array; + } + } + + @Test + public void testFillArrayBeanFromCollectionBean() + { + final CollectionWrapper1 colWrapper = new CollectionWrapper1(); + final List<String> list = Arrays.asList("blue", "yellow", "green"); + colWrapper.setArray(list); + final ArrayWrapper3 aWrapper = BeanUtils.fillBean(ArrayWrapper3.class, colWrapper); + final String[] array = aWrapper.getArray(); + assertNotNull(array); + assertEquals(list.size(), array.length); + for (int i = 0; i < array.length; ++i) + { + assertEquals("Element " + i, list.get(i), array[i]); + } + } + + @Test + public void testFillCollectionBeanFromArrayBean() + { + final ArrayWrapper3 aWrapper = new ArrayWrapper3(); + final String[] array = new String[] + { "hot", "warm", "cool", "icy" }; + aWrapper.setArray(array); + final CollectionWrapper1 colWrapper = BeanUtils.fillBean(CollectionWrapper1.class, aWrapper); + List<String> list = colWrapper.getArray(); + assertNotNull(list); + assertEquals(array.length, list.size()); + for (int i = 0; i < array.length; ++i) + { + assertEquals("Element " + i, array[i], list.get(i)); + } + } + + @Test + public void testFillCollectionBeanFromCollectionBean() + { + final CollectionWrapper1 colWrapper = new CollectionWrapper1(); + final List<String> list = new ArrayList<String>(Arrays.asList(new String[] + { "hot", "warm", "cool", "icy" })); + colWrapper.setArray(list); + final CollectionWrapper1 colWrapper2 = BeanUtils.fillBean(CollectionWrapper1.class, colWrapper); + List<String> list2 = colWrapper2.getArray(); + assertNotNull(list2); + assertEquals(list.size(), list2.size()); + for (int i = 0; i < list.size(); ++i) + { + assertEquals("Element " + i, list.get(i), list2.get(i)); + } + } + + public static class BeanWithBean1 + { + private Bean1a bean; + + public Bean1a getBean() + { + return bean; + } + + public void setBean(Bean1a bean) + { + this.bean = bean; + } + } + + public static class BeanWithBean2 + { + private Bean2a bean; + + public Bean2a getBean() + { + return bean; + } + + public void setBean(Bean2a bean) + { + this.bean = bean; + } + } + + @Test + public void testFillComplexBean() + { + final Bean1a b1 = new Bean1a(); + b1.setB(true); + b1.setF(0.2f); + b1.setI(17); + b1.setS("test"); + final BeanWithBean1 b3 = new BeanWithBean1(); + b3.setBean(b1); + final BeanWithBean2 b4 = BeanUtils.fillBean(BeanWithBean2.class, b3); + final Bean2a b2 = b4.getBean(); + assertBeansAreEqual("Bean comparison", b1, b2); + } + + public static class BeanWithBeanArray1 + { + private Bean1a[] bean; + + public Bean1a[] getBeanArray() + { + return bean; + } + + public void setBeanArray(Bean1a[] bean) + { + this.bean = bean; + } + } + + public static class BeanWithBeanArray2 + { + private Bean2a[] bean; + + public Bean2a[] getBeanArray() + { + return bean; + } + + public void setBeanArray(Bean2a[] bean) + { + this.bean = bean; + } + } + + public static class BeanWithBeanCollection1 + { + private Collection<Bean1a> bean; + + public Collection<Bean1a> getBeanArray() + { + return bean; + } + + @CollectionMapping(collectionClass = LinkedHashSet.class, elementClass = Bean1a.class) + public void setBeanArray(Collection<Bean1a> bean) + { + this.bean = bean; + } + } + + public static class BeanWithBeanCollection2 + { + private Collection<Bean2a> bean; + + public Collection<Bean2a> getBeanArray() + { + return bean; + } + + @CollectionMapping(collectionClass = LinkedList.class, elementClass = Bean2a.class) + public void setBeanArray(Collection<Bean2a> bean) + { + this.bean = bean; + } + } + + @Test + public void testFillBeanWithBeanCollectionFromBeanWithBeanArray1() + { + final Bean1a b1a = new Bean1a(); + b1a.setB(true); + b1a.setF(0.2f); + b1a.setI(17); + b1a.setS("test"); + final Bean1a b1b = new Bean1a(); + b1b.setB(false); + b1b.setF(1.1f); + b1b.setI(31); + b1b.setS("test2"); + final BeanWithBeanArray1 b1Array = new BeanWithBeanArray1(); + final Bean1a[] arrayb1 = new Bean1a[] + { b1a, b1b }; + b1Array.setBeanArray(arrayb1); + final BeanWithBeanCollection2 b2Collection = BeanUtils.fillBean(BeanWithBeanCollection2.class, b1Array); + final Collection<Bean2a> colb2 = b2Collection.getBeanArray(); + assertNotNull(colb2); + assertEquals(arrayb1.length, colb2.size()); + final Iterator<Bean2a> itb2 = colb2.iterator(); + for (int i = 0; i < arrayb1.length; ++i) + { + assertBeansAreEqual("Element " + i, arrayb1[i], itb2.next()); + } + } + + @Test + public void testFillBeanWithBeanCollectionFromBeanWithBeanArray2() + { + final Bean2a b2a = new Bean2a(); + b2a.setB(true); + b2a.setF(0.2f); + b2a.setI(17); + b2a.setS("test"); + final Bean2a b2b = new Bean2a(); + b2b.setB(false); + b2b.setF(1.1f); + b2b.setI(31); + b2b.setS("test2"); + final BeanWithBeanArray2 b2Array = new BeanWithBeanArray2(); + final Bean2a[] arrayb2 = new Bean2a[] + { b2a, b2b }; + b2Array.setBeanArray(arrayb2); + final BeanWithBeanCollection1 b1Collection = BeanUtils.fillBean(BeanWithBeanCollection1.class, b2Array); + final Collection<Bean1a> colb1 = b1Collection.getBeanArray(); + assertNotNull(colb1); + assertEquals(arrayb2.length, colb1.size()); + final Iterator<Bean1a> itb1 = colb1.iterator(); + for (int i = 0; i < arrayb2.length; ++i) + { + assertBeansAreEqual("Element " + i, arrayb2[i], itb1.next()); + } + } + + @Test + public void testFillBeanWithBeanArrayFromBeanWithBeanCollection() + { + final Bean1a b1a = new Bean1a(); + b1a.setB(true); + b1a.setF(0.2f); + b1a.setI(17); + b1a.setS("test"); + final Bean1a b1b = new Bean1a(); + b1b.setB(false); + b1b.setF(1.1f); + b1b.setI(31); + b1b.setS("test2"); + final BeanWithBeanCollection1 b1Collection = new BeanWithBeanCollection1(); + final Collection<Bean1a> colb1 = new LinkedHashSet<Bean1a>(Arrays.asList(new Bean1a[] + { b1a, b1b })); + b1Collection.setBeanArray(colb1); + final BeanWithBeanArray2 b2Array = BeanUtils.fillBean(BeanWithBeanArray2.class, b1Collection); + final Bean2a[] arrayb2 = b2Array.getBeanArray(); + assertNotNull(arrayb2); + assertEquals(colb1.size(), arrayb2.length); + int i = 0; + for (Bean1a b1 : colb1) + { + assertBeansAreEqual("Element " + i, b1, arrayb2[i]); + ++i; + } + } + + @Test + public void testFillBeanWithBeanArrayFromBeanWithBeanArray() + { + final Bean1a b1a = new Bean1a(); + b1a.setB(true); + b1a.setF(0.2f); + b1a.setI(17); + b1a.setS("test"); + final Bean1a b1b = new Bean1a(); + b1b.setB(false); + b1b.setF(1.1f); + b1b.setI(31); + b1b.setS("test2"); + final BeanWithBeanArray1 b1Array = new BeanWithBeanArray1(); + final Bean1a[] arrayb1 = new Bean1a[] + { b1a, b1b }; + b1Array.setBeanArray(arrayb1); + final BeanWithBeanArray2 b2Array = BeanUtils.fillBean(BeanWithBeanArray2.class, b1Array); + final Bean2a[] arrayb2 = b2Array.getBeanArray(); + assertNotNull(arrayb2); + assertEquals(arrayb1.length, arrayb2.length); + for (int i = 0; i < arrayb1.length; ++i) + { + assertBeansAreEqual("Element " + i, arrayb1[i], arrayb2[i]); + } + } + + @Test + public void testFillBeanWithBeanCollectionFromBeanWithBeanCollection() + { + final Bean1a b1a = new Bean1a(); + b1a.setB(true); + b1a.setF(0.2f); + b1a.setI(17); + b1a.setS("test"); + final Bean1a b1b = new Bean1a(); + b1b.setB(false); + b1b.setF(1.1f); + b1b.setI(31); + b1b.setS("test2"); + final BeanWithBeanCollection1 b1Collection = new BeanWithBeanCollection1(); + final Collection<Bean1a> colb1 = new LinkedHashSet<Bean1a>(Arrays.asList(new Bean1a[] + { b1a, b1b })); + b1Collection.setBeanArray(colb1); + final BeanWithBeanCollection2 b2Collection = BeanUtils.fillBean(BeanWithBeanCollection2.class, b1Collection); + final Collection<Bean2a> colb2 = b2Collection.getBeanArray(); + assertNotNull(colb2); + assertEquals(colb1.size(), colb2.size()); + final Iterator<Bean2a> itb2 = colb2.iterator(); + int i = 0; + for (Bean1a b1 : colb1) + { + assertBeansAreEqual("Element " + (i++), b1, itb2.next()); + } + } + + private void assertBeansAreEqual(String msg, Bean1a b1, Bean2a b2) + { + assertNotNull(msg, b1); + assertNotNull(msg, b2); + assertEquals(msg, b1.isB(), b2.isB()); + assertEquals(msg, b1.getF(), b2.getF()); + assertEquals(msg, b1.getI(), b2.getI()); + assertEquals(msg, b1.getS(), b2.getS()); + } + + private void assertBeansAreEqual(String msg, Bean2a b2, Bean1a b1) + { + assertNotNull(msg, b1); + assertNotNull(msg, b2); + assertEquals(msg, b2.isB(), b1.isB()); + assertEquals(msg, b2.getF(), b1.getF()); + assertEquals(msg, b2.getI(), b1.getI()); + assertEquals(msg, b2.getS(), b1.getS()); + } + + public static class FooBean + { + private String foo; + + public String getFoo() + { + return foo; + } + + public void setFoo(String foo) + { + this.foo = foo; + } + } + + public static class BarBean + { + private String bar; + + public String getBar() + { + return bar; + } + + @BeanNameMapping(names = {"bar", "foo"}) + public void setBar(String bar) + { + this.bar = bar; + } + } + + @Test + public void testNameMapping1() + { + final FooBean fooBean = new FooBean(); + fooBean.setFoo("foo is now bar"); + final BarBean barBean = BeanUtils.fillBean(BarBean.class, fooBean); + assertEquals(fooBean.getFoo(), barBean.getBar()); + } + + @Test + public void testNameMapping2() + { + final BarBean barBean = new BarBean(); + barBean.setBar("bar is still bar"); + final BarBean barBean2 = BeanUtils.fillBean(BarBean.class, barBean); + assertEquals(barBean.getBar(), barBean2.getBar()); + } + + @Test + public void testConverter() + { + final FooBean tofuBean = new FooBean(); + tofuBean.setFoo("some tofu"); + final BarBean toFooBean = BeanUtils.fillBean(BarBean.class, tofuBean, new BeanUtils.Converter() + { + @SuppressWarnings("unused") + public String convertToBar(FooBean foo) + { + return StringUtils.replace(foo.getFoo(), "tofu", "to Foo"); + } + }); + assertEquals("some to Foo", toFooBean.getBar()); + } } diff --git a/common/sourceTest/java/ch/systemsx/cisd/common/utilities/ClassUtilsTest.java b/common/sourceTest/java/ch/systemsx/cisd/common/utilities/ClassUtilsTest.java index a18b8f1864149cc113045f2b496beea0de5e9380..ebaa9f1cd0662aaebbbc83a31cbfc54ec8f7d054 100644 --- a/common/sourceTest/java/ch/systemsx/cisd/common/utilities/ClassUtilsTest.java +++ b/common/sourceTest/java/ch/systemsx/cisd/common/utilities/ClassUtilsTest.java @@ -16,12 +16,8 @@ package ch.systemsx.cisd.common.utilities; -import static org.testng.AssertJUnit.*; +import static org.testng.AssertJUnit.assertEquals; -import java.util.Arrays; -import java.util.List; - -import org.testng.AssertJUnit; import org.testng.annotations.Test; /** @@ -59,83 +55,4 @@ public final class ClassUtilsTest } } - 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)); - } - }