All Versions
11
Latest Version
Avg Release Cycle
101 days
Latest Release
21 days ago

Changelog History
Page 1

  • v1.3.1.Final

    September 29, 2019

    ✨ Enhancements

    • @AfterMapping methods with non unique parameters (#1457) - Stricter matching for lifecycle methods / non-unique parameters
      In case a lifecycle method has multiple matching parameters (e. g. same type)
      all parameter names must match exactly with the ones from the mapping method,
      ⚠ otherwise the lifecycle method will not be used and a warning will be shown.
    • 🏗 Ability to disable builders on method level via Builder#disableBuilder (#1661)
    • Vague message when handling nested property mapping (#1756)

    🐛 Bug fixes

    • MapStruct producing uncompilable code when using bounded wildcard (#1738)
    • 🐛 Bug with Nested Properties and ReportingPolicy.ERROR on Unmapped Source Properties (#1772)
    • 👉 Make MapStruct generate compilable mapping code for attributes of type EnumSet (#1797)
    • 0️⃣ StackOverflowError in DefaultBuilderProvider` when a type has a public static generic method that returns the type (#1751)
    • 👻 Null pointer exception in nested property mapping method with presence check (#1826)
    • 1.3.0.Final Regression in nullValuePropertyMappingStrategy when inherited (#1790)
    • Some Mappers using @Context not yielding Impl classes in Java11 (#1904)
    • Fluent setters on fields with names starting with set are not working #1799
    • MapStruct 1.3.0.Final produces uncompilable code when using Java 11 + Lombok 1.18.6 (#1742)
    • 🏗 Using constructor as builderCreationMethod in custom builder provider causes NullPointerException (#1801)
    • MapStruct 1.3.0.Final generates invalid implementation when nested property of target is populated with multiple nested properties of source (#1828)
    • Nullptr in 1.3.0.Final due to result type definition (#1821)

    📚 Documentation

    • ⚡️ Clarify use of clearing collections in case of update methods (#1142)
    • 🛠 Fix typo in documentation (PR #1760)
    • 🛠 Fix typo and code error in documentation (PR #1779)
    • 📚 Wrong documentation in relation to NullValueMappingStrategy.RETURN_DEFAULT (#1784)
    • 📚 Documentation clarification on obtaining Mapper (#1819)
    • 👌 Improve terms in qualifier docs (PR #1814)
    • 📚 Update @MappingTarget documentation to take builders (#1862)
  • v1.3.0.Final

    February 10, 2019

    🚀 This contains only changes between 1.3.0.Beta2 and 1.3.0.Final. To read the changes from the betas go to 1.3.0.Beta1 and 1.3.0.Beta2

    ✨ Enhancements

    • 👌 Improvement: builder for Mapper/Decorator/GeneratedType (PR #1649)
    • Builtin mapping of String <-> Duration/Period/Instant (#1656)
    • ➕ Add Mappers.getMapperClass for getting the class of a Mapper (#1657)
    • Defaults for `NullValuePropertyMapping#SET_TO_DEFAULT (boxed types, Strings and primitives) (#1699)
    • Optimising code (local variables) for CollectionMappingStrategy#ADDER_PREFERRED
    • NullValuePropertyMapping strategy not implemented fully (#1685)
    • Consider sensible defaults for NullValuePropertyMappingStrategy.SET_TO_DEFAULT (#1699)
    • Optimise AdderWrapper / StreamAdderWrapper to use local variable (#1700)

    🐛 Bug fixes

    • unmappedSourcePolicy may lead to false positives (#1648)
    • Static factory method incorrectly recognised as a fluent setter (#1660) - With the fix for this a method is only considered a candidate if it is public not static
    • ➕ Adder with primitive type not being used (#1665)
    • Nested mapping & MappingTarget - "cannot find symbol" (#1650)
    • NullValuePropertyMappingStrategy was not implemented completely (#1685)
    • ⚡️ Non-void update methods try calling build() on the @MappingTarget when a Builder is available (#1681)
    • Uncompilable code is generated when mapping Stream to List and using @AfterMapping on result (#1707)

    📚 Documentation

    • 📚 Use Repeatable Mapping annotation in the reference documentation (#1645)
    • ⚡️ Update gradle installation guide (#1695)

    🏗 Build

  • v1.3.0.Beta2

    November 11, 2018

    IMPORTANT: Starting from this version MapStruct uses Java 8 as a baseline (#1301)

    🔋 Features

    • Apply source presence tracking recursively (#1456)

    ✨ Enhancements

    • Avoid using java.beans.Introspector (#1524)
    • Cache javax.xml.datatype.DatatypeFactory (#1532)
    • Rename isBuilderSetter in isFluentSetter in the DefaultAccessorNamingStrategy (#1578) - NB : The isBuilderSetter was added in 1.3.0.Beta1
    • ➕ Add support for "adders" in combination with java.util.stream.Stream (#1561)
    • 👍 Allow nullValueCheckStrategy on @BeanMapping (#1571)
    • 👌 Support for conversion between java.time.Instant and java.util.Date (#1595)
    • 👉 Use javax.annotation.processing.Generated if available (#1551)
    • Map java.sql.Date to a java.time.LocalDate (#1591)
    • 👀 When source is null target should NOT be set to null (#1306) - Added new NullValuePropertyMappingStrategy. See PR #1618 and Behavior for more information
    • ➕ Adder wrapper should use singular from the source for the Iterable element (#1478)
    • ⚠ Emit warnings for precision loss (#5)
    • Introduce mechanism to report error from MappingResolver (#1458)
    • 0️⃣ Access to Types and Elements in AccessorNamingStrategy (#1253) - The AccessorNamingStrategy has been extended with a default init method that allows for initialising it with the Elements and Types utils through the MapStructProcessingEnvironment
    • 🏗 Use MapStructProcessingEnvironment for initialising the BuilderProvider (#1640) - The BuilderProvider has been extended with the same init functionality as the AccessorNamingStrategy
    • 🌲 Property error logging on @Mapping annotation (#1504)
    • 👀 FQN of LocalDateTime is used when a simple name is possible (#1576) - With this issue we have also optimised the way we store the required imports (see PR #1642 for more information)

    🐛 Bug fixes

    • NPE when using varargs in mapping method (#1541)
    • ZoneOffset not fully qualified (#1569)
    • 👻 Exception when processing mapping from constants/expressions to inner fields with multi-arg mapping (#1552)
    • [Compilation Error] class java.util.ArrayList not found. MappersImpl cannot be compiled. (#1590)
    • 🏗 Generated code fails to build when the source type is a byte array annotated with @NotNull (#1558) - Fixes a generic problem for all usages of annotations with ElementType.TYPE_VAR
    • Missing imports for Immutables (#1596)
    • Fluent setters starting with is are not correctly handled (#1608)
    • Similar with #1148 (Nested target properties uses same method for different mappings) (#1594)
    • 🏗 Setters on a Builder super class are not called (#1566) - As part of this a new custom AccessorNamingStrategy has been added for FreeBuilder (see 104ebf8 for more information)

    📚 Documentation

    • ➕ Adding an issue template. PR #1616

    🏗 Build

    • ➕ Add Integration tests with Protobuf (#1499)
    • 🔧 Inherit configuration for sub classes using @InheritConfiguration (#1593) - Add tests to show it is working
    • 🛠 Fix wrong line number in JDK for @Repeatable Mappings (#1633) - There is a bug in the javac compiler that does not report the diagnostics on the correct place. See JDK-8042710 and #1628 for tracking it on our side

    Behavior

    Nested source presence tracking

    👀 With #1456 MapStruct now uses nested source presence tracking for nested objects. If the first property has a presence check method then a presence check would be checked recursively. See the issue description for what has changed.

    Handling null or missing source properties

    ⚡️ With #1306 MapStruct now has a NullValuePropertyMappingStrategy that can be used to control how null or not present source properties are updated within a target. The possibilities are:

    • SET_TO_NULL - If the source property is null or not present the target property is set to null. This is also the default, which is the same behaviour from before.
    • SET_TO_DEFAULT - If the source property is null or not present the target property is set to default (empty list, empty set, new object instantiation etc)
    • IGNORE - If the source property is null or not present the target property is not set at all

    NB : During this we noticed that we handle differently collections / maps for normal mapping methods (i.e. we were setting those to null if the source property was null or not present). This is now changed and collections / maps won't be set if the source property is null or not present. In such case one needs to use @ObjectFactory or set the default in the constructor of the target object

    NB2 : In 1.2.0.Final with #1273 we added support for using NullValueMappingStrategy#RETURN_DEFAULT to control how collections / maps default values are set. We realized that this was a mistake on our side and now one should use NullValuePropertyMappingStrategy#SET_TO_DEFAULT.

    👀 See this for more information as well

    🏗 BuilderProvider

    🏗 The BuilderProvider interface has been changed from 1.3.0.Beta1. Now it has an init method that can be used to get access to the Elements and Types utils and the findBuilderInfo method only gets the TypeMirror

  • v1.3.0.Beta1

    July 15, 2018

    🔋 Features

    • 👌 Support for Builders (#782 and #802). Support tested with:
      • Lombok - requires having the Lombok classes in a separate module see rzwitserloot/lombok#1538
      • AutoValue
      • Immutables - see (#1415) for more info for the out of the box support
      • FreeBuilder
      • It also works for custom builder if the object being build provides a parameterless public static method for instantiating the builder. Otherwise, you would need to write a custom BuilderProvider
    • ➕ Add a NoOpBuilderProvider (#1418) - BuilderProvider that allows users to disable the using of Builders in MapStruct. You need to enable it explicitly by creating a org.mapstruct.ap.spi.BuilderProvider file in the META-INF/services directory with org.mapstruct.ap.spi.NoOpBuilderProvider as its content.
    • 👍 Out of the box support for Immutables (#1415)
    • ➕ Add Constructor Injection for Annotation Based Component Model (#571)
    • ➕ Add support for unmappedSourcePolicy (#610)
    • ➕ Add support for ignoring source properties (#1317)
    • 👍 Allow defaultValue to be an expression (#1363) - A new defaultExpression has been added to @Mapping
    • 🏗 Object factory needs to be considered for builder types as well (#1431)
    • 🔧 Ignore mappings by default (#1392) - With @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
    • Access to Builder type in @BeforeMapping and @AfterMapping (#1433) - NB : Lifecycle methods for the type being build are not invoked yet (see #1454)

    ✨ Enhancements

    • Exceptions in nested beanmapping are not declared in generated code (#1332)
    • @Mapping arguments should be trimmed (#1353)
    • ➕ Add implicit conversion between String and java.util.Currency (#1355)
    • Shared configuration not applied when using InheritInverseConfiguration (#1367) - aligning @Inherit(Inverse)Configuration with strategy AUTO_INHERIT_*
    • 🐎 Extremily low mapstruct-processor performance on Java 9 (#1378) - Use Types when searching for TypeElement(s) instead of getting a new TypeElement each time
    • Report error on the @Mapping annotation when using invalid @Mapping values (#1383)
    • 👌 Improve error message when unknown source parameter is used in @Mapping (#1387)
    • 🐎 Possible performance improvement of constant / defaultValue primitive to String mappings (#1401) - See behavior changes
    • 👍 Allow using update mappings for types with builders (#1423)
    • Lazy load SPIs in annotation processor context (#1473)
    • @ObjectFactory not called when on an @Context object (#1398)
    • 👍 Allow package-private mapper (#1365)
    • ➕ Add support for Builders with multiple build methods (#1479) - See PR #1498 for more details

    🐛 Bug fixes

    • 👻 Context annotation on primitive types with @AfterMapping throws exception on compile (#1339)
    • Enum mapper generates mapping method with wrong signature. Wrong amount of parameters (#1340)
    • Not generating setter methods for all nested constants (#1320)
    • Ignore doesn't work for readonly properties (#1345)
    • Invalid mapper is created when there is no read accessor for nested target mappings (#1375)
    • Injection strategy Constructor does not generate compilable code (#1395)
    • 🔧 Shared configuration not applied when using @InheritInverseConfiguration (#1367)
    • ⚠ Mapping String to org.joda.time.LocalDate issues compiler error (#1370) - When using date format MapStruct tries to validate it by invoking the Joda formatter. This means that the Joda dependency needs to be on the classpath. If the MapStruct processor is invoked from the processor path, and Joda is not there we can't invoke Joda classes. If this is the case we will now issue a warning saying what the user needs to do (add Joda to the processor path) and consider the format as valid
    • ⚡️ MapStruct throws an exception during collection update mapping when target is immutable and there is no target read accessor (#1359)
    • ➕ Adder argument cannot be determined when collection type is not generic (#1338)
    • Pass originating elements to the javax.annotation.processing.Filer API (#1414)
    • org.joda.time.LocalDate tojava.time.LocalDate generated code has compilation error (#1425) - With this fix we have also improved the builtin templates, so something similar should not happen again
    • 0️⃣ Improper @BeanMapping(ignoreByDefault=true) treatment with Immutable target (#1452)
    • Direct constant assignment causes problems for byte and short values (#1462)
    • ➕ Adder method not working for builders (#1449)
    • String to enum conversion: Compile error in generated mapper (#1460) - Ensures the FQN will be used for SimpleConversion if required, something like this should not happen again
    • Compilation error on CollectionMapping. Wrong capture generated (#1453)
    • 🔧 NullPointerException when using unknown source properties with shared configuration (#1180)
    • ZonedDateTime to XmlGregorianCalendar losses time zone information (#1523)
    • Generic mapping method not selected (#1482)
    • ✅ "Ambiguous mapping methods found" when the same method is found twice (#537) - Fixed in an earlier version, but now we have a test for it.

    📚 Documentation

    • ➕ Add IntelliJ Formatter to CONTRIBUTING.md (#1297)
    • 🔄 Change MapStruct Version in README to latest 1.2.0.Final (#1312)
    • 📄 Injection Strategy docs (#1314)
    • ➕ Add since tags for unmappedSourcePolicy() (#1333)
    • ➕ Add change of behaviour for constant and defaultValue in @Mapping (#1459)
    • 👉 Use constants instead of strings in @ValueMapping javadoc (PR #1480)
    • 📚 Update documentation about the latest gradle apt plugin (#1419)
    • Document of sample code is broken (PR #1530)
    • ➕ Add sample of @Mapping annotation to @InheritInverseConfiguration (#1531)
    • ➕ Add documentation about the Builders support (#1417)
    • ➕ Add @since tag to @Mapping#defaultExpression() (#1436)

    Behavior

    0️⃣ With #1401 MapStruct now tries 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:

    @Mapperpublic 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 { @Overridepublic 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 { @Overridepublic 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; } }
    

    📜 On top of that MapStruct the possible values are more and you can use anything that the compiler would consider as a valid integer (for example 10_000). The parse functions don't accept such strings as valid.

  • v1.2.0.Final

    October 17, 2017

    ✨ Enhancements

    • 👌 Improve support for Java 9 (#744)

    🐛 Bug fixes

    • Exceptions in nested mapping methods are not thrown (#1304)
    • Wrong reporting for non suitable constructor when a Factory exists (#1283)
    • 0️⃣ NullValueMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT was not always applied to Collection(s) (#1273)

    Tooling

    • 🗄 Don't depend on deprecated Sonatype OSS Parent pom (#1281)

    🚀 If you need the release notes from the 1.2.0 Beta and CR have a look at the appropriate tags

  • v1.2.0.CR2

    August 28, 2017

    ✨ Enhancements

    • 👀 Extension of mappingInheritanceStrategy, removing of name based ignore reverse mapping (#1255) - See important notice

    🐛 Bug fixes

    • ⚡️ Use update methods for different sources for nested targets (#1269)

    📚 Documentation

    • 🛠 Fixing typos in the documentation
    • ➕ Add note that @MappingTarget must not be null (#748)

    Tooling

    • ➕ Add japicmp for the MapStruct API (#1231)
    • 🚀 Deploy SNAPSHOTs from Travis (#1251)

    Important notice:

    • With the fix for #1065 in 1.2.0.Beta2, where we added inheritance of Reverse Mappings as well, the issue #1255 occurred. Therefore the MappingInheritanceStrategy has been extend:
      • EXPLICIT - Only inherits if explicitly stated
      • AUTO_INHERIT_FROM_CONFIG - Will automatically inherit only forward configuration
      • AUTO_INHERIT_REVERSE_FROM_CONFIG - Will automatically inherit only reverse configuration
      • AUTO_INHERIT_ALL_FROM_CONFIG - Will automatically inherit both forward and reverse configuration

    ➕ Additionally mappings that only have target name and ignore are inherited only in forward mappings, no matter of the inheritance strategy.

    A mapping like:

    @Mapping(target = "field1", ignore = true)TargetBase map(SourceBase source)
    

    Will only inherit forward mappings. There won't be any name based matching for ignoring in the reverse. If you want to ignore a field with the same name in SourceBase you will need to define a mapping like:

    @Mapping(target = "field1", source = "field1`, ignore = true)`TargetBase map(SourceBase source)
    
  • v1.2.0.CR1

    July 15, 2017

    ✨ Enhancements

    • 👉 Make sure that only types belonging to java.lang are not imported (#1227)
    • 👌 Improve error reporting for nested properties (#1150)
    • Report the specific type for which a nested target property has no write accessor or not exists (#1185)
    • ➕ Add Java 9 Automatic Module Name in Manifest (#1224)

    🐛 Bug fixes

    • 🛠 Fix wildcards in collection adder mappings (#1170)
    • 0️⃣ Make sure that capitilization and decapitilization does not use the default locale (#883)
    • Wildcard generics generated code contains fully qualified names (#543)
    • 👍 Nested Mapper Interface not supported (#611)
    • Mapping does not work when parameter name is size (#1244) - The fix in PR #1245 should stop any other FreeMarker special treatments of parameters
    • Source parameter for @ObjectFactory method is not well defined (#1131)
    • Ambiguous factory method for @ObjectFactory with and without parameters (#1242)
    • Several mappings ignored when defined another mapping with embedded paths (#1247)

    📚 Documentation

    • 📚 Mention ability to turn of automatic sub-mapping generation in documentation (#1219)

    Important notice:

    • 📚 During the generation of automatic sub-mapping methods Shared Configurations will not be taken into consideration, yet. Follow issue #1086 for more information.

    Behavior changes:

    • With the fix for #611 the way nested mappers are created has been changed. Example:

      public interface MyMapper { @Mapperpublic interface NestedMapper { } }

    The NestedMapperImpl will be generated in the following java file: MyMapper$NestedMapperImpl.java

  • v1.2.0.Beta3

    May 31, 2017

    ✨ Enhancements

    • ➕ Add a switch to turn off auto-mappings (#993)
    • Validate value given for date format is valid (#725 and #445)
    • 🐎 Set initial capacity for new collection / map element in collection / map mappings (#777). This one also increases the performance of the generated code
    • ➕ Add SPI for excluding types/elements from automatic sub-mapping generation (#1154)
    • Suggest property name in error message when referring to a non-existent property in @mapping (#122)
    • General code cleanups (#1213)

    🐛 Bug fixes and other changes

    • Field mapping does not work for nested target properties (#1155)
    • 👷 Use Travis CI for PRs (#1171)
    • ➕ Add Codecov for coverage integration within PRs (#1194)
    • 👉 Make sure that all import types of a Type are imported for the collection and map wrappers (#1164) PR #1165
    • Do not use invalid TargetReferences when creating nested target mappings (#1153)
    • Nested target properties uses same method for different mappings (#1148)
    • ⬆️ Regression: Missing import when upgrading to 1.2.0.Beta2 (#1215)
    • Don't use equals and hashCode from TypeMirror (#1129)

    Behavior changes:

    • ⚡️ Make sure we don't do a null check all the time for SetterWrapperForCollections (#1164) PR #1175 - behavior change: Add branch for explicit set to null for not present collections in create methods, there is no behavior change in update methods. E.g.

    Before:

    List\<String\> list = source.getStrings();if ( list != null ) { domain.setStrings( new HashSet\<String\>( list ) ); }if ( source.hasStrings() ) { List\<String\> list = source.getStrings(); domain.setStrings( new HashSet\<String\>( list ) ); }
    

    After:

    List\<String\> list = source.getStrings();if ( list != null ) { domain.setStrings( new HashSet\<String\>( list ) ); }else { domain.setStrings( null ); }if ( source.hasStrings() ) { List\<String\> list = source.getStrings(); domain.setStrings( new HashSet\<String\>( list ) ); }else { domain.setStrings( null ); }
    
    • No automatic sub-mapping methods will be generated between some custom type and some type declared in the Java class library (#1154) PR #1183
  • v1.2.0.Beta2

    July 16, 2017
  • v1.2.0.Beta1

    July 16, 2017