Accesso a campi ereditati privati ​​tramite riflessione in Java

Ho trovato un modo per ottenere membri ereditati tramite class.getDeclaredFields(); e accesso ai membri privati ​​tramite class.getFields() Ma sto cercando campi ereditati privati. Come posso raggiungere questo objective?

Questo dovrebbe dimostrare come risolverlo:

 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[] fs = b.getClass().getSuperclass().getDeclaredFields(); fs[0].setAccessible(true); System.out.println(fs[0].get(b)); } } 

Produzione:

 5 

L’approccio migliore in questo caso è l’utilizzo del pattern Visitor per trovare tutti i campi della class e tutte le super classi ed eseguire un’azione di callback su di essi.


Implementazione

Spring ha una buona class di utilità ReflectionUtils che fa proprio questo: definisce un metodo per eseguire il loop su tutti i campi di tutte le super classi con un callback: ReflectionUtils.doWithFields()

Documentazione:

Richiamare il callback specificato su tutti i campi della class di destinazione, risalendo la gerarchia delle classi per ottenere tutti i campi dichiarati.

parametri:
– clazz: la class target da analizzare
– fc – la richiamata da richiamare per ogni campo
– ff – il filtro che determina i campi per applicare la richiamata a

Codice d’esempio:

 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); } }); 

Produzione:

Campo trovato transiente privato booleano javax.management.relation.RoleUnresolvedList.typeSafe nella class tipo javax.management.relation.RoleUnresolvedList
Campo trovato transiente privato booleano javax.management.relation.RoleUnresolvedList.tainted nella class tipo javax.management.relation.RoleUnresolvedList
Campo trovato transient privato java.lang.Object [] java.util.ArrayList.elementData nella class type java.util.ArrayList
Campo trovato privato int java.util.ArrayList.size nella class type java.util.ArrayList
Campo transitorio protetto trovato int java.util.AbstractList.modCount nella class del tipo java.util.AbstractList

Questo lo farà:

 private List getInheritedPrivateFields(Class type) { List result = new ArrayList(); Class i = type; while (i != null && i != Object.class) { Collections.addAll(result, i.getDeclaredFields()); i = i.getSuperclass(); } return result; } 

Se usi uno strumento di copertura del codice come Eclemma , devi stare attento: aggiungono un campo nascosto a ciascuna delle tue classi. Nel caso di EclEmma, ​​questi campi sono contrassegnati come sintetici e puoi filtrarli in questo modo:

 private List getInheritedPrivateFields(Class type) { List result = new ArrayList(); 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); } 

(basato su questa risposta)

In effetti io uso una gerarchia di tipo complesso, quindi la soluzione non è completa. Devo effettuare una chiamata ricorsiva per ottenere tutti i campi ereditati privati. Ecco la mia soluzione

  /** * Return the set of fields declared at all level of class hierachy */ public Vector getAllFields(Class clazz) { return getAllFieldsRec(clazz, new Vector()); } private Vector getAllFieldsRec(Class clazz, Vector vector) { Class superClazz = clazz.getSuperclass(); if(superClazz != null){ getAllFieldsRec(superClazz, vector); } vector.addAll(toVector(clazz.getDeclaredFields())); return vector; } 
 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); } 

Avevo bisogno di aggiungere il supporto per i campi ereditati per i modelli in Model Citizen . Ho derivato questo metodo che è un po ‘più conciso per il recupero di campi di una class + campi ereditati.

 private List getAllFields(Class clazz) { List fields = new ArrayList(); fields.addAll(Arrays.asList( clazz.getDeclaredFields() )); Class superClazz = clazz.getSuperclass(); if(superClazz != null){ fields.addAll( getAllFields(superClazz) ); } return fields; }