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 toString
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:
- Lombok - requires having the Lombok classes in a separate module see rzwitserloot/lombok#1538
- AutoValue
- Immutables
- FreeBuilder
- Protocol Buffer builder
- It also works for custom builders if the object being build provides a parameterless public static method for instantiating the builder. Otherwise, you would need to write a custom
BuilderProvider
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
andjava.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:
- Annotation JAR: org.mapstruct:mapstruct-jdk8:1.3.0.Beta1 (for usage with Java >= 8) or org.mapstruct:mapstruct:1.3.0.Beta1 (for earlier Java versions)
- Annotation processor JAR: org.mapstruct:mapstruct-processor:1.3.0.Beta1
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:
- Get help at the mapstruct-users group or in our Gitter room
- Report bugs and feature requests via the issue tracker
- Follow @GetMapStruct on Twitter
- Follow MapStruct on Google+