【问题标题】:Complex Bean Mapping复杂 Bean 映射
【发布时间】:2014-03-02 06:50:12
【问题描述】:

我正在尝试为我在映射一个简单的 bean 结构时遇到的问题找到最佳解决方案,该结构被发送到基于浏览器的 JavaScript 应用程序。当前的要求是管理旧 Java 后端上的大部分显示控件。目前我们有一个服务样式层,它正在生成没有内置显示逻辑的值对象,例如:

public class Example1 {
    String value1;
    Boolean value2;
    Example3 value3;

    public String getValue1(){...}
    public void setValue1(){...}
    ....
 }

我的目标是能够在所有字段上映射通用结构,以便添加前端所需的新显示结构。我只想管理原始结构类(Example1 类)结构,只需将包装器中的额外值设置为旧服务层。

通用结构将采用以下类的形式:

public class Presentable<T> {
    T value;
    boolean visible = true; 
    boolean mandatory = false;
    List<String> errors = new ArrayList<>();

    public T getValue() {...}
    public void setValue(T value) {...}
    ...
}

最终结果如下所示,其中值等于原始结构中的值:

public class Example2{
    Presentable<String> value1;
    Presentable<Boolean> value2;
    Presentable<Example3> value3;

    public Presentable<String> getValue1(){...}
    public void setValue1(){...}
    ...
}

如果不编写 Example2 样式类并复制每个值,是否有解决此问题的方法?我愿意修改 Example1 类,因为它不会影响旧服务的消费者。

谢谢。

【问题讨论】:

  • 更新:我发现的唯一解决方案是使用带有注释的代码生成。虽然我确实写了一个快速工作的 POC,但它很脏。
  • 您需要有多个Example1的对象,根据客户的要求。那么为什么你需要一个通用类。您可以使用前端 arraylist 映射,因此每次用户添加一个新对象时,它都会自动在 ArrayList 中添加 Example1 的另一个对象,您将拥有一个 List,其中包含 example1 的所有对象。跨度>

标签: java jakarta-ee javabeans java-6


【解决方案1】:

您基本上可以在 Spring 中使用 AOP(面向方面​​的编程)。在春天,您可以创建一个包含您需要的额外信息的代理对象。 好的起点是: http://www.mkyong.com/spring3/spring-aop-aspectj-annotation-example/

面向切面编程的官方页面: http://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/html/aop.html

此示例/答案可能很有用: Intercepting method with Spring AOP using only annotations

【讨论】:

  • 这与我正在寻找的很接近,但 Spring 不是一个选项,尽管我确实意识到现在大多数企业 Java 应用程序都包含 Spring。
【解决方案2】:

所以我不确定我是否正确理解了你。不过……

这是一个我们可以很容易使用反射的地方。

对于我们的类 Example1.class,我们调用 getDeclaredMethods、getDeclaredFields(在简单用例中)或更复杂的 getMethods、getFields(简单 pojo 但具有继承)。您可能需要一些简单的逻辑,例如删除带有 static 修饰符或类似内容的字段。

对于每个方法/字段,我们使用 getMethod(String name) 或 getField(String name) 从 Example2.class 中获取适当的方法/字段

并通过字段或设置器将我们的值设置为新对象。如果 private 等修饰符有问题,我们使用 setAccessible。

一些简单用例的代码:

public Example2 decorateWithWrapper(Example1 obj) {
    Example2 wrapped = new Example2();
    for (Field field : obj.getClass().getDeclaredFields()) {
        Field toAssign = wrapped.getClass().getField(field.getName());
        toAssign.setAccessible(true);
        toAssign.set(wrapped, field.get(obj));
    }
    return wrapped;
}

如果需要,可以很容易地从上面执行更通用的方法。

您不需要任何外部库或工具。

【讨论】:

    【解决方案3】:

    您可以使用 Jackson ObjectMapper 并配置 [Dozer][1] mapper 来做这个复杂的 bean 映射,并让 JSON 在应用程序和浏览器之间进行通信。

    Dozer 允许您将一个类逐个字段映射到其他字段。 Dozer映射的基本代码如下:

    <mappings>          
      <mapping>
        <class-a>org.dozer.vo.TestObject</class-a>
        <class-b>org.dozer.vo.TestObjectPrime</class-b>
        <!-- Any custom field mapping xml would go here -->
      </mapping>
    </mappings>
    

    这里,在上面的例子中,TestObject 的所有变量都被映射到TestObjectPrime。对于您的情况,您需要为此配置添加自定义映射,如下所示:

    <mapping>
      <class-a>org.dozer.vo.deep.SrcDeepObj</class-a>
      <class-b>org.dozer.vo.deep.DestDeepObj</class-b>
    
      <field>
        <a>srcNestedObj.src1</a>
        <b>dest1</b>
      </field>
    
      <field>
        <a>srcNestedObj.src2</a>
        <b>dest2</b>
      </field>
    
      <field>
        <a>srcNestedObj.srcNestedObj2.src5</a>
        <b>dest5</b>
      </field>
    
      <field><!-- java.util.List to java.util.List -->
        <a>srcNestedObj.hintList</a>
        <b>hintList</b>
        <a-hint>java.lang.String</a-hint>         
        <b-hint>java.lang.Integer</b-hint> 
      </field>
    
      <field>
        <a>srcNestedObj.hintList2</a>
        <b>hintList2</b>
        <a-hint>org.dozer.vo.TheFirstSubClass</a-hint>
        <b-hint>org.dozer.vo.TheFirstSubClassPrime</b-hint> 
      </field>
    
      <field copy-by-reference="true">
        <a>srcNestedObj.hintList3</a>
        <b>hintList3</b>
      </field-deep>
    
    </mapping>
    

    正如推土机教程所说:

    可以映射深层属性。一个例子是当你 有一个带有 String 属性的对象。你的另一个对象有一个字符串 属性,但它在对象图中有几个层次。在里面 DestDeepObj 下面的示例在对象内具有嵌套属性 需要映射的图形。深场支持类型提示 映射。属性 copy-by-reference、type=one-way 和 也可以使用关系类型。

    以上示例摘自 Dozer documentation

    希希尔

    【讨论】:

      【解决方案4】:

      要启用 AspectJ,您需要 aspectjrt.jar、aspectjweaver.jarspring-aop.jar。 对于我们的类 Example1.class,我们调用 getDeclaredMethods、getDeclaredFields(在简单用例中)或 getMethods、getFields 在更复杂的情况下(简单的 pojo,但具有继承性)。

      【讨论】:

        猜你喜欢
        • 2015-03-03
        • 2012-04-19
        • 2011-03-27
        • 2021-08-15
        • 2013-01-07
        • 2018-02-19
        • 1970-01-01
        • 2011-11-04
        • 2012-10-29
        相关资源
        最近更新 更多