当前位置: 首页 > 知识库问答 >
问题:

如何强制初始化子级-父级关系?

曹泉
2023-03-14

我有一个配置元素的层次结构,它们都实现了一个接口(简化了):

interface Configuration {
    val elements: Long
    val data: Long?
    var parent: Configuration?
}

实现将由jackson-kotlin读取如下所示的Yaml文件来构建:

checks:
  elements: 10
  data: 1234
  ports:
    elements: 5

代码可能会执行同样的操作:

CheckConfig(elements = 10, data = 1234, portConfig = PortConfig(elements = 5))
inline fun <reified T: Configuration> T.updateChildLinks() {
    (this::class as KClass<T>).memberProperties.forEach {
        if (it.returnType.isSubtypeOf(Configuration::class.createType(nullable = true))) {
            it.isAccessible = true
            val config: Configuration = it.get(this) as Configuration
            config.parent = this
        }
    }
}

并在每个父级的init块中调用它。我能做得更好吗(特别是,我不喜欢我必须记住在init阶段调用helper函数)?

编辑后添加:以前,我有一个只使用代码的解决方案,它将数据沿链传递:

CheckConfig(elements = 10, data = 1234, 
        portConfig = PortConfig(elements = 5, parentData = 1234))

然后使用data查看parentdata,但我在使用Jackson时遇到了麻烦。

共有1个答案

颛孙正谊
2023-03-14

因此,为了将来的参考,下面是我的结论:

诀窍是承认我的数据类不能有指向其父类的链接,因为子类将在其父类之前构造。

但是,我可以利用Jackson来解决最初的回退问题,方法是实现一个自定义的反序列化器,该反序列化器跟踪父属性值并应用它(如果缺少该值)。

唯一的缺点是,反序列化器只知道属性值被反序列化之后(显然),所以不能将它传递给可能需要它的子值。因此,这将错误地给出123,而它应该是345:

top:
  data: 123
  sub:
    subsub:
      important: false
    data: 345

但如果您可以控制,那么您可以使用以下命令:

class PropInheritance : JsonDeserializer<Long>() {
    override fun deserialize(p: JsonParser, ctxt: DeserializationContext): Long {
        val currentContextName = p.parsingContext
                .pathAsPointer().toString()
                // cut the last "prop" variable name
                .replaceAfterLast("/", "")
        val prop = p.longValue
        val propStack = initStackIfNeeded(ctxt)
        propStack.push(currentContextName to prop)
        return prop
    }

    override fun getNullValue(ctxt: DeserializationContext): Long {
        val propStack = initStackIfNeeded(ctxt)

        // here, the prop name is missing the context is just the parent
        val currentContextName = ctxt.parser.parsingContext
                .pathAsPointer().toString()
        // find a prop on stack that has the same path
        while (propStack.isNotEmpty() 
                && !currentContextName.startsWith(propStack.peek().first)) {
            propStack.pop()
        }

        val prop = if (propStack.isNotEmpty()) 
                       propStack.peek().second
                   else 
                       ctxt.getAttribute("default") as Long

        // record current prop on the stack so potential children can find it
        propStack.push(currentContextName to prop)
        return prop
    }

    private fun initStackIfNeeded(ctxt: DeserializationContext)
            : Deque<Pair<String, Long>> {
        if (ctxt.getAttribute("stack") == null) {
            ctxt.setAttribute("stack", ArrayDeque<Pair<String, Long>>())
        }
        return ctxt.getAttribute("stack") as Deque<Pair<String, Long>>
    }
}

在我的示例中,我使用了一个混合项来将@JsonDeserialize(using=PropInherity::class)应用于我的接口方法的getter:

interface HasProp {
    val prop: Long
}

interface HasPropMixin {
    @JsonDeserialize(using = PropInheritance::class)
    fun getProp(): Long
}

mapper = ObjectMapper(YAMLFactory()).registerModule(KotlinModule())
    .addMixin(HasProp::class.java, HasPropMixin::class.java)
 类似资料:
  • 问题内容: 在Python中,请考虑以下代码: 如何在子类中初始化?我正在关注Python教程,但没有涵盖。当我在Google上搜索时,发现了不止一种方法。处理此问题的标准方法是什么? 问题答案: Python(直到第3版)支持“旧式”和新式类。新样式类派生自您使用的类,并通过调用它们的基类,例如 因为python了解旧样式和新样式的类,所以有不同的方法可以调用基本方法,这就是为什么您找到了多种方

  • 问题内容: 我有一个具有以下结构的网站: 导航在左侧,内容div在右侧。内容div的信息是通过PHP获取的,因此每次都不同。 无论加载哪个页面,如何垂直缩放导航使其高度与内容div的高度相同? 问题答案: 注意 :此答案适用于不支持Flexbox标准的旧版浏览器。 我建议您看看使用Cross-Browser CSS和NoHacks的等高列。 基本上,以与浏览器兼容的方式使用CSS做到这一点并不是一

  • 我有一份抽象的课堂报告: 我需要强制所有子类填充此 surrogateId 属性。(如果子类未填充属性,则会出现编译错误) 我尝试使用 final 关键字来强制我在构造函数中引入此属性的值,但我必须手动生成构造函数而不是使用 Lombok,很多样板代码。有没有办法在不手动生成结构的情况下实现相同的期望。

  • 问题内容: public class A{ private int getC(){ return 0; } } 您能告诉我是否有可能通过java中的反射来做一些吸引人的事情吗? 问题答案: class A{ 编辑:这是一个安静的老帖子,但增加了一些建议 重新考虑您的设计 调用父方法的私有方法,虽然可以通过反射实现,但是不应该这样做。在父对象上调用私有方法可能会使类处于无效状态,并可能导致意外行为。

  • 问题是要确定子数据的总和是否等于父数据。如果是,返回真,否则返回假。 下面是我的代码,在提交时出现错误。我知道这是一个简单的问题,但在编写了条件之后,我很难通过遍历所有左右节点来递归检查二叉树中每个节点的和条件。 请指导我,因为我哪里做错了。

  • 在应用程序中使用JavaFX,我有一个main.fxml文件,其中包含一些fxml子文件。 我想从子控制器访问Main.fxml的MainController类。 我试着用一个例子来解释得更好: MainFXML: 主控制器: ChildFXML: