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