Support for builders, mapper constructor injection and much more: MapStruct 1.3.0.Beta1 is out

It’ my pleasure to announce the first Beta release of MapStruct 1.3.

The new release comes with a whole lot of new functionality, e.g.:

  • Mapping of (immutable) objects using builders
  • Constructor injection for Annotation Based component models
  • unmappedSourcePolicy support
  • Support for defaultExpression
  • Limit mapping only to explicitly defined mappings
  • Performance improvement of constant / defaultValue primitive to String mappings

Altogether, not less than 59 issues were fixed for this release.

This would not have been possible without our fantastic community of contributors: Christian Bandowski, David Feinblum, Darren Rambaud, Daniel Strobusch, Eric Martineau, Gervais Blaise, Jeff Smyth, Joshua Spoerri, Kevin Grüneberg, Lauri Apple, Richard Lea, Sergey Grekov, Tomoya Yokota, as well as seasoned MapStruct hackers Andreas Gudian, Filip Hrisafov, Gunnar Morling and Sjaak Derksen.

Thanks a lot everyone for all your hard work!

Big thanks to all the users of the 1.3.0-SNAPSHOT dependency of MapStruct. Without their input we would not have been able to release such a thorough support of the Builder mappings.

Enough of the pep talk, let’s take a closer look at some of the new features!

Mapping of (immutable) objects using builders

Use of builder to map (immutable) objects has been one of the most requested features of MapStruct.

We are happy to announce that as of 1.3.0.Beta1 MapStruct has out of the box support for builders. Works with:

For more details how the Builder support works have a look at the Using builders of the reference guide

We have modified our example project with protobuf support to use the out of the box support for Builders. Have a look at it here.

Constructor injection for annotation based component models

Construction injection for annotation based component models (spring, cdi, jsr330) can bow be used.

Example:

@Mapper(uses = OrderMapper.class, componentModel = "spring", injectionStrategy = InjectionStrategy.CONSTRUCTOR)
public interface CustomerMapper {

    CustomerDto mapCustomer(Customer customer);
}

Support for unmapped properties in the source type

Using Mapper#unmappedSourcePolicy one can now control how unmapped properties of the source type of a mapping should be reported. For backwards compatibility it is set to ReportingPolicy.IGNORE.

Support for defaultExpression

Mapping#defaultExpression can now be used to customize the default value of a mapping.

@Mapper
public interface CustomerMapper {

    @Mapping(target = "id", defaultExpression = "java(UUID.randomUUID().toString())")
    PersonDto map(Person person);
}

Limit mapping only to explicitly defined mappings

By using @BeanMapping(ignoreByDefault = true) one can limit the mapping only to the explicitly defined mappings. This annotation actually applies ignore to all target properties, which means that it can be used in configuration mappings to only map explicit properties in base classes.

Performance improvement of constant / defaultValue primitive to String mappings

With #1401 we now try to check if it is possible to assign a defaultValue and / or a constant directly without doing a conversion. For example for the following mapper:

@Mapper
public interface PersonMapper {

    @Mapping(target = "price", constant = "10.5")
    @Mapping(target = "age", defaultValue = "10)
    Order order(OrderDto source);   
}

Before the following was generated:

public class PersonMapperImpl implements PersonMapper {

    @Override
    public Order order(OrderDto source) {
        if (source == null) {
            return null;
        }

        Order order = new Order();
        order.setConstant(Double.parseDouble("10.5"));
        if (source.getAge() == null) {
            order.setAge(Integer.parse("10"));
        } else {
            order.setAge(source.getAge());
        }
        return order;
    } 
}

And now the following is generated:

public class PersonMapperImpl implements PersonMapper {

    @Override
    public Order order(OrderDto source) {
        if (source == null) {
            return null;
        }

        Order order = new Order();
        order.setConstant(10.5));
        if (source.getAge() == null) {
            order.setAge(10);
        } else {
            order.setAge(source.getAge());
        }
        return order;
    } 
}

Enhancements

  • Package private mappers with the default component model
  • Improve performance of mapstruct-processor on Java 9
  • Support for using @ObjectFactory on objects passed with @Context
  • Implicit converstion between String and java.util.Currency
  • Improved error messages and locations

Download

This concludes our tour through MapStruct 1.3 Beta1. If you’d like to try out the features described above, you can fetch the new release from Maven Central using the following GAV coordinates:

Alternatively, you can get ZIP and TAR.GZ distribution bundles - containing all the JARs, documentation etc. - from GitHub.

If you run into any trouble or would like to report a bug, feature request or similar, use the following channels to get in touch:

comments powered by Disqus