Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Complex Bean Mapping

I am trying to find the best solution for a problem I have with mapping a simple bean structure that is being sent to a browser-based JavaScript application. The current requirement is to manage most of the display control on the old Java backend. Currently we have a service style layer that is producing value objects with no display logic built into them like:

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

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

My goal is to be able to map a generic structure over all fields such that it adds the new display structure that is required by the front-end. I would like to manage only the original structure class (Example1 class) structure and simply set the extra values in a wrapper to the old service layer.

The generic structure would take the form of the following class:

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) {...}
    ...
}

The end result would look something like the following, where value is equal to the value in the original structure:

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

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

Is there a solution to this problem without writing an Example2 style class and copying in every single value? I am open to modification to the Example1 class as it does not affect consumers of the old service.

Thanks.

like image 660
rock-fall Avatar asked Feb 05 '14 17:02

rock-fall


People also ask

What is bean mapping?

It is mainly bean to bean mapper that recursively copies data from one java object to another java object – attribute by attribute. We realize it's full capability when We are dealing with deeply-nested complex java beans, which we are easily seen in large enterprise applications.

What is the use of @mapper annotation?

The @Mapper annotation 1 marks the interface as mapping interface and lets the MapStruct processor kick in during compilation. The actual mapping method 2 expects the source object as parameter and returns the target object. Its name can be freely chosen.

What is the purpose of MapStruct?

MapStruct is a code generator tool that greatly simplifies the implementation of mappings between Java bean types based on a convention over configuration approach. The generated mapping code uses plain method invocations and thus is fast, type-safe, and easy to understand.

What is DozerBeanMapper?

Dozer is a Java Bean to Java Bean mapper that recursively copies data from one object to another, attribute by attribute. The library not only supports mapping between attribute names of Java Beans, but also automatically converts between types – if they're different.


2 Answers

You can use basically AOP (Aspect Oriented Programming) with Spring. On spring you can create a proxy object with extra information you need. Good starting point is: http://www.mkyong.com/spring3/spring-aop-aspectj-annotation-example/

Official page on Aspect Oriented Programming: http://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/html/aop.html

This example/answer can be useful: Intercepting method with Spring AOP using only annotations

like image 124
g.annunziata Avatar answered Sep 24 '22 17:09

g.annunziata


So I'm not sure if I have correctly understood you. However...

This is a place where we can very easy use reflection.

For our class Example1.class we invoke getDeclaredMethods, getDeclaredFields (in simple use case) or getMethods, getFields in more complex (simple pojo but with inheritance). You may need some simple logic for example to remove fields with static modifier or something like that.

For each method/field we get appropriate method/field from Example2.class with getMethod(String name) or getField(String name)

And set our value to new object through field or setter. If there is a problem with modifiers such as private we use setAccessible.

Some code for simple use case:

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;
}

It's pretty easy to do more generic method from this above if needed.

You do not need any external library or tool.

like image 41
zimi Avatar answered Sep 23 '22 17:09

zimi