2014-02-05 118 views
13

我想找到一个问题的最佳解决方案,我已经映射了一个简单的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类,因为它不会影响旧服务的使用者。

谢谢。

+0

更新:我发现的唯一解决方案是使用带有注释的代码生成。虽然我确实写了一个快速工作的POC,但它很脏。 –

+0

根据客户需求,您需要拥有Example1的多个对象。那么为什么你需要一个通用的类。您可以使用前端数组列表映射,所以每当用户添加一个新数组时,它就会自动在ArrayList中添加另一个Example1对象,您将拥有一个列表,其中包含example1的所有对象。 – Dileep

回答

4

你可以基本上使用AOP(Aspect Oriented Programming)和Spring。在春天,您可以创建一个包含所需额外信息的代理对象。 良好的出发点是: 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

+0

这与我正在寻找的内容很接近,但Spring并不是一种选择,尽管我确实意识到大多数Enterprise Java应用程序现在都合并了Spring。 –

1

所以我不知道如果我理解正确的您。然而...

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

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

对于每个方法/领域,我们得到适当的方法/字段从Example2.class与getMethod(字符串名称)或getfield命令(字符串名称)

通过现场或setter设置我们的价值,新的对象。如果私人等修饰符存在问题,我们使用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; 
} 

这是很容易,如果需要从这个上面做的比较通用的方法。

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

1

您可以使用杰克逊ObjectMapper和配置[Dozer][1]映射做这个复杂的豆映射,让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和 relationship-type。

以上示例摘自推土机documentation

Shishir

0

要启用AspectJ时,你需要aspectjrt.jar,aspectjweaver.jar弹簧aop.jar。 对于我们的类Example1.class,我们调用getDeclaredMethods,getDeclaredFields(简单用例)或getMethods,getFields更复杂(简单pojo但带继承)。