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