NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
Maven Central · #827 by repository stars
Deprecated MapStruct artifact containing annotations to be used with JDK 8 and later - Relocated to mapstruct
Last release 3 months ago
27 Jun 2026
Release timing varies
gaps range from 9 days to 1.2 years
Rarely documented
notes for 4 of 18 stable releases
Nothing withdrawn
no release was ever pulled
12 years old
46 releases · first in 2014
Make URLToStringConversion generate URI.create(String).toURL() instead of the deprecated new URL(String)
@NonNull, @Nullable, @NullMarked and @NullUnmarked from org.jspecify.annotations to control null check generation:
@NonNull skips null checks; target @NonNull always adds them@NonNull source parameters skip the method-level null guard@NonNull source on collection-typed property mappings skips the wrapping null guardIterable, Map, Stream, arrays) honor JSpecify on their source parameter@NonNull mapping-method return type implies NullValueMappingStrategy.RETURN_DEFAULT semantics across bean, iterable, map and stream mapping methods@NullMarked / @NullUnmarked scope is resolved by walking method → class → outer class → package@NonNull constructor parameter without a defaultValuemapstruct.disableJSpecify compiler optionURI to String built-in conversions (#4018)ClassAccessibility enum to control the declared accessibility of generated mappers (#2513)SET_TO_NULL for overloaded target methods, requiring a cast (#3949)URLToStringConversion generate URI.create(String).toURL() instead of the deprecated new URL(String) (#4041)SET_TO_DEFAULT when the target has no accessible no-args constructor (#4060)new expressions in generated code (#4045)LinkedHashMap and LinkedHashSet when targeting SequencedSet and SequencedMap (#3990)Type.describe() (#3991)Optional target not using the static builder factory method (#4046)ZonedDateTime or OffsetDateTime to LocalDateTime or Instant (#4027)SECURITY.md and .github/INCIDENT_RESPONSE.mdjava-kotlin to noneCustomImportOrder (#4024)fail in assertCheckstyleRulesNumber API usage from testsStandardCharsets.UTF_8 in testsModifiableURLClassLoader test util (#4052)LauncherDiscoveryListener with CompilerLauncherInterceptor (#4051)ParenPad for ENUM_CONSTANT_DEF via Checkstyle (#4075)JavaFileAssert#hasSameMapperContent to include file information in the diff (#4063)Visitor6 usages to Visitor8TypeFactory.getTypeParameters (#4020)ValueMappingMethod by removing inversion (#4007)keySet() invocation (#3989)Fields (#4010)GeneratedTypeBuilder (#4009)equals of Type (#3995)isDefaultMethod (#4053)One column per quarter.
Support for Java 21 Sequenced Collections
java.util.Optional mapping (#674) - MapStruct now fully supports Optional as both source and target types:
Optional to Optional - Both source and target wrapped in OptionalOptional to Non-Optional - Unwrapping Optional valuesOptional to Optional - Wrapping values in OptionalOptional properties in beans with automatic presence checks. Note, there is no null check done for Optional properties.org.jetbrains.kotlin:kotlin-metadata-jvm.
@IgnoredBuilder and has a constructor with parameters,@SubclassMapping mapping (#3821) - Available on @BeanMapping, @Mapper and @MappingConfig.NullValuePropertyMappingStrategy#CLEAR for clearing Collection and Map properties when updating a bean (#1830)@AnnotatedWith on decorators (#3659)ignoreUnmappedSourceProperties entries (#3906)Optional with Optional.empty instead of null (#3852)String to Number as lossy conversion (#3848)@TargetPropertyName failing for nested update mappings (#3809)mapstruct.disableLifecycleOverloadDeduplicateSelector.@Context (#3711)NullValuePropertyMappingStrategy.IGNORE for collections / maps without setters (#3806)NullValuePropertyMappingStrategy.SET_TO_DEFAULT initializes empty collection/map when target is null (#3884)Override (#3905)With this change, if the target bean does not have any target properties, a warning will be shown.
This is like this to avoid potential mistakes by users, where they might think that the target bean has properties, but it does not.
ignoreUnmappedSourceProperties entries (#3906)With this change, if the ignoreUnmappedSourceProperties configuration contains properties that are actually mapped, a warning or compiler error will be shown.
The unmappedSourcePolicy is used to determine whether a warning, or an error is shown.
Optional with Optional.empty instead of null (#3852)With this change, if the target Optional property is null, it will be initialized with Optional.empty() instead of null.
String to Number as lossy conversion (#3848)With this change, if the source String property is mapped to a Number property, a warning will be shown.
This is similar to what is happening when mapping long to int, etc.
The typeConversionPolicy ReportingPolicy is used to determine whether a warning, error or ignore is shown.
Redundant if condition in Java record mapping with RETURN_DEFAULT strategy
RETURN_DEFAULT strategy (#3747)java.time.LocalDate when mapping source LocalDateTime to target LocalDate (#3732)Regression from 1.6.1: ClassCastException when using records
Use Java LinkedHashSet and LinkedHashMap new factory method with known capacity when on Java 19 or later
LinkedHashSet and LinkedHashMap new factory method with known capacity when on Java 19 or later (#3113)SubclassMapping: generic vs raw types (#3668)InheritInverseConfiguration with nested target properties and reversing target = "." (#3670)@AfterMapping methods are called twice when using target with builder (#3678)@AfterMapping method with Builder and TargetObject (#3703)Prior to this fix @Mapping(target = "myProperty", ignore = true) was being ignored when using @InheritInverseConfiguration.
e.g.
@Mapper
public interface ModelMapper {
@Mapping(target = "creationDate", ignore = true)
Entity toEntity(Model model);
@InheritInverseConfiguration
Model toModel(Entity entity);
}In the example above prior 1.6.1 the Model toModel(Entity entity) was going to map the id property. In order to keep that behavior you'll need to explicitly do the mapping for it.
@Mapper
public interface ModelMappe {
@Mapping(target = "creationDate", ignore = true) // NOTE: Handled by JPA.
Entity toEntity(Model model);
@InheritInverseConfiguration
@Mapping(target = "creationDate", source = "creationDate") // Allow reading from Entity
Model toModel(Entity entity);
}Previous Release Notes 1.6.0.RC1 1.6.0.Beta2 1.6.0.Beta1
Breaking change: ( #3574 ) - This reverts #2560 , because we've decided that @BeanMapping(ignoreByDefault = true) should only be applied to target pro…
@BeanMapping(ignoreByDefault = true) should only be applied to target properties and not to source properties.BeanMapping#unmappedSourcePolicy should be used to control what should happen with unmapped source policy@SubclassMapping not working with @BeanMapping#ignoreUnmappedSourceProperties (#3609)unmappedSourcePolicy default value (#3635)In 1.6, support for presence checks on source parameters has been added.
This means that even if you want to map a source parameter directly to some target property the new @SourceParameterCondition or @Condition(appliesTo = ConditionStrategy.SOURCE_PARAMETERS) should be used.
e.g.
If we had the following in 1.5:
@Mapper
public interface OrderMapper {
@Mapping(source = "dto", target = "customer", conditionQualifiedByName = "mapCustomerFromOrder")
Order map(OrderDTO dto);
@Condition
@Named("mapCustomerFromOrder")
default boolean mapCustomerFromOrder(OrderDTO dto) {
return dto != null && dto.getCustomerName() != null;
}
}Then MapStruct would generate
public class OrderMapperImpl implements OrderMapper {
@Override
public Order map(OrderDTO dto) {
if ( dto == null ) {
return null;
}
Order order = new Order();
if ( mapCustomerFromOrder( dto ) ) {
order.setCustomer( orderDtoToCustomer( orderDTO ) );
}
return order;
}
}In order for the same to be generated in 1.6, the mapper needs to look like this:
@Mapper
public interface OrderMapper {
@Mapping(source = "dto", target = "customer", conditionQualifiedByName = "mapCustomerFromOrder")
Order map(OrderDTO dto);
@SourceParameterCondition
@Named("mapCustomerFromOrder")
default boolean mapCustomerFromOrder(OrderDTO dto) {
return dto != null && dto.getCustomerName() != null;
}
}Support conditional mapping for source parameters ( #2610 , #3459 , #3270 )
@SourcePropertyName to handle a property name of the source object (#3323) - Currently only applicable for @Condition methodstarget = "." using expression (#3485)@Condition cannot be used only with @Context parameters (#3561)@Condition treated as ambiguous mapping for methods returning Boolean/boolean (#3565)Mapping#expression and Mapping#conditionalQualifiedBy(Name) should lead to compile error (#3413)Mapping#ignoreByDefault is inherited in nested mappings in documentation (#3577)Breaking change: Mapping from Map to Bean
@TargetPropertyName can be used to access the target property name to conditional and mapping methods@AnnotateWith. If a method is annotated with @Deprecated it is automatically copied into the generated code.nullValueIterableMappingStrategy and nullValueMapMappingStrategy (#2953) - The different strategies can be configured using mapstruct.nullValueIterableMappingStrategy and mapstruct.nullValueMapMappingStrategy respectivelySubclassMapping annotated methods (#3119)AdditionalSupportedOptionsProvider that can be used to defined the supported options for a custom SPI. The additional options cannot start with mapstruct.@JavadocEnum and Integer (#2963)Locale and String (#3172)java.time.LocalDate and java.time.LocalDateTime (#3199)@AnnotateWith(value = Service.class, elements = @AnnotateWith.Element(strings = "cakeMapperV2"))@ValueMapping (#3037)CollectionMappingStrategy#TARGET_IMMUTABLE (#2952)SubclassMapping (#3202)@InheritConfiguration for @SubclassMapping in methods with identical signature (#3125)subclassExhaustiveStrategy when source is a sealed class and all subtypes are specified (#3054)String type for @TargetPropertyName (#2863)@BeforeMapping with @TargetType the type being build@AfterMapping with @TargetType the type being build@AfterMapping with @MappingTarget the type being build@Default on Java Record's constructor isn't respected (#3231)InjectionStrategy.SETTER (#3229)BeanMapping#unmappedSourcePolicy (#3309)Iterable to Collection (#3376)@TargetType on Collection fails to compile (#2901)@SubclassMapping (#3174)@BeanMapping(ignoreByDefault = true) does not work for constructor properties (#3158)@ValueMapping strips spaces from source (#3153)defaultExpression does not work when mapping a collection of custom types (#3159)NullPointerException when ignoring target '.' (#3238) - There is now a compilation error instead of an error in the processorNullValuePropertyMappingStrategy.IGNORE does not ignore target collection even when source one is null (only when collectionMappingStrategy = CollectionMappingStrategy.TARGET_IMMUTABLE) (#3104)@SubclassMapping not working with @Mapping nested properties and target all (#3126)default and static methods in @MapperConfig (#3296)CollectionMappingStrategy.ADDER_PREFERRED fails (#3310)@InheritConfiguration (#3361)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)
}
@BeanMapping inheritanceAll, except resultType and ignoredUnmappedSourceProperties attributes of @BeanMapping have been made to consistently be passed down to the generated nested methods. This means that if you were relying on some buggy behavior it might no longer work.
e.g. BeanMapping#ignoreByDefault was not being passed down properly, i.e. implicit mapping was being done for nested properties. This has been fixed. If you want to implicitly map nested mappings then you'll have to define your own mapper appropriatelly.
@Mapper
interface MyMapper {
@BeanMapping( ignoreByDefault = true )
@Mapping( source = "sub", target = "target" )
Target map( Source source );
}needs to be replaced with
@Mapper
interface MyMapper {
@BeanMapping( ignoreByDefault = true )
@Mapping( source = "sub", target = "target" )
Target map( Source source );
// this is the mapping `source = "sub"` and `target = "target"`
// redefined to get rid of the `ignoreByDefault=true`, because this property is inherited
SubTarget subSourceToSubTarget( SubSource subSource );
}After the request from the community we have enabled sponsoring for the project. See #2340 for how you can sponsor us if you want to.
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Your coding agent can read these notes before it upgrades. Set up the MCP server →