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