Eu encontrei uma maneira de obter membros herdados via class.getDeclaredFields();
e acesso a membros privados via class.getFields()
Mas estou procurando por campos herdados privados. Como posso conseguir isso?
Eu encontrei uma maneira de obter membros herdados via class.getDeclaredFields();
e acesso a membros privados via class.getFields()
Mas estou procurando por campos herdados privados. Como posso conseguir isso?
Respostas:
Isso deve demonstrar como resolvê-lo:
import java.lang.reflect.Field;
class Super {
private int i = 5;
}
public class B extends Super {
public static void main(String[] args) throws Exception {
B b = new B();
Field f = b.getClass().getSuperclass().getDeclaredField("i");
f.setAccessible(true);
System.out.println(f.get(b));
}
}
(Ou Class.getDeclaredFields
para uma matriz de todos os campos.)
Resultado:
5
getSuperclass()
até chegar null
se quiser ir mais alto.
getDeclaredFields()[0]
ou, em getDeclaredField("i")
vez disso, repete o [0]
acesso à matriz nas próximas duas instruções?
getDeclaredFields
. A resposta foi atualizada.
A melhor abordagem aqui é usar o padrão de visitante para localizar todos os campos na classe e todas as superclasses e executar uma ação de retorno de chamada neles.
Spring tem uma boa classe Utility ReflectionUtils
que faz exatamente isso: define um método para fazer um loop em todos os campos de todas as superclasses com um retorno de chamada:ReflectionUtils.doWithFields()
Invoque o retorno de chamada fornecido em todos os campos da classe de destino, subindo na hierarquia de classes para obter todos os campos declarados.
Parâmetros:
- clazz - a classe de destino a ser analisada
- fc - o callback a ser invocado para cada campo
- ff - o filtro que determina os campos aos quais aplicar o callback
ReflectionUtils.doWithFields(RoleUnresolvedList.class,
new FieldCallback(){
@Override
public void doWith(final Field field) throws IllegalArgumentException,
IllegalAccessException{
System.out.println("Found field " + field + " in type "
+ field.getDeclaringClass());
}
},
new FieldFilter(){
@Override
public boolean matches(final Field field){
final int modifiers = field.getModifiers();
// no static fields please
return !Modifier.isStatic(modifiers);
}
});
Encontrado campo private transient boolean javax.management.relation.RoleUnresolvedList.typeSafe na classe de tipo javax.management.relation.RoleUnresolvedList
Campo encontrado private transient boolean javax.management.relation.RoleUnresolvedList.tainted na classe de tipo javax.managementUnresolvedList
. private transient java.lang.Object [] java.util.ArrayList.elementData no tipo classe java.util.ArrayList
Campo encontrado private int java.util.ArrayList.size no tipo classe java.util.ArrayList
Campo encontrado protegido transiente int java. util.AbstractList.modCount na classe de tipo java.util.AbstractList
Isso vai resolver:
private List<Field> getInheritedPrivateFields(Class<?> type) {
List<Field> result = new ArrayList<Field>();
Class<?> i = type;
while (i != null && i != Object.class) {
Collections.addAll(result, i.getDeclaredFields());
i = i.getSuperclass();
}
return result;
}
Se você usa uma ferramenta de cobertura de código como o EclEmma , deve ficar atento: eles adicionam um campo oculto a cada uma de suas classes. No caso do EclEmma, esses campos são marcados como sintéticos e você pode filtrá-los assim:
private List<Field> getInheritedPrivateFields(Class<?> type) {
List<Field> result = new ArrayList<Field>();
Class<?> i = type;
while (i != null && i != Object.class) {
for (Field field : i.getDeclaredFields()) {
if (!field.isSynthetic()) {
result.add(field);
}
}
i = i.getSuperclass();
}
return result;
}
public static Field getField(Class<?> clazz, String fieldName) {
Class<?> tmpClass = clazz;
do {
try {
Field f = tmpClass.getDeclaredField(fieldName);
return f;
} catch (NoSuchFieldException e) {
tmpClass = tmpClass.getSuperclass();
}
} while (tmpClass != null);
throw new RuntimeException("Field '" + fieldName
+ "' not found on class " + clazz);
}
(com base nesta resposta)
Na verdade, eu uso uma hierarquia de tipo complexa, então sua solução não está completa. Preciso fazer uma chamada recursiva para obter todos os campos herdados privados. Aqui está minha solução
/**
* Return the set of fields declared at all level of class hierachy
*/
public Vector<Field> getAllFields(Class clazz) {
return getAllFieldsRec(clazz, new Vector<Field>());
}
private Vector<Field> getAllFieldsRec(Class clazz, Vector<Field> vector) {
Class superClazz = clazz.getSuperclass();
if(superClazz != null){
getAllFieldsRec(superClazz, vector);
}
vector.addAll(toVector(clazz.getDeclaredFields()));
return vector;
}
Eu precisava adicionar suporte para campos herdados para blueprints no Model Citizen . Eu deduzi esse método que é um pouco mais conciso para recuperar os campos + campos herdados de uma classe.
private List<Field> getAllFields(Class clazz) {
List<Field> fields = new ArrayList<Field>();
fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
Class superClazz = clazz.getSuperclass();
if(superClazz != null){
fields.addAll(getAllFields(superClazz));
}
return fields;
}
private static Field getField(Class<?> clazz, String fieldName) {
Class<?> tmpClass = clazz;
do {
for ( Field field : tmpClass.getDeclaredFields() ) {
String candidateName = field.getName();
if ( ! candidateName.equals(fieldName) ) {
continue;
}
field.setAccessible(true);
return field;
}
tmpClass = tmpClass.getSuperclass();
} while ( clazz != null );
throw new RuntimeException("Field '" + fieldName +
"' not found on class " + clazz);
}