2017-10-31 2 views
2

Ich versuche, private Merkmal Feld in Tests zu verwenden. Sehr einfaches Beispiel:Erhalten Sie private Feld in Scala-Eigenschaft mit Java-Reflektion

//Works fine with class A, but not trait A 
trait A { 
    private val foo = "Some string" 
} 

class Test extends A { 
    val field = classOf[A].getDeclaredField("foo") 
    field.setAccessible(true) 
    val str = field.get(this).asInstanceOf[String] 
} 

Ich habe:

java.lang.NoSuchFieldException: foo bei java.lang.Class.getDeclaredField

anschauliches Beispiel here

Wie diesen Snippet ausführbar machen?

+0

Wie Sie aus dem Beispiel sehen können, wirft es auch einen Fehler – Pavel

+0

Ok. Aber wie vermeide ich das? – Oleg

+0

Vielleicht kann [diese] (https://stackoverflow.com/questions/7708485/scala-class-getfields) Antwort helfen? – jrook

Antwort

4

A ist eine Eigenschaft, die Scala in eine JVM-Schnittstelle übersetzt. Schnittstellen können keine Felder haben, daher gibt es kein solches Feld. Das zugrunde liegende Feld wird erst hinzugefügt, wenn die Schnittstelle tatsächlich in eine Klasse gemischt ist.

Also die erste Sache, die Sie tun müssen, ist das Ausführen ist Änderung classOf[A] zu classOf[Test]. Die zweite Sache ist, getDeclaredField("foo") zu .getDeclaredField("A$$foo") zu ändern.

+0

Seth du hast es! Woher wusstest du, dass der Wert, der als String gestellt werden sollte, "A $$ foo" war? –

+0

Ich untersuchte die Ausgabe von 'javap -private Test'. Beachten Sie, dass die Details zur Codierung von Merkmalen von Scala-Version zu Scala-Version variieren können. –

+0

Sie Regeln! wirklich, ich fügte es meiner ursprünglichen Antwort, aber zitieren Sie, ich hoffe, Sie bekommen die richtige Kredit für das, ich war eine lange Zeit versucht, herauszufinden, dass ich auch für die Ausgabe, Genie; Ausschau gehalten;) –

2

bearbeiten besonderer Dank an @Seth Tisue (bis Stimmen und akzeptiert ihn bitte)

class Test extends A { 
    val field:Field = this.getClass.getDeclaredField("A$$foo") 

    field.setAccessible(true) 

    println(field.get(this).asInstanceOf[String]) 

} 

"A $$ foo" ist der richtige Weg, um das Super-type-Attribut, diese und verwenden this.getClass zu erhalten . Ich wusste es vorher nicht, aber mit dieser Korrektur funktioniert dein Code einfach großartig!

Erste Idee:

trait A { 
    private val foo = "Some string" 
} 


class Test extends A { 
    val fields: Seq[Field] = this.getClass.getDeclaredFields.toList 

    val field = fields.filter(x => { 
    println(x.getName) 
    x.getName.contains("foo") 
    }).head 

    field.setAccessible(true) 

    println(field.get(this).asInstanceOf[String]) 

} 

Wie Sie sehen können, wenn Sie den Namen des "foo" Variable drucken, ist nicht wirklich "foo", es ist etwas anderes:

A$A295$A$A295$A$$foo 

in meinem Fall, und das ist, warum Sie (und ich)

java.lang.NoSuchFieldException: foo at java.lang.Class.getDeclaredField 

Also den Fehler bekam, mein i Ich hoffe, jemand kam mit einem besseren, ist schauen, ob "foo" innerhalb des Variablennamens "A $ A295 $ A $ A295 $ A $$ foo" ist, so können Sie sagen, das ist die Variable, die Sie suchen.

Verwandte Themen