mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
Compare commits
38 Commits
main
...
1.5.5.Fina
Author | SHA1 | Date | |
---|---|---|---|
|
0f92764de9 | ||
|
f1edbd25c2 | ||
|
75fb02a19f | ||
|
922258fea7 | ||
|
b657209b12 | ||
|
85b2a18b3c | ||
|
7a0ed4e409 | ||
|
35228b3cb7 | ||
|
998b3e96d7 | ||
|
b9c6256d3c | ||
|
a5f57a77cf | ||
|
257796b959 | ||
|
9794543946 | ||
|
53baf96126 | ||
|
a67e4e5f96 | ||
|
50d96eb367 | ||
|
429cc3f914 | ||
|
60026437e4 | ||
|
c4e3320b98 | ||
|
6f262ef405 | ||
|
7cfac7c060 | ||
|
9d2bed09ca | ||
|
a98986c08e | ||
|
73f70b1564 | ||
|
b1eda5a04e | ||
|
45e01fea91 | ||
|
473d581528 | ||
|
290189652c | ||
|
51e67ebca4 | ||
|
1c3c46f1ef | ||
|
383ed23ed2 | ||
|
d0e9d69be1 | ||
|
082b36a50a | ||
|
febed7ea1c | ||
|
3a94eb80b0 | ||
|
d9ad48154a | ||
|
e5c7fdb2f6 | ||
|
e3f9a1ccd5 |
@ -12,7 +12,7 @@
|
||||
<parent>
|
||||
<groupId>org.mapstruct</groupId>
|
||||
<artifactId>mapstruct-parent</artifactId>
|
||||
<version>1.6.0-SNAPSHOT</version>
|
||||
<version>1.5.5.Final</version>
|
||||
<relativePath>../parent/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
<parent>
|
||||
<groupId>org.mapstruct</groupId>
|
||||
<artifactId>mapstruct-parent</artifactId>
|
||||
<version>1.6.0-SNAPSHOT</version>
|
||||
<version>1.5.5.Final</version>
|
||||
<relativePath>../parent/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
<parent>
|
||||
<groupId>org.mapstruct</groupId>
|
||||
<artifactId>mapstruct-parent</artifactId>
|
||||
<version>1.6.0-SNAPSHOT</version>
|
||||
<version>1.5.5.Final</version>
|
||||
<relativePath>../parent/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
@ -98,7 +98,7 @@ public @interface EnumMapping {
|
||||
* <ul>
|
||||
* <li>{@link MappingConstants#SUFFIX_TRANSFORMATION} - applies the given {@link #configuration()} as a
|
||||
* suffix to the source enum</li>
|
||||
* <li>{@link MappingConstants#STRIP_SUFFIX_TRANSFORMATION} - strips the the given {@link #configuration()}
|
||||
* <li>{@link MappingConstants#STRIP_SUFFIX_TRANSFORMATION} - strips the given {@link #configuration()}
|
||||
* from the end of the source enum</li>
|
||||
* <li>{@link MappingConstants#PREFIX_TRANSFORMATION} - applies the given {@link #configuration()} as a
|
||||
* prefix to the source enum</li>
|
||||
|
@ -81,8 +81,8 @@ import java.lang.annotation.Target;
|
||||
public @interface InheritInverseConfiguration {
|
||||
|
||||
/**
|
||||
* The name of the inverse mapping method to inherit the mappings from. Needs only to be specified in case more than
|
||||
* one inverse method with matching source and target type exists.
|
||||
* The name of the inverse mapping method to inherit the mappings from. Needs to be specified only in case more than
|
||||
* one inverse method exists with a matching source and target type exists.
|
||||
*
|
||||
* @return The name of the inverse mapping method to inherit the mappings from.
|
||||
*/
|
||||
|
@ -298,7 +298,7 @@ public @interface Mapper {
|
||||
* Can be configured by the {@link MapperConfig#disableSubMappingMethodsGeneration()} as well.
|
||||
* <p>
|
||||
* Note: If you need to use {@code disableSubMappingMethodsGeneration} please contact the MapStruct team at
|
||||
* <a href="http://mapstruct.org">mapstruct.org</a> or
|
||||
* <a href="https://mapstruct.org">mapstruct.org</a> or
|
||||
* <a href="https://github.com/mapstruct/mapstruct">github.com/mapstruct/mapstruct</a> to share what problem you
|
||||
* are facing with the automatic sub-mapping generation.
|
||||
*
|
||||
|
@ -269,7 +269,7 @@ public @interface MapperConfig {
|
||||
* Can be overridden by {@link Mapper#disableSubMappingMethodsGeneration()}
|
||||
* <p>
|
||||
* Note: If you need to use {@code disableSubMappingMethodsGeneration} please contact the MapStruct team at
|
||||
* <a href="http://mapstruct.org">mapstruct.org</a> or
|
||||
* <a href="https://mapstruct.org">mapstruct.org</a> or
|
||||
* <a href="https://github.com/mapstruct/mapstruct">github.com/mapstruct/mapstruct</a> to share what problem you
|
||||
* are facing with the automatic sub-mapping generation.
|
||||
*
|
||||
|
@ -109,7 +109,12 @@ public final class MappingConstants {
|
||||
public static final String DEFAULT = "default";
|
||||
|
||||
/**
|
||||
* The generated mapper is an application-scoped CDI bean and can be retrieved via @Inject
|
||||
* The generated mapper is an application-scoped CDI bean and can be retrieved via @Inject.
|
||||
* The annotations are either from {@code javax} or {@code jakarta}.
|
||||
* Priority have the {@code javax} annotations.
|
||||
* In case you want to only use Jakarta then use {@link #JAKARTA_CDI}.
|
||||
*
|
||||
* @see #JAKARTA_CDI
|
||||
*/
|
||||
public static final String CDI = "cdi";
|
||||
|
||||
@ -138,6 +143,12 @@ public final class MappingConstants {
|
||||
*/
|
||||
public static final String JAKARTA = "jakarta";
|
||||
|
||||
/**
|
||||
* The generated mapper is an application-scoped Jakarta CDI bean and can be retrieved via @Inject.
|
||||
* @see #CDI
|
||||
*/
|
||||
public static final String JAKARTA_CDI = "jakarta-cdi";
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ package org.mapstruct;
|
||||
/**
|
||||
* Strategy for dealing with null source values.
|
||||
*
|
||||
* <b>Note:</b> This strategy is not in effect when the a specific source presence check method is defined
|
||||
* <b>Note:</b> This strategy is not in effect when a specific source presence check method is defined
|
||||
* in the service provider interface (SPI).
|
||||
* <p>
|
||||
* <b>Note</b>: some types of mappings (collections, maps), in which MapStruct is instructed to use a getter or adder
|
||||
|
@ -13,6 +13,6 @@
|
||||
* This package contains several annotations which allow to configure how mapper interfaces are generated.
|
||||
* </p>
|
||||
*
|
||||
* @see <a href="http://mapstruct.org/">MapStruct reference documentation</a>
|
||||
* @see <a href="https://mapstruct.org/">MapStruct reference documentation</a>
|
||||
*/
|
||||
package org.mapstruct;
|
||||
|
@ -12,7 +12,7 @@
|
||||
<parent>
|
||||
<groupId>org.mapstruct</groupId>
|
||||
<artifactId>mapstruct-parent</artifactId>
|
||||
<version>1.6.0-SNAPSHOT</version>
|
||||
<version>1.5.5.Final</version>
|
||||
<relativePath>../parent/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
@ -39,6 +39,13 @@
|
||||
<groupId>org.mapstruct.tools.gem</groupId>
|
||||
<artifactId>gem-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>jakarta.xml.bind</groupId>
|
||||
<artifactId>jakarta.xml.bind-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
@ -93,7 +100,7 @@
|
||||
<doctitle>MapStruct ${project.version}</doctitle>
|
||||
<windowtitle>MapStruct ${project.version}</windowtitle>
|
||||
<bottom>
|
||||
<![CDATA[Copyright © ${project.inceptionYear}-{currentYear} <a href="http://mapstruct.org/">MapStruct Authors</a>; All rights reserved. Released under the <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache Software License 2.0</a>.]]>
|
||||
<![CDATA[Copyright © ${project.inceptionYear}-{currentYear} <a href="https://mapstruct.org/">MapStruct Authors</a>; All rights reserved. Released under the <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache Software License 2.0</a>.]]>
|
||||
</bottom>
|
||||
|
||||
<groups>
|
||||
@ -187,7 +194,6 @@
|
||||
<dependency>
|
||||
<groupId>javax.xml.bind</groupId>
|
||||
<artifactId>jaxb-api</artifactId>
|
||||
<version>2.3.1</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
@ -12,7 +12,7 @@
|
||||
<parent>
|
||||
<groupId>org.mapstruct</groupId>
|
||||
<artifactId>mapstruct-parent</artifactId>
|
||||
<version>1.6.0-SNAPSHOT</version>
|
||||
<version>1.5.5.Final</version>
|
||||
<relativePath>../parent/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
@ -292,7 +292,7 @@ The source presence checker name can be changed in the MapStruct service provide
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
Some types of mappings (collections, maps), in which MapStruct is instructed to use a getter or adder as target accessor see `CollectionMappingStrategy`, MapStruct will always generate a source property
|
||||
Some types of mappings (collections, maps), in which MapStruct is instructed to use a getter or adder as target accessor (see `CollectionMappingStrategy`), MapStruct will always generate a source property
|
||||
null check, regardless the value of the `NullValueCheckStrategy` to avoid addition of `null` to the target collection or map.
|
||||
====
|
||||
|
||||
|
@ -130,7 +130,7 @@ You can find a complete example in the https://github.com/mapstruct/mapstruct-ex
|
||||
|
||||
The MapStruct code generator can be configured using _annotation processor options_.
|
||||
|
||||
When invoking javac directly, these options are passed to the compiler in the form _-Akey=value_. When using MapStruct via Maven, any processor options can be passed using an `options` element within the configuration of the Maven processor plug-in like this:
|
||||
When invoking javac directly, these options are passed to the compiler in the form _-Akey=value_. When using MapStruct via Maven, any processor options can be passed using `compilerArgs` within the configuration of the Maven processor plug-in like this:
|
||||
|
||||
.Maven configuration
|
||||
====
|
||||
@ -215,10 +215,11 @@ suppressGeneratorVersionInfoComment`
|
||||
Supported values are:
|
||||
|
||||
* `default`: the mapper uses no component model, instances are typically retrieved via `Mappers#getMapper(Class)`
|
||||
* `cdi`: the generated mapper is an application-scoped CDI bean and can be retrieved via `@Inject`
|
||||
* `cdi`: the generated mapper is an application-scoped (from javax.enterprise.context or jakarta.enterprise.context, depending on which one is available with javax.inject having priority) CDI bean and can be retrieved via `@Inject`
|
||||
* `spring`: the generated mapper is a singleton-scoped Spring bean and can be retrieved via `@Autowired`
|
||||
* `jsr330`: the generated mapper is annotated with {@code @Named} and can be retrieved via `@Inject` (from javax.inject or jakarta.inject, depending which one is available with javax.inject having priority), e.g. using Spring
|
||||
* `jakarta`: the generated mapper is annotated with {@code @Named} and can be retrieved via `@Inject` (from jakarta.inject), e.g. using Spring
|
||||
* `jakarta-cdi`: the generated mapper is an application-scoped (from jakarta.enterprise.context) CDI bean and can be retrieved via `@Inject`
|
||||
|
||||
If a component model is given for a specific mapper via `@Mapper#componentModel()`, the value from the annotation takes precedence.
|
||||
|`default`
|
||||
@ -273,3 +274,28 @@ disableBuilders`
|
||||
MapStruct can be used with Java 9 and higher versions.
|
||||
|
||||
To allow usage of the `@Generated` annotation `java.annotation.processing.Generated` (part of the `java.compiler` module) can be enabled.
|
||||
|
||||
=== IDE Integration
|
||||
|
||||
There are optional MapStruct plugins for IntelliJ and Eclipse that allow you to have additional completion support (and more) in the annotations.
|
||||
|
||||
==== IntelliJ
|
||||
|
||||
The https://plugins.jetbrains.com/plugin/10036-mapstruct-support[MapStruct IntelliJ] plugin offers assistance in projects that use MapStruct.
|
||||
|
||||
Some features include:
|
||||
|
||||
* Code completion in `target`, `source`, `expression`
|
||||
* Go To Declaration for properties in `target` and `source`
|
||||
* Find Usages of properties in `target` and `source`
|
||||
* Refactoring support
|
||||
* Errors and Quick Fixes
|
||||
|
||||
==== Eclipse
|
||||
|
||||
The https://marketplace.eclipse.org/content/mapstruct-eclipse-plugin[MapStruct Eclipse] Plugin offers assistance in projects that use MapStruct.
|
||||
|
||||
Some features include:
|
||||
|
||||
* Code completion in `target` and `source`
|
||||
* Quick Fixes
|
||||
|
@ -65,7 +65,7 @@ public class OrderMapperImpl implements OrderMapper {
|
||||
----
|
||||
====
|
||||
By default an error will be raised by MapStruct in case a constant of the source enum type does not have a corresponding constant with the same name in the target type and also is not mapped to another constant via `@ValueMapping`. This ensures that all constants are mapped in a safe and predictable manner. The generated
|
||||
mapping method will throw an IllegalStateException if for some reason an unrecognized source value occurs.
|
||||
mapping method will throw an `IllegalStateException` if for some reason an unrecognized source value occurs.
|
||||
|
||||
MapStruct also has a mechanism for mapping any remaining (unspecified) mappings to a default. This can be used only once in a set of value mappings and only applies to the source. It comes in two flavors: `<ANY_REMAINING>` and `<ANY_UNMAPPED>`. They cannot be used at the same time.
|
||||
|
||||
@ -75,14 +75,18 @@ MapStruct will *not* attempt such name based mapping for `<ANY_UNMAPPED>` and di
|
||||
|
||||
MapStruct is able to handle `null` sources and `null` targets by means of the `<NULL>` keyword.
|
||||
|
||||
In addition, the constant value `<THROW_EXCEPTION>` can be used for throwing an exception for particular value mappings. This value is only applicable to `ValueMapping#target()` and not `ValueMapping#source()` since MapStruct can't map from exceptions.
|
||||
|
||||
[TIP]
|
||||
====
|
||||
Constants for `<ANY_REMAINING>`, `<ANY_UNMAPPED>` and `<NULL>` are available in the `MappingConstants` class.
|
||||
Constants for `<ANY_REMAINING>`, `<ANY_UNMAPPED>`, `<THROW_EXCEPTION>` and `<NULL>` are available in the `MappingConstants` class.
|
||||
====
|
||||
|
||||
Finally `@InheritInverseConfiguration` and `@InheritConfiguration` can be used in combination with `@ValueMappings`. `<ANY_REMAINING>` and `<ANY_UNMAPPED>` will be ignored in that case.
|
||||
|
||||
.Enum mapping method, <NULL> and <ANY_REMAINING>
|
||||
The following code snippets exemplify the use of the aforementioned constants.
|
||||
|
||||
.Enum mapping method, `<NULL>` and `<ANY_REMAINING>`
|
||||
====
|
||||
[source, java, linenums]
|
||||
[subs="verbatim,attributes"]
|
||||
@ -102,7 +106,7 @@ public interface SpecialOrderMapper {
|
||||
----
|
||||
====
|
||||
|
||||
.Enum mapping method result, <NULL> and <ANY_REMAINING>
|
||||
.Enum mapping method result, `<NULL>` and `<ANY_REMAINING>`
|
||||
====
|
||||
[source, java, linenums]
|
||||
[subs="verbatim,attributes"]
|
||||
@ -137,6 +141,55 @@ public class SpecialOrderMapperImpl implements SpecialOrderMapper {
|
||||
*Note:* MapStruct would have refrained from mapping the `RETAIL` and `B2B` when `<ANY_UNMAPPED>` was used instead of `<ANY_REMAINING>`.
|
||||
|
||||
|
||||
.Enum mapping method with `<THROW_EXCEPTION>`
|
||||
====
|
||||
[source, java, linenums]
|
||||
[subs="verbatim,attributes"]
|
||||
----
|
||||
@Mapper
|
||||
public interface SpecialOrderMapper {
|
||||
|
||||
SpecialOrderMapper INSTANCE = Mappers.getMapper( SpecialOrderMapper.class );
|
||||
|
||||
@ValueMappings({
|
||||
@ValueMapping( source = "STANDARD", target = "DEFAULT" ),
|
||||
@ValueMapping( source = "C2C", target = MappingConstants.THROW_EXCEPTION )
|
||||
})
|
||||
ExternalOrderType orderTypeToExternalOrderType(OrderType orderType);
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
.Enum mapping method with `<THROW_EXCEPTION>` result
|
||||
====
|
||||
[source, java, linenums]
|
||||
[subs="verbatim,attributes"]
|
||||
----
|
||||
// GENERATED CODE
|
||||
public class SpecialOrderMapperImpl implements SpecialOrderMapper {
|
||||
|
||||
@Override
|
||||
public ExternalOrderType orderTypeToExternalOrderType(OrderType orderType) {
|
||||
if ( orderType == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ExternalOrderType externalOrderType;
|
||||
|
||||
switch ( orderType ) {
|
||||
case STANDARD: externalOrderType = ExternalOrderType.DEFAULT;
|
||||
break;
|
||||
case C2C: throw new IllegalArgumentException( "Unexpected enum constant: " + orderType );
|
||||
default: throw new IllegalArgumentException( "Unexpected enum constant: " + orderType );
|
||||
}
|
||||
|
||||
return externalOrderType;
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
|
||||
[WARNING]
|
||||
====
|
||||
The mapping of enum to enum via the `@Mapping` annotation is *DEPRECATED*. It will be removed from future versions of MapStruct. Please adapt existing enum mapping methods to make use of `@ValueMapping` instead.
|
||||
@ -152,6 +205,7 @@ MapStruct supports enum to a String mapping along the same lines as is described
|
||||
2. Similarity: `<ANY_UNMAPPED`> stops after handling defined mapping and proceeds to the switch/default clause value.
|
||||
3. Difference: `<ANY_REMAINING>` will result in an error. It acts on the premise that there is name similarity between enum constants in source and target which does not make sense for a String type.
|
||||
4. Difference: Given 1. and 3. there will never be unmapped values.
|
||||
5. Similarity: `<THROW_EXCEPTION>` can be used for throwing an exception for particular enum values.
|
||||
|
||||
*`String` to enum*
|
||||
|
||||
@ -159,6 +213,7 @@ MapStruct supports enum to a String mapping along the same lines as is described
|
||||
2. Similarity: `<ANY_UNMAPPED`> stops after handling defined mapping and proceeds to the switch/default clause value.
|
||||
3. Similarity: `<ANY_REMAINING>` will create a mapping for each target enum constant and proceed to the switch/default clause value.
|
||||
4. Difference: A switch/default value needs to be provided to have a determined outcome (enum has a limited set of values, `String` has unlimited options). Failing to specify `<ANY_REMAINING>` or `<ANY_UNMAPPED`> will result in a warning.
|
||||
5. Similarity: `<THROW_EXCEPTION>` can be used for throwing an exception for any arbitrary `String` value.
|
||||
|
||||
=== Custom name transformation
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
<parent>
|
||||
<groupId>org.mapstruct</groupId>
|
||||
<artifactId>mapstruct-parent</artifactId>
|
||||
<version>1.6.0-SNAPSHOT</version>
|
||||
<version>1.5.5.Final</version>
|
||||
<relativePath>../parent/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
@ -133,8 +133,8 @@
|
||||
<dependency>
|
||||
<groupId>javax.xml.bind</groupId>
|
||||
<artifactId>jaxb-api</artifactId>
|
||||
<version>2.3.1</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
|
@ -28,6 +28,14 @@ public final class FullFeatureCompilationExclusionCliEnhancer implements Process
|
||||
additionalExcludes.add( "org/mapstruct/ap/test/bugs/_1801/*.java" );
|
||||
|
||||
switch ( currentJreVersion ) {
|
||||
case JAVA_8:
|
||||
if ( processorType == ProcessorTest.ProcessorType.ECLIPSE_JDT ) {
|
||||
additionalExcludes.add(
|
||||
"org/mapstruct/ap/test/selection/methodgenerics/wildcards/LifecycleIntersectionMapper.java" );
|
||||
}
|
||||
additionalExcludes.add( "org/mapstruct/ap/test/injectionstrategy/cdi/**/*.java" );
|
||||
additionalExcludes.add( "org/mapstruct/ap/test/injectionstrategy/jakarta_cdi/**/*.java" );
|
||||
break;
|
||||
case JAVA_9:
|
||||
// TODO find out why this fails:
|
||||
additionalExcludes.add( "org/mapstruct/ap/test/collection/wildcard/BeanMapper.java" );
|
||||
|
@ -75,6 +75,10 @@ public class MavenIntegrationTest {
|
||||
void jaxbTest() {
|
||||
}
|
||||
|
||||
@ProcessorTest(baseDir = "jakartaJaxbTest")
|
||||
void jakartaJaxbTest() {
|
||||
}
|
||||
|
||||
@ProcessorTest(baseDir = "jsr330Test")
|
||||
void jsr330Test() {
|
||||
}
|
||||
|
@ -64,6 +64,10 @@
|
||||
<groupId>jakarta.inject</groupId>
|
||||
<artifactId>jakarta.inject-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.enterprise</groupId>
|
||||
<artifactId>jakarta.enterprise.cdi-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring -->
|
||||
<dependency>
|
||||
@ -79,6 +83,13 @@
|
||||
<groupId>joda-time</groupId>
|
||||
<artifactId>joda-time</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>jakarta.xml.bind</groupId>
|
||||
<artifactId>jakarta.xml.bind-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<profiles>
|
||||
@ -89,14 +100,16 @@
|
||||
</activation>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>jakarta.xml.bind</groupId>
|
||||
<artifactId>jakarta.xml.bind-api</artifactId>
|
||||
<version>2.3.2</version>
|
||||
<groupId>javax.xml.bind</groupId>
|
||||
<artifactId>jaxb-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jaxb</groupId>
|
||||
<artifactId>jaxb-runtime</artifactId>
|
||||
<version>2.3.2</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
|
64
integrationtest/src/test/resources/jakartaJaxbTest/pom.xml
Normal file
64
integrationtest/src/test/resources/jakartaJaxbTest/pom.xml
Normal file
@ -0,0 +1,64 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Copyright MapStruct Authors.
|
||||
|
||||
Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.mapstruct</groupId>
|
||||
<artifactId>mapstruct-it-parent</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>jakartaJaxbTest</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>jakarta.xml.bind</groupId>
|
||||
<artifactId>jakarta.xml.bind-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.xml.bind</groupId>
|
||||
<artifactId>jaxb-impl</artifactId>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>jaxb2-maven-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>xjc</id>
|
||||
<phase>initialize</phase>
|
||||
<goals>
|
||||
<goal>xjc</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<xjbSources>
|
||||
<xjbSource>${project.build.resources[0].directory}/binding</xjbSource>
|
||||
</xjbSources>
|
||||
<sources>
|
||||
<source>${project.build.resources[0].directory}/schema</source>
|
||||
</sources>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.itest.jakarta.jaxb;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Sjaak Derksen
|
||||
*/
|
||||
public class OrderDetailsDto {
|
||||
|
||||
private String name;
|
||||
private List<String> description;
|
||||
private OrderStatusDto status;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public List<String> getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(List<String> description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public OrderStatusDto getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(OrderStatusDto status) {
|
||||
this.status = status;
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.itest.jakarta.jaxb;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author Sjaak Derksen
|
||||
*/
|
||||
public class OrderDto {
|
||||
|
||||
private Long orderNumber;
|
||||
private Date orderDate;
|
||||
private OrderDetailsDto orderDetails;
|
||||
private ShippingAddressDto shippingAddress;
|
||||
|
||||
public Long getOrderNumber() {
|
||||
return orderNumber;
|
||||
}
|
||||
|
||||
public void setOrderNumber(Long orderNumber) {
|
||||
this.orderNumber = orderNumber;
|
||||
}
|
||||
|
||||
public Date getOrderDate() {
|
||||
return orderDate;
|
||||
}
|
||||
|
||||
public void setOrderDate(Date orderDate) {
|
||||
this.orderDate = orderDate;
|
||||
}
|
||||
|
||||
public OrderDetailsDto getOrderDetails() {
|
||||
return orderDetails;
|
||||
}
|
||||
|
||||
public void setOrderDetails(OrderDetailsDto orderDetails) {
|
||||
this.orderDetails = orderDetails;
|
||||
}
|
||||
|
||||
public ShippingAddressDto getShippingAddress() {
|
||||
return shippingAddress;
|
||||
}
|
||||
|
||||
public void setShippingAddress(ShippingAddressDto shippingAddress) {
|
||||
this.shippingAddress = shippingAddress;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.itest.jakarta.jaxb;
|
||||
|
||||
/**
|
||||
* @author Sjaak Derksen
|
||||
*/
|
||||
public enum OrderStatusDto {
|
||||
|
||||
ORDERED( "small" ),
|
||||
PROCESSED( "medium" ),
|
||||
DELIVERED( "large" );
|
||||
private final String value;
|
||||
|
||||
OrderStatusDto(String v) {
|
||||
value = v;
|
||||
}
|
||||
|
||||
public String value() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public static OrderStatusDto fromValue(String v) {
|
||||
for ( OrderStatusDto c : OrderStatusDto.values() ) {
|
||||
if ( c.value.equals( v ) ) {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException( v );
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.itest.jakarta.jaxb;
|
||||
|
||||
/**
|
||||
* @author Sjaak Derksen
|
||||
*/
|
||||
public class ShippingAddressDto {
|
||||
|
||||
private String street;
|
||||
private String houseNumber;
|
||||
private String city;
|
||||
private String country;
|
||||
|
||||
public String getStreet() {
|
||||
return street;
|
||||
}
|
||||
|
||||
public void setStreet(String street) {
|
||||
this.street = street;
|
||||
}
|
||||
|
||||
public String getHouseNumber() {
|
||||
return houseNumber;
|
||||
}
|
||||
|
||||
public void setHouseNumber(String houseNumber) {
|
||||
this.houseNumber = houseNumber;
|
||||
}
|
||||
|
||||
public String getCity() {
|
||||
return city;
|
||||
}
|
||||
|
||||
public void setCity(String city) {
|
||||
this.city = city;
|
||||
}
|
||||
|
||||
public String getCountry() {
|
||||
return country;
|
||||
}
|
||||
|
||||
public void setCountry(String country) {
|
||||
this.country = country;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.itest.jakarta.jaxb;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
import org.mapstruct.itest.jakarta.jaxb.xsd.test1.OrderDetailsType;
|
||||
import org.mapstruct.itest.jakarta.jaxb.xsd.test1.OrderType;
|
||||
import org.mapstruct.itest.jakarta.jaxb.xsd.test2.OrderStatusType;
|
||||
import org.mapstruct.itest.jakarta.jaxb.xsd.test2.ShippingAddressType;
|
||||
import org.mapstruct.itest.jakarta.jaxb.xsd.underscores.SubType;
|
||||
|
||||
|
||||
/**
|
||||
* @author Sjaak Derksen
|
||||
*/
|
||||
@Mapper(uses = {
|
||||
org.mapstruct.itest.jakarta.jaxb.xsd.test1.ObjectFactory.class,
|
||||
org.mapstruct.itest.jakarta.jaxb.xsd.test2.ObjectFactory.class,
|
||||
org.mapstruct.itest.jakarta.jaxb.xsd.underscores.ObjectFactory.class
|
||||
})
|
||||
public interface SourceTargetMapper {
|
||||
|
||||
SourceTargetMapper INSTANCE = Mappers.getMapper( SourceTargetMapper.class );
|
||||
|
||||
// source 2 target methods
|
||||
OrderDto sourceToTarget(OrderType source);
|
||||
|
||||
OrderDetailsDto detailsToDto(OrderDetailsType source);
|
||||
|
||||
OrderStatusDto statusToDto(OrderStatusType source);
|
||||
|
||||
ShippingAddressDto shippingAddressToDto(ShippingAddressType source);
|
||||
|
||||
SubTypeDto subTypeToDto(SubType source);
|
||||
|
||||
// target 2 source methods
|
||||
OrderType targetToSource(OrderDto target);
|
||||
|
||||
OrderDetailsType dtoToDetails(OrderDetailsDto target);
|
||||
|
||||
OrderStatusType dtoToStatus(OrderStatusDto target);
|
||||
|
||||
ShippingAddressType dtoToShippingAddress(ShippingAddressDto source);
|
||||
|
||||
SubType dtoToSubType(SubTypeDto source);
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.itest.jakarta.jaxb;
|
||||
|
||||
public class SubTypeDto extends SuperTypeDto {
|
||||
private String declaredCamelCase;
|
||||
private String declaredUnderscore;
|
||||
|
||||
public String getDeclaredCamelCase() {
|
||||
return declaredCamelCase;
|
||||
}
|
||||
|
||||
public void setDeclaredCamelCase(String declaredCamelCase) {
|
||||
this.declaredCamelCase = declaredCamelCase;
|
||||
}
|
||||
|
||||
public String getDeclaredUnderscore() {
|
||||
return declaredUnderscore;
|
||||
}
|
||||
|
||||
public void setDeclaredUnderscore(String declaredUnderscore) {
|
||||
this.declaredUnderscore = declaredUnderscore;
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.itest.jakarta.jaxb;
|
||||
|
||||
public class SuperTypeDto {
|
||||
private String inheritedCamelCase;
|
||||
private String inheritedUnderscore;
|
||||
|
||||
public String getInheritedCamelCase() {
|
||||
return inheritedCamelCase;
|
||||
}
|
||||
|
||||
public void setInheritedCamelCase(String inheritedCamelCase) {
|
||||
this.inheritedCamelCase = inheritedCamelCase;
|
||||
}
|
||||
|
||||
public String getInheritedUnderscore() {
|
||||
return inheritedUnderscore;
|
||||
}
|
||||
|
||||
public void setInheritedUnderscore(String inheritedUnderscore) {
|
||||
this.inheritedUnderscore = inheritedUnderscore;
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Copyright MapStruct Authors.
|
||||
|
||||
Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
-->
|
||||
<jaxb:bindings xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:jaxb="https://jakarta.ee/xml/ns/jaxb"
|
||||
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
|
||||
jaxb:extensionBindingPrefixes="xjc"
|
||||
version="3.0" >
|
||||
|
||||
|
||||
<jaxb:globalBindings
|
||||
fixedAttributeAsConstantProperty="true"
|
||||
typesafeEnumBase="xs:string"
|
||||
typesafeEnumMemberName="generateName"
|
||||
generateIsSetMethod="true"
|
||||
generateElementProperty="true" >
|
||||
<xjc:noValidator/>
|
||||
<xjc:noValidatingUnmarshaller/>
|
||||
</jaxb:globalBindings>
|
||||
|
||||
</jaxb:bindings>
|
||||
|
||||
|
@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Copyright MapStruct Authors.
|
||||
|
||||
Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
-->
|
||||
<schema xmlns="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:test1="http://www.mapstruct.org/itest/jakarta/jaxb/xsd/test1"
|
||||
xmlns:test2="http://www.mapstruct.org/itest/jakarta/jaxb/xsd/test2"
|
||||
targetNamespace="http://www.mapstruct.org/itest/jakarta/jaxb/xsd/test1"
|
||||
elementFormDefault="qualified" version="1.0.0">
|
||||
|
||||
<import namespace="http://www.mapstruct.org/itest/jakarta/jaxb/xsd/test2" schemaLocation="test2.xsd"/>
|
||||
|
||||
<element name="Order" type="test1:OrderType" />
|
||||
<complexType name="OrderType">
|
||||
<sequence>
|
||||
<element name="orderNumber" type="long"/>
|
||||
<element name="orderDate" type="dateTime"/>
|
||||
<element name="orderDetails" type="test1:OrderDetailsType"/>
|
||||
<element name="shippingAddress" type="test2:ShippingAddressType"/>
|
||||
</sequence>
|
||||
</complexType>
|
||||
|
||||
<element name="OrderDetails" type="test1:OrderDetailsType" />
|
||||
<complexType name="OrderDetailsType">
|
||||
<sequence>
|
||||
<element name="name" type="string"/>
|
||||
<element name="description" minOccurs="1" maxOccurs="5" type="string"/>
|
||||
<element name="status" type="test2:OrderStatusType"/>
|
||||
</sequence>
|
||||
</complexType>
|
||||
|
||||
</schema>
|
@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Copyright MapStruct Authors.
|
||||
|
||||
Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
-->
|
||||
<schema xmlns="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:test2="http://www.mapstruct.org/itest/jakarta/jaxb/xsd/test2"
|
||||
targetNamespace="http://www.mapstruct.org/itest/jakarta/jaxb/xsd/test2"
|
||||
elementFormDefault="qualified" version="1.0.0">
|
||||
|
||||
<element name="OrderStatus" type="test2:OrderStatusType" />
|
||||
<simpleType name="OrderStatusType">
|
||||
<restriction base="string">
|
||||
<enumeration value="ordered" />
|
||||
<enumeration value="processed" />
|
||||
<enumeration value="delivered" />
|
||||
</restriction>
|
||||
</simpleType>
|
||||
|
||||
<element name="ShippingAddress" type="test2:ShippingAddressType" />
|
||||
<complexType name="ShippingAddressType">
|
||||
<sequence>
|
||||
<element name="street" type="string"/>
|
||||
<element name="houseNumber" type="string"/>
|
||||
<element name="city" type="string"/>
|
||||
<element name="country" type="string"/>
|
||||
</sequence>
|
||||
</complexType>
|
||||
|
||||
</schema>
|
@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Copyright MapStruct Authors.
|
||||
|
||||
Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
-->
|
||||
<schema xmlns="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:underscores="http://www.mapstruct.org/itest/jakarta/jaxb/xsd/underscores"
|
||||
targetNamespace="http://www.mapstruct.org/itest/jakarta/jaxb/xsd/underscores"
|
||||
elementFormDefault="qualified" version="1.0.0">
|
||||
|
||||
<element name="Super" type="underscores:SuperType" />
|
||||
<complexType name="SuperType">
|
||||
<sequence>
|
||||
<element name="inheritedCamelCase" type="string"/>
|
||||
<element name="inherited_underscore" type="string"/>
|
||||
</sequence>
|
||||
</complexType>
|
||||
|
||||
<element name="Sub" type="underscores:SubType" />
|
||||
<complexType name="SubType">
|
||||
<complexContent>
|
||||
<extension base="underscores:SuperType">
|
||||
<sequence>
|
||||
<element name="declaredCamelCase" type="string"/>
|
||||
<element name="declared_underscore" type="string"/>
|
||||
</sequence>
|
||||
</extension>
|
||||
</complexContent>
|
||||
</complexType>
|
||||
|
||||
</schema>
|
@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.itest.jakarta.jaxb;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
|
||||
import jakarta.xml.bind.JAXBContext;
|
||||
import jakarta.xml.bind.JAXBElement;
|
||||
import jakarta.xml.bind.JAXBException;
|
||||
import jakarta.xml.bind.Marshaller;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.mapstruct.itest.jakarta.jaxb.xsd.test1.ObjectFactory;
|
||||
import org.mapstruct.itest.jakarta.jaxb.xsd.test1.OrderType;
|
||||
import org.mapstruct.itest.jakarta.jaxb.xsd.underscores.SubType;
|
||||
|
||||
/**
|
||||
* Test for generation of Jakarta JAXB based mapper implementations.
|
||||
*
|
||||
* @author Iaroslav Bogdanchikov
|
||||
*/
|
||||
public class JakartaJaxbBasedMapperTest {
|
||||
|
||||
@Test
|
||||
public void shouldMapJakartaJaxb() throws ParseException, JAXBException {
|
||||
|
||||
SourceTargetMapper mapper = SourceTargetMapper.INSTANCE;
|
||||
|
||||
OrderDto source1 = new OrderDto();
|
||||
source1.setOrderDetails( new OrderDetailsDto() );
|
||||
source1.setOrderNumber( 11L );
|
||||
source1.setOrderDate( createDate( "31-08-1982 10:20:56" ) );
|
||||
source1.setShippingAddress( new ShippingAddressDto() );
|
||||
source1.getShippingAddress().setCity( "SmallTown" );
|
||||
source1.getShippingAddress().setHouseNumber( "11a" );
|
||||
source1.getShippingAddress().setStreet( "Awesome rd" );
|
||||
source1.getShippingAddress().setCountry( "USA" );
|
||||
source1.getOrderDetails().setDescription( new ArrayList<String>() );
|
||||
source1.getOrderDetails().setName( "Shopping list for a Mapper" );
|
||||
source1.getOrderDetails().getDescription().add( "1 MapStruct" );
|
||||
source1.getOrderDetails().getDescription().add( "3 Lines of Code" );
|
||||
source1.getOrderDetails().getDescription().add( "1 Dose of Luck" );
|
||||
source1.getOrderDetails().setStatus( OrderStatusDto.ORDERED );
|
||||
|
||||
// map to JAXB
|
||||
OrderType target = mapper.targetToSource( source1 );
|
||||
|
||||
// do a pretty print
|
||||
ObjectFactory of = new ObjectFactory();
|
||||
System.out.println( toXml( of.createOrder( target ) ) );
|
||||
|
||||
// map back from JAXB
|
||||
OrderDto source2 = mapper.sourceToTarget( target );
|
||||
|
||||
// verify that source1 and source 2 are equal
|
||||
assertThat( source2.getOrderNumber() ).isEqualTo( source1.getOrderNumber() );
|
||||
assertThat( source2.getOrderDate() ).isEqualTo( source1.getOrderDate() );
|
||||
assertThat( source2.getOrderDetails().getDescription().size() ).isEqualTo(
|
||||
source1.getOrderDetails().getDescription().size()
|
||||
);
|
||||
assertThat( source2.getOrderDetails().getDescription().get( 0 ) ).isEqualTo(
|
||||
source1.getOrderDetails().getDescription().get( 0 )
|
||||
);
|
||||
assertThat( source2.getOrderDetails().getDescription().get( 1 ) ).isEqualTo(
|
||||
source1.getOrderDetails().getDescription().get( 1 )
|
||||
);
|
||||
assertThat( source2.getOrderDetails().getDescription().get( 2 ) ).isEqualTo(
|
||||
source1.getOrderDetails().getDescription().get( 2 )
|
||||
);
|
||||
assertThat( source2.getOrderDetails().getName() ).isEqualTo( source1.getOrderDetails().getName() );
|
||||
assertThat( source2.getOrderDetails().getStatus() ).isEqualTo( source1.getOrderDetails().getStatus() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void underscores() throws ParseException, JAXBException {
|
||||
|
||||
SourceTargetMapper mapper = SourceTargetMapper.INSTANCE;
|
||||
|
||||
SubTypeDto source1 = new SubTypeDto();
|
||||
source1.setInheritedCamelCase("InheritedCamelCase");
|
||||
source1.setInheritedUnderscore("InheritedUnderscore");
|
||||
source1.setDeclaredCamelCase("DeclaredCamelCase");
|
||||
source1.setDeclaredUnderscore("DeclaredUnderscore");
|
||||
|
||||
SubType target = mapper.dtoToSubType( source1 );
|
||||
|
||||
SubTypeDto source2 = mapper.subTypeToDto( target );
|
||||
|
||||
assertThat( source2.getInheritedCamelCase() ).isEqualTo( source1.getInheritedCamelCase() );
|
||||
assertThat( source2.getInheritedUnderscore() ).isEqualTo( source1.getInheritedUnderscore() );
|
||||
assertThat( source2.getDeclaredCamelCase() ).isEqualTo( source1.getDeclaredCamelCase() );
|
||||
assertThat( source2.getDeclaredUnderscore() ).isEqualTo( source1.getDeclaredUnderscore() );
|
||||
}
|
||||
|
||||
private Date createDate(String date) throws ParseException {
|
||||
SimpleDateFormat sdf = new SimpleDateFormat( "dd-M-yyyy hh:mm:ss" );
|
||||
return sdf.parse( date );
|
||||
}
|
||||
|
||||
private String toXml(JAXBElement<?> element) throws JAXBException {
|
||||
JAXBContext jc = JAXBContext.newInstance( element.getValue().getClass() );
|
||||
Marshaller marshaller = jc.createMarshaller();
|
||||
marshaller.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE );
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
marshaller.marshal( element, baos );
|
||||
return baos.toString();
|
||||
}
|
||||
}
|
@ -51,7 +51,7 @@
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jaxb</groupId>
|
||||
<artifactId>jaxb-runtime</artifactId>
|
||||
<version>2.3.2</version>
|
||||
<version>${jaxb-runtime.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
@ -66,14 +66,16 @@
|
||||
</activation>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>jakarta.xml.bind</groupId>
|
||||
<artifactId>jakarta.xml.bind-api</artifactId>
|
||||
<version>2.3.2</version>
|
||||
<groupId>javax.xml.bind</groupId>
|
||||
<artifactId>jaxb-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jaxb</groupId>
|
||||
<artifactId>jaxb-runtime</artifactId>
|
||||
<version>2.3.2</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
|
@ -11,12 +11,12 @@
|
||||
|
||||
<groupId>org.mapstruct</groupId>
|
||||
<artifactId>mapstruct-parent</artifactId>
|
||||
<version>1.6.0-SNAPSHOT</version>
|
||||
<version>1.5.5.Final</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>MapStruct Parent</name>
|
||||
<description>An annotation processor for generating type-safe bean mappers</description>
|
||||
<url>http://mapstruct.org/</url>
|
||||
<url>https://mapstruct.org/</url>
|
||||
<inceptionYear>2012</inceptionYear>
|
||||
|
||||
<properties>
|
||||
@ -42,6 +42,7 @@
|
||||
-->
|
||||
<minimum.java.version>1.8</minimum.java.version>
|
||||
<protobuf.version>3.21.2</protobuf.version>
|
||||
<jaxb-runtime.version>2.3.2</jaxb-runtime.version>
|
||||
</properties>
|
||||
|
||||
<licenses>
|
||||
@ -70,7 +71,7 @@
|
||||
<connection>scm:git:git://github.com/mapstruct/mapstruct.git</connection>
|
||||
<developerConnection>scm:git:git@github.com:mapstruct/mapstruct.git</developerConnection>
|
||||
<url>https://github.com/mapstruct/mapstruct/</url>
|
||||
<tag>HEAD</tag>
|
||||
<tag>1.5.5.Final</tag>
|
||||
</scm>
|
||||
|
||||
<distributionManagement>
|
||||
@ -160,6 +161,11 @@
|
||||
<artifactId>cdi-api</artifactId>
|
||||
<version>2.0.SP1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.enterprise</groupId>
|
||||
<artifactId>jakarta.enterprise.cdi-api</artifactId>
|
||||
<version>4.0.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.inject</groupId>
|
||||
<artifactId>javax.inject</artifactId>
|
||||
@ -250,6 +256,30 @@
|
||||
<version>2.9</version>
|
||||
</dependency>
|
||||
|
||||
<!-- XML Binding -->
|
||||
<!-- Old (javax) -->
|
||||
<dependency>
|
||||
<groupId>javax.xml.bind</groupId>
|
||||
<artifactId>jaxb-api</artifactId>
|
||||
<version>2.3.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jaxb</groupId>
|
||||
<artifactId>jaxb-runtime</artifactId>
|
||||
<version>${jaxb-runtime.version}</version>
|
||||
</dependency>
|
||||
<!-- New (jakarta) -->
|
||||
<dependency>
|
||||
<groupId>jakarta.xml.bind</groupId>
|
||||
<artifactId>jakarta.xml.bind-api</artifactId>
|
||||
<version>3.0.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.xml.bind</groupId>
|
||||
<artifactId>jaxb-impl</artifactId>
|
||||
<version>3.0.2</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Plexus Eclipse Compiler -->
|
||||
<dependency>
|
||||
<groupId>org.eclipse.tycho</groupId>
|
||||
@ -483,12 +513,12 @@
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>animal-sniffer-maven-plugin</artifactId>
|
||||
<version>1.17</version>
|
||||
<version>1.20</version>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.ow2.asm</groupId>
|
||||
<artifactId>asm</artifactId>
|
||||
<version>6.2.1</version>
|
||||
<version>7.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
|
4
pom.xml
4
pom.xml
@ -13,7 +13,7 @@
|
||||
<parent>
|
||||
<groupId>org.mapstruct</groupId>
|
||||
<artifactId>mapstruct-parent</artifactId>
|
||||
<version>1.6.0-SNAPSHOT</version>
|
||||
<version>1.5.5.Final</version>
|
||||
<relativePath>parent/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
@ -54,7 +54,7 @@
|
||||
<connection>scm:git:git://github.com/mapstruct/mapstruct.git</connection>
|
||||
<developerConnection>scm:git:git@github.com:mapstruct/mapstruct.git</developerConnection>
|
||||
<url>https://github.com/mapstruct/mapstruct/</url>
|
||||
<tag>HEAD</tag>
|
||||
<tag>1.5.5.Final</tag>
|
||||
</scm>
|
||||
|
||||
<profiles>
|
||||
|
@ -12,7 +12,7 @@
|
||||
<parent>
|
||||
<groupId>org.mapstruct</groupId>
|
||||
<artifactId>mapstruct-parent</artifactId>
|
||||
<version>1.6.0-SNAPSHOT</version>
|
||||
<version>1.5.5.Final</version>
|
||||
<relativePath>../parent/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
@ -89,6 +89,11 @@
|
||||
<artifactId>jakarta.inject-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.enterprise</groupId>
|
||||
<artifactId>jakarta.enterprise.cdi-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- plexus-container-default is a runtime-dependency of the tycho-compiler -->
|
||||
<dependency>
|
||||
@ -132,6 +137,13 @@
|
||||
<artifactId>joda-time</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>jakarta.xml.bind</groupId>
|
||||
<artifactId>jakarta.xml.bind-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
@ -370,7 +382,6 @@
|
||||
<dependency>
|
||||
<groupId>javax.xml.bind</groupId>
|
||||
<artifactId>jaxb-api</artifactId>
|
||||
<version>2.3.1</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
@ -21,15 +21,15 @@ import org.mapstruct.ap.internal.util.Strings;
|
||||
* </p>
|
||||
* <p>
|
||||
* In general each type comes with a "parse" method to convert a string to this particular type.
|
||||
* For formatting a dedicated instance of {@link java.time.format.DateTimeFormatter} is used.
|
||||
* For formatting a dedicated instance of {@link DateTimeFormatter} is used.
|
||||
* </p>
|
||||
* <p>
|
||||
* If no date format for mapping is specified predefined ISO* formatters from
|
||||
* {@link java.time.format.DateTimeFormatter} are used.
|
||||
* {@link DateTimeFormatter} are used.
|
||||
* </p>
|
||||
* <p>
|
||||
* An overview of date and time types shipped with Java 8 can be found at
|
||||
* http://docs.oracle.com/javase/tutorial/datetime/iso/index.html.
|
||||
* An overview of date and time types shipped with Java 8 can be found at the
|
||||
* <a href="http://docs.oracle.com/javase/tutorial/datetime/iso/index.html">Standard Calendar Tutorial</a>
|
||||
* </p>
|
||||
*/
|
||||
public abstract class AbstractJavaTimeToStringConversion extends SimpleConversion {
|
||||
|
@ -51,6 +51,8 @@ public final class MappingConstantsGem {
|
||||
public static final String JSR330 = "jsr330";
|
||||
|
||||
public static final String JAKARTA = "jakarta";
|
||||
|
||||
public static final String JAKARTA_CDI = "jakarta-cdi";
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.internal.gem.jakarta;
|
||||
|
||||
import jakarta.xml.bind.annotation.XmlElementDecl;
|
||||
import jakarta.xml.bind.annotation.XmlElementRef;
|
||||
import org.mapstruct.tools.gem.GemDefinition;
|
||||
|
||||
/**
|
||||
* This class is a temporary solution to an issue in the Gem Tools library.
|
||||
*
|
||||
* <p>
|
||||
* This class can be merged with {@link org.mapstruct.ap.internal.gem.GemGenerator}
|
||||
* after the mentioned issue is resolved.
|
||||
* </p>
|
||||
*
|
||||
* @see <a href="https://github.com/mapstruct/tools-gem/issues/10">Gem Tools issue #10</a>
|
||||
* @author Iaroslav Bogdanchikov
|
||||
*/
|
||||
@GemDefinition(XmlElementDecl.class)
|
||||
@GemDefinition(XmlElementRef.class)
|
||||
class JakartaGemGenerator {
|
||||
}
|
@ -340,6 +340,14 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
|
||||
if ( factoryMethod != null ) {
|
||||
forgedMethod.addThrownTypes( factoryMethod.getThrownTypes() );
|
||||
}
|
||||
for ( LifecycleCallbackMethodReference beforeMappingMethod : beforeMappingMethods ) {
|
||||
forgedMethod.addThrownTypes( beforeMappingMethod.getThrownTypes() );
|
||||
}
|
||||
|
||||
for ( LifecycleCallbackMethodReference afterMappingMethod : afterMappingMethods ) {
|
||||
forgedMethod.addThrownTypes( afterMappingMethod.getThrownTypes() );
|
||||
}
|
||||
|
||||
|
||||
for ( PropertyMapping propertyMapping : propertyMappings ) {
|
||||
if ( propertyMapping.getAssignment() != null ) {
|
||||
@ -398,15 +406,13 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
|
||||
"SubclassMapping for " + sourceType.getFullyQualifiedName() );
|
||||
SelectionCriteria criteria =
|
||||
SelectionCriteria
|
||||
.forMappingMethods(
|
||||
.forSubclassMappingMethods(
|
||||
new SelectionParameters(
|
||||
Collections.emptyList(),
|
||||
Collections.emptyList(),
|
||||
subclassMappingOptions.getTarget(),
|
||||
ctx.getTypeUtils() ).withSourceRHS( rightHandSide ),
|
||||
null,
|
||||
null,
|
||||
false );
|
||||
subclassMappingOptions.getMappingControl( ctx.getElementUtils() ) );
|
||||
Assignment assignment = ctx
|
||||
.getMappingResolver()
|
||||
.getTargetAssignment(
|
||||
|
@ -196,7 +196,7 @@ public class ForgedMethod implements Method {
|
||||
public ForgedMethod(String name, ForgedMethod forgedMethod) {
|
||||
this.parameters = forgedMethod.parameters;
|
||||
this.returnType = forgedMethod.returnType;
|
||||
this.thrownTypes = new ArrayList<>();
|
||||
this.thrownTypes = forgedMethod.thrownTypes;
|
||||
this.history = forgedMethod.history;
|
||||
|
||||
this.sourceParameters = Parameter.getSourceParameters( parameters );
|
||||
|
@ -257,8 +257,10 @@ public abstract class GeneratedType extends ModelElement {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( needsImportDeclaration( typeToAdd ) ) {
|
||||
collection.add( typeToAdd );
|
||||
for ( Type type : typeToAdd.getImportTypes() ) {
|
||||
if ( needsImportDeclaration( type ) ) {
|
||||
collection.add( type );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -176,7 +176,7 @@ public abstract class HelperMethod implements Method {
|
||||
*
|
||||
* @param parameter source
|
||||
* @param returnType target
|
||||
* @return {@code true}, iff the the type variables match
|
||||
* @return {@code true}, iff the type variables match
|
||||
*/
|
||||
public boolean doTypeVarsMatch(Type parameter, Type returnType) {
|
||||
return true;
|
||||
|
@ -141,7 +141,7 @@ public final class LifecycleMethodResolver {
|
||||
callbackMethods,
|
||||
Collections.emptyList(),
|
||||
targetType,
|
||||
method.getReturnType(),
|
||||
method.getResultType(),
|
||||
SelectionCriteria.forLifecycleMethods( selectionParameters ) );
|
||||
|
||||
return toLifecycleCallbackMethodRefs(
|
||||
|
@ -22,7 +22,7 @@ import org.mapstruct.ap.internal.gem.NullValuePropertyMappingStrategyGem;
|
||||
/**
|
||||
* This wrapper handles the situation where an assignment is done for an update method.
|
||||
*
|
||||
* In case of a pre-existing target the wrapper checks if there is an collection or map initialized on the target bean
|
||||
* In case of a pre-existing target the wrapper checks if there is a collection or map initialized on the target bean
|
||||
* (not null). If so it uses the addAll (for collections) or putAll (for maps). The collection / map is cleared in case
|
||||
* of a pre-existing target {@link org.mapstruct.MappingTarget }before adding the source entries.
|
||||
*
|
||||
|
@ -16,7 +16,7 @@ import org.mapstruct.ap.internal.model.common.Type;
|
||||
* This wrapper handles the situation were an assignment must be done via a target getter method because there
|
||||
* is no setter available.
|
||||
*
|
||||
* The wrapper checks if there is an collection or map initialized on the target bean (not null). If so it uses the
|
||||
* The wrapper checks if there is a collection or map initialized on the target bean (not null). If so it uses the
|
||||
* addAll (for collections) or putAll (for maps). The collection / map is cleared in case of a pre-existing target
|
||||
* {@link org.mapstruct.MappingTarget }before adding the source entries. The goal is that the same collection / map
|
||||
* is used as target.
|
||||
|
@ -54,7 +54,7 @@ public class UpdateWrapper extends AssignmentWrapper {
|
||||
return targetType.getImplementationType();
|
||||
}
|
||||
|
||||
// no factory method means we create a new instance ourself and thus need to import the type
|
||||
// no factory method means we create a new instance ourselves and thus need to import the type
|
||||
return targetType;
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ import org.mapstruct.ap.internal.util.accessor.ReadAccessor;
|
||||
|
||||
/**
|
||||
* A PropertyEntry contains information on the name, readAccessor and presenceCheck (for source)
|
||||
* and return type of a property.
|
||||
* and return type of property.
|
||||
*/
|
||||
public class PropertyEntry {
|
||||
|
||||
|
@ -143,7 +143,7 @@ public class SourceReference extends AbstractReference {
|
||||
* the parameter name to avoid ambiguity
|
||||
*
|
||||
* consider: {@code Target map( Source1 source1 )}
|
||||
* entries in an @Mapping#source can be "source1.propx" or just "propx" to be valid
|
||||
* entries in a @Mapping#source can be "source1.propx" or just "propx" to be valid
|
||||
*
|
||||
* @param segments the segments of @Mapping#source
|
||||
* @param parameter the one and only parameter
|
||||
@ -213,7 +213,7 @@ public class SourceReference extends AbstractReference {
|
||||
* needs to match the parameter name to avoid ambiguity
|
||||
*
|
||||
* consider: {@code Target map( Source1 source1, Source2 source2 )}
|
||||
* entries in an @Mapping#source need to be "source1.propx" or "source2.propy.propz" to be valid
|
||||
* entries in a @Mapping#source need to be "source1.propx" or "source2.propy.propz" to be valid
|
||||
*
|
||||
* @param segments the segments of @Mapping#source
|
||||
* @return parameter that matches with first segment of @Mapping#source
|
||||
|
@ -28,6 +28,7 @@ import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.element.VariableElement;
|
||||
import javax.lang.model.type.ArrayType;
|
||||
import javax.lang.model.type.DeclaredType;
|
||||
import javax.lang.model.type.IntersectionType;
|
||||
import javax.lang.model.type.PrimitiveType;
|
||||
import javax.lang.model.type.TypeKind;
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
@ -114,6 +115,7 @@ public class Type extends ModelElement implements Comparable<Type> {
|
||||
private List<Accessor> alternativeTargetAccessors = null;
|
||||
|
||||
private Type boundingBase = null;
|
||||
private List<Type> boundTypes = null;
|
||||
|
||||
private Type boxedEquivalent = null;
|
||||
|
||||
@ -181,9 +183,16 @@ public class Type extends ModelElement implements Comparable<Type> {
|
||||
|
||||
this.loggingVerbose = loggingVerbose;
|
||||
|
||||
TypeElement typeElementForTopLevel;
|
||||
if ( Boolean.TRUE.equals( isToBeImported ) ) {
|
||||
// If the is to be imported is explicitly set to true then we shouldn't look for the top level type
|
||||
typeElementForTopLevel = null;
|
||||
}
|
||||
else {
|
||||
// The top level type for an array type is the top level type of the component type
|
||||
TypeElement typeElementForTopLevel =
|
||||
typeElementForTopLevel =
|
||||
this.componentType == null ? this.typeElement : this.componentType.getTypeElement();
|
||||
}
|
||||
this.topLevelType = topLevelType( typeElementForTopLevel, this.typeFactory );
|
||||
this.nameWithTopLevelTypeName = nameWithTopLevelTypeName( typeElementForTopLevel, this.name );
|
||||
}
|
||||
@ -347,6 +356,10 @@ public class Type extends ModelElement implements Comparable<Type> {
|
||||
return (typeMirror.getKind() == TypeKind.TYPEVAR);
|
||||
}
|
||||
|
||||
public boolean isIntersection() {
|
||||
return typeMirror.getKind() == TypeKind.INTERSECTION;
|
||||
}
|
||||
|
||||
public boolean isJavaLangType() {
|
||||
return packageName != null && packageName.startsWith( "java." );
|
||||
}
|
||||
@ -1257,6 +1270,29 @@ public class Type extends ModelElement implements Comparable<Type> {
|
||||
return boundingBase;
|
||||
}
|
||||
|
||||
public List<Type> getTypeBounds() {
|
||||
if ( this.boundTypes != null ) {
|
||||
return boundTypes;
|
||||
}
|
||||
Type bound = getTypeBound();
|
||||
if ( bound == null ) {
|
||||
this.boundTypes = Collections.emptyList();
|
||||
}
|
||||
else if ( !bound.isIntersection() ) {
|
||||
this.boundTypes = Collections.singletonList( bound );
|
||||
}
|
||||
else {
|
||||
List<? extends TypeMirror> bounds = ( (IntersectionType) bound.typeMirror ).getBounds();
|
||||
this.boundTypes = new ArrayList<>( bounds.size() );
|
||||
for ( TypeMirror mirror : bounds ) {
|
||||
boundTypes.add( typeFactory.getType( mirror ) );
|
||||
}
|
||||
}
|
||||
|
||||
return this.boundTypes;
|
||||
|
||||
}
|
||||
|
||||
public boolean hasAccessibleConstructor() {
|
||||
if ( hasAccessibleConstructor == null ) {
|
||||
hasAccessibleConstructor = false;
|
||||
|
@ -193,7 +193,24 @@ public class TypeFactory {
|
||||
return getType( mirror, false );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a type that is always going to be imported.
|
||||
* This is useful when using it in {@code Mapper#imports}
|
||||
* for types that should be used in expressions.
|
||||
*
|
||||
* @param mirror the type mirror for which we need a type
|
||||
*
|
||||
* @return the type
|
||||
*/
|
||||
public Type getAlwaysImportedType(TypeMirror mirror) {
|
||||
return getType( mirror, false, true );
|
||||
}
|
||||
|
||||
private Type getType(TypeMirror mirror, boolean isLiteral) {
|
||||
return getType( mirror, isLiteral, null );
|
||||
}
|
||||
|
||||
private Type getType(TypeMirror mirror, boolean isLiteral, Boolean alwaysImport) {
|
||||
if ( !canBeProcessed( mirror ) ) {
|
||||
throw new TypeHierarchyErroneousException( mirror );
|
||||
}
|
||||
@ -212,7 +229,7 @@ public class TypeFactory {
|
||||
String qualifiedName;
|
||||
TypeElement typeElement;
|
||||
Type componentType;
|
||||
Boolean toBeImported = null;
|
||||
Boolean toBeImported = alwaysImport;
|
||||
|
||||
if ( mirror.getKind() == TypeKind.DECLARED ) {
|
||||
DeclaredType declaredType = (DeclaredType) mirror;
|
||||
|
@ -34,31 +34,48 @@ import org.mapstruct.tools.gem.GemValue;
|
||||
public class BeanMappingOptions extends DelegatingOptions {
|
||||
|
||||
private final SelectionParameters selectionParameters;
|
||||
private final List<String> ignoreUnmappedSourceProperties;
|
||||
private final BeanMappingGem beanMapping;
|
||||
|
||||
/**
|
||||
* creates a mapping for inheritance. Will set
|
||||
*
|
||||
* @param beanMapping the bean mapping options that should be used
|
||||
* @param isInverse whether the inheritance is inverse
|
||||
*
|
||||
* @return new mapping
|
||||
*/
|
||||
public static BeanMappingOptions forInheritance(BeanMappingOptions beanMapping) {
|
||||
public static BeanMappingOptions forInheritance(BeanMappingOptions beanMapping, boolean isInverse) {
|
||||
BeanMappingOptions options = new BeanMappingOptions(
|
||||
SelectionParameters.forInheritance( beanMapping.selectionParameters ),
|
||||
isInverse ? Collections.emptyList() : beanMapping.ignoreUnmappedSourceProperties,
|
||||
beanMapping.beanMapping,
|
||||
beanMapping
|
||||
);
|
||||
return options;
|
||||
}
|
||||
|
||||
public static BeanMappingOptions forForgedMethods(BeanMappingOptions beanMapping) {
|
||||
BeanMappingOptions options = new BeanMappingOptions(
|
||||
beanMapping.selectionParameters != null ?
|
||||
SelectionParameters.withoutResultType( beanMapping.selectionParameters ) : null,
|
||||
Collections.emptyList(),
|
||||
beanMapping.beanMapping,
|
||||
beanMapping
|
||||
);
|
||||
return options;
|
||||
}
|
||||
|
||||
public static BeanMappingOptions empty(DelegatingOptions delegatingOptions) {
|
||||
return new BeanMappingOptions( null, Collections.emptyList(), null, delegatingOptions );
|
||||
}
|
||||
|
||||
public static BeanMappingOptions getInstanceOn(BeanMappingGem beanMapping, MapperOptions mapperOptions,
|
||||
ExecutableElement method, FormattingMessager messager,
|
||||
TypeUtils typeUtils, TypeFactory typeFactory
|
||||
) {
|
||||
if ( beanMapping == null || !isConsistent( beanMapping, method, messager ) ) {
|
||||
BeanMappingOptions options = new BeanMappingOptions( null, null, mapperOptions );
|
||||
return options;
|
||||
return empty( mapperOptions );
|
||||
}
|
||||
|
||||
Objects.requireNonNull( method );
|
||||
@ -77,6 +94,7 @@ public class BeanMappingOptions extends DelegatingOptions {
|
||||
//TODO Do we want to add the reporting policy to the BeanMapping as well? To give more granular support?
|
||||
BeanMappingOptions options = new BeanMappingOptions(
|
||||
selectionParameters,
|
||||
beanMapping.ignoreUnmappedSourceProperties().get(),
|
||||
beanMapping,
|
||||
mapperOptions
|
||||
);
|
||||
@ -86,6 +104,7 @@ public class BeanMappingOptions extends DelegatingOptions {
|
||||
private static boolean isConsistent(BeanMappingGem gem, ExecutableElement method,
|
||||
FormattingMessager messager) {
|
||||
if ( !gem.resultType().hasValue()
|
||||
&& !gem.mappingControl().hasValue()
|
||||
&& !gem.qualifiedBy().hasValue()
|
||||
&& !gem.qualifiedByName().hasValue()
|
||||
&& !gem.ignoreUnmappedSourceProperties().hasValue()
|
||||
@ -104,10 +123,12 @@ public class BeanMappingOptions extends DelegatingOptions {
|
||||
}
|
||||
|
||||
private BeanMappingOptions(SelectionParameters selectionParameters,
|
||||
List<String> ignoreUnmappedSourceProperties,
|
||||
BeanMappingGem beanMapping,
|
||||
DelegatingOptions next) {
|
||||
super( next );
|
||||
this.selectionParameters = selectionParameters;
|
||||
this.ignoreUnmappedSourceProperties = ignoreUnmappedSourceProperties;
|
||||
this.beanMapping = beanMapping;
|
||||
}
|
||||
|
||||
@ -188,9 +209,7 @@ public class BeanMappingOptions extends DelegatingOptions {
|
||||
}
|
||||
|
||||
public List<String> getIgnoreUnmappedSourceProperties() {
|
||||
return Optional.ofNullable( beanMapping ).map( BeanMappingGem::ignoreUnmappedSourceProperties )
|
||||
.map( GemValue::get )
|
||||
.orElse( Collections.emptyList() );
|
||||
return ignoreUnmappedSourceProperties;
|
||||
}
|
||||
|
||||
public AnnotationMirror getMirror() {
|
||||
|
@ -167,7 +167,7 @@ public class MappingMethodOptions {
|
||||
}
|
||||
|
||||
if ( !getBeanMapping().hasAnnotation() && templateOptions.getBeanMapping().hasAnnotation() ) {
|
||||
setBeanMapping( BeanMappingOptions.forInheritance( templateOptions.getBeanMapping( ) ) );
|
||||
setBeanMapping( BeanMappingOptions.forInheritance( templateOptions.getBeanMapping( ), isInverse ) );
|
||||
}
|
||||
|
||||
if ( !getEnumMappingOptions().hasAnnotation() && templateOptions.getEnumMappingOptions().hasAnnotation() ) {
|
||||
@ -365,7 +365,7 @@ public class MappingMethodOptions {
|
||||
options.mappings,
|
||||
options.iterableMapping,
|
||||
options.mapMapping,
|
||||
options.beanMapping,
|
||||
BeanMappingOptions.forForgedMethods( options.beanMapping ),
|
||||
options.enumMappingOptions,
|
||||
options.valueMappings,
|
||||
Collections.emptySet(),
|
||||
|
@ -82,6 +82,17 @@ public class MethodMatcher {
|
||||
// (the relation target / target type, target type being a class)
|
||||
|
||||
if ( !analyser.candidateReturnType.isVoid() ) {
|
||||
if ( targetType.isPrimitive() ) {
|
||||
// If the target type is primitive
|
||||
// then we are going to check if its boxed equivalent
|
||||
// is assignable to the candidate return type
|
||||
// This is done because primitives can be assigned from their own narrower counterparts
|
||||
// directly without any casting.
|
||||
// e.g. a Long is assignable to a primitive double
|
||||
// However, in order not to lose information we are not going to allow this
|
||||
return targetType.getBoxedEquivalent()
|
||||
.isAssignableTo( analyser.candidateReturnType.getBoxedEquivalent() );
|
||||
}
|
||||
if ( !( analyser.candidateReturnType.isAssignableTo( targetType ) ) ) {
|
||||
return false;
|
||||
}
|
||||
@ -314,8 +325,7 @@ public class MethodMatcher {
|
||||
*/
|
||||
private boolean candidatesWithinBounds(Map<Type, TypeVarCandidate> methodParCandidates ) {
|
||||
for ( Map.Entry<Type, TypeVarCandidate> entry : methodParCandidates.entrySet() ) {
|
||||
Type bound = entry.getKey().getTypeBound();
|
||||
if ( bound != null ) {
|
||||
for ( Type bound : entry.getKey().getTypeBounds() ) {
|
||||
for ( Type.ResolvedPair pair : entry.getValue().pairs ) {
|
||||
if ( entry.getKey().hasUpperBound() ) {
|
||||
if ( !pair.getMatch().asRawType().isAssignableTo( bound.asRawType() ) ) {
|
||||
@ -374,7 +384,9 @@ public class MethodMatcher {
|
||||
// something went wrong
|
||||
return null;
|
||||
}
|
||||
typeArgs[i] = matchingType.getTypeMirror();
|
||||
// Use the boxed equivalent for the type arguments,
|
||||
// because a primitive type cannot be a type argument
|
||||
typeArgs[i] = matchingType.getBoxedEquivalent().getTypeMirror();
|
||||
}
|
||||
else {
|
||||
// it is not a type var (e.g. Map<String, T> ), String is not a type var
|
||||
|
@ -39,6 +39,10 @@ public class SelectionParameters {
|
||||
* @return the selection parameters based on the given ones
|
||||
*/
|
||||
public static SelectionParameters forInheritance(SelectionParameters selectionParameters) {
|
||||
return withoutResultType( selectionParameters );
|
||||
}
|
||||
|
||||
public static SelectionParameters withoutResultType(SelectionParameters selectionParameters) {
|
||||
return new SelectionParameters(
|
||||
selectionParameters.qualifiers,
|
||||
selectionParameters.qualifyingNames,
|
||||
|
@ -8,6 +8,7 @@ package org.mapstruct.ap.internal.model.source.builtin;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.mapstruct.ap.internal.model.common.Type;
|
||||
import org.mapstruct.ap.internal.model.common.TypeFactory;
|
||||
import org.mapstruct.ap.internal.util.JaxbConstants;
|
||||
import org.mapstruct.ap.internal.util.JodaTimeConstants;
|
||||
@ -24,7 +25,7 @@ public class BuiltInMappingMethods {
|
||||
|
||||
public BuiltInMappingMethods(TypeFactory typeFactory) {
|
||||
boolean isXmlGregorianCalendarPresent = isXmlGregorianCalendarAvailable( typeFactory );
|
||||
builtInMethods = new ArrayList<>( 20 );
|
||||
builtInMethods = new ArrayList<>( 21 );
|
||||
if ( isXmlGregorianCalendarPresent ) {
|
||||
builtInMethods.add( new DateToXmlGregorianCalendar( typeFactory ) );
|
||||
builtInMethods.add( new XmlGregorianCalendarToDate( typeFactory ) );
|
||||
@ -39,8 +40,14 @@ public class BuiltInMappingMethods {
|
||||
builtInMethods.add( new XmlGregorianCalendarToLocalDateTime( typeFactory ) );
|
||||
}
|
||||
|
||||
if ( isJaxbAvailable( typeFactory ) ) {
|
||||
builtInMethods.add( new JaxbElemToValue( typeFactory ) );
|
||||
if ( isJavaxJaxbAvailable( typeFactory ) ) {
|
||||
Type type = typeFactory.getType( JaxbConstants.JAVAX_JAXB_ELEMENT_FQN );
|
||||
builtInMethods.add( new JaxbElemToValue( type ) );
|
||||
}
|
||||
|
||||
if ( isJakartaJaxbAvailable( typeFactory ) ) {
|
||||
Type type = typeFactory.getType( JaxbConstants.JAKARTA_JAXB_ELEMENT_FQN );
|
||||
builtInMethods.add( new JaxbElemToValue( type ) );
|
||||
}
|
||||
|
||||
builtInMethods.add( new ZonedDateTimeToCalendar( typeFactory ) );
|
||||
@ -58,8 +65,12 @@ public class BuiltInMappingMethods {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isJaxbAvailable(TypeFactory typeFactory) {
|
||||
return typeFactory.isTypeAvailable( JaxbConstants.JAXB_ELEMENT_FQN );
|
||||
private static boolean isJavaxJaxbAvailable(TypeFactory typeFactory) {
|
||||
return typeFactory.isTypeAvailable( JaxbConstants.JAVAX_JAXB_ELEMENT_FQN );
|
||||
}
|
||||
|
||||
private static boolean isJakartaJaxbAvailable(TypeFactory typeFactory) {
|
||||
return typeFactory.isTypeAvailable( JaxbConstants.JAKARTA_JAXB_ELEMENT_FQN );
|
||||
}
|
||||
|
||||
private static boolean isXmlGregorianCalendarAvailable(TypeFactory typeFactory) {
|
||||
|
@ -190,7 +190,7 @@ public abstract class BuiltInMethod implements Method {
|
||||
*
|
||||
* @param parameter source
|
||||
* @param returnType target
|
||||
* @return {@code true}, iff the the type variables match
|
||||
* @return {@code true}, iff the type variables match
|
||||
*/
|
||||
public boolean doTypeVarsMatch(Type parameter, Type returnType) {
|
||||
return true;
|
||||
|
@ -5,26 +5,23 @@
|
||||
*/
|
||||
package org.mapstruct.ap.internal.model.source.builtin;
|
||||
|
||||
import static org.mapstruct.ap.internal.util.Collections.asSet;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.mapstruct.ap.internal.model.common.Parameter;
|
||||
import org.mapstruct.ap.internal.model.common.Type;
|
||||
import org.mapstruct.ap.internal.model.common.TypeFactory;
|
||||
import org.mapstruct.ap.internal.util.JaxbConstants;
|
||||
|
||||
import static org.mapstruct.ap.internal.util.Collections.asSet;
|
||||
|
||||
/**
|
||||
* @author Sjaak Derksen
|
||||
*/
|
||||
public class JaxbElemToValue extends BuiltInMethod {
|
||||
class JaxbElemToValue extends BuiltInMethod {
|
||||
|
||||
private final Parameter parameter;
|
||||
private final Type returnType;
|
||||
private final Set<Type> importTypes;
|
||||
|
||||
public JaxbElemToValue(TypeFactory typeFactory) {
|
||||
Type type = typeFactory.getType( JaxbConstants.JAXB_ELEMENT_FQN );
|
||||
JaxbElemToValue(Type type) {
|
||||
this.parameter = new Parameter( "element", type );
|
||||
this.returnType = type.getTypeParameters().get( 0 );
|
||||
this.importTypes = asSet( parameter.getType() );
|
||||
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.internal.model.source.selector;
|
||||
|
||||
import javax.lang.model.element.Element;
|
||||
|
||||
import org.mapstruct.ap.internal.gem.jakarta.XmlElementDeclGem;
|
||||
import org.mapstruct.ap.internal.gem.jakarta.XmlElementRefGem;
|
||||
import org.mapstruct.ap.internal.util.TypeUtils;
|
||||
|
||||
/**
|
||||
* The concrete implementation of the {@link XmlElementDeclSelector} that
|
||||
* works with {@link jakarta.xml.bind.annotation.XmlElementRef} and
|
||||
* {@link jakarta.xml.bind.annotation.XmlElementDecl}.
|
||||
*
|
||||
* @author Iaroslav Bogdanchikov
|
||||
*/
|
||||
class JakartaXmlElementDeclSelector extends XmlElementDeclSelector {
|
||||
|
||||
JakartaXmlElementDeclSelector(TypeUtils typeUtils) {
|
||||
super( typeUtils );
|
||||
}
|
||||
|
||||
@Override
|
||||
XmlElementDeclInfo getXmlElementDeclInfo(Element element) {
|
||||
XmlElementDeclGem gem = XmlElementDeclGem.instanceOn( element );
|
||||
|
||||
if (gem == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new XmlElementDeclInfo( gem.name().get(), gem.scope().get() );
|
||||
}
|
||||
|
||||
@Override
|
||||
XmlElementRefInfo getXmlElementRefInfo(Element element) {
|
||||
XmlElementRefGem gem = XmlElementRefGem.instanceOn( element );
|
||||
|
||||
if (gem == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new XmlElementRefInfo( gem.name().get(), gem.type().get() );
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.internal.model.source.selector;
|
||||
|
||||
import javax.lang.model.element.Element;
|
||||
|
||||
import org.mapstruct.ap.internal.gem.XmlElementDeclGem;
|
||||
import org.mapstruct.ap.internal.gem.XmlElementRefGem;
|
||||
import org.mapstruct.ap.internal.util.TypeUtils;
|
||||
|
||||
/**
|
||||
* The concrete implementation of the {@link XmlElementDeclSelector} that
|
||||
* works with {@link javax.xml.bind.annotation.XmlElementRef} and
|
||||
* {@link javax.xml.bind.annotation.XmlElementDecl}.
|
||||
*
|
||||
* @author Iaroslav Bogdanchikov
|
||||
*/
|
||||
class JavaxXmlElementDeclSelector extends XmlElementDeclSelector {
|
||||
|
||||
JavaxXmlElementDeclSelector(TypeUtils typeUtils) {
|
||||
super( typeUtils );
|
||||
}
|
||||
|
||||
@Override
|
||||
XmlElementDeclInfo getXmlElementDeclInfo(Element element) {
|
||||
XmlElementDeclGem gem = XmlElementDeclGem.instanceOn( element );
|
||||
|
||||
if (gem == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new XmlElementDeclInfo( gem.name().get(), gem.scope().get() );
|
||||
}
|
||||
|
||||
@Override
|
||||
XmlElementRefInfo getXmlElementRefInfo(Element element) {
|
||||
XmlElementRefGem gem = XmlElementRefGem.instanceOn( element );
|
||||
|
||||
if (gem == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new XmlElementRefInfo( gem.name().get(), gem.type().get() );
|
||||
}
|
||||
}
|
@ -32,7 +32,8 @@ public class MethodSelectors {
|
||||
new TypeSelector( typeFactory, messager ),
|
||||
new QualifierSelector( typeUtils, elementUtils ),
|
||||
new TargetTypeSelector( typeUtils ),
|
||||
new XmlElementDeclSelector( typeUtils ),
|
||||
new JavaxXmlElementDeclSelector( typeUtils ),
|
||||
new JakartaXmlElementDeclSelector( typeUtils ),
|
||||
new InheritanceSelector(),
|
||||
new CreateOrUpdateSelector(),
|
||||
new SourceRhsSelector(),
|
||||
|
@ -141,6 +141,10 @@ public class SelectionCriteria {
|
||||
return allow2Steps;
|
||||
}
|
||||
|
||||
public boolean isSelfAllowed() {
|
||||
return type != Type.SELF_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
public static SelectionCriteria forMappingMethods(SelectionParameters selectionParameters,
|
||||
MappingControl mappingControl,
|
||||
String targetPropertyName, boolean preferUpdateMapping) {
|
||||
@ -165,10 +169,16 @@ public class SelectionCriteria {
|
||||
return new SelectionCriteria( selectionParameters, null, null, Type.PRESENCE_CHECK );
|
||||
}
|
||||
|
||||
public static SelectionCriteria forSubclassMappingMethods(SelectionParameters selectionParameters,
|
||||
MappingControl mappingControl) {
|
||||
return new SelectionCriteria( selectionParameters, mappingControl, null, Type.SELF_NOT_ALLOWED );
|
||||
}
|
||||
|
||||
public enum Type {
|
||||
PREFER_UPDATE_MAPPING,
|
||||
OBJECT_FACTORY,
|
||||
LIFECYCLE_CALLBACK,
|
||||
PRESENCE_CHECK,
|
||||
SELF_NOT_ALLOWED,
|
||||
}
|
||||
}
|
||||
|
@ -11,19 +11,17 @@ import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.ElementKind;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
import org.mapstruct.ap.internal.util.TypeUtils;
|
||||
|
||||
import org.mapstruct.ap.internal.gem.XmlElementRefGem;
|
||||
import org.mapstruct.ap.internal.model.common.Type;
|
||||
import org.mapstruct.ap.internal.model.source.Method;
|
||||
import org.mapstruct.ap.internal.model.source.SourceMethod;
|
||||
import org.mapstruct.ap.internal.gem.XmlElementDeclGem;
|
||||
import org.mapstruct.ap.internal.util.TypeUtils;
|
||||
|
||||
/**
|
||||
* Finds the {@link javax.xml.bind.annotation.XmlElementRef} annotation on a field (of the mapping result type or its
|
||||
* Finds the {@code XmlElementRef} annotation on a field (of the mapping result type or its
|
||||
* super types) matching the
|
||||
* target property name. Then selects those methods with matching {@code name} and {@code scope} attributes of the
|
||||
* {@link javax.xml.bind.annotation.XmlElementDecl} annotation, if that is present. Matching happens in the following
|
||||
* {@code XmlElementDecl} annotation, if that is present. Matching happens in the following
|
||||
* order:
|
||||
* <ol>
|
||||
* <li>Name and Scope matches</li>
|
||||
@ -34,12 +32,15 @@ import org.mapstruct.ap.internal.gem.XmlElementDeclGem;
|
||||
* the given method is not annotated with {@code XmlElementDecl} it will be considered as matching.
|
||||
*
|
||||
* @author Sjaak Derksen
|
||||
*
|
||||
* @see JavaxXmlElementDeclSelector
|
||||
* @see JakartaXmlElementDeclSelector
|
||||
*/
|
||||
public class XmlElementDeclSelector implements MethodSelector {
|
||||
abstract class XmlElementDeclSelector implements MethodSelector {
|
||||
|
||||
private final TypeUtils typeUtils;
|
||||
|
||||
public XmlElementDeclSelector(TypeUtils typeUtils) {
|
||||
XmlElementDeclSelector(TypeUtils typeUtils) {
|
||||
this.typeUtils = typeUtils;
|
||||
}
|
||||
|
||||
@ -63,15 +64,14 @@ public class XmlElementDeclSelector implements MethodSelector {
|
||||
}
|
||||
|
||||
SourceMethod candidateMethod = (SourceMethod) candidate.getMethod();
|
||||
XmlElementDeclGem xmlElementDecl =
|
||||
XmlElementDeclGem.instanceOn( candidateMethod.getExecutable() );
|
||||
XmlElementDeclInfo xmlElementDeclInfo = getXmlElementDeclInfo( candidateMethod.getExecutable() );
|
||||
|
||||
if ( xmlElementDecl == null ) {
|
||||
if ( xmlElementDeclInfo == null ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String name = xmlElementDecl.name().get();
|
||||
TypeMirror scope = xmlElementDecl.scope().getValue();
|
||||
String name = xmlElementDeclInfo.nameValue();
|
||||
TypeMirror scope = xmlElementDeclInfo.scopeType();
|
||||
|
||||
boolean nameIsSetAndMatches = name != null && name.equals( xmlElementRefInfo.nameValue() );
|
||||
boolean scopeIsSetAndMatches =
|
||||
@ -142,9 +142,9 @@ public class XmlElementDeclSelector implements MethodSelector {
|
||||
for ( Element enclosed : currentElement.getEnclosedElements() ) {
|
||||
if ( enclosed.getKind().equals( ElementKind.FIELD )
|
||||
&& enclosed.getSimpleName().contentEquals( targetPropertyName ) ) {
|
||||
XmlElementRefGem xmlElementRef = XmlElementRefGem.instanceOn( enclosed );
|
||||
if ( xmlElementRef != null ) {
|
||||
return new XmlElementRefInfo( xmlElementRef.name().get(), currentMirror );
|
||||
XmlElementRefInfo xmlElementRefInfo = getXmlElementRefInfo( enclosed );
|
||||
if ( xmlElementRefInfo != null ) {
|
||||
return new XmlElementRefInfo( xmlElementRefInfo.nameValue(), currentMirror );
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -154,7 +154,11 @@ public class XmlElementDeclSelector implements MethodSelector {
|
||||
return defaultInfo;
|
||||
}
|
||||
|
||||
private static class XmlElementRefInfo {
|
||||
abstract XmlElementDeclInfo getXmlElementDeclInfo(Element element);
|
||||
|
||||
abstract XmlElementRefInfo getXmlElementRefInfo(Element element);
|
||||
|
||||
static class XmlElementRefInfo {
|
||||
private final String nameValue;
|
||||
private final TypeMirror sourceType;
|
||||
|
||||
@ -163,12 +167,37 @@ public class XmlElementDeclSelector implements MethodSelector {
|
||||
this.sourceType = sourceType;
|
||||
}
|
||||
|
||||
public String nameValue() {
|
||||
String nameValue() {
|
||||
return nameValue;
|
||||
}
|
||||
|
||||
public TypeMirror sourceType() {
|
||||
TypeMirror sourceType() {
|
||||
return sourceType;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A class, whose purpose is to combine the use of
|
||||
* {@link org.mapstruct.ap.internal.gem.XmlElementDeclGem}
|
||||
* and
|
||||
* {@link org.mapstruct.ap.internal.gem.jakarta.XmlElementDeclGem}.
|
||||
*/
|
||||
static class XmlElementDeclInfo {
|
||||
|
||||
private final String nameValue;
|
||||
private final TypeMirror scopeType;
|
||||
|
||||
XmlElementDeclInfo(String nameValue, TypeMirror scopeType) {
|
||||
this.nameValue = nameValue;
|
||||
this.scopeType = scopeType;
|
||||
}
|
||||
|
||||
String nameValue() {
|
||||
return nameValue;
|
||||
}
|
||||
|
||||
TypeMirror scopeType() {
|
||||
return scopeType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,8 @@ import java.util.List;
|
||||
import org.mapstruct.ap.internal.gem.MappingConstantsGem;
|
||||
import org.mapstruct.ap.internal.model.Annotation;
|
||||
import org.mapstruct.ap.internal.model.Mapper;
|
||||
import org.mapstruct.ap.internal.model.common.Type;
|
||||
import org.mapstruct.ap.internal.util.AnnotationProcessingException;
|
||||
|
||||
/**
|
||||
* A {@link ModelElementProcessor} which converts the given {@link Mapper}
|
||||
@ -30,13 +32,13 @@ public class CdiComponentProcessor extends AnnotationBasedComponentModelProcesso
|
||||
@Override
|
||||
protected List<Annotation> getTypeAnnotations(Mapper mapper) {
|
||||
return Collections.singletonList(
|
||||
new Annotation( getTypeFactory().getType( "javax.enterprise.context.ApplicationScoped" ) )
|
||||
new Annotation( getType( "ApplicationScoped" ) )
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Annotation> getMapperReferenceAnnotations() {
|
||||
return Arrays.asList( new Annotation( getTypeFactory().getType( "javax.inject.Inject" ) ) );
|
||||
return Arrays.asList( new Annotation( getType( "Inject" ) ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -48,4 +50,24 @@ public class CdiComponentProcessor extends AnnotationBasedComponentModelProcesso
|
||||
protected boolean additionalPublicEmptyConstructor() {
|
||||
return true;
|
||||
}
|
||||
|
||||
private Type getType(String simpleName) {
|
||||
String javaxPrefix = "javax.inject.";
|
||||
String jakartaPrefix = "jakarta.inject.";
|
||||
if ( "ApplicationScoped".equals( simpleName ) ) {
|
||||
javaxPrefix = "javax.enterprise.context.";
|
||||
jakartaPrefix = "jakarta.enterprise.context.";
|
||||
}
|
||||
if ( getTypeFactory().isTypeAvailable( javaxPrefix + simpleName ) ) {
|
||||
return getTypeFactory().getType( javaxPrefix + simpleName );
|
||||
}
|
||||
|
||||
if ( getTypeFactory().isTypeAvailable( jakartaPrefix + simpleName ) ) {
|
||||
return getTypeFactory().getType( jakartaPrefix + simpleName );
|
||||
}
|
||||
|
||||
throw new AnnotationProcessingException(
|
||||
"Couldn't find any of the CDI or Jakarta CDI Dependency types." +
|
||||
" Are you missing a dependency on your classpath?" );
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.internal.processor;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.mapstruct.ap.internal.gem.MappingConstantsGem;
|
||||
import org.mapstruct.ap.internal.model.Annotation;
|
||||
import org.mapstruct.ap.internal.model.Mapper;
|
||||
|
||||
/**
|
||||
* A {@link ModelElementProcessor} which converts the given {@link Mapper}
|
||||
* object into an application-scoped Jakarta CDI bean in case Jakarta CDI
|
||||
* is configured as the target component model for this mapper.
|
||||
*
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
public class JakartaCdiComponentProcessor extends AnnotationBasedComponentModelProcessor {
|
||||
|
||||
@Override
|
||||
protected String getComponentModelIdentifier() {
|
||||
return MappingConstantsGem.ComponentModelGem.JAKARTA_CDI;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Annotation> getTypeAnnotations(Mapper mapper) {
|
||||
return Collections.singletonList(
|
||||
new Annotation( getTypeFactory().getType( "jakarta.enterprise.context.ApplicationScoped" ) )
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Annotation> getMapperReferenceAnnotations() {
|
||||
return Arrays.asList( new Annotation( getTypeFactory().getType( "jakarta.inject.Inject" ) ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean requiresGenerationOfDecoratorClass() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean additionalPublicEmptyConstructor() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -301,7 +301,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
|
||||
|
||||
|
||||
for ( TypeMirror extraImport : mapperOptions.imports() ) {
|
||||
Type type = typeFactory.getType( extraImport );
|
||||
Type type = typeFactory.getAlwaysImportedType( extraImport );
|
||||
extraImports.add( type );
|
||||
}
|
||||
|
||||
|
@ -196,7 +196,6 @@ public class MappingResolverImpl implements MappingResolver {
|
||||
|
||||
this.mappingMethod = mappingMethod;
|
||||
this.description = description;
|
||||
this.methods = filterPossibleCandidateMethods( sourceModel );
|
||||
this.formattingParameters =
|
||||
formattingParameters == null ? FormattingParameters.EMPTY : formattingParameters;
|
||||
this.sourceRHS = sourceRHS;
|
||||
@ -207,13 +206,14 @@ public class MappingResolverImpl implements MappingResolver {
|
||||
this.builtIns = builtIns;
|
||||
this.messager = messager;
|
||||
this.reportingLimitAmbiguous = verboseLogging ? Integer.MAX_VALUE : LIMIT_REPORTING_AMBIGUOUS;
|
||||
this.methods = filterPossibleCandidateMethods( sourceModel, mappingMethod );
|
||||
}
|
||||
// CHECKSTYLE:ON
|
||||
|
||||
private <T extends Method> List<T> filterPossibleCandidateMethods(List<T> candidateMethods) {
|
||||
private <T extends Method> List<T> filterPossibleCandidateMethods(List<T> candidateMethods, T mappingMethod) {
|
||||
List<T> result = new ArrayList<>( candidateMethods.size() );
|
||||
for ( T candidate : candidateMethods ) {
|
||||
if ( isCandidateForMapping( candidate ) ) {
|
||||
if ( isCandidateForMapping( candidate ) && isNotSelfOrSelfAllowed( mappingMethod, candidate )) {
|
||||
result.add( candidate );
|
||||
}
|
||||
}
|
||||
@ -221,6 +221,10 @@ public class MappingResolverImpl implements MappingResolver {
|
||||
return result;
|
||||
}
|
||||
|
||||
private <T extends Method> boolean isNotSelfOrSelfAllowed(T mappingMethod, T candidate) {
|
||||
return selectionCriteria == null || selectionCriteria.isSelfAllowed() || !candidate.equals( mappingMethod );
|
||||
}
|
||||
|
||||
private Assignment getTargetAssignment(Type sourceType, Type targetType) {
|
||||
|
||||
Assignment assignment;
|
||||
|
@ -10,7 +10,8 @@ package org.mapstruct.ap.internal.util;
|
||||
*/
|
||||
public final class JaxbConstants {
|
||||
|
||||
public static final String JAXB_ELEMENT_FQN = "javax.xml.bind.JAXBElement";
|
||||
public static final String JAVAX_JAXB_ELEMENT_FQN = "javax.xml.bind.JAXBElement";
|
||||
public static final String JAKARTA_JAXB_ELEMENT_FQN = "jakarta.xml.bind.JAXBElement";
|
||||
|
||||
private JaxbConstants() {
|
||||
}
|
||||
|
@ -159,7 +159,7 @@ public enum Message {
|
||||
RETRIEVAL_NO_INPUT_ARGS( "Can't generate mapping method with no input arguments." ),
|
||||
RETRIEVAL_DUPLICATE_MAPPING_TARGETS( "Can't generate mapping method with more than one @MappingTarget parameter." ),
|
||||
RETRIEVAL_VOID_MAPPING_METHOD( "Can't generate mapping method with return type void." ),
|
||||
RETRIEVAL_NON_ASSIGNABLE_RESULTTYPE( "The result type is not assignable to the the return type." ),
|
||||
RETRIEVAL_NON_ASSIGNABLE_RESULTTYPE( "The result type is not assignable to the return type." ),
|
||||
RETRIEVAL_ITERABLE_TO_NON_ITERABLE( "Can't generate mapping method from iterable type from java stdlib to non-iterable type." ),
|
||||
RETRIEVAL_MAPPING_HAS_TARGET_TYPE_PARAMETER( "Can't generate mapping method that has a parameter annotated with @TargetType." ),
|
||||
RETRIEVAL_NON_ITERABLE_TO_ITERABLE( "Can't generate mapping method from non-iterable type to iterable type from java stdlib." ),
|
||||
|
@ -41,7 +41,7 @@ public class RoundContext {
|
||||
|
||||
/**
|
||||
* Whether the given type has been found to be ready for further processing or not. This is the case if the type's
|
||||
* hierarchy is complete (no super-types need to be generated by other processors) an no processors have signaled
|
||||
* hierarchy is complete (no super-types need to be generated by other processors) and no processors have signaled
|
||||
* the intention to amend the given type.
|
||||
*
|
||||
* @param type the typed to be checked for its readiness
|
||||
|
@ -15,7 +15,7 @@ import org.mapstruct.util.Experimental;
|
||||
* <p>
|
||||
* This contract will be queried by MapStruct when examining types referenced by mappers to be generated, most notably
|
||||
* the source and target types of mapping methods. If at least one AST-modifying processor announces further changes to
|
||||
* such type, the generation of the affected mapper(s) will be deferred to a future round in the annnotation processing
|
||||
* such type, the generation of the affected mapper(s) will be deferred to a future round in the annotation processing
|
||||
* cycle.
|
||||
* <p>
|
||||
* Implementations are discovered via the service loader, i.e. a JAR providing an AST-modifying processor needs to
|
||||
|
@ -20,8 +20,8 @@ import org.mapstruct.util.Experimental;
|
||||
* <li>{@code mergeFrom(Target.Builder)}</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* When the JavaBean convention is not used with FreeBuilder then the getters are non standard and MapStruct
|
||||
* won't recognize them. Therefore one needs to use the JavaBean convention in which the fluent setters
|
||||
* When the JavaBean convention is not used with FreeBuilder then the getters are non-standard and MapStruct
|
||||
* won't recognize them. Therefore, one needs to use the JavaBean convention in which the fluent setters
|
||||
* start with {@code set}.
|
||||
*
|
||||
* @author Filip Hrisafov
|
||||
|
@ -10,9 +10,9 @@ import javax.lang.model.element.ExecutableElement;
|
||||
import org.mapstruct.util.Experimental;
|
||||
|
||||
/**
|
||||
* Accesor naming strategy for Immutables.
|
||||
* Accessor naming strategy for Immutables.
|
||||
* The generated Immutables also have a from that works as a copy. Our default strategy considers this method
|
||||
* as a setter with a name {@code from}. Therefore we are ignoring it.
|
||||
* as a setter with a name {@code from}. Therefore, we are ignoring it.
|
||||
*
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
|
@ -3,6 +3,7 @@
|
||||
# Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
org.mapstruct.ap.internal.processor.CdiComponentProcessor
|
||||
org.mapstruct.ap.internal.processor.JakartaCdiComponentProcessor
|
||||
org.mapstruct.ap.internal.processor.Jsr330ComponentProcessor
|
||||
org.mapstruct.ap.internal.processor.JakartaComponentProcessor
|
||||
org.mapstruct.ap.internal.processor.MapperCreationProcessor
|
||||
|
@ -62,6 +62,7 @@
|
||||
-->
|
||||
<#macro _assignment assignmentToUse>
|
||||
<@includeModel object=assignmentToUse
|
||||
presenceCheck=ext.presenceCheck
|
||||
targetBeanName=ext.targetBeanName
|
||||
existingInstanceMapping=ext.existingInstanceMapping
|
||||
targetReadAccessorName=ext.targetReadAccessorName
|
||||
|
@ -7,4 +7,5 @@
|
||||
-->
|
||||
<#-- @ftlvariable name="" type="org.mapstruct.ap.internal.model.MethodReferencePresenceCheck" -->
|
||||
<@includeModel object=methodReference
|
||||
presenceCheck=true
|
||||
targetType=ext.targetType/>
|
@ -111,7 +111,7 @@
|
||||
<#else>
|
||||
<#-- Streams are immutable so we can't update them -->
|
||||
<#if !existingInstanceMapping>
|
||||
<#--TODO fhr: after the the result is no longer the same instance, how does it affect the
|
||||
<#--TODO fhr: after the result is no longer the same instance, how does it affect the
|
||||
Before mapping methods. Does it even make sense to have before mapping on a stream? -->
|
||||
<#if sourceParameter.type.arrayType>
|
||||
<@returnLocalVarDefOrUpdate>Stream.of( ${sourceParameter.name} )<@streamMapSupplier />;</@returnLocalVarDefOrUpdate>
|
||||
|
@ -7,7 +7,7 @@
|
||||
-->
|
||||
<#-- @ftlvariable name="" type="org.mapstruct.ap.internal.model.ValueMappingMethod" -->
|
||||
<#if overridden>@Override</#if>
|
||||
<#lt>${accessibility.keyword} <@includeModel object=returnType/> ${name}(<#list parameters as param><@includeModel object=param/><#if param_has_next>, </#if></#list>) {
|
||||
<#lt>${accessibility.keyword} <@includeModel object=returnType/> ${name}(<#list parameters as param><@includeModel object=param/><#if param_has_next>, </#if></#list>)<@throws/> {
|
||||
<#list beforeMappingReferencesWithoutMappingTarget as callback>
|
||||
<@includeModel object=callback targetBeanName=resultName targetType=resultType/>
|
||||
<#if !callback_has_next>
|
||||
@ -66,3 +66,11 @@
|
||||
</#if>
|
||||
</@compress>
|
||||
</#macro>
|
||||
<#macro throws>
|
||||
<#if (thrownTypes?size > 0)><#lt> throws </#if><@compress single_line=true>
|
||||
<#list thrownTypes as exceptionType>
|
||||
<@includeModel object=exceptionType/>
|
||||
<#if exceptionType_has_next>, </#if><#t>
|
||||
</#list>
|
||||
</@compress>
|
||||
</#macro>
|
||||
|
@ -6,4 +6,4 @@
|
||||
|
||||
-->
|
||||
<#-- @ftlvariable name="" type="org.mapstruct.ap.internal.model.common.SourceRHS" -->
|
||||
<#if sourceLoopVarName??>${sourceLoopVarName}<#elseif sourceLocalVarName??>${sourceLocalVarName}<#else>${sourceReference}</#if>
|
||||
<#if sourceLoopVarName?? && !ext.presenceCheck??>${sourceLoopVarName}<#elseif sourceLocalVarName??>${sourceLocalVarName}<#else>${sourceReference}</#if>
|
@ -23,8 +23,8 @@ public class Issue1719Test {
|
||||
|
||||
/**
|
||||
* For adder methods MapStuct cannot generate an update method. MapStruct would cannot know how to remove objects
|
||||
* from the child-parent relation. It cannot even assume that the the collection can be cleared at forehand.
|
||||
* Therefore the only sensible choice is for MapStruct to create a create method for the target elements.
|
||||
* from the child-parent relation. It cannot even assume that the collection can be cleared at forehand.
|
||||
* Therefore, the only sensible choice is for MapStruct to create a create method for the target elements.
|
||||
*/
|
||||
@ProcessorTest
|
||||
@WithClasses(Issue1719Mapper.class)
|
||||
|
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.test.bugs._2743;
|
||||
|
||||
import org.mapstruct.BeanMapping;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.ReportingPolicy;
|
||||
|
||||
/**
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
@Mapper(unmappedSourcePolicy = ReportingPolicy.ERROR)
|
||||
public interface Issue2743Mapper {
|
||||
|
||||
@BeanMapping(ignoreUnmappedSourceProperties = { "number" })
|
||||
Target map(Source source);
|
||||
|
||||
class Source {
|
||||
|
||||
private final int number = 10;
|
||||
private final NestedSource nested;
|
||||
|
||||
public Source(NestedSource nested) {
|
||||
this.nested = nested;
|
||||
}
|
||||
|
||||
public int getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
||||
public NestedSource getNested() {
|
||||
return nested;
|
||||
}
|
||||
}
|
||||
|
||||
class NestedSource {
|
||||
private final String value;
|
||||
|
||||
public NestedSource(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
class Target {
|
||||
|
||||
private final NestedTarget nested;
|
||||
|
||||
public Target(NestedTarget nested) {
|
||||
this.nested = nested;
|
||||
}
|
||||
|
||||
public NestedTarget getNested() {
|
||||
return nested;
|
||||
}
|
||||
}
|
||||
|
||||
class NestedTarget {
|
||||
private final String value;
|
||||
|
||||
public NestedTarget(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.test.bugs._2743;
|
||||
|
||||
import org.mapstruct.ap.testutil.IssueKey;
|
||||
import org.mapstruct.ap.testutil.ProcessorTest;
|
||||
import org.mapstruct.ap.testutil.WithClasses;
|
||||
|
||||
/**
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
@IssueKey("2743")
|
||||
@WithClasses({
|
||||
Issue2743Mapper.class
|
||||
})
|
||||
class Issue2743Test {
|
||||
|
||||
@ProcessorTest
|
||||
void shouldCompile() {
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.test.bugs._2825;
|
||||
|
||||
/**
|
||||
* @author orange add
|
||||
*/
|
||||
public class Animal {
|
||||
private String name;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.test.bugs._2825;
|
||||
|
||||
/**
|
||||
* @author orange add
|
||||
*/
|
||||
public class Cat extends Animal {
|
||||
private String race;
|
||||
|
||||
public String getRace() {
|
||||
return race;
|
||||
}
|
||||
|
||||
public void setRace(String race) {
|
||||
this.race = race;
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.test.bugs._2825;
|
||||
|
||||
/**
|
||||
* @author orange add
|
||||
*/
|
||||
public class Dog extends Animal {
|
||||
private String race;
|
||||
|
||||
public String getRace() {
|
||||
return race;
|
||||
}
|
||||
|
||||
public void setRace(String race) {
|
||||
this.race = race;
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.test.bugs._2825;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.ReportingPolicy;
|
||||
import org.mapstruct.SubclassMapping;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
/**
|
||||
* @author orange add
|
||||
*/
|
||||
@Mapper(unmappedTargetPolicy = ReportingPolicy.IGNORE)
|
||||
public interface Issue2825Mapper {
|
||||
|
||||
Issue2825Mapper INSTANCE = Mappers.getMapper( Issue2825Mapper.class );
|
||||
|
||||
@SubclassMapping(target = TargetAnimal.class, source = Dog.class)
|
||||
@SubclassMapping(target = TargetAnimal.class, source = Cat.class)
|
||||
TargetAnimal map(Animal source);
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.test.bugs._2825;
|
||||
|
||||
import org.mapstruct.ap.testutil.IssueKey;
|
||||
import org.mapstruct.ap.testutil.ProcessorTest;
|
||||
import org.mapstruct.ap.testutil.WithClasses;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author orange add
|
||||
*/
|
||||
@IssueKey("2825")
|
||||
@WithClasses({
|
||||
Animal.class,
|
||||
Cat.class,
|
||||
Dog.class,
|
||||
Issue2825Mapper.class,
|
||||
TargetAnimal.class,
|
||||
})
|
||||
public class Issue2825Test {
|
||||
|
||||
@ProcessorTest
|
||||
public void mappingMethodShouldNotBeReusedForSubclassMappings() {
|
||||
Dog dog = new Dog();
|
||||
dog.setName( "Lucky" );
|
||||
dog.setRace( "Shepherd" );
|
||||
TargetAnimal target = Issue2825Mapper.INSTANCE.map( dog );
|
||||
assertThat( target.getName() ).isEqualTo( "Lucky" );
|
||||
assertThat( target.getRace() ).isEqualTo( "Shepherd" );
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.test.bugs._2825;
|
||||
|
||||
/**
|
||||
* @author orange add
|
||||
*/
|
||||
public class TargetAnimal {
|
||||
private String name;
|
||||
|
||||
private String race;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getRace() {
|
||||
return race;
|
||||
}
|
||||
|
||||
public void setRace(String race) {
|
||||
this.race = race;
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.test.bugs._2839;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Hakan Özkan
|
||||
*/
|
||||
public final class Car {
|
||||
|
||||
private final Id id;
|
||||
private final List<? extends Id> seatIds;
|
||||
private final List<? extends Id> tireIds;
|
||||
|
||||
public Car(Id id, List<? extends Id> seatIds, List<? extends Id> tireIds) {
|
||||
this.id = id;
|
||||
this.seatIds = seatIds;
|
||||
this.tireIds = tireIds;
|
||||
}
|
||||
|
||||
public Id getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public List<? extends Id> getSeatIds() {
|
||||
return seatIds;
|
||||
}
|
||||
|
||||
public List<? extends Id> getTireIds() {
|
||||
return tireIds;
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.test.bugs._2839;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Hakan Özkan
|
||||
*/
|
||||
public final class CarDto {
|
||||
|
||||
private final String id;
|
||||
private final List<String> seatIds;
|
||||
private final List<String> tireIds;
|
||||
|
||||
public CarDto(String id, List<String> seatIds, List<String> tireIds) {
|
||||
this.id = id;
|
||||
this.seatIds = seatIds;
|
||||
this.tireIds = tireIds;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public List<String> getSeatIds() {
|
||||
return seatIds;
|
||||
}
|
||||
|
||||
public List<String> getTireIds() {
|
||||
return tireIds;
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.test.bugs._2839;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
/**
|
||||
* @author Hakan Özkan
|
||||
*/
|
||||
@Mapper
|
||||
public abstract class CarMapper {
|
||||
|
||||
public static final CarMapper MAPPER = Mappers.getMapper( CarMapper.class );
|
||||
|
||||
public abstract Car toEntity(CarDto dto);
|
||||
|
||||
protected Id mapId(String id) throws Issue2839Exception {
|
||||
throw new Issue2839Exception("For id " + id);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.test.bugs._2839;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author Hakan Özkan
|
||||
*/
|
||||
public class Id {
|
||||
|
||||
private final UUID id;
|
||||
|
||||
public Id() {
|
||||
this.id = UUID.randomUUID();
|
||||
}
|
||||
|
||||
public Id(UUID id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public UUID getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.test.bugs._2839;
|
||||
|
||||
/**
|
||||
* @author Hakan Özkan
|
||||
*/
|
||||
public class Issue2839Exception extends Exception {
|
||||
|
||||
public Issue2839Exception(String message) {
|
||||
super( message );
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.test.bugs._2839;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.mapstruct.ap.testutil.IssueKey;
|
||||
import org.mapstruct.ap.testutil.ProcessorTest;
|
||||
import org.mapstruct.ap.testutil.WithClasses;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
/**
|
||||
* @author Hakan Özkan
|
||||
*/
|
||||
@IssueKey("2839")
|
||||
@WithClasses({
|
||||
Car.class,
|
||||
CarDto.class,
|
||||
CarMapper.class,
|
||||
Id.class,
|
||||
Issue2839Exception.class,
|
||||
})
|
||||
public class Issue2839Test {
|
||||
|
||||
@ProcessorTest
|
||||
void shouldCompile() {
|
||||
CarDto car1 = new CarDto(
|
||||
"carId",
|
||||
Collections.singletonList( "seatId" ),
|
||||
Collections.singletonList( "tireId" )
|
||||
);
|
||||
assertThatThrownBy( () -> CarMapper.MAPPER.toEntity( car1 ) )
|
||||
.isExactlyInstanceOf( RuntimeException.class )
|
||||
.getCause()
|
||||
.isInstanceOf( Issue2839Exception.class )
|
||||
.hasMessage( "For id seatId" );
|
||||
|
||||
CarDto car2 = new CarDto( "carId", Collections.emptyList(), Collections.singletonList( "tireId" ) );
|
||||
assertThatThrownBy( () -> CarMapper.MAPPER.toEntity( car2 ) )
|
||||
.isExactlyInstanceOf( RuntimeException.class )
|
||||
.getCause()
|
||||
.isInstanceOf( Issue2839Exception.class )
|
||||
.hasMessage( "For id tireId" );
|
||||
|
||||
CarDto car3 = new CarDto( "carId", Collections.emptyList(), Collections.emptyList() );
|
||||
assertThatThrownBy( () -> CarMapper.MAPPER.toEntity( car3 ) )
|
||||
.isExactlyInstanceOf( RuntimeException.class )
|
||||
.getCause()
|
||||
.isInstanceOf( Issue2839Exception.class )
|
||||
.hasMessage( "For id carId" );
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.test.bugs._2840;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
/**
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
@Mapper
|
||||
public interface Issue2840Mapper {
|
||||
|
||||
Issue2840Mapper INSTANCE =
|
||||
Mappers.getMapper( Issue2840Mapper.class );
|
||||
|
||||
Issue2840Mapper.Target map(Short shortValue, Integer intValue);
|
||||
|
||||
default int toInt(Number number) {
|
||||
return number.intValue() + 5;
|
||||
}
|
||||
|
||||
default short toShort(Number number) {
|
||||
return (short) (number.shortValue() + 10);
|
||||
}
|
||||
|
||||
class Target {
|
||||
|
||||
private int intValue;
|
||||
private short shortValue;
|
||||
|
||||
public int getIntValue() {
|
||||
return intValue;
|
||||
}
|
||||
|
||||
public void setIntValue(int intValue) {
|
||||
this.intValue = intValue;
|
||||
}
|
||||
|
||||
public short getShortValue() {
|
||||
return shortValue;
|
||||
}
|
||||
|
||||
public void setShortValue(short shortValue) {
|
||||
this.shortValue = shortValue;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.test.bugs._2840;
|
||||
|
||||
import org.mapstruct.ap.testutil.IssueKey;
|
||||
import org.mapstruct.ap.testutil.ProcessorTest;
|
||||
import org.mapstruct.ap.testutil.WithClasses;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
@IssueKey("2840")
|
||||
@WithClasses({
|
||||
Issue2840Mapper.class,
|
||||
})
|
||||
class Issue2840Test {
|
||||
|
||||
@ProcessorTest
|
||||
void shouldUseMethodWithMostSpecificReturnType() {
|
||||
Issue2840Mapper.Target target = Issue2840Mapper.INSTANCE.map( (short) 10, 50 );
|
||||
|
||||
assertThat( target.getShortValue() ).isEqualTo( (short) 20 );
|
||||
assertThat( target.getIntValue() ).isEqualTo( 55 );
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.test.bugs._2897;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.ap.test.bugs._2897.util.Util;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
/**
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
@Mapper(imports = Util.Factory.class)
|
||||
public interface Issue2897Mapper {
|
||||
|
||||
Issue2897Mapper INSTANCE = Mappers.getMapper( Issue2897Mapper.class );
|
||||
|
||||
@Mapping( target = "value", expression = "java(Factory.parse( source ))")
|
||||
Target map(Source source);
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.test.bugs._2897;
|
||||
|
||||
import org.mapstruct.ap.test.bugs._2897.util.Util;
|
||||
import org.mapstruct.ap.testutil.IssueKey;
|
||||
import org.mapstruct.ap.testutil.ProcessorTest;
|
||||
import org.mapstruct.ap.testutil.WithClasses;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
@IssueKey("2897")
|
||||
@WithClasses({
|
||||
Util.class,
|
||||
Issue2897Mapper.class,
|
||||
Source.class,
|
||||
Target.class,
|
||||
})
|
||||
class Issue2897Test {
|
||||
|
||||
@ProcessorTest
|
||||
void shouldImportNestedClassInMapperImports() {
|
||||
Target target = Issue2897Mapper.INSTANCE.map( new Source( "test" ) );
|
||||
|
||||
assertThat( target.getValue() ).isEqualTo( "parsed(test)" );
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.test.bugs._2897;
|
||||
|
||||
/**
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
public class Source {
|
||||
|
||||
private final String value;
|
||||
|
||||
public Source(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.test.bugs._2897;
|
||||
|
||||
/**
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
public class Target {
|
||||
|
||||
private final String value;
|
||||
|
||||
public Target(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user