简体   繁体   中英

Spring + Scala + anonymous block or class

I don't know why but the class below doesn't work if instance variable text is private, but if I leave out private, it works.

Debugging the test in section "setField" I could see that the instance variable name should be "text" but it becomes "com$test$SimpleTest$$text"

package com.test
import org.testng.annotations.Test
import org.springframework.test.util.ReflectionTestUtils

class SimpleTest {
  private var text = ""

  @Test
  def testValueOfX(): Unit = {
    val simpleTest = new SimpleTest
    ReflectionTestUtils.setField(simpleTest,"text", "abc")

    println(
      Option[String](null)
        .map(v => v + " 123")
        .getOrElse {
          simpleTest.text + " 321"
    })
  }
}

I believe that the problem someway be the "getOrElse" because if I leave out too, it works.

Scala compiler has a right to compile your private field into an any working java code, as it doesn't affect interoperability (if you don't do any tricks). Spring's setField actually do such trick, as it makes your private field accessible ( setAccessible(true) inside). Public fields are always compiling as is to give you appropriate interface from Java.

Use http://docs.scala-lang.org/overviews/reflection/environment-universes-mirrors.html to work with Scala reflection. Also this article may be helpful.

Here is explanation why scalac uses another name for private field.

PS The reason why removing .getOrElse(text) make it work is because you don't use text anywhere but inside this piece of code.

This class is only to show the problem, actually it is very different of real class. So I changed the strategy to receive an instance by @Autowired a method instead @Autowired a field.

package com.test
import org.testng.annotations.Test
import org.springframework.test.util.ReflectionTestUtils

class SimpleTest {
  // item 1
  private var text = ""

  @Test
  def testValueOfX(): Unit = {
    val simpleTest = new SimpleTest
    ReflectionTestUtils.invokeSetterMethod(simpleTest, "text", "abc")

    println(
          Option[String](null)
        .map(v => v + " 123")
        .getOrElse {
        simpleTest.text + " 321"
      })
  }
  // item 2
  def setText(text: String): Unit = {
    this.text = text
  }
}

I'm not using @Autowired in this sample but in the real class I am. So if you need to get an instance follow instructions below.

Item 1 -> if I put on @Autowired it doesn't work because like said Scala compiler has a right to compile your private field into an any working java code. Scala编译器有权将您的私有字段编译成任何有效的Java代码。 So, the compiler change the field's name when it compiles the class

Item 2 -> I put on @Autowired in the setter method, it works.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM