Package com.jayway.awaitility.reflect

Source Code of com.jayway.awaitility.reflect.WhiteboxImpl

/*
* Copyright 2008 the original author or authors.
*
* 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.jayway.awaitility.reflect;

import com.jayway.awaitility.reflect.exception.FieldNotFoundException;
import com.jayway.awaitility.reflect.exception.TooManyFieldsFoundException;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

/**
* Various utilities for accessing internals of a class. Basically a simplified
* reflection utility. Copied with permission from PowerMock project.
*/
public class WhiteboxImpl {

    /**
     * Get the value of a field using reflection. This method will iterate
     * through the entire class hierarchy and return the value of the first
     * field named <tt>fieldName</tt>. If you want to get a specific field value
     * at specific place in the class hierarchy please refer to
     *
     * @param <T>       the generic type
     * @param object    the object to modify
     * @param fieldName the name of the field
     * @return the internal state.
     */
    @SuppressWarnings("unchecked")
    public static <T> T getInternalState(Object object, String fieldName) {
        Field foundField = findFieldInHierarchy(object, fieldName);
        try {
            return (T) foundField.get(object);
        } catch (IllegalAccessException e) {
            throw new RuntimeException("Internal error: Failed to get field in method getInternalState.", e);
        }
    }

    /**
     * Find field in hierarchy.
     *
     * @param object    the object
     * @param fieldName the field name
     * @return the field
     */
    private static Field findFieldInHierarchy(Object object, String fieldName) {
        return findFieldInHierarchy(object, new FieldNameMatcherStrategy(fieldName));
    }

    /**
     * Find field in hierarchy.
     *
     * @param object   the object
     * @param strategy the strategy
     * @return the field
     */
    private static Field findFieldInHierarchy(Object object, FieldMatcherStrategy strategy) {
        assertObjectInGetInternalStateIsNotNull(object);
        return findSingleFieldUsingStrategy(strategy, object, true, getType(object));
    }

    /**
     * Assert object in get internal state is not null.
     *
     * @param object the object
     */
    private static void assertObjectInGetInternalStateIsNotNull(Object object) {
        if (object == null) {
            throw new IllegalArgumentException("The object containing the field cannot be null");
        }
    }

    /**
     * Find single field using strategy.
     *
     * @param strategy       the strategy
     * @param object         the object
     * @param checkHierarchy the check hierarchy
     * @param startClass     the start class
     * @return the field
     */
    private static Field findSingleFieldUsingStrategy(FieldMatcherStrategy strategy, Object object,
                                                      boolean checkHierarchy, Class<?> startClass) {
        assertObjectInGetInternalStateIsNotNull(object);
        Field foundField = null;
        final Class<?> originalStartClass = startClass;
        while (startClass != null) {
            final Field[] declaredFields = startClass.getDeclaredFields();
            for (Field field : declaredFields) {
                if (strategy.matches(field) && hasFieldProperModifier(object, field)) {
                    if (foundField != null) {
                        throw new TooManyFieldsFoundException("Two or more fields matching " + strategy + ".");
                    }
                    foundField = field;
                }
            }
            if (foundField != null) {
                break;
            } else if (checkHierarchy == false) {
                break;
            }
            startClass = startClass.getSuperclass();
        }
        if (foundField == null) {
            strategy.notFound(originalStartClass, !isClass(object));
        }
        foundField.setAccessible(true);
        return foundField;
    }

    /**
     * Checks for field proper modifier.
     *
     * @param object the object
     * @param field  the field
     * @return true, if successful
     */
    private static boolean hasFieldProperModifier(Object object, Field field) {
        return ((object instanceof Class<?> && Modifier.isStatic(field.getModifiers())) || ((object instanceof Class<?> == false && Modifier
                .isStatic(field.getModifiers()) == false)));
    }

    /**
     * Get the value of a field using reflection. This method will traverse the
     * super class hierarchy until the first field of type <tt>fieldType</tt> is
     * found. The value of this field will be returned.
     *
     * @param <T>       the generic type
     * @param object    the object to modify
     * @param fieldType the type of the field
     * @return the internal state
     */
    @SuppressWarnings("unchecked")
    public static <T> T getInternalState(Object object, Class<T> fieldType) {
        Field foundField = findFieldInHierarchy(object, new AssignableToFieldTypeMatcherStrategy(fieldType));
        try {
            return (T) foundField.get(object);
        } catch (IllegalAccessException e) {
            throw new RuntimeException("Internal error: Failed to get field in method getInternalState.", e);
        }
    }

    /**
     * Throw exception if field was not found.
     *
     * @param type      the type
     * @param fieldName the field name
     * @param fieldName the field name
     * @param field     the field
     */
    public static void throwExceptionIfFieldWasNotFound(Class<?> type, String fieldName, Field field) {
        if (field == null) {
            throw new FieldNotFoundException("No field was found with name '" + fieldName + "' in class "
                    + type.getName() + ".");
        }
    }

    /**
     * Gets the type.
     *
     * @param object the object
     * @return The type of the of an object.
     */
    public static Class<?> getType(Object object) {
        Class<?> type = null;
        if (isClass(object)) {
            type = (Class<?>) object;
        } else if (object != null) {
            type = object.getClass();
        }
        return type;
    }

    /**
     * Get field annotated with a particular annotation. This method traverses
     * the class hierarchy when checking for the annotation.
     *
     * @param object         The object to look for annotations. Note that if're you're
     *                       passing an object only instance fields are checked, passing a
     *                       class will only check static fields.
     * @param annotationType The annotation types to look for
     * @return A set of all fields containing the particular annotation(s).
     * @since 1.3
     */
    public static Field getFieldAnnotatedWith(Object object, Class<? extends Annotation> annotationType) {
        return findSingleFieldUsingStrategy(new FieldAnnotationMatcherStrategy(annotationType), object, true,
                getType(object));
    }

    /**
     * Checks if is class.
     *
     * @param argument the argument
     * @return a boolean.
     */
    public static boolean isClass(Object argument) {
        return argument instanceof Class<?>;
    }

    /**
     * <p>getByNameAndType.</p>
     *
     * @param object a {@link java.lang.Object} object.
     * @param fieldName a {@link java.lang.String} object.
     * @param expectedFieldType a {@link java.lang.Class} object.
     * @param <T> a T object.
     * @return a T object.
     */
    @SuppressWarnings("unchecked")
    public static <T> T getByNameAndType(Object object, String fieldName, Class<T> expectedFieldType) {
        Field foundField = findSingleFieldUsingStrategy(new FieldNameAndTypeMatcherStrategy(fieldName,
                expectedFieldType), object, true, getType(object));
        try {
            return (T) foundField.get(object);
        } catch (IllegalAccessException e) {
            throw new RuntimeException("Internal error: Failed to get field in method getInternalState.", e);
        }
    }
}
TOP

Related Classes of com.jayway.awaitility.reflect.WhiteboxImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.