Spring + Scala + 匿名块或 class

Spring + Scala + anonymous block or class

我不知道为什么,但如果实例变量文本是私有的,下面的 class 就不起作用,但如果我省略私有的,它就起作用了。

调试 "setField" 部分的测试我可以看到实例变量名称应该是 "text" 但它变成了 "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"
    })
  }
}

我认为问题出在 "getOrElse" 上,因为如果我也省略了,它会起作用。

Scala 编译器有权将您的私有字段编译成任何可用的 java 代码,因为它不会影响互操作性(如果您不采取任何技巧)。 Spring 的 setField 实际上做了这样的把戏,因为它使您的私有字段可访问(setAccessible(true) 内部)。 Public 字段总是按原样编译,以便从 Java 为您提供适当的接口。

使用 http://docs.scala-lang.org/overviews/reflection/environment-universes-mirrors.html to work with Scala reflection. Also this article 可能会有帮助。

Here 解释了为什么 scalac 使用另一个名称作为私有字段。

P.S。删除 .getOrElse(text) 使它起作用的原因是因为除了这段代码之外,您没有在任何地方使用 text

这个class只是为了说明问题,实际上和真正的class有很大的不同。所以我改变了策略,通过@Autowired 方法而不是@Autowired 字段接收实例。

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

我没有在这个示例中使用@Autowired,但在真实的 class 中我是。因此,如果您需要获取实例,请按照以下说明进行操作。

项目 1 -> 如果我使用 @Autowired 它不起作用,因为就像说的那样 dk14 Scala 编译器有权将您的私有字段编译成任何工作 java代码。因此,编译器在编译 class

时更改字段名称

项目 2 -> 我在 setter 方法中添加了 @Autowired,它起作用了。