java—使用反射验证trait的所有示例都有一个唯一字段

qxgroojn  于 2021-06-30  发布在  Java
关注(0)|答案(1)|浏览(451)

考虑以下代码。动物应该有一个唯一的id。我想动态验证(在测试中)动物的所有具体子类型都有唯一的id。我想我的测试失败,如果,例如,猫和鱼都试图通过 uniqueId = 2.

sealed trait Animal {
  val uniqueId: Int
}

abstract class Mammal(val uniqueId: Int) extends Animal

abstract class Fish(val uniqueId: Int) extends Animal

case class Dog(age: Int, name: String) extends Mammal(1)

case class Cat(favouriteFood: String) extends Mammal(2)

case class Salmon(isCute: Boolean) extends Fish(3)

我用反射来上课。

import org.reflections.Reflections
    val reflections                 = new Reflections("package.blah")
    val allSubtypes: Seq[Class[_ <: Animal]] = reflections.getSubTypesOf(classOf[Animal]).asScala.toList
    val concreteSubtypes: Seq[Class[_ <: Animal]] = allSubtypes.filter(c => !Modifier.isAbstract(c.getModifiers))

我开始怀疑这可能是不可能的,但我希望是错误的!我有这些类,但无法示例化它们的示例,因为所有构造函数都不同,我不确定是否可以访问 uniqueId 从班级里。

hiz5n14c

hiz5n14c1#

正如托默谢塔赫的评论所说,这似乎不可能如所说。但如果你能分开的话,它可能会起作用 Animal 以及 AnimalCompanion ,并根据 AnimalCompanion :

abstract class AnimalCompanion(val uniqueId: Int)

sealed trait Animal {
  def companion: AnimalCompanion
  def uniqueId = companion.uniqueId
}

abstract class Mammal(val companion: AnimalCompanion) extends Animal

abstract class Fish(val companion: AnimalCompanion) extends Animal

case class Dog(age: Int, name: String) extends Mammal(Dog)

object Dog extends AnimalCompanion(1)

case class Cat(favouriteFood: String) extends Mammal(Cat)

object Cat extends AnimalCompanion(2)

case class Salmon(isCute: Boolean) extends Fish(Salmon)

object Salmon extends AnimalCompanion(3)

然后你会发现 AnimalCompanion 以同样的方式,因为他们都是 object 他们会有 MODULE$ 包含示例的字段,该示例将具有 uniqueId 场和吸气剂法。
在没有测试的情况下,这样的方法应该是可行的:

val allCompanionClasses = reflections.getSubTypesOf(classOf[AnimalCompanion]).asScala
val allCompanionInstances = allCompanionClasses.map(_.getField("MODULE$").get(null))
val allUniqueIds = allCompanionInstances.map(x => x.getClass().getMethod("uniqueId").invoke(x))

然后还要检查它们是否是唯一的,例如

allUniqueIds.toSet.size == allUniqueIds.size

在不改变结构的情况下,我会考虑另一种方法:自己提供示例,验证它们是否包含所有类。

val instances = Set(Dog(0, ""), Cat(""), Salmon(true))

// allSubtypes defined in the question
assert(allSubtypes.toSet == instances.map(_.getClass))
// same logic as above but we already have a Set
assert(instances.map(_.uniqueId).size == instances.size)

相关问题