Array mappings, configuration inheritance: MapStruct 1.0.0.Beta4 released
The MapStruct community proudly announces the release of MapStruct 1.0.0.Beta4!
The new release provides support for mapping arrays of Java beans, re-use of mapping configurations via a brand-new inheritance mechanism and ordered setter invocations on the target side. We also fixed quite a few bugs. You can find the complete list of 48 issues in the change log. When upgrading from a previous Beta release, please check out the migration notes for changes which may affect existing applications.
One thing I’m especially excited about is the new MapStruct Eclipse plug-in which will give you an even better experience when using MapStruct within the Eclipse IDE. You’ll find out more below.
This release has been a true team effort; Many, many thanks to Sjaak Derksen, Andreas Gudian, Timo Eckhardt, Ewald Volkert, Christian Schuster, Sebastian Hasait and Dilip Krishnan who all worked on the Beta4 release.
Array mappings
While MapStruct has had support for mapping collections (List
, Set
etc.) of primitive and Java bean types for a long time, this was not the case for arrays. This is finally possible, so you can now declare mapping methods such as the following:
@Mapper public interface CustomerMapper { CustomerDto[] customersToDtos(Customer[] customers); CustomerDto customerToDto(Customer customer); }
As known from collection mapping methods, the generated customersToDtos()
implementation will invoke the customerToDto()
method for mapping the individual array elements. Similar to collection mapping methods, you can use the @IterableMapping
annotation for applying specific configuration options:
@IterableMapping(dateFormat = "dd.MM.yyyy") String[] dateArrayToStringArray(Date[] dates);
If needed, you also can map between collections and arrays:
CustomerDto[] customersToDtos(List<Customer> customers);
Configuration inheritance
With help of the new @InheritConfiguration
annotation you can advice MapStruct to apply the configuration from one mapping method to another.
This comes in handy for instance when having a “normal” mapping method and an update method for the same types. Instead of configuring both methods individually, you can let one method inherit the configuration from the other:
@Mapping(target="lastName", source="surName") @Mapping(target="accountNumber", source="customerNumber") Customer customerDtoToCustomer(CustomerDto customerDto); @InheritConfiguration void updateCustomerFromDto(CustomerDto dto, @MappingTarget Customer customer);
The @InheritConfiguration
annotation will let the updateCustomerFromDto()
inherit all the mappings from customerDtoToCustomer()
. The selection of the template method is done by matching source and target types, but you could explicitly specify a method as configuration source if needed.
Configuration inheritance is particularly useful when working with complex type hierarchies. You can define a configuration for the base types of the source and target models and let specific mapping methods inherit this configuration. But what if a base type is abstract? Naturally, MapStruct cannot generate an implementation of a method whose return type is an abstract one.
This can be resolved by declaring a “prototype method” within a configuration class referenced by the mapper:
@Mapper(config=BaseMappings.class) public interface CustomerMapper { @InheritConfiguration(name="anyDtoToEntity") CustomerDto customerToDto(Customer customer); }
@MapperConfig public interface BaseMappings { // no implementation will be generated, it only serves as configuration source @Mapping(target = "primaryKey", source = "id") BaseDto anyEntityToDto(BaseEntity entity); }
Methods declared within configuration classes such as BaseMappings
are not usable as mapping methods themselves (no implementation will be generated for them). They solely serve as configuration source. In the example the customerToDto()
method would inherit the configuration given at anyEntityToDto()
.
Note that you optionally can have prototype configurations automatically be applied to methods with compatbile source and target types. You can find the details in the reference documentation.
Ordered setter invocations
Sometimes it is required to invoke the setters of the target bean in a specific order, e.g. if one setter depends on the value of other properties of the same bean. For that purpose there is a new attribute on the @Mapping
annotation, dependsOn()
. The following shows an example:
@Mapping(target = "givenName", source = "firstName") @Mapping(target = "middleName", dependsOn = "givenName") @Mapping(target = "lastName", dependsOn = "middleName") AddressDto addressToDto(Address address);
This configuration makes sure that the generated implementation of addressToDto()
first calls setGivenName()
, then setMiddleName()
and finally setLastName()
. A single property can also depend on several other ones:
@Mapping(target = "lastName", dependsOn = { "firstName", "middleName"}) AddressDto addressToDto(Address address);
This would ensure that setLastName()
is invoked after setGivenName()
and setMiddleName()
, but no guarantee is given for the order of these two.
MapStruct Eclipse plug-in
Being a JSR 269 annotation processor, MapStruct is meant to run equally well within command line builds (plain javac, Mavent etc.) as well as IDEs. Indeed the annotation processor works nicely for instance in Eclipse, generating mappers upon save, showing error markers next to the affected elements etc.
Still there are some advanced features which cannot be provided by an annotation processor, e.g. auto-completion for annotation attributes, refactoring support, navigation to referenced elements and more. This is where the MapStruct Eclipse plug-in comes in.
Developed by my good friend Lars Wetzer, it aims at providing an even better experience when using MapStruct within Eclipse. The plug-in is still at a very early stage, currently it provides auto-completion for @Mapping#source()
and target()
. The following shows a screenshot:
More functionality will be coming soon. You can find the list of features planned for the plug-in here. There is no official release of the plug-in yet. But if you feel adventurous, you can install the latest nightly build from the update site at our CI server.
Download
If you work with Maven, Gradle or another dependency management tool, use the following GAV coordinates to obtain the MapStruct artifacts from Maven Central:
- org.mapstruct:mapstruct:1.0.0.Beta4 for the annotation JAR (to be used with Java <= 7) or org.mapstruct:mapstruct-jdk8:1.0.0.Beta4 (for usage with Java >= 8)
- org.mapstruct:mapstruct-processor:1.0.0.Beta4 for the annotation processor.
Alternatively, you can download distribution bundles (ZIP, TAR.GZ) from SourceForge.
The Beta4 contains almost all the features we envisioned for the 1.0 release. We’ll now focus on bug-fixing and addressing some more minor edge cases. The CR1 (candidate release) should be out in four to six weeks from now, followed by 1.0 Final after four more weeks from there.
Finally, some useful links:
- Get help at the mapstruct-users group
- Report bugs and feature requests via the issue tracker
- Follow @GetMapStruct on Twitter
- Follow MapStruct on Google+