/** * Copyright (C) 2008 Mathieu Carbou <mathieu.carbou@gmail.com> * * 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 com.mycila.testing.core.introspect; import com.mycila.testing.MycilaTestingException; import static com.mycila.testing.core.api.Ensure.*; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Arrays; import java.util.List; /** * Handles a test instance * * @author Mathieu Carbou (mathieu.carbou@gmail.com) */ public final class Introspector { private final Object instance; public Introspector(Object instance) { notNull("Object to introspect", instance); this.instance = instance; } /** * @return The test instance */ public Object instance() { return instance; } /** * @return The test instance's class */ public Class<?> testClass() { return instance.getClass(); } /** * Select some fields. Use the {@link Filters} class to create and compose filters * * @param filter Filter to use for selection * @return A list containing the selected objects */ public List<Field> selectFields(Filter<Field> filter) { notNull("Filter", filter); for (Class<?> c = testClass(); c != Object.class; c = c.getSuperclass()) { for (Field field : c.getDeclaredFields()) { filter.add(accessible(field)); } } return filter.select(); } /** * Select some methods. Use the {@link Filters} class to create and compose filters * * @param filter Filter to use for selection * @return A list containing the selected objects */ public List<Method> selectMethods(Filter<Method> filter) { notNull("Filter", filter); for (Class<?> c = testClass(); c != Object.class; c = c.getSuperclass()) { for (Method method : c.getDeclaredMethods()) { filter.add(accessible(method)); } } return filter.select(); } /** * Invoke a method on this test instance * * @param method Method to be invoked * @param args Method argument * @return The result of the invokation */ public Object invoke(Method method, Object... args) { notNull("Method", method); notNull("Method argumentd", args); try { return method.invoke(instance(), args); } catch (IllegalAccessException e) { throw new MycilaTestingException(e, "Error invoking method '%s' with arguments: %s: %s", method, Arrays.deepToString(args), e.getMessage()); } catch (InvocationTargetException e) { throw new MycilaTestingException(e.getTargetException().getClass().getSimpleName() + ": " + e.getTargetException().getMessage(), e.getTargetException()); } catch (Exception e) { throw new MycilaTestingException(e, "Error invoking method '%s' with arguments: %s: %s", method, Arrays.deepToString(args), e.getMessage()); } } /** * Get a field's value * * @param field The field * @return The field value */ public Object get(Field field) { notNull("Field", field); try { return field.get(instance()); } catch (Exception e) { throw new MycilaTestingException(e, "Error getting value of field '%s' on test class '%s': %s", field, testClass().getName(), e.getMessage()); } } /** * Set a field value * * @param field The field * @param value The new field value */ public void set(Field field, Object value) { notNull("Field", field); try { field.set(instance(), value); } catch (Exception e) { throw new MycilaTestingException(e, "Error setting value on field '%s' on test class '%s': %s", field, testClass().getName(), e.getMessage()); } } public boolean hasAnnotation(Class<? extends Annotation> annot) { notNull("Annotation", annot); return testClass().isAnnotationPresent(annot); } }