Home | History | Annotate | Download | only in reflection
      1 /*
      2  * Copyright (c) 2007 Mockito contributors
      3  * This program is made available under the terms of the MIT License.
      4  */
      5 package org.mockito.internal.util.reflection;
      6 
      7 import org.mockito.internal.util.Checks;
      8 import org.mockito.internal.util.collections.ListUtil;
      9 import org.mockito.internal.util.collections.ListUtil.Filter;
     10 
     11 import java.lang.annotation.Annotation;
     12 import java.lang.reflect.Field;
     13 import java.util.ArrayList;
     14 import java.util.List;
     15 
     16 /**
     17  * Small fluent reflection tools to work with fields.
     18  *
     19  * Code is very new and might need rework.
     20  */
     21 public abstract class Fields {
     22 
     23     /**
     24      * Instance fields declared in the class and superclasses of the given instance.
     25      *
     26      * @param instance Instance from which declared fields will be retrieved.
     27      * @return InstanceFields of this object instance.
     28      */
     29     public static InstanceFields allDeclaredFieldsOf(Object instance) {
     30         List<InstanceField> instanceFields = new ArrayList<InstanceField>();
     31         for (Class<?> clazz = instance.getClass(); clazz != Object.class; clazz = clazz.getSuperclass()) {
     32             instanceFields.addAll(instanceFieldsIn(instance, clazz.getDeclaredFields()));
     33         }
     34         return new InstanceFields(instance, instanceFields);
     35     }
     36 
     37     /**
     38      * Instance fields declared in the class of the given instance.
     39      *
     40      * @param instance Instance from which declared fields will be retrieved.
     41      * @return InstanceFields of this object instance.
     42      */
     43     public static InstanceFields declaredFieldsOf(Object instance) {
     44         List<InstanceField> instanceFields = new ArrayList<InstanceField>();
     45         instanceFields.addAll(instanceFieldsIn(instance, instance.getClass().getDeclaredFields()));
     46         return new InstanceFields(instance, instanceFields);
     47     }
     48 
     49     private static List<InstanceField> instanceFieldsIn(Object instance, Field[] fields) {
     50         List<InstanceField> instanceDeclaredFields = new ArrayList<InstanceField>();
     51         for (Field field : fields) {
     52             InstanceField instanceField = new InstanceField(field, instance);
     53             instanceDeclaredFields.add(instanceField);
     54         }
     55         return instanceDeclaredFields;
     56     }
     57 
     58     /**
     59      * Accept fields annotated by the given annotations.
     60      *
     61      * @param annotations Annotation types to check.
     62      * @return The filter.
     63      */
     64     @SuppressWarnings({"unchecked", "vararg"})
     65     public static Filter<InstanceField> annotatedBy(final Class<? extends Annotation>... annotations) {
     66         return new Filter<InstanceField>() {
     67             public boolean isOut(InstanceField instanceField) {
     68                 Checks.checkNotNull(annotations, "Provide at least one annotation class");
     69 
     70                 for (Class<? extends Annotation> annotation : annotations) {
     71                     if(instanceField.isAnnotatedBy(annotation)) {
     72                         return false;
     73                     }
     74                 }
     75                 return true;
     76             }
     77         };
     78     }
     79 
     80     /**
     81      * Accept fields with non null value.
     82      *
     83      * @return The filter.
     84      */
     85     private static Filter<InstanceField> nullField() {
     86         return new Filter<InstanceField>() {
     87             public boolean isOut(InstanceField instanceField) {
     88                 return instanceField.isNull();
     89             }
     90         };
     91     }
     92 
     93     /**
     94      * Accept fields with non null value.
     95      *
     96      * @return The filter.
     97      */
     98     public static Filter<InstanceField> syntheticField() {
     99         return new Filter<InstanceField>() {
    100             public boolean isOut(InstanceField instanceField) {
    101                 return instanceField.isSynthetic();
    102             }
    103         };
    104     }
    105 
    106     public static class InstanceFields {
    107         private final Object instance;
    108 
    109         private final List<InstanceField> instanceFields;
    110 
    111         public InstanceFields(Object instance, List<InstanceField> instanceFields) {
    112             this.instance = instance;
    113             this.instanceFields = instanceFields;
    114         }
    115 
    116         public InstanceFields filter(Filter<InstanceField> withFilter) {
    117             return new InstanceFields(instance, ListUtil.filter(instanceFields, withFilter));
    118         }
    119 
    120         public InstanceFields notNull() {
    121             return filter(nullField());
    122         }
    123 
    124         public List<InstanceField> instanceFields() {
    125             return new ArrayList<InstanceField>(instanceFields);
    126         }
    127 
    128         public List<Object> assignedValues() {
    129             List<Object> values = new ArrayList<Object>(instanceFields.size());
    130             for (InstanceField instanceField : instanceFields) {
    131                 values.add(instanceField.read());
    132             }
    133             return values;
    134         }
    135 
    136         public List<String> names() {
    137             List<String> fieldNames = new ArrayList<String>(instanceFields.size());
    138             for (InstanceField instanceField : instanceFields) {
    139                 fieldNames.add(instanceField.name());
    140             }
    141             return fieldNames;
    142         }
    143     }
    144 }
    145