Bean Mapping With ModelMapper

I’ve never found a satisfactory method for mapping bean properties. They always add too much ugly set-up code, especially for conditional mapping or type conversions.

Perhaps ModelMapper is the best so far.

Let’s say you have a source bean with a these properties plus getters and setters:


public class SourceBean {

    private String firstName;
    private String lastName;
    private int age;

And you have a destination bean with these:


public class TargetBean {

    private String fullName;
    private Boolean oldEnoughToVote;

Now you want the bean mapping to do the equivalent of


    target.setFullName(
      source.getFirstName() + " " + source.getLastName());

and


    if(source.getAge() >= 18) {
        target.setIsOldEnoughToVote(true);
    }

Then the ModelMapper solution looks like:


    private PropertyMap<SourceBean, TargetBean> mapping =
      new PropertyMap<SourceBean, TargetBean>() {

      Converter<SourceBean, String> concatWithSpace =
        new Converter<SourceBean, String>() {
        public String convert(MappingContext<SourceBean, String> context) {
          SourceBean src= context.getSource();
          return src.getFirstName() + " " + src.getLastName();
        }
      };

      Converter<Integer, Boolean> over18 =
        new Converter<Integer, Boolean>() {
        public Boolean convert(MappingContext<Integer, Boolean> context) {
          return context.getSource() >= 18;
        }
      };

      protected void configure() {
        using(over18).map(source.getAge()).setOldEnoughToVote(null);
        using(concatWithSpace).map(source).setFullName(null);
      }
    };

    ModelMapper modelMapper = new ModelMapper();
    modelMapper.addMappings(mapping);

    TargetBean result = modelMapper.map(incoming, TargetBean.class);

I’m still not so sure that’s gained us very much, and some of it is rather uncomfortable to look at. For example ,can you work out why we pass null to “setOldEnoughToVote” and “setFullName”, without reading the manual and the developer mailing list?

But if you were to extract your re-usable common converters, and if you had a load of properties that just map with the default property mapping, then you have something a bit simpler and perhaps saving some tedious code:

 


    private PropertyMap<SourceBean, TargetBean> mapping =
      new PropertyMap<SourceBean, TargetBean>() {

      protected void configure() {
        using(over18).map(source.getAge()).setOldEnoughToVote(null);
        using(concatWithSpace).map(source).setFullName(null);
      }
    };

    ModelMapper modelMapper = new ModelMapper();
    modelMapper.addMappings(mapping);

    TargetBean result = modelMapper.map(incoming, TargetBean.class);

….and perhaps, ultimately, at the point of use, where you really don’t want a load of low-level mapping code obscuring the expression of what is really happening in the higher-level process, you would just have:

 

TargetBean result = modelMapper.map(incoming, TargetBean.class);

 

Hmm. It has promise, but I need to do further experiments with this….

For example, how to use ModelMapper’s “not null” condition to handle null firstName or lastName, without adding so much clutter that you don’t gain over just doing it manually.

If you’re using ModelMapper extensively, I’d love to hear your insights into doing it cleanly.

Advertisements
Posted in Java

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: