【问题标题】:how to generate class instances of attributes on demand?如何按需生成属性的类实例?
【发布时间】:2013-03-19 11:02:17
【问题描述】:

我正在正确评估推土机框架。我想知道是否可以处理以下用例:

类:

public ClassA {

   private Set<ItemA> aItems;
}

public ClassB {

   private ClassC cInstance;
}

public ClassC {

   private List<ItemB> bItems;
}

推土机映射:

<mapping>
   <class-a>ClassA</class-a>
   <class-b>ClassB</class-b>
   <field>
      <a>aItems</a>
      <b>cInstance.bItems</b>
   </field>
 </mapping>

从我目前的测试来看,这似乎不起作用。我特别想知道我应该如何告诉推土机它应该按需生成 ClassB ClassC 的实例?特别是我是否需要为 ClassB 提供特定的推土机映射,它仅作为“中间”类存在于我的目标模型中?

PS:如果有帮助,我的目标模型由 JAXB 类组成

PPS:我还尝试修改 cInstance 的 setter 方法,如果它为 null,它应该生成一个新的 ClassC 实例 - 不幸的是,没有任何运气。此外,我不想以这种方式修改 setter 方法(但是,也许我可以将其外包给将用于映射的 Factory 类)

【问题讨论】:

  • 哇,不知道你想在这里做什么。看来您正在尝试将 Dozer 用作对象工厂,而不是用作复制工具。
  • 你修改了 cInstance 的 setter 还是 getter?你写的是前者,但应该是后者。 Deep mapping 听起来像你想要的,但也像你尝试过的,所以我不知道它是如何失败的。 create method 可能有助于创建 ClassB 的实例,其中 cInstance 字段已经初始化,如果可以接受的话。
  • 非常感谢您的评论@MvG。是的,你可能是对的,我修改了 setter 而不是 getter(所以我会反过来尝试)。你也是对的,我正在尝试进行更深入的映射。我将尝试使用特定的 create 方法来解决此问题(尽管我最初并不打算修改目标模型的生成的 JAXB 类)。
  • 只是一个简短的说明:我让它以某种方式工作,但是,并不是很理想,即,我现在正在使用直接访问 ('is-accessible="true"') 并做到了JAXB 类的一些修改(但这不是我的初衷)。所以我会尝试找到一个有自定义bean工厂并且可能直接访问的解决方案。

标签: java dozer


【解决方案1】:

我没有使用 Dozer 的经验,但从手册来看,以下应该可行:为实现 dozer BeanFactory interfaceClassB 创建一个 custom bean factory

public class FactoryB implements BeanFactory {
  public Object createBean(Object source, Class sourceClass,
                           String targetBeanId) {
    assert(sourceClass.equals(ClassA.class));
    assert(ClassB.class.getName().equals(targetBeanId));
    ClassA a = (ClassA)source;
    ClassB b = new ClassB();
    if (a.aItems != null && !a.aItems.isEmpty())
      b.cInstance = new ClassC();
    return b;
  }
}

如果您的字段确实是私有的,并且您没有针对它们的公共访问器,您可能必须规避访问限制,但对于 JAXB 生成的类,情况不应该如此。

现在您应该可以像这样使用deep mapping 映射事物:

<mapping>
   <class-a>ClassA</class-a>
   <class-b bean-factory="FactoryB">ClassB</class-b>
   <field>
      <a>aItems</a>
      <b>cInstance.bItems</b>
   </field>
 </mapping>

【讨论】:

  • 非常感谢您的回复@MvG。据我了解推土机手册,我必须将 org.dozer.factory.JAXBBeanFactory 定义为 bean 工厂,然后它将加载生成 XJC 的 JAXB 类的相关 ObjectFactory。但是,也许我需要创建和定义另一个与推土机需求相关的工厂。
  • @zazi:JAXB 工厂可以创建对象,但是当且仅当需要时,它才会创建初始 cInstance 失败。除非模式已经定义当且仅当它的 bItems 不为空时,该对象才会存在。在任何情况下,您都可以通过调用 JAXB 工厂来替换我的代码中的 new ClassB()new ClassC(),尽管我希望该工厂做同样的事情。
  • 我在目标字段尝试了您的建议(也与 create-method 结合使用),但没有任何运气。它仍然会引发 NPE,并且无法真正了解原因。
  • 查看我对该问题的评论。我现在找到了一个可行但并不理想的解决方案。
【解决方案2】:

所以看起来最终的解决方案相当简单,因为我的目标类是 JAXB 类,我可以简单地使用 JAXB 类的默认工厂 (org.dozer.factory.JAXBBeanFactory)。引爆点可能是应该直接访问深度映射目标字段('is-accessible="true"')。但是,我还创建了从 ClassA.aitems 到 ClassC.cItems 的进一步直接映射(但我不能 100% 确定这是否将用于所描述的 ClassA 到 ClassB 的映射)。 无论如何,最后我找到了一个相当简单直观的解决方案,只需更少/不需要额外的工厂编码。

【讨论】:

    猜你喜欢
    • 2020-03-28
    • 2016-03-17
    • 2021-10-25
    • 2023-03-27
    • 2021-11-07
    • 1970-01-01
    • 2021-08-06
    • 1970-01-01
    • 2019-09-14
    相关资源
    最近更新 更多