2009-10-11 15 views
7

Ho una situazione in cui il codice di un utente sta lanciando un IllegalAccessException su un campo a cui si accede per riflessione. Appena prima di accedere al campo, viene chiamato setAccessible(true). Quindi, mi sembra che questo metodo stia silenziosamente fallendo.In quali situazioni il field.setAccessible (true) di Java fallirà?

In quali situazioni ciò accadrebbe? Questo potrebbe avere qualcosa a che fare con un responsabile della sicurezza?

Ecco il frammento di codice che causa l'eccezione:

private static Field levelField; 
public int getLevel() { 
    try { 
     if (levelField == null) { 
      levelField = MessageInfo.class.getDeclaredField("level"); 
      levelField.setAccessible(true); 
     } 
     return levelField.getInt(this); // <-- IllegalAccessException thrown here 
    } catch (Exception e) { 
     handleException(e); 
    } 
    return ICompilationUnit.NO_AST; 
} 
+1

Stampare il messaggio di eccezione e lo stacktrace sarebbe utile. – NawaMan

risposta

4

setAccessible è documentato per lanciare un SecurityException. Si noti che la documentazione fornisce casi in cui SecurityException verrà lanciato anche se non è presente SecurityManager. Naturalmente potrebbe anche non riuscire a causa di un'eccezione asincrona: Thread.stop, eccezione relativa al buffer NIO o un errore JVM.

Il vero problema con questo codice (oltre a quello che utilizza la riflessione) è che c'è un campo che può essere impostato per essere parzialmente inizializzato. Ciò causa una condizione di competizione (hai una statica mutabile, quindi devi preoccuparti dei thread (suggerimento, evitare statiche mutabili!)).Un altro thread può chiamare getInt sullo stesso Field prima che venga chiamato setAccessible. E come sembra essere stato scoperto dall'interlocutore originale, non è nemmeno un'eccezione. Sarebbe molto più sicuro e più chiaro impostare il campo in un inizializzatore statico.

+0

Questo ha molto senso per me. Grazie. Non so se questo è il problema che sto vedendo, ma sembra possibile perché so che più thread sono noti per abitare quella parte del codice. Ma anche se questo non è il vero problema, dovrei cambiare il mio codice. –

0

Da Java propria documentation per setAccessible():

Un SecurityException viene generato se flag è vero, ma l'accessibilità di uno degli elementi dell'array di input non può essere modificato (ad esempio, se l'oggetto elemento è un oggetto Constructor per la classe Class). Nel caso di tale SecurityException, l'accessibilità degli oggetti è impostata per contrassegnare gli elementi dell'array fino a (ed escludere) l'elemento per il quale si è verificata l'eccezione; l'accessibilità degli elementi oltre (e compresi) l'elemento per il quale si è verificata l'eccezione è rimasta invariata.

Purtroppo non menzionano nulla di un IllegalAccessException.

6

Non dovrebbe essere un problema di security manager - si otterrebbe un SecurityException o sottoclasse.

Il codice levelField.getInt(*this*) non sembra giusto ...

si dovrebbe essere passando un'istanza MessageInfo come parametro.

Stai chiamando questo all'interno della classe MessageInfo? (perché?!?) o una sottoclasse di MessageInfo? (Cercando di fare un campo privato di un atto superclasse come se fosse protetto? Vuol MessageInfo hanno un metodo di getLevel()? Se è così, si potrebbe chiamare super.getLevel() per ottenere il valore invece di tentare in questo modo.)

Se non è MessageInfo o una sottoclasse, questo è il tuo problema: hai il campo level della classe MessageInfo e stai cercando di ottenere il valore di quel campo dalla classe corrente. Anche se questo dovrebbe essere gettando un IllegalArgumentExeception invece di IllegalAccessException ...

Se è davvero 'IllegalAccessExeception' - prova a mettere un po 'di registrazione dentro quella if (levelField == null) blocca - assicurarsi che sia davvero di essere exececuted. Il campo è statico: potrebbero esserci altre istanze o metodi che impostano un valore su di esso.

+0

Sì, questa classe è una sottoclasse della classe MessageInfo, che fa parte di un framework che sto utilizzando. Quindi, il campo di livello è un campo protetto da pacchetto di MessageInfo senza getter, e quindi è altrimenti inaccessibile alla mia sottoclasse. Questo codice funziona correttamente per molti, molti utenti, ma non proprio questo particolare. Quindi, mi chiedo se potrebbe esserci qualcosa di strano nel setup di questa particolare persona che sta facendo fallire la chiamata qui. Questo è quello che mi fa pensare che potrebbe essere una cosa del responsabile della sicurezza, ma mi chiedo se potrebbe esserci qualcos'altro. –

+0

Forse quell'utente ha una versione più recente/più vecchia di questo framework sul classpath? Uno dove MessageInfo.level non esiste o ha un nome diverso? Post scriptum - Che struttura è? Potrebbe aiutare a risolvere questo ... – Nate

+0

Forse, ma improbabile. Il framework che sto descrivendo è JDT di Eclipse. E questo è il codice che usiamo da almeno 3.3 (prima di aver lavorato al progetto). E ho provato questo fino a includere Eclipse 3.5.1. Come descritto da Tom nella risposta accettata, credo che potrebbe essere un problema di threading. –

Problemi correlati