简体   繁体   中英

How to map different Java-Bean structures onto one another

In our project we have to map one nested structures of beans onto another. (These are actually JAXB mapped Java-Representations of XML documents that, say, represent an incoming order document.) This has to be mapped onto the quite different order document structure of another system.

What are the options to do this? I would prefer something that fulfills the following requirements:

  1. The mapping should alert me when the mapping of one field was not defined
  2. The mapping should have some defaults, like mapping fields of equal names onto one another and providing standard mappings for, say, int to String and vice versa.
  3. The mapping should be bidirectional.
  4. One should be able to use code completion when defining the mapping.

A promising framework for this is Dozer , but it does not fulfill 1 and 4. Same with JBeanMapper . Just programming it in Java does 4 but not the other requirements; using XSLT fulfills perhaps 2 but nothing else. Do you have better ideas?

ModelMapper is the one library that meets all of your criteria. It offers a mapping API that uses actual code to map properties - so you get code completion. And it offers validation to ensure that all destination properties are mapped. Additionally it offers some things you didn't even know you wanted such as intelligent mapping :)

Check out the ModelMapper homepage for more info:

http://modelmapper.org

另一种选择是MapStruct ,它在构建时生成映射代码,从而产生类型安全的映射,在运行时不需要任何依赖(免责声明:我是MapStruct的作者)。

Have a look at GeDA which uses byte code to create mapping classes during runtime, which makes it extremely fast http://genericdtoassembler.org/ . It would cover point 1-3. Regarding point 4 I would imagine it is an IDE thing so I do not think you will find any library that would facilitate that unless it has IDE plugins.

When we've had this problem, we've ended up doing field mappings in Java in a utility class. It's a real hassle, especially when you have to map to several different web services and have to write mappings for each of them (some of which are a simple 2D map of named attributes rather than a hierarchy of objects, cries ).

However in that way you do have the power to analyse the requirements of the target of the mapping to get the best quality mapping, setting defaults where data isn't set, and so on. You can throw a custom "UndefinedMappingException" in your mapper where you need to. And by not being a fluffy library that uses reflection and/or complex XML mapping configuration files, it's a darn sight faster.

Ie, this is the post arguing for "write it in Java".

I solved a similar issue with commons-beanutils .

My final goal was a big Java file which would build the data structure and the mapper created that file for me. This way, I could create test data from snapshots made while the program was running.

The mapper allowed to define the keys by which to sort the objects, the field to use to generate object names in the Java file and I used a map with "class:field" as the key. The value was an object implementing a simple "Mapping" interface (one method: toJava(Object instance, String field, Object value)).

My main problem was to compile 2MB+ Java files :)

Transmorph, EZMorph, Dozer, OTOM are some of them you could look at for Bean to Bean mapping. I have used Dozer in the past and feel that it has grown quite stable over years.

There is an interesting solution that might help you if you are mapping data structures that have many slightly different variants. For example if you are modelling business order structures for different business cases and product variants, and different variants require different combinations of the same attributes like adresses, account ids, configuration information for the products etc.

Thus, you have many structurally similar beans that contain different subsets of a number of attributes. If you do not want to write code for each individual variant, you could introduce a Java-interface that has all attributes that occur in these beans, and use java.lang.reflect.Proxy to construct proxy instances for the bean you want to map, and which returns null for getters the actual bean does not have / throws an exception if a non existent setter is called on the actual bean. In a manner of speaking, you inject an interface into those beans that has more methods than the bean itself.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM