Support for accessing property names, passing annotations to generated code, sponsoring MapStruct and much more: MapStruct 1.6.0.Beta1 is out
It’s my pleasure to announce the first Beta release of MapStruct 1.6.
The new release comes with a lot of new functionality, e.g.:
- Access to target / source property names in conditional and mapping methods
- Passing annotations to generated code
- Add javadoc to generated code
- New built-in conversions
With this release we are also happy to announce that MapStruct has started accepting donations through Open Collective or GitHub. We’d like to thank to everyone that has already started in supporting us:
Altogether, not less than 63 issues were fixed for this release.
This would not have been possible without our fantastic community of contributors:
-
our latest MapStruct contributor Oliver Erhart
-
and of course seasoned MapStruct hackers Ben Zegveld, Sjaak Derksen, Filip Hrisafov.
Thank you everyone for all your hard work!
Slightly more than a year after the first Beta release of 1.6, we are proud to present you with the first Beta of the 1.6 release.
Enough of the pep talk, let’s take a closer look at some of the new features and enhancement!
Access to target / source property names in conditional and mapping methods
It is now possible to get access to the target property name in conditional and mapping methods.
e.g.
public class HibernateUtils { @Condition public static boolean isAccessible(Customer customer, @TargetPropertyName String propertyName) { return Hibernate.isPropertyInitialized(customer, propertyName); } } @Mapper(uses = HibernateUtils.class) public interface CustomerMapper { CustomerDto map(Customer customer); }
Will generate something like
// GENERATED CODE public class CustomerMapperImpl implements CustomerMapper { @Override public CustomerDto map(Customer customer) { // ... if ( HiberateUtils.isAccessible( customer, "orders" ) ) { customer.setOrders( mapOrders( customer.getOrders() ) ); } // ... } // ... }
Passing annotations to generate code
Using @AnnotateWith
custom annotations can be passed to the generated code.
@AnnotateWith( value = Component.class, elements = @AnnotateWith.Element( strings = "customerMapperV1" ) ) @Mapper( componentModel = MappingConstants.ComponentModel.SPRING ) public interface CustomerMapper { // ... }
This will generate:
// GENERATED CODE @Component("customerMapperV1") public class CustomerMapperImpl implements CustomerMapper { // ... }
This for example can be used to provide a custom name for the Spring @Component
Add Javadoc to generated code
Using @Javadoc
it is possible to pass custom javadoc to the generated code.
e.g.
@Mapper @Javadoc("This is the description\n" + "\n" + "@author author1\n" + "@author author2\n" + "\n" + "@deprecated Use {@link CustomerV2Mapper} instead\n" + "@since 0.1\n") @Deprecated public interface CustomerMapper { }
or
@Mapper @Javadoc( value = "This is the description", authors = { "author1", "author2" }, deprecated = "Use {@link CustomerV2Mapper} instead", since = "0.1" ) @Deprecated public interface CustomerMapper { }
In both cases the generated code looks like:
/** * This is the description * * @author author1 * @author author2 * * @deprecated Use {@link CustomerV2Mapper} instead * @since 0.1 */ @Deprecated // GENERATED CODE public class CustomerMapperImpl implements CustomerMapper { }
New Built-In conversions
We have extensive number of built-in conversions between different types. As of this release we have 4 more:
- Between
Enum
andInteger
- This basically usesEnum#ordinal
to map to integer andMyEnum.values()[value]
to map from an integer value - Between
Locale
andString
- Between
java.time.LocalDate
andjava.time.LocalDateTime
- Between
Iterable
andCollection
Enhancements
- New compiler options have been added for defining
nullValueIterableMappingStrategy
andnullValueMapMappingStrategy
globally. The options aremapstruct.nullValueIterableMappingStrategy
andmapstruct.nullValueMapMappingStrategy
respectively. - Subclass mappings now support qualifiers
- SPI implementations now have the possibility to provide custom compiler options.
A new SPI (
AdditionalSupportedOptionsProvider
) needs to be implemented to provide the custom options. Custom compiler options are not allowed to start withmapstruct
- The most specific mapping will be picked when the return type can be assigned to a simpler type. e.g.
public static java.util.Date toUtilDate(String strDate); public static java.sql.TimeStamp toTimeStamp(String strDate); public static java.sql.Date toSqlDate(String strDate);
Previously mapping from aString
tojava.util.Date
would fail since any of the 3 methods could be used. However, now thetoUtilDate
would be picked - Collection getter is not treated as a write accessor when using
CollectionMappingStrategy#TARGET_IMMUTABLE
- Error location has been improved for
@SubclassMapping
- Support
@InheritConfiguration
for@SubclassMapping
- Do not require
subclassExhaustiveStrategy
when source is a sealed class and all subtypes are specified - All lifecycle methods are support for builders
@BeforeMapping
with@TargetType
the type being build@AfterMapping
with@TargetType
the type being build@AfterMapping
with@MappingTarget
the type being build
- Some redundant null checks have been removed for nested properties
- Support
@Default
for records - Add
InjectionStrategy.SETTER
- Add
BeanMapping#unmappedSourcePolicy
- Improve support for
Map
attributes for Immutables
Breaking Changes
Map to Bean In 1.5 we added support for mapping a map to a bean by implicitly mapping all the properties from the target bean by accessing them from the map. However, this lead to some problems in multi mapping methods. Therefore, in this release we tightened up a bit and in multi source mapping methods the Map will not be considered when doing implicit mappings.
e.g.
@Mapper public interface CarMapper { // This method is going to implicitly map all the target properties from the map Target map(Map<String, Object> map); // This method is not going to use the map for implicit mappings. // Only the name will be mapped from the map (since it has been defined like that @Mapping(target = "name", source = "map.name") Target map(Source source, Map<String, Object> map) }
Download
This concludes our tour through MapStruct 1.6 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:1.6.0.Beta1
- Annotation processor JAR: org.mapstruct:mapstruct-processor:1.6.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 in our Gitter room, the GitHub Discussion or StackOverflow
- Report bugs and feature requests via the issue tracker
- Follow @GetMapStruct on Twitter