Compare commits

..

No commits in common. "main" and "1.6.0" have entirely different histories.
main ... 1.6.0

376 changed files with 1355 additions and 10781 deletions

View File

@ -7,11 +7,15 @@ env:
jobs: jobs:
test_jdk_ea: test_jdk_ea:
name: 'Linux JDK EA' strategy:
fail-fast: false
matrix:
java: [19-ea]
name: 'Linux JDK ${{ matrix.java }}'
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: 'Checkout' - name: 'Checkout'
uses: actions/checkout@v4 uses: actions/checkout@v3
- name: 'Set up JDK' - name: 'Set up JDK'
uses: oracle-actions/setup-java@v1 uses: oracle-actions/setup-java@v1
with: with:

View File

@ -1,20 +0,0 @@
name: Mac OS CI
on: push
env:
MAVEN_ARGS: -V -B --no-transfer-progress -Dhttp.keepAlive=false -Dmaven.wagon.http.pool=false -Dmaven.wagon.httpconnectionManager.ttlSeconds=120
jobs:
mac:
name: 'Mac OS'
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- name: 'Set up JDK 21'
uses: actions/setup-java@v4
with:
distribution: 'zulu'
java-version: 21
- name: 'Test'
run: ./mvnw ${MAVEN_ARGS} install

View File

@ -12,49 +12,80 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
java: [21] java: [17, 21]
name: 'Linux JDK ${{ matrix.java }}' name: 'Linux JDK ${{ matrix.java }}'
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: 'Checkout' - name: 'Checkout'
uses: actions/checkout@v4 uses: actions/checkout@v3
- name: 'Set up JDK' - name: 'Set up JDK'
uses: actions/setup-java@v4 uses: actions/setup-java@v3
with: with:
distribution: 'zulu' distribution: 'zulu'
java-version: ${{ matrix.java }} java-version: ${{ matrix.java }}
- name: 'Test' - name: 'Test'
run: ./mvnw ${MAVEN_ARGS} -Djacoco.skip=${{ matrix.java != 21 }} install -DskipDistribution=${{ matrix.java != 21 }} run: ./mvnw ${MAVEN_ARGS} -Djacoco.skip=true install -DskipDistribution=true
- name: 'Generate coverage report' linux:
if: matrix.java == 21 name: 'Linux JDK 11'
run: ./mvnw jacoco:report
- name: 'Upload coverage to Codecov'
if: matrix.java == 21
uses: codecov/codecov-action@v2
- name: 'Publish Snapshots'
if: matrix.java == 21 && github.event_name == 'push' && github.ref == 'refs/heads/main' && github.repository == 'mapstruct/mapstruct'
run: ./mvnw -s etc/ci-settings.xml -DskipTests=true -DskipDistribution=true deploy
integration_test_jdk:
strategy:
fail-fast: false
matrix:
java: [ 8, 11, 17 ]
name: 'Linux JDK ${{ matrix.java }}'
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: 'Checkout' - name: 'Checkout'
uses: actions/checkout@v4 uses: actions/checkout@v3
- name: 'Set up JDK 21 for building everything' - name: 'Set up JDK 11'
uses: actions/setup-java@v4 uses: actions/setup-java@v3
with: with:
distribution: 'zulu' distribution: 'zulu'
java-version: 21 java-version: 11
- name: 'Test'
run: ./mvnw ${MAVEN_ARGS} install
- name: 'Generate coverage report'
run: ./mvnw jacoco:report
- name: 'Upload coverage to Codecov'
uses: codecov/codecov-action@v2
- name: 'Publish Snapshots'
if: github.event_name == 'push' && github.ref == 'refs/heads/main' && github.repository == 'mapstruct/mapstruct'
run: ./mvnw -s etc/ci-settings.xml -DskipTests=true -DskipDistribution=true deploy
linux-jdk-8:
name: 'Linux JDK 8'
runs-on: ubuntu-latest
steps:
- name: 'Checkout'
uses: actions/checkout@v3
- name: 'Set up JDK 11 for building everything'
uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: 11
- name: 'Install Processor' - name: 'Install Processor'
run: ./mvnw ${MAVEN_ARGS} -DskipTests install -pl processor -am run: ./mvnw ${MAVEN_ARGS} -DskipTests install -pl processor -am
- name: 'Set up JDK ${{ matrix.java }} for running integration tests' - name: 'Set up JDK 8 for running integration tests'
uses: actions/setup-java@v4 uses: actions/setup-java@v3
with: with:
distribution: 'zulu' distribution: 'zulu'
java-version: ${{ matrix.java }} java-version: 8
- name: 'Run integration tests' - name: 'Run integration tests'
run: ./mvnw ${MAVEN_ARGS} verify -pl integrationtest run: ./mvnw ${MAVEN_ARGS} verify -pl integrationtest
windows:
name: 'Windows'
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
- name: 'Set up JDK 11'
uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: 11
- name: 'Test'
run: ./mvnw %MAVEN_ARGS% install
mac:
name: 'Mac OS'
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
- name: 'Set up JDK 11'
uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: 11
- name: 'Test'
run: ./mvnw ${MAVEN_ARGS} install

View File

@ -22,7 +22,7 @@ jobs:
- name: Setup Java - name: Setup Java
uses: actions/setup-java@v4 uses: actions/setup-java@v4
with: with:
java-version: 21 java-version: 11
distribution: 'zulu' distribution: 'zulu'
cache: maven cache: maven
@ -38,7 +38,7 @@ jobs:
NEXT_VERSION=$COMPUTED_NEXT_VERSION NEXT_VERSION=$COMPUTED_NEXT_VERSION
fi fi
./mvnw -ntp -B versions:set versions:commit -DnewVersion=$RELEASE_VERSION -pl :mapstruct-parent -DgenerateBackupPoms=false ./mvnw -ntp -B versions:set versions:commit -DnewVersion=$RELEASE_VERSION -pl :mapstruct-parent -DgenerateBackupPoms=false
git config --global user.email "${{ vars.GH_BOT_EMAIL }}" git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
git config --global user.name "GitHub Action" git config --global user.name "GitHub Action"
git commit -a -m "Releasing version $RELEASE_VERSION" git commit -a -m "Releasing version $RELEASE_VERSION"
git push git push

View File

@ -1,20 +0,0 @@
name: Windows CI
on: push
env:
MAVEN_ARGS: -V -B --no-transfer-progress -Dhttp.keepAlive=false -Dmaven.wagon.http.pool=false -Dmaven.wagon.httpconnectionManager.ttlSeconds=120
jobs:
windows:
name: 'Windows'
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- name: 'Set up JDK 21'
uses: actions/setup-java@v4
with:
distribution: 'zulu'
java-version: 21
- name: 'Test'
run: ./mvnw %MAVEN_ARGS% install

117
.mvn/wrapper/MavenWrapperDownloader.java vendored Normal file
View File

@ -0,0 +1,117 @@
/*
* Copyright 2007-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.net.*;
import java.io.*;
import java.nio.channels.*;
import java.util.Properties;
public class MavenWrapperDownloader {
private static final String WRAPPER_VERSION = "0.5.6";
/**
* Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
*/
private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
+ WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
/**
* Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
* use instead of the default one.
*/
private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
".mvn/wrapper/maven-wrapper.properties";
/**
* Path where the maven-wrapper.jar will be saved to.
*/
private static final String MAVEN_WRAPPER_JAR_PATH =
".mvn/wrapper/maven-wrapper.jar";
/**
* Name of the property which should be used to override the default download url for the wrapper.
*/
private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
public static void main(String args[]) {
System.out.println("- Downloader started");
File baseDirectory = new File(args[0]);
System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
// If the maven-wrapper.properties exists, read it and check if it contains a custom
// wrapperUrl parameter.
File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
String url = DEFAULT_DOWNLOAD_URL;
if(mavenWrapperPropertyFile.exists()) {
FileInputStream mavenWrapperPropertyFileInputStream = null;
try {
mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
Properties mavenWrapperProperties = new Properties();
mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
} catch (IOException e) {
System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
} finally {
try {
if(mavenWrapperPropertyFileInputStream != null) {
mavenWrapperPropertyFileInputStream.close();
}
} catch (IOException e) {
// Ignore ...
}
}
}
System.out.println("- Downloading from: " + url);
File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
if(!outputFile.getParentFile().exists()) {
if(!outputFile.getParentFile().mkdirs()) {
System.out.println(
"- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
}
}
System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
try {
downloadFileFromURL(url, outputFile);
System.out.println("Done");
System.exit(0);
} catch (Throwable e) {
System.out.println("- Error downloading");
e.printStackTrace();
System.exit(1);
}
}
private static void downloadFileFromURL(String urlString, File destination) throws Exception {
if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
String username = System.getenv("MVNW_USERNAME");
char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});
}
URL website = new URL(urlString);
ReadableByteChannel rbc;
rbc = Channels.newChannel(website.openStream());
FileOutputStream fos = new FileOutputStream(destination);
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
fos.close();
rbc.close();
}
}

BIN
.mvn/wrapper/maven-wrapper.jar vendored Normal file

Binary file not shown.

View File

@ -1,19 +1,2 @@
# Licensed to the Apache Software Foundation (ASF) under one distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.2/apache-maven-3.8.2-bin.zip
# or more contributor license agreements. See the NOTICE file wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
wrapperVersion=3.3.2
distributionType=only-script
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip

View File

@ -1,29 +1,10 @@
### Features ### Features
* Support for Java 21 Sequenced Collections (#3240)
### Enhancements ### Enhancements
* Add support for locale parameter for numberFormat and dateFormat (#3628)
* Detect Builder without a factory method (#3729) - With this if there is an inner class that ends with `Builder` and has a constructor with parameters,
it will be treated as a potential builder.
Builders through static methods on the type have a precedence.
* Behaviour change: Warning when the target has no target properties (#1140)
### Bugs ### Bugs
* Improve error message when mapping non-iterable to array (#3786)
### Documentation ### Documentation
### Build ### Build
### Behaviour Change
#### Warning when the target has no target properties
With this change, if the target bean does not have any target properties, a warning will be shown.
This is like this to avoid potential mistakes by users, where they might think that the target bean has properties, but it does not.

View File

@ -12,7 +12,7 @@
<parent> <parent>
<groupId>org.mapstruct</groupId> <groupId>org.mapstruct</groupId>
<artifactId>mapstruct-parent</artifactId> <artifactId>mapstruct-parent</artifactId>
<version>1.7.0-SNAPSHOT</version> <version>1.6.0</version>
<relativePath>../parent/pom.xml</relativePath> <relativePath>../parent/pom.xml</relativePath>
</parent> </parent>

View File

@ -12,7 +12,7 @@
<parent> <parent>
<groupId>org.mapstruct</groupId> <groupId>org.mapstruct</groupId>
<artifactId>mapstruct-parent</artifactId> <artifactId>mapstruct-parent</artifactId>
<version>1.7.0-SNAPSHOT</version> <version>1.6.0</version>
<relativePath>../parent/pom.xml</relativePath> <relativePath>../parent/pom.xml</relativePath>
</parent> </parent>

View File

@ -12,7 +12,7 @@
<parent> <parent>
<groupId>org.mapstruct</groupId> <groupId>org.mapstruct</groupId>
<artifactId>mapstruct-parent</artifactId> <artifactId>mapstruct-parent</artifactId>
<version>1.7.0-SNAPSHOT</version> <version>1.6.0</version>
<relativePath>../parent/pom.xml</relativePath> <relativePath>../parent/pom.xml</relativePath>
</parent> </parent>

View File

@ -132,18 +132,6 @@ public @interface BeanMapping {
*/ */
SubclassExhaustiveStrategy subclassExhaustiveStrategy() default COMPILE_ERROR; SubclassExhaustiveStrategy subclassExhaustiveStrategy() default COMPILE_ERROR;
/**
* Specifies the exception type to be thrown when a missing subclass implementation is detected
* in combination with {@link SubclassMappings}, based on the {@link #subclassExhaustiveStrategy()}.
* <p>
* This exception will only be thrown when the {@code subclassExhaustiveStrategy} is set to
* {@link SubclassExhaustiveStrategy#RUNTIME_EXCEPTION}.
*
* @return the exception class to throw when missing implementations are found.
* Defaults to {@link IllegalArgumentException}.
*/
Class<? extends Exception> subclassExhaustiveException() default IllegalArgumentException.class;
/** /**
* Default ignore all mappings. All mappings have to be defined manually. No automatic mapping will take place. No * Default ignore all mappings. All mappings have to be defined manually. No automatic mapping will take place. No
* warning will be issued on missing source or target properties. * warning will be issued on missing source or target properties.

View File

@ -1,67 +0,0 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Configures the ignored of one bean attribute.
*
* <p>
* The name all attributes of for ignored is to be specified via {@link #targets()}.
* </p>
*
* <p>
* <strong>Example 1:</strong> Implicitly mapping fields with the same name:
* </p>
*
* <pre><code class='java'>
* // We need ignored Human.name and Human.lastName
* // we can use &#64;Ignored with parameters "name", "lastName" {@link #targets()}
* &#64;Mapper
* public interface HumanMapper {
* &#64;Ignored( targets = { "name", "lastName" } )
* HumanDto toHumanDto(Human human)
* }
* </code></pre>
* <pre><code class='java'>
* // generates:
* &#64;Override
* public HumanDto toHumanDto(Human human) {
* humanDto.setFullName( human.getFullName() );
* // ...
* }
* </code></pre>
*
* @author Ivashin Aleksey
*/
@Repeatable(IgnoredList.class)
@Retention(RetentionPolicy.CLASS)
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
public @interface Ignored {
/**
* Whether the specified properties should be ignored by the generated mapping method.
* This can be useful when certain attributes should not be propagated from source to target or when properties in
* the target object are populated using a decorator and thus would be reported as unmapped target property by
* default.
*
* @return The target names of the configured properties that should be ignored
*/
String[] targets();
/**
* The prefix that should be applied to all the properties specified via {@link #targets()}.
*
* @return The target prefix to be applied to the defined properties
*/
String prefix() default "";
}

View File

@ -1,54 +0,0 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Configures the ignored list for several bean attributes.
* <p>
* <strong>TIP: When using Java 8 or later, you can omit the {@code @IgnoredList}
* wrapper annotation and directly specify several {@code @Ignored} annotations on one method.</strong>
*
* <p>These two examples are equal.
* </p>
* <pre><code class='java'>
* // before Java 8
* &#64;Mapper
* public interface MyMapper {
* &#64;IgnoredList({
* &#64;Ignored(targets = { "firstProperty" } ),
* &#64;Ignored(targets = { "secondProperty" } )
* })
* HumanDto toHumanDto(Human human);
* }
* </code></pre>
* <pre><code class='java'>
* // Java 8 and later
* &#64;Mapper
* public interface MyMapper {
* &#64;Ignored(targets = { "firstProperty" } ),
* &#64;Ignored(targets = { "secondProperty" } )
* HumanDto toHumanDto(Human human);
* }
* </code></pre>
*
* @author Ivashin Aleksey
*/
@Retention(RetentionPolicy.CLASS)
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE })
public @interface IgnoredList {
/**
* The configuration of the bean attributes.
*
* @return The configuration of the bean attributes.
*/
Ignored[] value();
}

View File

@ -66,38 +66,19 @@ public @interface IterableMapping {
/** /**
* A format string as processable by {@link SimpleDateFormat} if the annotated method maps from an iterable of * A format string as processable by {@link SimpleDateFormat} if the annotated method maps from an iterable of
* {@code String} to an iterable {@link Date} or vice-versa. Will be ignored for all other element types. * {@code String} to an iterable {@link Date} or vice-versa. Will be ignored for all other element types.
* <p>
* If the {@link #locale()} is also specified, the format will consider the specified locale when processing
* the date. Otherwise, the system's default locale will be used.
* *
* @return A date format string as processable by {@link SimpleDateFormat}. * @return A date format string as processable by {@link SimpleDateFormat}.
* @see #locale()
*/ */
String dateFormat() default ""; String dateFormat() default "";
/** /**
* A format string as processable by {@link DecimalFormat} if the annotated method maps from a * A format string as processable by {@link DecimalFormat} if the annotated method maps from a
* {@link Number} to a {@link String} or vice-versa. Will be ignored for all other element types. * {@link Number} to a {@link String} or vice-versa. Will be ignored for all other element types.
* <p>
* If the {@link #locale()} is also specified, the number format will be applied in the context of the given locale.
* Otherwise, the system's default locale will be used to process the number format.
* *
* @return A decimal format string as processable by {@link DecimalFormat}. * @return A decimal format string as processable by {@link DecimalFormat}.
* @see #locale()
*/ */
String numberFormat() default ""; String numberFormat() default "";
/**
* Specifies the locale to be used when processing {@link #dateFormat()} or {@link #numberFormat()}.
* <p>
* The locale should be a plain tag representing the language, such as "en" for English, "de" for German, etc.
* <p>
* If no locale is specified, the system's default locale will be used.
*
* @return A string representing the locale to be used when formatting dates or numbers.
*/
String locale() default "";
/** /**
* A qualifier can be specified to aid the selection process of a suitable mapper. This is useful in case multiple * A qualifier can be specified to aid the selection process of a suitable mapper. This is useful in case multiple
* mappers (hand written of internal) qualify and result in an 'Ambiguous mapping methods found' error. * mappers (hand written of internal) qualify and result in an 'Ambiguous mapping methods found' error.

View File

@ -56,12 +56,8 @@ public @interface MapMapping {
/** /**
* A format string as processable by {@link SimpleDateFormat} if the annotated method maps from a map with key type * A format string as processable by {@link SimpleDateFormat} if the annotated method maps from a map with key type
* {@code String} to an map with key type {@link Date} or vice-versa. Will be ignored for all other key types. * {@code String} to an map with key type {@link Date} or vice-versa. Will be ignored for all other key types.
* <p>
* If the {@link #locale()} is specified, the format will consider the specified locale when processing the date.
* Otherwise, the system's default locale will be used.
* *
* @return A date format string as processable by {@link SimpleDateFormat}. * @return A date format string as processable by {@link SimpleDateFormat}.
* @see #locale()
*/ */
String keyDateFormat() default ""; String keyDateFormat() default "";
@ -69,50 +65,27 @@ public @interface MapMapping {
* A format string as processable by {@link SimpleDateFormat} if the annotated method maps from a map with value * A format string as processable by {@link SimpleDateFormat} if the annotated method maps from a map with value
* type {@code String} to an map with value type {@link Date} or vice-versa. Will be ignored for all other value * type {@code String} to an map with value type {@link Date} or vice-versa. Will be ignored for all other value
* types. * types.
* <p>
* If the {@link #locale()} is specified, the format will consider the specified locale when processing the date.
* Otherwise, the system's default locale will be used.
* *
* @return A date format string as processable by {@link SimpleDateFormat}. * @return A date format string as processable by {@link SimpleDateFormat}.
* @see #locale()
*/ */
String valueDateFormat() default ""; String valueDateFormat() default "";
/** /**
* A format string as processable by {@link DecimalFormat} if the annotated method maps from a * A format string as processable by {@link DecimalFormat} if the annotated method maps from a
* {@link Number} to a {@link String} or vice-versa. Will be ignored for all other key types. * {@link Number} to a {@link String} or vice-versa. Will be ignored for all other key types.
* <p>
* If the {@link #locale()} is specified, the number format will be applied in the context of the given locale.
* Otherwise, the system's default locale will be used.
* *
* @return A decimal format string as processable by {@link DecimalFormat}. * @return A decimal format string as processable by {@link DecimalFormat}.
* @see #locale()
*/ */
String keyNumberFormat() default ""; String keyNumberFormat() default "";
/** /**
* A format string as processable by {@link DecimalFormat} if the annotated method maps from a * A format string as processable by {@link DecimalFormat} if the annotated method maps from a
* {@link Number} to a {@link String} or vice-versa. Will be ignored for all other value types. * {@link Number} to a {@link String} or vice-versa. Will be ignored for all other value types.
* <p>
* If the {@link #locale()} is specified, the number format will be applied in the context of the given locale.
* Otherwise, the system's default locale will be used.
* *
* @return A decimal format string as processable by {@link DecimalFormat}. * @return A decimal format string as processable by {@link DecimalFormat}.
* @see #locale()
*/ */
String valueNumberFormat() default ""; String valueNumberFormat() default "";
/**
* Specifies the locale to be used when processing {@link SimpleDateFormat} or {@link DecimalFormat} for key or
* value mappings in maps. The locale should be a plain tag representing the language, such as "en" for English,
* "de" for German, etc.
* <p>
* If no locale is specified, the system's default locale will be used.
*
* @return A string representing the locale to be used when formatting dates or numbers in maps.
*/
String locale() default "";
/** /**
* A key value qualifier can be specified to aid the selection process of a suitable mapper. This is useful in * A key value qualifier can be specified to aid the selection process of a suitable mapper. This is useful in
* case multiple mappers (hand written of internal) qualify and result in an 'Ambiguous mapping methods found' * case multiple mappers (hand written of internal) qualify and result in an 'Ambiguous mapping methods found'

View File

@ -281,18 +281,6 @@ public @interface Mapper {
*/ */
SubclassExhaustiveStrategy subclassExhaustiveStrategy() default COMPILE_ERROR; SubclassExhaustiveStrategy subclassExhaustiveStrategy() default COMPILE_ERROR;
/**
* Specifies the exception type to be thrown when a missing subclass implementation is detected
* in combination with {@link SubclassMappings}, based on the {@link #subclassExhaustiveStrategy()}.
* <p>
* This exception will only be thrown when the {@code subclassExhaustiveStrategy} is set to
* {@link SubclassExhaustiveStrategy#RUNTIME_EXCEPTION}.
*
* @return the exception class to throw when missing implementations are found.
* Defaults to {@link IllegalArgumentException}.
*/
Class<? extends Exception> subclassExhaustiveException() default IllegalArgumentException.class;
/** /**
* Determines whether to use field or constructor injection. This is only used on annotated based component models * Determines whether to use field or constructor injection. This is only used on annotated based component models
* such as CDI, Spring and JSR 330. * such as CDI, Spring and JSR 330.

View File

@ -249,18 +249,6 @@ public @interface MapperConfig {
*/ */
SubclassExhaustiveStrategy subclassExhaustiveStrategy() default COMPILE_ERROR; SubclassExhaustiveStrategy subclassExhaustiveStrategy() default COMPILE_ERROR;
/**
* Specifies the exception type to be thrown when a missing subclass implementation is detected
* in combination with {@link SubclassMappings}, based on the {@link #subclassExhaustiveStrategy()}.
* <p>
* This exception will only be thrown when the {@code subclassExhaustiveStrategy} is set to
* {@link SubclassExhaustiveStrategy#RUNTIME_EXCEPTION}.
*
* @return the exception class to throw when missing implementations are found.
* Defaults to {@link IllegalArgumentException}.
*/
Class<? extends Exception> subclassExhaustiveException() default IllegalArgumentException.class;
/** /**
* Determines whether to use field or constructor injection. This is only used on annotated based component models * Determines whether to use field or constructor injection. This is only used on annotated based component models
* such as CDI, Spring and JSR 330. * such as CDI, Spring and JSR 330.

View File

@ -175,38 +175,19 @@ public @interface Mapping {
/** /**
* A format string as processable by {@link SimpleDateFormat} if the attribute is mapped from {@code String} to * A format string as processable by {@link SimpleDateFormat} if the attribute is mapped from {@code String} to
* {@link Date} or vice-versa. Will be ignored for all other attribute types and when mapping enum constants. * {@link Date} or vice-versa. Will be ignored for all other attribute types and when mapping enum constants.
* <p>
* If the {@link #locale()} is also specified, the format will consider the specified locale when processing
* the date. Otherwise, the system's default locale will be used.
* *
* @return A date format string as processable by {@link SimpleDateFormat}. * @return A date format string as processable by {@link SimpleDateFormat}.
* @see #locale()
*/ */
String dateFormat() default ""; String dateFormat() default "";
/** /**
* A format string as processable by {@link DecimalFormat} if the annotated method maps from a * A format string as processable by {@link DecimalFormat} if the annotated method maps from a
* {@link Number} to a {@link String} or vice-versa. Will be ignored for all other element types. * {@link Number} to a {@link String} or vice-versa. Will be ignored for all other element types.
* <p>
* If the {@link #locale()} is also specified, the number format will be applied in the context of the given locale.
* Otherwise, the system's default locale will be used to process the number format.
* *
* @return A decimal format string as processable by {@link DecimalFormat}. * @return A decimal format string as processable by {@link DecimalFormat}.
* @see #locale()
*/ */
String numberFormat() default ""; String numberFormat() default "";
/**
* Specifies the locale to be used when processing {@link #dateFormat()} or {@link #numberFormat()}.
* <p>
* The locale should be a plain tag representing the language, such as "en" for English, "de" for German, etc.
* <p>
* If no locale is specified, the system's default locale will be used.
*
* @return A string representing the locale to be used when formatting dates or numbers.
*/
String locale() default "";
/** /**
* A constant {@link String} based on which the specified target property is to be set. * A constant {@link String} based on which the specified target property is to be set.
* <p> * <p>
@ -306,9 +287,6 @@ public @interface Mapping {
* This can be useful when certain attributes should not be propagated from source to target or when properties in * This can be useful when certain attributes should not be propagated from source to target or when properties in
* the target object are populated using a decorator and thus would be reported as unmapped target property by * the target object are populated using a decorator and thus would be reported as unmapped target property by
* default. * default.
* <p>
* If you have multiple properties to ignore,
* you can use the {@link Ignored} annotation instead and group them all at once.
* *
* @return {@code true} if the given property should be ignored, {@code false} otherwise * @return {@code true} if the given property should be ignored, {@code false} otherwise
*/ */

View File

@ -10,7 +10,7 @@ package org.mapstruct;
* {@link NullValuePropertyMappingStrategy} can be defined on {@link MapperConfig}, {@link Mapper}, {@link BeanMapping} * {@link NullValuePropertyMappingStrategy} can be defined on {@link MapperConfig}, {@link Mapper}, {@link BeanMapping}
* and {@link Mapping}. * and {@link Mapping}.
* Precedence is arranged in the reverse order. So {@link Mapping} will override {@link BeanMapping}, will * Precedence is arranged in the reverse order. So {@link Mapping} will override {@link BeanMapping}, will
* override {@link Mapper} * overide {@link Mapper}
* *
* The enum <b>only applies to update methods</b>: methods that update a pre-existing target (annotated with * The enum <b>only applies to update methods</b>: methods that update a pre-existing target (annotated with
* {@code @}{@link MappingTarget}). * {@code @}{@link MappingTarget}).

View File

@ -12,7 +12,7 @@
<parent> <parent>
<groupId>org.mapstruct</groupId> <groupId>org.mapstruct</groupId>
<artifactId>mapstruct-parent</artifactId> <artifactId>mapstruct-parent</artifactId>
<version>1.7.0-SNAPSHOT</version> <version>1.6.0</version>
<relativePath>../parent/pom.xml</relativePath> <relativePath>../parent/pom.xml</relativePath>
</parent> </parent>
@ -130,7 +130,7 @@
<!-- <!--
There is a bug in JDK 11 (https://bugs.openjdk.java.net/browse/JDK-8215291) which doesn't work correctly when searching and adds undefined. There is a bug in JDK 11 (https://bugs.openjdk.java.net/browse/JDK-8215291) which doesn't work correctly when searching and adds undefined.
It has been fixed since JDK 12, but not yet backported to JDK 11 (https://bugs.openjdk.java.net/browse/JDK-8244171). It has been fixed since JDK 12, but not yet backported to JDK 11 (https://bugs.openjdk.java.net/browse/JDK-8244171).
One workaround is https://stackoverflow.com/a/57284322/1115491. One workardound is https://stackoverflow.com/a/57284322/1115491.
--> -->
<bottom> <bottom>
<![CDATA[ <![CDATA[

View File

@ -12,7 +12,7 @@
<parent> <parent>
<groupId>org.mapstruct</groupId> <groupId>org.mapstruct</groupId>
<artifactId>mapstruct-parent</artifactId> <artifactId>mapstruct-parent</artifactId>
<version>1.7.0-SNAPSHOT</version> <version>1.6.0</version>
<relativePath>../parent/pom.xml</relativePath> <relativePath>../parent/pom.xml</relativePath>
</parent> </parent>

View File

@ -308,7 +308,7 @@ Conditional mapping can also be used to check if a source parameter should be ma
A custom condition method for properties is a method that is annotated with `org.mapstruct.Condition` and returns `boolean`. A custom condition method for properties is a method that is annotated with `org.mapstruct.Condition` and returns `boolean`.
A custom condition method for source parameters is annotated with `org.mapstruct.SourceParameterCondition`, `org.mapstruct.Condition(appliesTo = org.mapstruct.ConditionStrategy#SOURCE_PARAMETERS)` or meta-annotated with `Condition(appliesTo = ConditionStrategy#SOURCE_PARAMETERS)` A custom condition method for source parameters is annotated with `org.mapstruct.SourceParameterCondition`, `org.mapstruct.Condition(appliesTo = org.mapstruct.ConditionStrategy#SOURCE_PARAMETERS)` or meta-annotated with `Condition(appliesTo = ConditionStrategy#SOURCE_PARAMETERS)`
e.g. if you only want to map a String property when it is not `null` and not empty then you can do something like: e.g. if you only want to map a String property when it is not `null`, and it is not empty then you can do something like:
.Mapper using custom condition check method .Mapper using custom condition check method
==== ====

View File

@ -302,7 +302,7 @@ If you don't want explicitly name all properties from nested source bean, you ca
The generated code will map every property from `CustomerDto.record` to `Customer` directly, without need to manually name any of them. The generated code will map every property from `CustomerDto.record` to `Customer` directly, without need to manually name any of them.
The same goes for `Customer.account`. The same goes for `Customer.account`.
When there are conflicts, these can be resolved by explicitly defining the mapping. For instance in the example above. `name` occurs in `CustomerDto.record` and in `CustomerDto.account`. The mapping `@Mapping( target = "name", source = "record.name" )` resolves this conflict. When there are conflicts, these can be resolved by explicitely defining the mapping. For instance in the example above. `name` occurs in `CustomerDto.record` and in `CustomerDto.account`. The mapping `@Mapping( target = "name", source = "record.name" )` resolves this conflict.
This "target this" notation can be very useful when mapping hierarchical objects to flat objects and vice versa (`@InheritInverseConfiguration`). This "target this" notation can be very useful when mapping hierarchical objects to flat objects and vice versa (`@InheritInverseConfiguration`).
@ -421,11 +421,8 @@ If a Builder exists for a certain type, then that builder will be used for the m
The default implementation of the `BuilderProvider` assumes the following: The default implementation of the `BuilderProvider` assumes the following:
* The type has either * The type has a parameterless public static builder creation method that returns a builder.
** A parameterless public static builder creation method that returns a builder. So for example `Person` has a public static method that returns `PersonBuilder`.
e.g. `Person` has a public static method that returns `PersonBuilder`.
** A public static inner class with the name having the suffix "Builder", and a public no-args constructor
e.g. `Person` has an inner class `PersonBuilder` with a public no-args constructor.
* The builder type has a parameterless public method (build method) that returns the type being built. * The builder type has a parameterless public method (build method) that returns the type being built.
In our example `PersonBuilder` has a method returning `Person`. In our example `PersonBuilder` has a method returning `Person`.
* In case there are multiple build methods, MapStruct will look for a method called `build`, if such method exists * In case there are multiple build methods, MapStruct will look for a method called `build`, if such method exists

View File

@ -280,13 +280,6 @@ This puts the configuration of the nested mapping into one place (method) where
instead of re-configuring the same things on all of those upper methods. instead of re-configuring the same things on all of those upper methods.
==== ====
[TIP]
====
When ignoring multiple properties instead of defining multiple `@Mapping` annotations, you can use the `@Ignored` annotation to group them together.
e.g. for the `FishTankMapperWithDocument` example above, you could write:
`@Ignored(targets = { "plant", "ornament", "material" })`
====
[NOTE] [NOTE]
==== ====
In some cases the `ReportingPolicy` that is going to be used for the generated nested method would be `IGNORE`. In some cases the `ReportingPolicy` that is going to be used for the generated nested method would be `IGNORE`.

View File

@ -192,7 +192,7 @@ The option `DEFAULT` should not be used explicitly. It is used to distinguish be
[TIP] [TIP]
==== ====
When working with an `adder` method and JPA entities, Mapstruct assumes that the target collections are initialized with a collection implementation (e.g. an `ArrayList`). You can use factories to create a new target entity with initialized collections instead of Mapstruct creating the target entity by its constructor. When working with an `adder` method and JPA entities, Mapstruct assumes that the target collections are initialized with a collection implementation (e.g. an `ArrayList`). You can use factories to create a new target entity with intialized collections instead of Mapstruct creating the target entity by its constructor.
==== ====
[[implementation-types-for-collection-mappings]] [[implementation-types-for-collection-mappings]]
@ -212,20 +212,16 @@ When an iterable or map mapping method declares an interface type as return type
|`Set`|`LinkedHashSet` |`Set`|`LinkedHashSet`
|`SequencedSet`|`LinkedHashSet`
|`SortedSet`|`TreeSet` |`SortedSet`|`TreeSet`
|`NavigableSet`|`TreeSet` |`NavigableSet`|`TreeSet`
|`Map`|`LinkedHashMap` |`Map`|`LinkedHashMap`
|`SequencedMap`|`LinkedHashMap`
|`SortedMap`|`TreeMap` |`SortedMap`|`TreeMap`
|`NavigableMap`|`TreeMap` |`NavigableMap`|`TreeMap`
|`ConcurrentMap`|`ConcurrentHashMap` |`ConcurrentMap`|`ConcurrentHashMap`
|`ConcurrentNavigableMap`|`ConcurrentSkipListMap` |`ConcurrentNavigableMap`|`ConcurrentSkipListMap`
|=== |===

View File

@ -12,7 +12,7 @@
<parent> <parent>
<groupId>org.mapstruct</groupId> <groupId>org.mapstruct</groupId>
<artifactId>mapstruct-parent</artifactId> <artifactId>mapstruct-parent</artifactId>
<version>1.7.0-SNAPSHOT</version> <version>1.6.0</version>
<relativePath>../parent/pom.xml</relativePath> <relativePath>../parent/pom.xml</relativePath>
</parent> </parent>

View File

@ -30,11 +30,9 @@ public final class FullFeatureCompilationExclusionCliEnhancer implements Process
switch ( currentJreVersion ) { switch ( currentJreVersion ) {
case JAVA_8: case JAVA_8:
additionalExcludes.add( "org/mapstruct/ap/test/**/spring/**/*.java" );
additionalExcludes.add( "org/mapstruct/ap/test/injectionstrategy/cdi/**/*.java" ); additionalExcludes.add( "org/mapstruct/ap/test/injectionstrategy/cdi/**/*.java" );
additionalExcludes.add( "org/mapstruct/ap/test/injectionstrategy/jakarta_cdi/**/*.java" ); additionalExcludes.add( "org/mapstruct/ap/test/injectionstrategy/jakarta_cdi/**/*.java" );
additionalExcludes.add( "org/mapstruct/ap/test/annotatewith/deprecated/jdk11/*.java" ); additionalExcludes.add( "org/mapstruct/ap/test/annotatewith/deprecated/jdk11/*.java" );
additionalExcludes.add( "org/mapstruct/ap/test/**/jdk21/*.java" );
if ( processorType == ProcessorTest.ProcessorType.ECLIPSE_JDT ) { if ( processorType == ProcessorTest.ProcessorType.ECLIPSE_JDT ) {
additionalExcludes.add( additionalExcludes.add(
"org/mapstruct/ap/test/selection/methodgenerics/wildcards/LifecycleIntersectionMapper.java" ); "org/mapstruct/ap/test/selection/methodgenerics/wildcards/LifecycleIntersectionMapper.java" );
@ -43,14 +41,6 @@ public final class FullFeatureCompilationExclusionCliEnhancer implements Process
case JAVA_9: case JAVA_9:
// TODO find out why this fails: // TODO find out why this fails:
additionalExcludes.add( "org/mapstruct/ap/test/collection/wildcard/BeanMapper.java" ); additionalExcludes.add( "org/mapstruct/ap/test/collection/wildcard/BeanMapper.java" );
additionalExcludes.add( "org/mapstruct/ap/test/**/jdk21/*.java" );
break;
case JAVA_11:
additionalExcludes.add( "org/mapstruct/ap/test/**/spring/**/*.java" );
additionalExcludes.add( "org/mapstruct/ap/test/**/jdk21/*.java" );
break;
case JAVA_17:
additionalExcludes.add( "org/mapstruct/ap/test/**/jdk21/*.java" );
break; break;
default: default:
} }

View File

@ -5,7 +5,6 @@
*/ */
package org.mapstruct.itest.tests; package org.mapstruct.itest.tests;
import org.junit.jupiter.api.condition.DisabledOnJre;
import org.junit.jupiter.api.condition.EnabledForJreRange; import org.junit.jupiter.api.condition.EnabledForJreRange;
import org.junit.jupiter.api.condition.JRE; import org.junit.jupiter.api.condition.JRE;
import org.junit.jupiter.api.parallel.Execution; import org.junit.jupiter.api.parallel.Execution;
@ -81,15 +80,12 @@ public class MavenIntegrationTest {
} }
@ProcessorTest(baseDir = "jsr330Test") @ProcessorTest(baseDir = "jsr330Test")
@EnabledForJreRange(min = JRE.JAVA_17)
@DisabledOnJre(JRE.OTHER)
void jsr330Test() { void jsr330Test() {
} }
@ProcessorTest(baseDir = "lombokBuilderTest", processorTypes = { @ProcessorTest(baseDir = "lombokBuilderTest", processorTypes = {
ProcessorTest.ProcessorType.JAVAC ProcessorTest.ProcessorType.JAVAC
}) })
@DisabledOnJre(JRE.OTHER)
void lombokBuilderTest() { void lombokBuilderTest() {
} }
@ -98,7 +94,6 @@ public class MavenIntegrationTest {
ProcessorTest.ProcessorType.JAVAC_WITH_PATHS ProcessorTest.ProcessorType.JAVAC_WITH_PATHS
}) })
@EnabledForJreRange(min = JRE.JAVA_11) @EnabledForJreRange(min = JRE.JAVA_11)
@DisabledOnJre(JRE.OTHER)
void lombokModuleTest() { void lombokModuleTest() {
} }
@ -136,13 +131,6 @@ public class MavenIntegrationTest {
void recordsCrossModuleTest() { void recordsCrossModuleTest() {
} }
@ProcessorTest(baseDir = "recordsCrossModuleInterfaceTest", processorTypes = {
ProcessorTest.ProcessorType.JAVAC
})
@EnabledForJreRange(min = JRE.JAVA_17)
void recordsCrossModuleInterfaceTest() {
}
@ProcessorTest(baseDir = "expressionTextBlocksTest", processorTypes = { @ProcessorTest(baseDir = "expressionTextBlocksTest", processorTypes = {
ProcessorTest.ProcessorType.JAVAC ProcessorTest.ProcessorType.JAVAC
}) })
@ -155,7 +143,6 @@ public class MavenIntegrationTest {
}, forkJvm = true) }, forkJvm = true)
// We have to fork the jvm because there is an NPE in com.intellij.openapi.util.SystemInfo.getRtVersion // We have to fork the jvm because there is an NPE in com.intellij.openapi.util.SystemInfo.getRtVersion
// and the kotlin-maven-plugin uses that. See also https://youtrack.jetbrains.com/issue/IDEA-238907 // and the kotlin-maven-plugin uses that. See also https://youtrack.jetbrains.com/issue/IDEA-238907
@DisabledOnJre(JRE.OTHER)
void kotlinDataTest() { void kotlinDataTest() {
} }
@ -169,8 +156,6 @@ public class MavenIntegrationTest {
} }
@ProcessorTest(baseDir = "springTest") @ProcessorTest(baseDir = "springTest")
@EnabledForJreRange(min = JRE.JAVA_17)
@DisabledOnJre(JRE.OTHER)
void springTest() { void springTest() {
} }

View File

@ -134,20 +134,14 @@ public class ProcessorInvocationInterceptor implements InvocationInterceptor {
} }
private void configureProcessor(Verifier verifier) { private void configureProcessor(Verifier verifier) {
ProcessorTest.ProcessorType processor = processorTestContext.getProcessor(); String compilerId = processorTestContext.getProcessor().getCompilerId();
String compilerId = processor.getCompilerId();
if ( compilerId != null ) { if ( compilerId != null ) {
String profile = processor.getProfile(); String profile = processorTestContext.getProcessor().getProfile();
if ( profile == null ) { if ( profile == null ) {
profile = "generate-via-compiler-plugin"; profile = "generate-via-compiler-plugin";
} }
verifier.addCliOption( "-P" + profile ); verifier.addCliOption( "-P" + profile );
verifier.addCliOption( "-Dcompiler-id=" + compilerId ); verifier.addCliOption( "-Dcompiler-id=" + compilerId );
if ( processor == ProcessorTest.ProcessorType.JAVAC ) {
if ( CURRENT_VERSION.ordinal() >= JRE.JAVA_21.ordinal() ) {
verifier.addCliOption( "-Dmaven.compiler.proc=full" );
}
}
} }
else { else {
verifier.addCliOption( "-Pgenerate-via-processor-plugin" ); verifier.addCliOption( "-Pgenerate-via-processor-plugin" );

View File

@ -27,11 +27,6 @@
<additionalExclude4>x</additionalExclude4> <additionalExclude4>x</additionalExclude4>
<additionalExclude5>x</additionalExclude5> <additionalExclude5>x</additionalExclude5>
<additionalExclude6>x</additionalExclude6> <additionalExclude6>x</additionalExclude6>
<additionalExclude7>x</additionalExclude7>
<additionalExclude8>x</additionalExclude8>
<additionalExclude9>x</additionalExclude9>
<additionalExclude10>x</additionalExclude10>
<additionalExclude11>x</additionalExclude11>
</properties> </properties>
<build> <build>
@ -54,13 +49,6 @@
<exclude>${additionalExclude4}</exclude> <exclude>${additionalExclude4}</exclude>
<exclude>${additionalExclude5}</exclude> <exclude>${additionalExclude5}</exclude>
<exclude>${additionalExclude6}</exclude> <exclude>${additionalExclude6}</exclude>
<exclude>${additionalExclude7}</exclude>
<exclude>${additionalExclude8}</exclude>
<exclude>${additionalExclude9}</exclude>
<exclude>${additionalExclude10}</exclude>
<exclude>${additionalExclude11}</exclude>
<exclude>${additionalExclude12}</exclude>
<exclude>${additionalExclude13}</exclude>
</excludes> </excludes>
</configuration> </configuration>
</plugin> </plugin>

View File

@ -1,22 +0,0 @@
<?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>
<artifactId>recordsCrossModuleInterfaceTest</artifactId>
<groupId>org.mapstruct</groupId>
<version>1.0.0</version>
</parent>
<artifactId>records-cross-module-1</artifactId>
</project>

View File

@ -1,10 +0,0 @@
/*
* 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.records.module1;
public interface NestedInterface {
String field();
}

View File

@ -1,10 +0,0 @@
/*
* 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.records.module1;
public interface RootInterface {
NestedInterface nested();
}

View File

@ -1,11 +0,0 @@
/*
* 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.records.module1;
public record SourceNestedRecord(
String field
) implements NestedInterface {
}

View File

@ -1,11 +0,0 @@
/*
* 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.records.module1;
public record SourceRootRecord(
SourceNestedRecord nested
) implements RootInterface {
}

View File

@ -1,30 +0,0 @@
<?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>
<artifactId>recordsCrossModuleInterfaceTest</artifactId>
<groupId>org.mapstruct</groupId>
<version>1.0.0</version>
</parent>
<artifactId>records-cross-module-2</artifactId>
<dependencies>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>records-cross-module-1</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
</project>

View File

@ -1,18 +0,0 @@
/*
* 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.records.module2;
import org.mapstruct.itest.records.module1.SourceRootRecord;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
@Mapper
public interface RecordInterfaceIssueMapper {
RecordInterfaceIssueMapper INSTANCE = Mappers.getMapper(RecordInterfaceIssueMapper.class);
TargetRootRecord map(SourceRootRecord source);
}

View File

@ -1,11 +0,0 @@
/*
* 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.records.module2;
public record TargetNestedRecord(
String field
) {
}

View File

@ -1,11 +0,0 @@
/*
* 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.records.module2;
public record TargetRootRecord(
TargetNestedRecord nested
) {
}

View File

@ -1,26 +0,0 @@
/*
* 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.records.module2;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Test;
import org.mapstruct.itest.records.module1.SourceRootRecord;
import org.mapstruct.itest.records.module1.SourceNestedRecord;
public class RecordsTest {
@Test
public void shouldMap() {
SourceRootRecord source = new SourceRootRecord( new SourceNestedRecord( "test" ) );
TargetRootRecord target = RecordInterfaceIssueMapper.INSTANCE.map( source );
assertThat( target ).isNotNull();
assertThat( target.nested() ).isNotNull();
assertThat( target.nested().field() ).isEqualTo( "test" );
}
}

View File

@ -1,26 +0,0 @@
<?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>recordsCrossModuleInterfaceTest</artifactId>
<packaging>pom</packaging>
<modules>
<module>module-1</module>
<module>module-2</module>
</modules>
</project>

View File

@ -1,13 +0,0 @@
/*
* 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.records.nested;
/**
* @author Filip Hrisafov
*/
public record Address(String street, String city) {
}

View File

@ -1,13 +0,0 @@
/*
* 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.records.nested;
/**
* @author Filip Hrisafov
*/
public record CareProvider(String externalId, Address address) {
}

View File

@ -1,13 +0,0 @@
/*
* 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.records.nested;
/**
* @author Filip Hrisafov
*/
public record CareProviderDto(String id, String street, String city) {
}

View File

@ -1,25 +0,0 @@
/*
* 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.records.nested;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.ReportingPolicy;
import org.mapstruct.factory.Mappers;
/**
* @author Filip Hrisafov
*/
@Mapper(unmappedTargetPolicy = ReportingPolicy.ERROR)
public interface CareProviderMapper {
CareProviderMapper INSTANCE = Mappers.getMapper( CareProviderMapper.class );
@Mapping(target = "id", source = "externalId")
@Mapping(target = "street", source = "address.street")
@Mapping(target = "city", source = "address.city")
CareProviderDto map(CareProvider source);
}

View File

@ -1,26 +0,0 @@
/*
* 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.records.nested;
import java.util.Arrays;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Test;
public class NestedRecordsTest {
@Test
public void shouldMapRecord() {
CareProvider source = new CareProvider( "kermit", new Address( "Sesame Street", "New York" ) );
CareProviderDto target = CareProviderMapper.INSTANCE.map( source );
assertThat( target ).isNotNull();
assertThat( target.id() ).isEqualTo( "kermit" );
assertThat( target.street() ).isEqualTo( "Sesame Street" );
assertThat( target.city() ).isEqualTo( "New York" );
}
}

View File

@ -32,6 +32,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration> <configuration>
<compilerArgs> <compilerArgs>
<compilerArg>-proc:none</compilerArg> <compilerArg>-proc:none</compilerArg>

View File

@ -38,6 +38,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration> <configuration>
<compilerArgs> <compilerArgs>
<compilerArg>-XprintProcessorInfo</compilerArg> <compilerArg>-XprintProcessorInfo</compilerArg>

View File

@ -32,6 +32,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration> <configuration>
<compilerArgs> <compilerArgs>
<compilerArg>-proc:none</compilerArg> <compilerArg>-proc:none</compilerArg>

View File

@ -38,6 +38,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration> <configuration>
<compilerArgs> <compilerArgs>
<compilerArg>-XprintProcessorInfo</compilerArg> <compilerArg>-XprintProcessorInfo</compilerArg>

479
mvnw vendored
View File

@ -19,241 +19,292 @@
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
# Apache Maven Wrapper startup batch script, version 3.3.2 # Maven Start Up Batch script
#
# Required ENV vars:
# ------------------
# JAVA_HOME - location of a JDK home dir
# #
# Optional ENV vars # Optional ENV vars
# ----------------- # -----------------
# JAVA_HOME - location of a JDK home dir, required when download maven via java source # M2_HOME - location of maven2's installed home dir
# MVNW_REPOURL - repo url base for downloading maven distribution # MAVEN_OPTS - parameters passed to the Java VM when running Maven
# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven # e.g. to debug Maven itself, use
# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
set -euf if [ -z "$MAVEN_SKIP_RC" ] ; then
[ "${MVNW_VERBOSE-}" != debug ] || set -x
# OS specific support. if [ -f /etc/mavenrc ] ; then
native_path() { printf %s\\n "$1"; } . /etc/mavenrc
case "$(uname)" in fi
CYGWIN* | MINGW*)
[ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")"
native_path() { cygpath --path --windows "$1"; }
;;
esac
# set JAVACMD and JAVACCMD if [ -f "$HOME/.mavenrc" ] ; then
set_java_home() { . "$HOME/.mavenrc"
# For Cygwin and MinGW, ensure paths are in Unix format before anything is touched fi
if [ -n "${JAVA_HOME-}" ]; then
if [ -x "$JAVA_HOME/jre/sh/java" ]; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
JAVACCMD="$JAVA_HOME/jre/sh/javac"
else
JAVACMD="$JAVA_HOME/bin/java"
JAVACCMD="$JAVA_HOME/bin/javac"
if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then fi
echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2
echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2 # OS specific support. $var _must_ be set to either true or false.
return 1 cygwin=false;
darwin=false;
mingw=false
case "`uname`" in
CYGWIN*) cygwin=true ;;
MINGW*) mingw=true;;
Darwin*) darwin=true
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
if [ -z "$JAVA_HOME" ]; then
if [ -x "/usr/libexec/java_home" ]; then
export JAVA_HOME="`/usr/libexec/java_home`"
else
export JAVA_HOME="/Library/Java/Home"
fi fi
fi fi
else
JAVACMD="$(
'set' +e
'unset' -f command 2>/dev/null
'command' -v java
)" || :
JAVACCMD="$(
'set' +e
'unset' -f command 2>/dev/null
'command' -v javac
)" || :
if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then
echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2
return 1
fi
fi
}
# hash string like Java String::hashCode
hash_string() {
str="${1:-}" h=0
while [ -n "$str" ]; do
char="${str%"${str#?}"}"
h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296))
str="${str#?}"
done
printf %x\\n $h
}
verbose() { :; }
[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; }
die() {
printf %s\\n "$1" >&2
exit 1
}
trim() {
# MWRAPPER-139:
# Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds.
# Needed for removing poorly interpreted newline sequences when running in more
# exotic environments such as mingw bash on Windows.
printf "%s" "${1}" | tr -d '[:space:]'
}
# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties
while IFS="=" read -r key value; do
case "${key-}" in
distributionUrl) distributionUrl=$(trim "${value-}") ;;
distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;;
esac
done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties"
[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties"
case "${distributionUrl##*/}" in
maven-mvnd-*bin.*)
MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/
case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in
*AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;;
:Darwin*x86_64) distributionPlatform=darwin-amd64 ;;
:Darwin*arm64) distributionPlatform=darwin-aarch64 ;;
:Linux*x86_64*) distributionPlatform=linux-amd64 ;;
*)
echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2
distributionPlatform=linux-amd64
;; ;;
esac
distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip"
;;
maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;;
*) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;;
esac esac
# apply MVNW_REPOURL and calculate MAVEN_HOME if [ -z "$JAVA_HOME" ] ; then
# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash> if [ -r /etc/gentoo-release ] ; then
[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}" JAVA_HOME=`java-config --jre-home`
distributionUrlName="${distributionUrl##*/}" fi
distributionUrlNameMain="${distributionUrlName%.*}"
distributionUrlNameMain="${distributionUrlNameMain%-bin}"
MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}"
MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")"
exec_maven() {
unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || :
exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD"
}
if [ -d "$MAVEN_HOME" ]; then
verbose "found existing MAVEN_HOME at $MAVEN_HOME"
exec_maven "$@"
fi fi
case "${distributionUrl-}" in if [ -z "$M2_HOME" ] ; then
*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;; ## resolve links - $0 may be a link to maven's home
*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;; PRG="$0"
esac
# prepare tmp dir # need this for relative symlinks
if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then while [ -h "$PRG" ] ; do
clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; } ls=`ls -ld "$PRG"`
trap clean HUP INT TERM EXIT link=`expr "$ls" : '.*-> \(.*\)$'`
else if expr "$link" : '/.*' > /dev/null; then
die "cannot create temp dir" PRG="$link"
fi else
PRG="`dirname "$PRG"`/$link"
mkdir -p -- "${MAVEN_HOME%/*}"
# Download and Install Apache Maven
verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
verbose "Downloading from: $distributionUrl"
verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
# select .zip or .tar.gz
if ! command -v unzip >/dev/null; then
distributionUrl="${distributionUrl%.zip}.tar.gz"
distributionUrlName="${distributionUrl##*/}"
fi
# verbose opt
__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR=''
[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v
# normalize http auth
case "${MVNW_PASSWORD:+has-password}" in
'') MVNW_USERNAME='' MVNW_PASSWORD='' ;;
has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;;
esac
if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then
verbose "Found wget ... using wget"
wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl"
elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then
verbose "Found curl ... using curl"
curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl"
elif set_java_home; then
verbose "Falling back to use Java to download"
javaSource="$TMP_DOWNLOAD_DIR/Downloader.java"
targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName"
cat >"$javaSource" <<-END
public class Downloader extends java.net.Authenticator
{
protected java.net.PasswordAuthentication getPasswordAuthentication()
{
return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() );
}
public static void main( String[] args ) throws Exception
{
setDefault( new Downloader() );
java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() );
}
}
END
# For Cygwin/MinGW, switch paths to Windows format before running javac and java
verbose " - Compiling Downloader.java ..."
"$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java"
verbose " - Running Downloader.java ..."
"$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")"
fi
# If specified, validate the SHA-256 sum of the Maven distribution zip file
if [ -n "${distributionSha256Sum-}" ]; then
distributionSha256Result=false
if [ "$MVN_CMD" = mvnd.sh ]; then
echo "Checksum validation is not supported for maven-mvnd." >&2
echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
exit 1
elif command -v sha256sum >/dev/null; then
if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then
distributionSha256Result=true
fi fi
elif command -v shasum >/dev/null; then done
if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then
distributionSha256Result=true saveddir=`pwd`
M2_HOME=`dirname "$PRG"`/..
# make it fully qualified
M2_HOME=`cd "$M2_HOME" && pwd`
cd "$saveddir"
# echo Using m2 at $M2_HOME
fi
# For Cygwin, ensure paths are in UNIX format before anything is touched
if $cygwin ; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --unix "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
fi
# For Mingw, ensure paths are in UNIX format before anything is touched
if $mingw ; then
[ -n "$M2_HOME" ] &&
M2_HOME="`(cd "$M2_HOME"; pwd)`"
[ -n "$JAVA_HOME" ] &&
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
fi
if [ -z "$JAVA_HOME" ]; then
javaExecutable="`which javac`"
if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
# readlink(1) is not available as standard on Solaris 10.
readLink=`which readlink`
if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
if $darwin ; then
javaHome="`dirname \"$javaExecutable\"`"
javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
else
javaExecutable="`readlink -f \"$javaExecutable\"`"
fi
javaHome="`dirname \"$javaExecutable\"`"
javaHome=`expr "$javaHome" : '\(.*\)/bin'`
JAVA_HOME="$javaHome"
export JAVA_HOME
fi
fi
fi
if [ -z "$JAVACMD" ] ; then
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi fi
else else
echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 JAVACMD="`which java`"
echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
exit 1
fi
if [ $distributionSha256Result = false ]; then
echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2
echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2
exit 1
fi fi
fi fi
# unzip and move if [ ! -x "$JAVACMD" ] ; then
if command -v unzip >/dev/null; then echo "Error: JAVA_HOME is not defined correctly." >&2
unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip" echo " We cannot execute $JAVACMD" >&2
exit 1
fi
if [ -z "$JAVA_HOME" ] ; then
echo "Warning: JAVA_HOME environment variable is not set."
fi
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
# traverses directory structure from process work directory to filesystem root
# first directory with .mvn subdirectory is considered project base directory
find_maven_basedir() {
if [ -z "$1" ]
then
echo "Path not specified to find_maven_basedir"
return 1
fi
basedir="$1"
wdir="$1"
while [ "$wdir" != '/' ] ; do
if [ -d "$wdir"/.mvn ] ; then
basedir=$wdir
break
fi
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
if [ -d "${wdir}" ]; then
wdir=`cd "$wdir/.."; pwd`
fi
# end of workaround
done
echo "${basedir}"
}
# concatenates all lines of a file
concat_lines() {
if [ -f "$1" ]; then
echo "$(tr -s '\n' ' ' < "$1")"
fi
}
BASE_DIR=`find_maven_basedir "$(pwd)"`
if [ -z "$BASE_DIR" ]; then
exit 1;
fi
##########################################################################################
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
# This allows using the maven wrapper in projects that prohibit checking in binary data.
##########################################################################################
if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found .mvn/wrapper/maven-wrapper.jar"
fi
else else
tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" if [ "$MVNW_VERBOSE" = true ]; then
fi echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url" fi
mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" if [ -n "$MVNW_REPOURL" ]; then
jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
else
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
fi
while IFS="=" read key value; do
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
esac
done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
if [ "$MVNW_VERBOSE" = true ]; then
echo "Downloading from: $jarUrl"
fi
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
if $cygwin; then
wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
fi
clean || : if command -v wget > /dev/null; then
exec_maven "$@" if [ "$MVNW_VERBOSE" = true ]; then
echo "Found wget ... using wget"
fi
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
wget "$jarUrl" -O "$wrapperJarPath"
else
wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
fi
elif command -v curl > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found curl ... using curl"
fi
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
curl -o "$wrapperJarPath" "$jarUrl" -f
else
curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Falling back to using Java to download"
fi
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
# For Cygwin, switch paths to Windows format before running javac
if $cygwin; then
javaClass=`cygpath --path --windows "$javaClass"`
fi
if [ -e "$javaClass" ]; then
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Compiling MavenWrapperDownloader.java ..."
fi
# Compiling the Java class
("$JAVA_HOME/bin/javac" "$javaClass")
fi
if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
# Running the downloader
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Running MavenWrapperDownloader.java ..."
fi
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
fi
fi
fi
fi
##########################################################################################
# End of extension
##########################################################################################
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
if [ "$MVNW_VERBOSE" = true ]; then
echo $MAVEN_PROJECTBASEDIR
fi
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
# For Cygwin, switch paths to Windows format before running java
if $cygwin; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --path --windows "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
fi
# Provide a "standardized" way to retrieve the CLI args that will
# work with both Windows and non-Windows executions.
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
export MAVEN_CMD_LINE_ARGS
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
exec "$JAVACMD" \
$MAVEN_OPTS \
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"

261
mvnw.cmd vendored
View File

@ -1,4 +1,3 @@
<# : batch portion
@REM ---------------------------------------------------------------------------- @REM ----------------------------------------------------------------------------
@REM Licensed to the Apache Software Foundation (ASF) under one @REM Licensed to the Apache Software Foundation (ASF) under one
@REM or more contributor license agreements. See the NOTICE file @REM or more contributor license agreements. See the NOTICE file
@ -19,131 +18,165 @@
@REM ---------------------------------------------------------------------------- @REM ----------------------------------------------------------------------------
@REM ---------------------------------------------------------------------------- @REM ----------------------------------------------------------------------------
@REM Apache Maven Wrapper startup batch script, version 3.3.2 @REM Maven Start Up Batch script
@REM
@REM Required ENV vars:
@REM JAVA_HOME - location of a JDK home dir
@REM @REM
@REM Optional ENV vars @REM Optional ENV vars
@REM MVNW_REPOURL - repo url base for downloading maven distribution @REM M2_HOME - location of maven2's installed home dir
@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
@REM e.g. to debug Maven itself, use
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
@REM ---------------------------------------------------------------------------- @REM ----------------------------------------------------------------------------
@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
@SET __MVNW_CMD__= @echo off
@SET __MVNW_ERROR__= @REM set title of command window
@SET __MVNW_PSMODULEP_SAVE=%PSModulePath% title %0
@SET PSModulePath= @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B)
@REM set %HOME% to equivalent of $HOME
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
@REM Execute a user defined script before this one
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
:skipRcPre
@setlocal
set ERROR_CODE=0
@REM To isolate internal variables from possible post scripts, we use another setlocal
@setlocal
@REM ==== START VALIDATION ====
if not "%JAVA_HOME%" == "" goto OkJHome
echo.
echo Error: JAVA_HOME not found in your environment. >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
:OkJHome
if exist "%JAVA_HOME%\bin\java.exe" goto init
echo.
echo Error: JAVA_HOME is set to an invalid directory. >&2
echo JAVA_HOME = "%JAVA_HOME%" >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
@REM ==== END VALIDATION ====
:init
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
@REM Fallback to current working directory if not found.
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
set EXEC_DIR=%CD%
set WDIR=%EXEC_DIR%
:findBaseDir
IF EXIST "%WDIR%"\.mvn goto baseDirFound
cd ..
IF "%WDIR%"=="%CD%" goto baseDirNotFound
set WDIR=%CD%
goto findBaseDir
:baseDirFound
set MAVEN_PROJECTBASEDIR=%WDIR%
cd "%EXEC_DIR%"
goto endDetectBaseDir
:baseDirNotFound
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
cd "%EXEC_DIR%"
:endDetectBaseDir
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
@setlocal EnableExtensions EnableDelayedExpansion
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
:endReadAdditionalConfig
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
) )
@SET PSModulePath=%__MVNW_PSMODULEP_SAVE%
@SET __MVNW_PSMODULEP_SAVE=
@SET __MVNW_ARG0_NAME__=
@SET MVNW_USERNAME=
@SET MVNW_PASSWORD=
@IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*)
@echo Cannot start maven from wrapper >&2 && exit /b 1
@GOTO :EOF
: end batch / begin powershell #>
$ErrorActionPreference = "Stop" @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
if ($env:MVNW_VERBOSE -eq "true") { @REM This allows using the maven wrapper in projects that prohibit checking in binary data.
$VerbosePreference = "Continue" if exist %WRAPPER_JAR% (
} if "%MVNW_VERBOSE%" == "true" (
echo Found %WRAPPER_JAR%
)
) else (
if not "%MVNW_REPOURL%" == "" (
SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
)
if "%MVNW_VERBOSE%" == "true" (
echo Couldn't find %WRAPPER_JAR%, downloading it ...
echo Downloading from: %DOWNLOAD_URL%
)
# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties powershell -Command "&{"^
$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl "$webclient = new-object System.Net.WebClient;"^
if (!$distributionUrl) { "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
} "}"^
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
"}"
if "%MVNW_VERBOSE%" == "true" (
echo Finished downloading %WRAPPER_JAR%
)
)
@REM End of extension
switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { @REM Provide a "standardized" way to retrieve the CLI args that will
"maven-mvnd-*" { @REM work with both Windows and non-Windows executions.
$USE_MVND = $true set MAVEN_CMD_LINE_ARGS=%*
$distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip"
$MVN_CMD = "mvnd.cmd"
break
}
default {
$USE_MVND = $false
$MVN_CMD = $script -replace '^mvnw','mvn'
break
}
}
# apply MVNW_REPOURL and calculate MAVEN_HOME %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash> if ERRORLEVEL 1 goto error
if ($env:MVNW_REPOURL) { goto end
$MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" }
$distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')"
}
$distributionUrlName = $distributionUrl -replace '^.*/',''
$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$',''
$MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain"
if ($env:MAVEN_USER_HOME) {
$MAVEN_HOME_PARENT = "$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain"
}
$MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join ''
$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME"
if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { :error
Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" set ERROR_CODE=1
Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"
exit $?
}
if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { :end
Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" @endlocal & set ERROR_CODE=%ERROR_CODE%
}
# prepare tmp dir if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile @REM check for post script, once with legacy .bat ending and once with .cmd ending
$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
trap { :skipRcPost
if ($TMP_DOWNLOAD_DIR.Exists) {
try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
}
}
New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
if "%MAVEN_BATCH_PAUSE%" == "on" pause
# Download and Install Apache Maven if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
Write-Verbose "Downloading from: $distributionUrl"
Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
$webclient = New-Object System.Net.WebClient exit /B %ERROR_CODE%
if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) {
$webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD)
}
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null
# If specified, validate the SHA-256 sum of the Maven distribution zip file
$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum
if ($distributionSha256Sum) {
if ($USE_MVND) {
Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties."
}
Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash
if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) {
Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property."
}
}
# unzip and move
Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null
Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null
try {
Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null
} catch {
if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) {
Write-Error "fail to move MAVEN_HOME"
}
} finally {
try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
}
Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"

View File

@ -11,7 +11,7 @@
<groupId>org.mapstruct</groupId> <groupId>org.mapstruct</groupId>
<artifactId>mapstruct-parent</artifactId> <artifactId>mapstruct-parent</artifactId>
<version>1.7.0-SNAPSHOT</version> <version>1.6.0</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<name>MapStruct Parent</name> <name>MapStruct Parent</name>
@ -28,13 +28,13 @@
<maven.compiler.source>${java.version}</maven.compiler.source> <maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target> <maven.compiler.target>${java.version}</maven.compiler.target>
<!-- value comes from property git.commit.author.time --> <!-- value comes from property git.commit.author.time -->
<project.build.outputTimestamp>${git.commit.author.time}</project.build.outputTimestamp> <project.build.outputTimestamp>2024-08-12T20:59:31Z</project.build.outputTimestamp>
<org.mapstruct.gem.version>1.0.0.Alpha3</org.mapstruct.gem.version> <org.mapstruct.gem.version>1.0.0.Alpha3</org.mapstruct.gem.version>
<org.apache.maven.plugins.enforcer.version>3.4.1</org.apache.maven.plugins.enforcer.version> <org.apache.maven.plugins.enforcer.version>3.4.1</org.apache.maven.plugins.enforcer.version>
<org.apache.maven.plugins.surefire.version>3.2.2</org.apache.maven.plugins.surefire.version> <org.apache.maven.plugins.surefire.version>3.2.2</org.apache.maven.plugins.surefire.version>
<org.apache.maven.plugins.javadoc.version>3.1.0</org.apache.maven.plugins.javadoc.version> <org.apache.maven.plugins.javadoc.version>3.1.0</org.apache.maven.plugins.javadoc.version>
<org.springframework.version>6.2.7</org.springframework.version> <org.springframework.version>5.3.31</org.springframework.version>
<org.eclipse.tycho.compiler-jdt.version>1.6.0</org.eclipse.tycho.compiler-jdt.version> <org.eclipse.tycho.compiler-jdt.version>1.6.0</org.eclipse.tycho.compiler-jdt.version>
<com.puppycrawl.tools.checkstyle.version>8.36.1</com.puppycrawl.tools.checkstyle.version> <com.puppycrawl.tools.checkstyle.version>8.36.1</com.puppycrawl.tools.checkstyle.version>
<org.junit.jupiter.version>5.10.1</org.junit.jupiter.version> <org.junit.jupiter.version>5.10.1</org.junit.jupiter.version>
@ -47,10 +47,10 @@
<m2e.apt.activation>jdt_apt</m2e.apt.activation> <m2e.apt.activation>jdt_apt</m2e.apt.activation>
<!-- <!--
The minimum Java Version that is needed to build a module in MapStruct. The minimum Java Version that is needed to build a module in MapStruct.
The processor module needs at least Java 21. The processor module needs at least Java 11.
--> -->
<minimum.java.version>1.8</minimum.java.version> <minimum.java.version>1.8</minimum.java.version>
<protobuf.version>3.25.5</protobuf.version> <protobuf.version>3.21.7</protobuf.version>
<jaxb-runtime.version>2.3.2</jaxb-runtime.version> <jaxb-runtime.version>2.3.2</jaxb-runtime.version>
</properties> </properties>
@ -400,7 +400,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version> <version>3.8.1</version>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>

View File

@ -13,7 +13,7 @@
<parent> <parent>
<groupId>org.mapstruct</groupId> <groupId>org.mapstruct</groupId>
<artifactId>mapstruct-parent</artifactId> <artifactId>mapstruct-parent</artifactId>
<version>1.7.0-SNAPSHOT</version> <version>1.6.0</version>
<relativePath>parent/pom.xml</relativePath> <relativePath>parent/pom.xml</relativePath>
</parent> </parent>

View File

@ -12,7 +12,7 @@
<parent> <parent>
<groupId>org.mapstruct</groupId> <groupId>org.mapstruct</groupId>
<artifactId>mapstruct-parent</artifactId> <artifactId>mapstruct-parent</artifactId>
<version>1.7.0-SNAPSHOT</version> <version>1.6.0</version>
<relativePath>../parent/pom.xml</relativePath> <relativePath>../parent/pom.xml</relativePath>
</parent> </parent>
@ -24,7 +24,7 @@
<!-- Netbeans has a problem when we use late binding with @ in the surefire arg line. <!-- Netbeans has a problem when we use late binding with @ in the surefire arg line.
Therefore we set this empty property here--> Therefore we set this empty property here-->
<jacocoArgLine /> <jacocoArgLine />
<minimum.java.version>21</minimum.java.version> <minimum.java.version>11</minimum.java.version>
</properties> </properties>
<dependencies> <dependencies>
@ -286,7 +286,6 @@
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<configuration> <configuration>
<testRelease>${minimum.java.version}</testRelease>
<annotationProcessorPaths> <annotationProcessorPaths>
<path> <path>
<groupId>org.mapstruct.tools.gem</groupId> <groupId>org.mapstruct.tools.gem</groupId>

View File

@ -13,16 +13,17 @@ import java.util.Comparator;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.ServiceLoader; import java.util.ServiceLoader;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor; import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes; import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedOptions;
import javax.lang.model.SourceVersion; import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element; import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind; import javax.lang.model.element.ElementKind;
@ -34,8 +35,9 @@ import javax.lang.model.util.ElementKindVisitor6;
import javax.tools.Diagnostic.Kind; import javax.tools.Diagnostic.Kind;
import org.mapstruct.ap.internal.gem.MapperGem; import org.mapstruct.ap.internal.gem.MapperGem;
import org.mapstruct.ap.internal.gem.NullValueMappingStrategyGem;
import org.mapstruct.ap.internal.gem.ReportingPolicyGem;
import org.mapstruct.ap.internal.model.Mapper; import org.mapstruct.ap.internal.model.Mapper;
import org.mapstruct.ap.internal.option.MappingOption;
import org.mapstruct.ap.internal.option.Options; import org.mapstruct.ap.internal.option.Options;
import org.mapstruct.ap.internal.processor.DefaultModelElementProcessorContext; import org.mapstruct.ap.internal.processor.DefaultModelElementProcessorContext;
import org.mapstruct.ap.internal.processor.ModelElementProcessor; import org.mapstruct.ap.internal.processor.ModelElementProcessor;
@ -82,6 +84,18 @@ import static javax.lang.model.element.ElementKind.CLASS;
* @author Gunnar Morling * @author Gunnar Morling
*/ */
@SupportedAnnotationTypes("org.mapstruct.Mapper") @SupportedAnnotationTypes("org.mapstruct.Mapper")
@SupportedOptions({
MappingProcessor.SUPPRESS_GENERATOR_TIMESTAMP,
MappingProcessor.SUPPRESS_GENERATOR_VERSION_INFO_COMMENT,
MappingProcessor.UNMAPPED_TARGET_POLICY,
MappingProcessor.UNMAPPED_SOURCE_POLICY,
MappingProcessor.DEFAULT_COMPONENT_MODEL,
MappingProcessor.DEFAULT_INJECTION_STRATEGY,
MappingProcessor.DISABLE_BUILDERS,
MappingProcessor.VERBOSE,
MappingProcessor.NULL_VALUE_ITERABLE_MAPPING_STRATEGY,
MappingProcessor.NULL_VALUE_MAP_MAPPING_STRATEGY,
})
public class MappingProcessor extends AbstractProcessor { public class MappingProcessor extends AbstractProcessor {
/** /**
@ -89,32 +103,18 @@ public class MappingProcessor extends AbstractProcessor {
*/ */
private static final boolean ANNOTATIONS_CLAIMED_EXCLUSIVELY = false; private static final boolean ANNOTATIONS_CLAIMED_EXCLUSIVELY = false;
// CHECKSTYLE:OFF protected static final String SUPPRESS_GENERATOR_TIMESTAMP = "mapstruct.suppressGeneratorTimestamp";
// Deprecated options, kept for backwards compatibility. protected static final String SUPPRESS_GENERATOR_VERSION_INFO_COMMENT =
// They will be removed in a future release. "mapstruct.suppressGeneratorVersionInfoComment";
@Deprecated protected static final String UNMAPPED_TARGET_POLICY = "mapstruct.unmappedTargetPolicy";
protected static final String SUPPRESS_GENERATOR_TIMESTAMP = MappingOption.SUPPRESS_GENERATOR_TIMESTAMP.getOptionName(); protected static final String UNMAPPED_SOURCE_POLICY = "mapstruct.unmappedSourcePolicy";
@Deprecated protected static final String DEFAULT_COMPONENT_MODEL = "mapstruct.defaultComponentModel";
protected static final String SUPPRESS_GENERATOR_VERSION_INFO_COMMENT = MappingOption.SUPPRESS_GENERATOR_VERSION_INFO_COMMENT.getOptionName(); protected static final String DEFAULT_INJECTION_STRATEGY = "mapstruct.defaultInjectionStrategy";
@Deprecated protected static final String ALWAYS_GENERATE_SERVICE_FILE = "mapstruct.alwaysGenerateServicesFile";
protected static final String UNMAPPED_TARGET_POLICY = MappingOption.UNMAPPED_TARGET_POLICY.getOptionName(); protected static final String DISABLE_BUILDERS = "mapstruct.disableBuilders";
@Deprecated protected static final String VERBOSE = "mapstruct.verbose";
protected static final String UNMAPPED_SOURCE_POLICY = MappingOption.UNMAPPED_SOURCE_POLICY.getOptionName(); protected static final String NULL_VALUE_ITERABLE_MAPPING_STRATEGY = "mapstruct.nullValueIterableMappingStrategy";
@Deprecated protected static final String NULL_VALUE_MAP_MAPPING_STRATEGY = "mapstruct.nullValueMapMappingStrategy";
protected static final String DEFAULT_COMPONENT_MODEL = MappingOption.DEFAULT_COMPONENT_MODEL.getOptionName();
@Deprecated
protected static final String DEFAULT_INJECTION_STRATEGY = MappingOption.DEFAULT_INJECTION_STRATEGY.getOptionName();
@Deprecated
protected static final String ALWAYS_GENERATE_SERVICE_FILE = MappingOption.ALWAYS_GENERATE_SERVICE_FILE.getOptionName();
@Deprecated
protected static final String DISABLE_BUILDERS = MappingOption.DISABLE_BUILDERS.getOptionName();
@Deprecated
protected static final String VERBOSE = MappingOption.VERBOSE.getOptionName();
@Deprecated
protected static final String NULL_VALUE_ITERABLE_MAPPING_STRATEGY = MappingOption.NULL_VALUE_ITERABLE_MAPPING_STRATEGY.getOptionName();
@Deprecated
protected static final String NULL_VALUE_MAP_MAPPING_STRATEGY = MappingOption.NULL_VALUE_MAP_MAPPING_STRATEGY.getOptionName();
// CHECKSTYLE:ON
private final Set<String> additionalSupportedOptions; private final Set<String> additionalSupportedOptions;
private final String additionalSupportedOptionsError; private final String additionalSupportedOptionsError;
@ -153,7 +153,7 @@ public class MappingProcessor extends AbstractProcessor {
public synchronized void init(ProcessingEnvironment processingEnv) { public synchronized void init(ProcessingEnvironment processingEnv) {
super.init( processingEnv ); super.init( processingEnv );
options = new Options( processingEnv.getOptions() ); options = createOptions();
annotationProcessorContext = new AnnotationProcessorContext( annotationProcessorContext = new AnnotationProcessorContext(
processingEnv.getElementUtils(), processingEnv.getElementUtils(),
processingEnv.getTypeUtils(), processingEnv.getTypeUtils(),
@ -168,6 +168,31 @@ public class MappingProcessor extends AbstractProcessor {
} }
} }
private Options createOptions() {
String unmappedTargetPolicy = processingEnv.getOptions().get( UNMAPPED_TARGET_POLICY );
String unmappedSourcePolicy = processingEnv.getOptions().get( UNMAPPED_SOURCE_POLICY );
String nullValueIterableMappingStrategy = processingEnv.getOptions()
.get( NULL_VALUE_ITERABLE_MAPPING_STRATEGY );
String nullValueMapMappingStrategy = processingEnv.getOptions().get( NULL_VALUE_MAP_MAPPING_STRATEGY );
return new Options(
Boolean.parseBoolean( processingEnv.getOptions().get( SUPPRESS_GENERATOR_TIMESTAMP ) ),
Boolean.parseBoolean( processingEnv.getOptions().get( SUPPRESS_GENERATOR_VERSION_INFO_COMMENT ) ),
unmappedTargetPolicy != null ? ReportingPolicyGem.valueOf( unmappedTargetPolicy.toUpperCase() ) : null,
unmappedSourcePolicy != null ? ReportingPolicyGem.valueOf( unmappedSourcePolicy.toUpperCase() ) : null,
processingEnv.getOptions().get( DEFAULT_COMPONENT_MODEL ),
processingEnv.getOptions().get( DEFAULT_INJECTION_STRATEGY ),
Boolean.parseBoolean( processingEnv.getOptions().get( ALWAYS_GENERATE_SERVICE_FILE ) ),
Boolean.parseBoolean( processingEnv.getOptions().get( DISABLE_BUILDERS ) ),
Boolean.parseBoolean( processingEnv.getOptions().get( VERBOSE ) ),
nullValueIterableMappingStrategy != null ?
NullValueMappingStrategyGem.valueOf( nullValueIterableMappingStrategy.toUpperCase( Locale.ROOT ) ) :
null,
nullValueMapMappingStrategy != null ?
NullValueMappingStrategyGem.valueOf( nullValueMapMappingStrategy.toUpperCase( Locale.ROOT ) ) : null
);
}
@Override @Override
public SourceVersion getSupportedSourceVersion() { public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported(); return SourceVersion.latestSupported();
@ -228,11 +253,13 @@ public class MappingProcessor extends AbstractProcessor {
@Override @Override
public Set<String> getSupportedOptions() { public Set<String> getSupportedOptions() {
return Stream.concat( Set<String> supportedOptions = super.getSupportedOptions();
Stream.of( MappingOption.values() ).map( MappingOption::getOptionName ), if ( additionalSupportedOptions.isEmpty() ) {
additionalSupportedOptions.stream() return supportedOptions;
) }
.collect( Collectors.toSet() ); Set<String> allSupportedOptions = new HashSet<>( supportedOptions );
allSupportedOptions.addAll( additionalSupportedOptions );
return allSupportedOptions;
} }
/** /**

View File

@ -14,9 +14,8 @@ import org.mapstruct.ap.internal.model.HelperMethod;
import org.mapstruct.ap.internal.model.common.ConversionContext; import org.mapstruct.ap.internal.model.common.ConversionContext;
import org.mapstruct.ap.internal.model.common.Type; import org.mapstruct.ap.internal.model.common.Type;
import static org.mapstruct.ap.internal.conversion.ConversionUtils.bigDecimal;
import static org.mapstruct.ap.internal.conversion.ConversionUtils.locale;
import static org.mapstruct.ap.internal.util.Collections.asSet; import static org.mapstruct.ap.internal.util.Collections.asSet;
import static org.mapstruct.ap.internal.conversion.ConversionUtils.bigDecimal;
/** /**
* Conversion between {@link BigDecimal} and {@link String}. * Conversion between {@link BigDecimal} and {@link String}.
@ -65,31 +64,18 @@ public class BigDecimalToStringConversion extends AbstractNumberToStringConversi
public List<HelperMethod> getRequiredHelperMethods(ConversionContext conversionContext) { public List<HelperMethod> getRequiredHelperMethods(ConversionContext conversionContext) {
List<HelperMethod> helpers = new ArrayList<>(); List<HelperMethod> helpers = new ArrayList<>();
if ( conversionContext.getNumberFormat() != null ) { if ( conversionContext.getNumberFormat() != null ) {
helpers.add( new CreateDecimalFormat( helpers.add( new CreateDecimalFormat( conversionContext.getTypeFactory() ) );
conversionContext.getTypeFactory(),
conversionContext.getLocale() != null
) );
} }
return helpers; return helpers;
} }
private void appendDecimalFormatter(StringBuilder sb, ConversionContext conversionContext) { private void appendDecimalFormatter(StringBuilder sb, ConversionContext conversionContext) {
boolean withLocale = conversionContext.getLocale() != null; sb.append( "createDecimalFormat( " );
sb.append( "createDecimalFormat" );
if ( withLocale ) {
sb.append( "WithLocale" );
}
sb.append( "( " );
if ( conversionContext.getNumberFormat() != null ) { if ( conversionContext.getNumberFormat() != null ) {
sb.append( "\"" ); sb.append( "\"" );
sb.append( conversionContext.getNumberFormat() ); sb.append( conversionContext.getNumberFormat() );
sb.append( "\"" ); sb.append( "\"" );
} }
if ( withLocale ) {
sb.append( ", " ).append( locale( conversionContext ) ).append( ".forLanguageTag( \"" );
sb.append( conversionContext.getLocale() );
sb.append( "\" )" );
}
sb.append( " )" ); sb.append( " )" );
} }

View File

@ -15,10 +15,9 @@ import org.mapstruct.ap.internal.model.HelperMethod;
import org.mapstruct.ap.internal.model.common.ConversionContext; import org.mapstruct.ap.internal.model.common.ConversionContext;
import org.mapstruct.ap.internal.model.common.Type; import org.mapstruct.ap.internal.model.common.Type;
import static org.mapstruct.ap.internal.conversion.ConversionUtils.locale; import static org.mapstruct.ap.internal.util.Collections.asSet;
import static org.mapstruct.ap.internal.conversion.ConversionUtils.bigDecimal; import static org.mapstruct.ap.internal.conversion.ConversionUtils.bigDecimal;
import static org.mapstruct.ap.internal.conversion.ConversionUtils.bigInteger; import static org.mapstruct.ap.internal.conversion.ConversionUtils.bigInteger;
import static org.mapstruct.ap.internal.util.Collections.asSet;
/** /**
* Conversion between {@link BigInteger} and {@link String}. * Conversion between {@link BigInteger} and {@link String}.
@ -73,31 +72,18 @@ public class BigIntegerToStringConversion extends AbstractNumberToStringConversi
public List<HelperMethod> getRequiredHelperMethods(ConversionContext conversionContext) { public List<HelperMethod> getRequiredHelperMethods(ConversionContext conversionContext) {
List<HelperMethod> helpers = new ArrayList<>(); List<HelperMethod> helpers = new ArrayList<>();
if ( conversionContext.getNumberFormat() != null ) { if ( conversionContext.getNumberFormat() != null ) {
helpers.add( new CreateDecimalFormat( helpers.add( new CreateDecimalFormat( conversionContext.getTypeFactory() ) );
conversionContext.getTypeFactory(),
conversionContext.getLocale() != null
) );
} }
return helpers; return helpers;
} }
private void appendDecimalFormatter(StringBuilder sb, ConversionContext conversionContext) { private void appendDecimalFormatter(StringBuilder sb, ConversionContext conversionContext) {
boolean withLocale = conversionContext.getLocale() != null; sb.append( "createDecimalFormat( " );
sb.append( "createDecimalFormat" );
if ( withLocale ) {
sb.append( "WithLocale" );
}
sb.append( "( " );
if ( conversionContext.getNumberFormat() != null ) { if ( conversionContext.getNumberFormat() != null ) {
sb.append( "\"" ); sb.append( "\"" );
sb.append( conversionContext.getNumberFormat() ); sb.append( conversionContext.getNumberFormat() );
sb.append( "\"" ); sb.append( "\"" );
} }
if ( withLocale ) {
sb.append( ", " ).append( locale( conversionContext ) ).append( ".forLanguageTag( \"" );
sb.append( conversionContext.getLocale() );
sb.append( "\" )" );
}
sb.append( " )" ); sb.append( " )" );
} }

View File

@ -11,7 +11,6 @@ import java.net.URL;
import java.sql.Time; import java.sql.Time;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
@ -280,15 +279,4 @@ public final class ConversionUtils {
return typeReferenceName( conversionContext, URL.class ); return typeReferenceName( conversionContext, URL.class );
} }
/**
* Name for {@link java.text.DecimalFormatSymbols}.
*
* @param conversionContext Conversion context
*
* @return Name or fully-qualified name.
*/
public static String decimalFormatSymbols(ConversionContext conversionContext) {
return typeReferenceName( conversionContext, DecimalFormatSymbols.class );
}
} }

View File

@ -268,10 +268,10 @@ public class Conversions {
if ( sourceType.isPrimitive() && targetType.isPrimitive() ) { if ( sourceType.isPrimitive() && targetType.isPrimitive() ) {
register( sourceType, targetType, new PrimitiveToPrimitiveConversion( sourceType ) ); register( sourceType, targetType, new PrimitiveToPrimitiveConversion( sourceType ) );
} }
else if ( sourceType.isPrimitive() ) { else if ( sourceType.isPrimitive() && !targetType.isPrimitive() ) {
register( sourceType, targetType, new PrimitiveToWrapperConversion( sourceType, targetType ) ); register( sourceType, targetType, new PrimitiveToWrapperConversion( sourceType, targetType ) );
} }
else if ( targetType.isPrimitive() ) { else if ( !sourceType.isPrimitive() && targetType.isPrimitive() ) {
register( sourceType, targetType, inverse( new PrimitiveToWrapperConversion( targetType, sourceType ) ) ); register( sourceType, targetType, inverse( new PrimitiveToWrapperConversion( targetType, sourceType ) ) );
} }
else { else {
@ -390,7 +390,11 @@ public class Conversions {
return false; return false;
} }
return Objects.equals( targetType, other.targetType ); if ( !Objects.equals( targetType, other.targetType ) ) {
return false;
}
return true;
} }
} }
} }

View File

@ -5,11 +5,9 @@
*/ */
package org.mapstruct.ap.internal.conversion; package org.mapstruct.ap.internal.conversion;
import static org.mapstruct.ap.internal.util.Collections.asSet;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Set; import java.util.Set;
import org.mapstruct.ap.internal.model.HelperMethod; import org.mapstruct.ap.internal.model.HelperMethod;
@ -18,8 +16,6 @@ import org.mapstruct.ap.internal.model.common.Type;
import org.mapstruct.ap.internal.model.common.TypeFactory; import org.mapstruct.ap.internal.model.common.TypeFactory;
import org.mapstruct.ap.internal.model.source.MappingMethodOptions; import org.mapstruct.ap.internal.model.source.MappingMethodOptions;
import static org.mapstruct.ap.internal.util.Collections.asSet;
/** /**
* HelperMethod that creates a {@link java.text.DecimalFormat} * HelperMethod that creates a {@link java.text.DecimalFormat}
* *
@ -31,30 +27,13 @@ import static org.mapstruct.ap.internal.util.Collections.asSet;
public class CreateDecimalFormat extends HelperMethod { public class CreateDecimalFormat extends HelperMethod {
private final Parameter parameter; private final Parameter parameter;
private final Parameter localeParameter;
private final Type returnType; private final Type returnType;
private final Set<Type> importTypes; private final Set<Type> importTypes;
public CreateDecimalFormat(TypeFactory typeFactory, boolean withLocale) { public CreateDecimalFormat(TypeFactory typeFactory) {
this.parameter = new Parameter( "numberFormat", typeFactory.getType( String.class ) ); this.parameter = new Parameter( "numberFormat", typeFactory.getType( String.class ) );
this.localeParameter = withLocale ? new Parameter( "locale", typeFactory.getType( Locale.class ) ) : null;
this.returnType = typeFactory.getType( DecimalFormat.class ); this.returnType = typeFactory.getType( DecimalFormat.class );
if ( withLocale ) { this.importTypes = asSet( parameter.getType(), returnType );
this.importTypes = asSet(
parameter.getType(),
returnType,
typeFactory.getType( DecimalFormatSymbols.class ),
typeFactory.getType( Locale.class )
);
}
else {
this.importTypes = asSet( parameter.getType(), returnType );
}
}
@Override
public String getName() {
return localeParameter == null ? "createDecimalFormat" : "createDecimalFormatWithLocale";
} }
@Override @Override
@ -81,12 +60,4 @@ public class CreateDecimalFormat extends HelperMethod {
public String describe() { public String describe() {
return null; return null;
} }
@Override
public List<Parameter> getParameters() {
if ( localeParameter == null ) {
return super.getParameters();
}
return Arrays.asList( getParameter(), localeParameter );
}
} }

View File

@ -10,18 +10,15 @@ import java.text.SimpleDateFormat;
import java.util.Collections; import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Set;
import org.mapstruct.ap.internal.model.HelperMethod; import org.mapstruct.ap.internal.model.HelperMethod;
import org.mapstruct.ap.internal.model.TypeConversion; import org.mapstruct.ap.internal.model.TypeConversion;
import org.mapstruct.ap.internal.model.common.Assignment; import org.mapstruct.ap.internal.model.common.Assignment;
import org.mapstruct.ap.internal.model.common.ConversionContext; import org.mapstruct.ap.internal.model.common.ConversionContext;
import org.mapstruct.ap.internal.model.common.Type;
import static org.mapstruct.ap.internal.conversion.ConversionUtils.locale; import static java.util.Arrays.asList;
import static org.mapstruct.ap.internal.conversion.ConversionUtils.simpleDateFormat;
import static org.mapstruct.ap.internal.util.Collections.asSet; import static org.mapstruct.ap.internal.util.Collections.asSet;
import static org.mapstruct.ap.internal.conversion.ConversionUtils.simpleDateFormat;
/** /**
* Conversion between {@link String} and {@link Date}. * Conversion between {@link String} and {@link Date}.
@ -32,7 +29,7 @@ public class DateToStringConversion implements ConversionProvider {
@Override @Override
public Assignment to(ConversionContext conversionContext) { public Assignment to(ConversionContext conversionContext) {
return new TypeConversion( getImportTypes( conversionContext ), return new TypeConversion( asSet( conversionContext.getTypeFactory().getType( SimpleDateFormat.class ) ),
Collections.emptyList(), Collections.emptyList(),
getConversionExpression( conversionContext, "format" ) getConversionExpression( conversionContext, "format" )
); );
@ -40,8 +37,8 @@ public class DateToStringConversion implements ConversionProvider {
@Override @Override
public Assignment from(ConversionContext conversionContext) { public Assignment from(ConversionContext conversionContext) {
return new TypeConversion( getImportTypes( conversionContext ), return new TypeConversion( asSet( conversionContext.getTypeFactory().getType( SimpleDateFormat.class ) ),
Collections.singletonList( conversionContext.getTypeFactory().getType( ParseException.class ) ), asList( conversionContext.getTypeFactory().getType( ParseException.class ) ),
getConversionExpression( conversionContext, "parse" ) getConversionExpression( conversionContext, "parse" )
); );
} }
@ -51,17 +48,6 @@ public class DateToStringConversion implements ConversionProvider {
return Collections.emptyList(); return Collections.emptyList();
} }
private Set<Type> getImportTypes(ConversionContext conversionContext) {
if ( conversionContext.getLocale() == null ) {
return Collections.singleton( conversionContext.getTypeFactory().getType( SimpleDateFormat.class ) );
}
return asSet(
conversionContext.getTypeFactory().getType( SimpleDateFormat.class ),
conversionContext.getTypeFactory().getType( Locale.class )
);
}
private String getConversionExpression(ConversionContext conversionContext, String method) { private String getConversionExpression(ConversionContext conversionContext, String method) {
StringBuilder conversionString = new StringBuilder( "new " ); StringBuilder conversionString = new StringBuilder( "new " );
conversionString.append( simpleDateFormat( conversionContext ) ); conversionString.append( simpleDateFormat( conversionContext ) );
@ -70,16 +56,7 @@ public class DateToStringConversion implements ConversionProvider {
if ( conversionContext.getDateFormat() != null ) { if ( conversionContext.getDateFormat() != null ) {
conversionString.append( " \"" ); conversionString.append( " \"" );
conversionString.append( conversionContext.getDateFormat() ); conversionString.append( conversionContext.getDateFormat() );
conversionString.append( "\"" ); conversionString.append( "\" " );
if ( conversionContext.getLocale() != null ) {
conversionString.append( ", " ).append( locale( conversionContext ) ).append( ".forLanguageTag( \"" );
conversionString.append( conversionContext.getLocale() );
conversionString.append( "\" ) " );
}
else {
conversionString.append( " " );
}
} }
conversionString.append( ")." ); conversionString.append( ")." );

View File

@ -7,8 +7,11 @@ package org.mapstruct.ap.internal.conversion;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.Set;
import org.mapstruct.ap.internal.model.common.ConversionContext; import org.mapstruct.ap.internal.model.common.ConversionContext;
import org.mapstruct.ap.internal.model.common.Type;
import org.mapstruct.ap.internal.util.Collections;
/** /**
* SimpleConversion for mapping {@link LocalDateTime} to * SimpleConversion for mapping {@link LocalDateTime} to
@ -22,9 +25,22 @@ public class JavaLocalDateTimeToLocalDateConversion extends SimpleConversion {
return "<SOURCE>.toLocalDate()"; return "<SOURCE>.toLocalDate()";
} }
@Override
protected Set<Type> getToConversionImportTypes(ConversionContext conversionContext) {
return Collections.asSet(
conversionContext.getTypeFactory().getType( LocalDate.class )
);
}
@Override @Override
protected String getFromExpression(ConversionContext conversionContext) { protected String getFromExpression(ConversionContext conversionContext) {
return "<SOURCE>.atStartOfDay()"; return "<SOURCE>.atStartOfDay()";
} }
@Override
protected Set<Type> getFromConversionImportTypes(ConversionContext conversionContext) {
return Collections.asSet(
conversionContext.getTypeFactory().getType( LocalDateTime.class )
);
}
} }

View File

@ -6,9 +6,7 @@
package org.mapstruct.ap.internal.conversion; package org.mapstruct.ap.internal.conversion;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Collections; import java.util.Collections;
import java.util.Locale;
import java.util.Set; import java.util.Set;
import org.mapstruct.ap.internal.model.common.ConversionContext; import org.mapstruct.ap.internal.model.common.ConversionContext;
@ -17,9 +15,6 @@ import org.mapstruct.ap.internal.util.NativeTypes;
import org.mapstruct.ap.internal.util.Strings; import org.mapstruct.ap.internal.util.Strings;
import static org.mapstruct.ap.internal.conversion.ConversionUtils.decimalFormat; import static org.mapstruct.ap.internal.conversion.ConversionUtils.decimalFormat;
import static org.mapstruct.ap.internal.conversion.ConversionUtils.decimalFormatSymbols;
import static org.mapstruct.ap.internal.conversion.ConversionUtils.locale;
import static org.mapstruct.ap.internal.util.Collections.asSet;
/** /**
* Conversion between primitive types such as {@code byte} or {@code long} and * Conversion between primitive types such as {@code byte} or {@code long} and
@ -58,15 +53,9 @@ public class PrimitiveToStringConversion extends AbstractNumberToStringConversio
@Override @Override
public Set<Type> getToConversionImportTypes(ConversionContext conversionContext) { public Set<Type> getToConversionImportTypes(ConversionContext conversionContext) {
if ( requiresDecimalFormat( conversionContext ) ) { if ( requiresDecimalFormat( conversionContext ) ) {
if ( conversionContext.getLocale() != null ) { return Collections.singleton(
return asSet( conversionContext.getTypeFactory().getType( DecimalFormat.class )
conversionContext.getTypeFactory().getType( DecimalFormat.class ), );
conversionContext.getTypeFactory().getType( DecimalFormatSymbols.class ),
conversionContext.getTypeFactory().getType( Locale.class )
);
}
return Collections.singleton( conversionContext.getTypeFactory().getType( DecimalFormat.class ) );
} }
return Collections.emptySet(); return Collections.emptySet();
@ -91,15 +80,9 @@ public class PrimitiveToStringConversion extends AbstractNumberToStringConversio
@Override @Override
protected Set<Type> getFromConversionImportTypes(ConversionContext conversionContext) { protected Set<Type> getFromConversionImportTypes(ConversionContext conversionContext) {
if ( requiresDecimalFormat( conversionContext ) ) { if ( requiresDecimalFormat( conversionContext ) ) {
if ( conversionContext.getLocale() != null ) { return Collections.singleton(
return asSet( conversionContext.getTypeFactory().getType( DecimalFormat.class )
conversionContext.getTypeFactory().getType( DecimalFormat.class ), );
conversionContext.getTypeFactory().getType( DecimalFormatSymbols.class ),
conversionContext.getTypeFactory().getType( Locale.class )
);
}
return Collections.singleton( conversionContext.getTypeFactory().getType( DecimalFormat.class ) );
} }
return Collections.emptySet(); return Collections.emptySet();
@ -114,16 +97,6 @@ public class PrimitiveToStringConversion extends AbstractNumberToStringConversio
sb.append( "\"" ); sb.append( "\"" );
sb.append( conversionContext.getNumberFormat() ); sb.append( conversionContext.getNumberFormat() );
sb.append( "\"" ); sb.append( "\"" );
if ( conversionContext.getLocale() != null ) {
sb.append( ", " )
.append( decimalFormatSymbols( conversionContext ) )
.append( ".getInstance( " )
.append( locale( conversionContext ) )
.append( ".forLanguageTag( \"" )
.append( conversionContext.getLocale() )
.append( " \" ) )" );
}
} }
sb.append( " )" ); sb.append( " )" );

View File

@ -6,9 +6,7 @@
package org.mapstruct.ap.internal.conversion; package org.mapstruct.ap.internal.conversion;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Collections; import java.util.Collections;
import java.util.Locale;
import java.util.Set; import java.util.Set;
import org.mapstruct.ap.internal.model.common.ConversionContext; import org.mapstruct.ap.internal.model.common.ConversionContext;
@ -17,9 +15,6 @@ import org.mapstruct.ap.internal.util.NativeTypes;
import org.mapstruct.ap.internal.util.Strings; import org.mapstruct.ap.internal.util.Strings;
import static org.mapstruct.ap.internal.conversion.ConversionUtils.decimalFormat; import static org.mapstruct.ap.internal.conversion.ConversionUtils.decimalFormat;
import static org.mapstruct.ap.internal.conversion.ConversionUtils.decimalFormatSymbols;
import static org.mapstruct.ap.internal.conversion.ConversionUtils.locale;
import static org.mapstruct.ap.internal.util.Collections.asSet;
/** /**
* Conversion between wrapper types such as {@link Integer} and {@link String}. * Conversion between wrapper types such as {@link Integer} and {@link String}.
@ -57,15 +52,9 @@ public class WrapperToStringConversion extends AbstractNumberToStringConversion
@Override @Override
public Set<Type> getToConversionImportTypes(ConversionContext conversionContext) { public Set<Type> getToConversionImportTypes(ConversionContext conversionContext) {
if ( requiresDecimalFormat( conversionContext ) ) { if ( requiresDecimalFormat( conversionContext ) ) {
if ( conversionContext.getLocale() != null ) { return Collections.singleton(
return asSet( conversionContext.getTypeFactory().getType( DecimalFormat.class )
conversionContext.getTypeFactory().getType( DecimalFormat.class ), );
conversionContext.getTypeFactory().getType( DecimalFormatSymbols.class ),
conversionContext.getTypeFactory().getType( Locale.class )
);
}
return Collections.singleton( conversionContext.getTypeFactory().getType( DecimalFormat.class ) );
} }
return Collections.emptySet(); return Collections.emptySet();
@ -90,15 +79,9 @@ public class WrapperToStringConversion extends AbstractNumberToStringConversion
@Override @Override
protected Set<Type> getFromConversionImportTypes(ConversionContext conversionContext) { protected Set<Type> getFromConversionImportTypes(ConversionContext conversionContext) {
if ( requiresDecimalFormat( conversionContext ) ) { if ( requiresDecimalFormat( conversionContext ) ) {
if ( conversionContext.getLocale() != null ) { return Collections.singleton(
return asSet( conversionContext.getTypeFactory().getType( DecimalFormat.class )
conversionContext.getTypeFactory().getType( DecimalFormat.class ), );
conversionContext.getTypeFactory().getType( DecimalFormatSymbols.class ),
conversionContext.getTypeFactory().getType( Locale.class )
);
}
return Collections.singleton( conversionContext.getTypeFactory().getType( DecimalFormat.class ) );
} }
return Collections.emptySet(); return Collections.emptySet();
@ -113,16 +96,6 @@ public class WrapperToStringConversion extends AbstractNumberToStringConversion
sb.append( "\"" ); sb.append( "\"" );
sb.append( conversionContext.getNumberFormat() ); sb.append( conversionContext.getNumberFormat() );
sb.append( "\"" ); sb.append( "\"" );
if ( conversionContext.getLocale() != null ) {
sb.append( ", " )
.append( decimalFormatSymbols( conversionContext ) )
.append( ".getInstance( " )
.append( locale( conversionContext ) )
.append( ".forLanguageTag( \"" )
.append( conversionContext.getLocale() )
.append( " \" ) )" );
}
} }
sb.append( " )" ); sb.append( " )" );

View File

@ -26,8 +26,6 @@ import org.mapstruct.MapMapping;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;
import org.mapstruct.MapperConfig; import org.mapstruct.MapperConfig;
import org.mapstruct.Mapping; import org.mapstruct.Mapping;
import org.mapstruct.Ignored;
import org.mapstruct.IgnoredList;
import org.mapstruct.MappingTarget; import org.mapstruct.MappingTarget;
import org.mapstruct.Mappings; import org.mapstruct.Mappings;
import org.mapstruct.Named; import org.mapstruct.Named;
@ -55,8 +53,6 @@ import org.mapstruct.tools.gem.GemDefinition;
@GemDefinition(AnnotateWiths.class) @GemDefinition(AnnotateWiths.class)
@GemDefinition(Mapper.class) @GemDefinition(Mapper.class)
@GemDefinition(Mapping.class) @GemDefinition(Mapping.class)
@GemDefinition(Ignored.class)
@GemDefinition(IgnoredList.class)
@GemDefinition(Mappings.class) @GemDefinition(Mappings.class)
@GemDefinition(IterableMapping.class) @GemDefinition(IterableMapping.class)
@GemDefinition(BeanMapping.class) @GemDefinition(BeanMapping.class)

View File

@ -41,7 +41,7 @@ class AbstractBaseBuilder<B extends AbstractBaseBuilder<B>> {
} }
/** /**
* Checks if MapStruct is allowed to generate an automatic sub-mapping between {@code sourceType} and {@code * Checks if MapStruct is allowed to generate an automatic sub-mapping between {@code sourceType} and @{code
* targetType}. * targetType}.
* This will evaluate to {@code true}, when: * This will evaluate to {@code true}, when:
* <li> * <li>
@ -66,7 +66,7 @@ class AbstractBaseBuilder<B extends AbstractBaseBuilder<B>> {
/** /**
* Creates a forged assignment from the provided {@code sourceRHS} and {@code forgedMethod}. If a mapping method * Creates a forged assignment from the provided {@code sourceRHS} and {@code forgedMethod}. If a mapping method
* for the {@code forgedMethod} already exists, this method will be used for the assignment. * for the {@code forgedMethod} already exists, then this method used for the assignment.
* *
* @param sourceRHS that needs to be used for the assignment * @param sourceRHS that needs to be used for the assignment
* @param forgedMethod the forged method for which we want to create an {@link Assignment} * @param forgedMethod the forged method for which we want to create an {@link Assignment}

View File

@ -36,14 +36,14 @@ public class AnnotatedConstructor extends ModelElement implements Constructor {
if ( constructor instanceof NoArgumentConstructor ) { if ( constructor instanceof NoArgumentConstructor ) {
noArgumentConstructor = (NoArgumentConstructor) constructor; noArgumentConstructor = (NoArgumentConstructor) constructor;
} }
NoArgumentConstructor noArgConstructorToBeIncluded = null; NoArgumentConstructor noArgConstructorToInBecluded = null;
Set<SupportingConstructorFragment> fragmentsToBeIncluded = Collections.emptySet(); Set<SupportingConstructorFragment> fragmentsToBeIncluded = Collections.emptySet();
if ( includeNoArgConstructor ) { if ( includeNoArgConstructor ) {
if ( noArgumentConstructor != null ) { if ( noArgumentConstructor != null ) {
noArgConstructorToBeIncluded = noArgumentConstructor; noArgConstructorToInBecluded = noArgumentConstructor;
} }
else { else {
noArgConstructorToBeIncluded = new NoArgumentConstructor( name, fragmentsToBeIncluded ); noArgConstructorToInBecluded = new NoArgumentConstructor( name, fragmentsToBeIncluded );
} }
} }
else if ( noArgumentConstructor != null ) { else if ( noArgumentConstructor != null ) {
@ -53,7 +53,7 @@ public class AnnotatedConstructor extends ModelElement implements Constructor {
name, name,
mapperReferences, mapperReferences,
annotations, annotations,
noArgConstructorToBeIncluded, noArgConstructorToInBecluded,
fragmentsToBeIncluded fragmentsToBeIncluded
); );
} }

View File

@ -65,7 +65,7 @@ import org.mapstruct.ap.internal.util.Message;
import org.mapstruct.ap.internal.util.Strings; import org.mapstruct.ap.internal.util.Strings;
import org.mapstruct.ap.internal.util.accessor.Accessor; import org.mapstruct.ap.internal.util.accessor.Accessor;
import org.mapstruct.ap.internal.util.accessor.AccessorType; import org.mapstruct.ap.internal.util.accessor.AccessorType;
import org.mapstruct.ap.internal.util.accessor.ElementAccessor; import org.mapstruct.ap.internal.util.accessor.ParameterElementAccessor;
import org.mapstruct.ap.internal.util.accessor.PresenceCheckAccessor; import org.mapstruct.ap.internal.util.accessor.PresenceCheckAccessor;
import org.mapstruct.ap.internal.util.accessor.ReadAccessor; import org.mapstruct.ap.internal.util.accessor.ReadAccessor;
@ -100,7 +100,6 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
private final String finalizedResultName; private final String finalizedResultName;
private final List<LifecycleCallbackMethodReference> beforeMappingReferencesWithFinalizedReturnType; private final List<LifecycleCallbackMethodReference> beforeMappingReferencesWithFinalizedReturnType;
private final List<LifecycleCallbackMethodReference> afterMappingReferencesWithFinalizedReturnType; private final List<LifecycleCallbackMethodReference> afterMappingReferencesWithFinalizedReturnType;
private final Type subclassExhaustiveException;
private final MappingReferences mappingReferences; private final MappingReferences mappingReferences;
@ -236,10 +235,9 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
this.unprocessedTargetProperties = new LinkedHashMap<>( accessors ); this.unprocessedTargetProperties = new LinkedHashMap<>( accessors );
boolean constructorAccessorHadError = false;
if ( !method.isUpdateMethod() && !hasFactoryMethod ) { if ( !method.isUpdateMethod() && !hasFactoryMethod ) {
ConstructorAccessor constructorAccessor = getConstructorAccessor( resultTypeToMap ); ConstructorAccessor constructorAccessor = getConstructorAccessor( resultTypeToMap );
if ( constructorAccessor != null && !constructorAccessor.hasError ) { if ( constructorAccessor != null ) {
this.unprocessedConstructorProperties = constructorAccessor.constructorAccessors; this.unprocessedConstructorProperties = constructorAccessor.constructorAccessors;
@ -252,10 +250,8 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
else { else {
this.unprocessedConstructorProperties = new LinkedHashMap<>(); this.unprocessedConstructorProperties = new LinkedHashMap<>();
} }
constructorAccessorHadError = constructorAccessor != null && constructorAccessor.hasError;
this.targetProperties.addAll( this.unprocessedConstructorProperties.keySet() ); this.targetProperties.addAll( this.unprocessedConstructorProperties.keySet() );
this.unprocessedTargetProperties.putAll( this.unprocessedConstructorProperties ); this.unprocessedTargetProperties.putAll( this.unprocessedConstructorProperties );
} }
else { else {
@ -299,11 +295,9 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
} }
} }
// If defined mappings should not be handled then we should not apply implicit mappings boolean applyImplicitMappings = !mappingReferences.isRestrictToDefinedMappings();
boolean applyImplicitMappings =
shouldHandledDefinedMappings && !mappingReferences.isRestrictToDefinedMappings();
if ( applyImplicitMappings ) { if ( applyImplicitMappings ) {
applyImplicitMappings = beanMapping == null || !beanMapping.isIgnoredByDefault(); applyImplicitMappings = beanMapping == null || !beanMapping.isignoreByDefault();
} }
if ( applyImplicitMappings ) { if ( applyImplicitMappings ) {
@ -326,7 +320,7 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
// report errors on unmapped properties // report errors on unmapped properties
if ( shouldHandledDefinedMappings ) { if ( shouldHandledDefinedMappings ) {
reportErrorForUnmappedTargetPropertiesIfRequired( resultTypeToMap, constructorAccessorHadError ); reportErrorForUnmappedTargetPropertiesIfRequired();
reportErrorForUnmappedSourcePropertiesIfRequired(); reportErrorForUnmappedSourcePropertiesIfRequired();
} }
reportErrorForMissingIgnoredSourceProperties(); reportErrorForMissingIgnoredSourceProperties();
@ -379,11 +373,6 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
} }
TypeMirror subclassExhaustiveException = method.getOptions()
.getBeanMapping()
.getSubclassExhaustiveException();
Type subclassExhaustiveExceptionType = ctx.getTypeFactory().getType( subclassExhaustiveException );
List<SubclassMapping> subclasses = new ArrayList<>(); List<SubclassMapping> subclasses = new ArrayList<>();
for ( SubclassMappingOptions subclassMappingOptions : method.getOptions().getSubclassMappings() ) { for ( SubclassMappingOptions subclassMappingOptions : method.getOptions().getSubclassMappings() ) {
subclasses.add( createSubclassMapping( subclassMappingOptions ) ); subclasses.add( createSubclassMapping( subclassMappingOptions ) );
@ -417,8 +406,9 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
existingVariableNames existingVariableNames
) ); ) );
keepMappingReferencesUsingTarget( beforeMappingReferencesWithFinalizedReturnType, actualReturnType ); // remove methods without parameters as they are already being invoked
keepMappingReferencesUsingTarget( afterMappingReferencesWithFinalizedReturnType, actualReturnType ); removeMappingReferencesWithoutSourceParameters( beforeMappingReferencesWithFinalizedReturnType );
removeMappingReferencesWithoutSourceParameters( afterMappingReferencesWithFinalizedReturnType );
} }
Map<String, PresenceCheck> presenceChecksByParameter = new LinkedHashMap<>(); Map<String, PresenceCheck> presenceChecksByParameter = new LinkedHashMap<>();
@ -457,37 +447,12 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
finalizeMethod, finalizeMethod,
mappingReferences, mappingReferences,
subclasses, subclasses,
presenceChecksByParameter, presenceChecksByParameter
subclassExhaustiveExceptionType
); );
} }
private void keepMappingReferencesUsingTarget(List<LifecycleCallbackMethodReference> references, Type type) { private void removeMappingReferencesWithoutSourceParameters(List<LifecycleCallbackMethodReference> references) {
references.removeIf( reference -> { references.removeIf( r -> r.getSourceParameters().isEmpty() && r.getReturnType().isVoid() );
List<ParameterBinding> bindings = reference.getParameterBindings();
if ( bindings.isEmpty() ) {
return true;
}
for ( ParameterBinding binding : bindings ) {
if ( binding.isMappingTarget() ) {
if ( type.isAssignableTo( binding.getType() ) ) {
// If the mapping target matches the type then we need to keep this
return false;
}
}
else if ( binding.isTargetType() ) {
Type targetType = binding.getType();
List<Type> targetTypeTypeParameters = targetType.getTypeParameters();
if ( targetTypeTypeParameters.size() == 1 ) {
if ( type.isAssignableTo( targetTypeTypeParameters.get( 0 ) ) ) {
return false;
}
}
}
}
return true;
} );
} }
private boolean doesNotAllowAbstractReturnTypeAndCanBeConstructed(Type returnTypeImpl) { private boolean doesNotAllowAbstractReturnTypeAndCanBeConstructed(Type returnTypeImpl) {
@ -974,7 +939,7 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
) )
.collect( Collectors.joining( ", " ) ) .collect( Collectors.joining( ", " ) )
); );
return new ConstructorAccessor( true, Collections.emptyList(), Collections.emptyMap() ); return null;
} }
else { else {
return getConstructorAccessor( type, accessibleConstructors.get( 0 ) ); return getConstructorAccessor( type, accessibleConstructors.get( 0 ) );
@ -1033,7 +998,7 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
GENERAL_CONSTRUCTOR_PROPERTIES_NOT_MATCHING_PARAMETERS, GENERAL_CONSTRUCTOR_PROPERTIES_NOT_MATCHING_PARAMETERS,
type type
); );
return new ConstructorAccessor( true, Collections.emptyList(), Collections.emptyMap() ); return null;
} }
else { else {
Map<String, Accessor> constructorAccessors = new LinkedHashMap<>(); Map<String, Accessor> constructorAccessors = new LinkedHashMap<>();
@ -1067,7 +1032,7 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
existingVariableNames existingVariableNames
); );
existingVariableNames.add( safeParameterName ); existingVariableNames.add( safeParameterName );
return new ElementAccessor( element, accessedType, safeParameterName ); return new ParameterElementAccessor( element, accessedType, safeParameterName );
} }
private boolean hasDefaultAnnotationFromAnyPackage(Element element) { private boolean hasDefaultAnnotationFromAnyPackage(Element element) {
@ -1374,7 +1339,7 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
handledTargets.add( targetPropertyName ); handledTargets.add( targetPropertyName );
} }
// it's a constant // its a constant
// if we have an unprocessed target that means that it most probably is nested and we should // if we have an unprocessed target that means that it most probably is nested and we should
// not generated any mapping for it now. Eventually it will be done though // not generated any mapping for it now. Eventually it will be done though
else if ( mapping.getConstant() != null ) { else if ( mapping.getConstant() != null ) {
@ -1394,7 +1359,7 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
handledTargets.add( targetPropertyName ); handledTargets.add( targetPropertyName );
} }
// it's an expression // its an expression
// if we have an unprocessed target that means that it most probably is nested and we should // if we have an unprocessed target that means that it most probably is nested and we should
// not generated any mapping for it now. Eventually it will be done though // not generated any mapping for it now. Eventually it will be done though
else if ( mapping.getJavaExpression() != null ) { else if ( mapping.getJavaExpression() != null ) {
@ -1410,7 +1375,7 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
.build(); .build();
handledTargets.add( targetPropertyName ); handledTargets.add( targetPropertyName );
} }
// it's a plain-old property mapping // its a plain-old property mapping
else { else {
SourceReference sourceRef = mappingRef.getSourceReference(); SourceReference sourceRef = mappingRef.getSourceReference();
@ -1732,7 +1697,7 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
return ReportingPolicyGem.IGNORE; return ReportingPolicyGem.IGNORE;
} }
// If we have ignoreByDefault = true, unprocessed target properties are not an issue. // If we have ignoreByDefault = true, unprocessed target properties are not an issue.
if ( method.getOptions().getBeanMapping().isIgnoredByDefault() ) { if ( method.getOptions().getBeanMapping().isignoreByDefault() ) {
return ReportingPolicyGem.IGNORE; return ReportingPolicyGem.IGNORE;
} }
if ( method.getOptions().getBeanMapping() != null ) { if ( method.getOptions().getBeanMapping() != null ) {
@ -1741,45 +1706,36 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
return method.getOptions().getMapper().unmappedTargetPolicy(); return method.getOptions().getMapper().unmappedTargetPolicy();
} }
private void reportErrorForUnmappedTargetPropertiesIfRequired(Type resultType, private void reportErrorForUnmappedTargetPropertiesIfRequired() {
boolean constructorAccessorHadError) {
// fetch settings from element to implement // fetch settings from element to implement
ReportingPolicyGem unmappedTargetPolicy = getUnmappedTargetPolicy(); ReportingPolicyGem unmappedTargetPolicy = getUnmappedTargetPolicy();
if ( targetProperties.isEmpty() ) { if ( method instanceof ForgedMethod && targetProperties.isEmpty() ) {
if ( method instanceof ForgedMethod ) { //TODO until we solve 1140 we report this error when the target properties are empty
ForgedMethod forgedMethod = (ForgedMethod) method; ForgedMethod forgedMethod = (ForgedMethod) method;
if ( forgedMethod.getHistory() == null ) { if ( forgedMethod.getHistory() == null ) {
Type sourceType = this.method.getParameters().get( 0 ).getType(); Type sourceType = this.method.getParameters().get( 0 ).getType();
Type targetType = this.method.getReturnType(); Type targetType = this.method.getReturnType();
ctx.getMessager().printMessage(
this.method.getExecutable(),
Message.PROPERTYMAPPING_FORGED_MAPPING_NOT_FOUND,
sourceType.describe(),
targetType.describe(),
targetType.describe(),
sourceType.describe()
);
}
else {
ForgedMethodHistory history = forgedMethod.getHistory();
ctx.getMessager().printMessage(
this.method.getExecutable(),
Message.PROPERTYMAPPING_FORGED_MAPPING_WITH_HISTORY_NOT_FOUND,
history.createSourcePropertyErrorMessage(),
history.getTargetType().describe(),
history.createTargetPropertyName(),
history.getTargetType().describe(),
history.getSourceType().describe()
);
}
}
else if ( !constructorAccessorHadError ) {
ctx.getMessager().printMessage( ctx.getMessager().printMessage(
method.getExecutable(), this.method.getExecutable(),
Message.PROPERTYMAPPING_TARGET_HAS_NO_TARGET_PROPERTIES, Message.PROPERTYMAPPING_FORGED_MAPPING_NOT_FOUND,
resultType.describe() sourceType.describe(),
targetType.describe(),
targetType.describe(),
sourceType.describe()
);
}
else {
ForgedMethodHistory history = forgedMethod.getHistory();
ctx.getMessager().printMessage(
this.method.getExecutable(),
Message.PROPERTYMAPPING_FORGED_MAPPING_WITH_HISTORY_NOT_FOUND,
history.createSourcePropertyErrorMessage(),
history.getTargetType().describe(),
history.createTargetPropertyName(),
history.getTargetType().describe(),
history.getSourceType().describe()
); );
} }
} }
@ -1799,8 +1755,7 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
reportErrorForUnmappedProperties( reportErrorForUnmappedProperties(
unprocessedTargetProperties, unprocessedTargetProperties,
unmappedPropertiesMsg, unmappedPropertiesMsg,
unmappedForgedPropertiesMsg unmappedForgedPropertiesMsg );
);
} }
} }
@ -1927,19 +1882,12 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
} }
private static class ConstructorAccessor { private static class ConstructorAccessor {
private final boolean hasError;
private final List<ParameterBinding> parameterBindings; private final List<ParameterBinding> parameterBindings;
private final Map<String, Accessor> constructorAccessors; private final Map<String, Accessor> constructorAccessors;
private ConstructorAccessor( private ConstructorAccessor(
List<ParameterBinding> parameterBindings, List<ParameterBinding> parameterBindings,
Map<String, Accessor> constructorAccessors) { Map<String, Accessor> constructorAccessors) {
this( false, parameterBindings, constructorAccessors );
}
private ConstructorAccessor(boolean hasError, List<ParameterBinding> parameterBindings,
Map<String, Accessor> constructorAccessors) {
this.hasError = hasError;
this.parameterBindings = parameterBindings; this.parameterBindings = parameterBindings;
this.constructorAccessors = constructorAccessors; this.constructorAccessors = constructorAccessors;
} }
@ -1961,8 +1909,7 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
MethodReference finalizerMethod, MethodReference finalizerMethod,
MappingReferences mappingReferences, MappingReferences mappingReferences,
List<SubclassMapping> subclassMappings, List<SubclassMapping> subclassMappings,
Map<String, PresenceCheck> presenceChecksByParameter, Map<String, PresenceCheck> presenceChecksByParameter) {
Type subclassExhaustiveException) {
super( super(
method, method,
annotations, annotations,
@ -1977,7 +1924,6 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
this.propertyMappings = propertyMappings; this.propertyMappings = propertyMappings;
this.returnTypeBuilder = returnTypeBuilder; this.returnTypeBuilder = returnTypeBuilder;
this.finalizerMethod = finalizerMethod; this.finalizerMethod = finalizerMethod;
this.subclassExhaustiveException = subclassExhaustiveException;
if ( this.finalizerMethod != null ) { if ( this.finalizerMethod != null ) {
this.finalizedResultName = this.finalizedResultName =
Strings.getSafeVariableName( getResultName() + "Result", existingVariableNames ); Strings.getSafeVariableName( getResultName() + "Result", existingVariableNames );
@ -2026,10 +1972,6 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
this.subclassMappings = subclassMappings; this.subclassMappings = subclassMappings;
} }
public Type getSubclassExhaustiveException() {
return subclassExhaustiveException;
}
public List<PropertyMapping> getConstantMappings() { public List<PropertyMapping> getConstantMappings() {
return constantMappings; return constantMappings;
} }

View File

@ -240,7 +240,6 @@ public class CollectionAssignmentBuilder {
result, result,
method.getThrownTypes(), method.getThrownTypes(),
targetType, targetType,
nvpms,
targetAccessorType.isFieldAssignment() targetAccessorType.isFieldAssignment()
); );
} }

View File

@ -7,15 +7,14 @@ package org.mapstruct.ap.internal.model;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.SortedSet; import java.util.SortedSet;
import javax.lang.model.element.TypeElement; import javax.lang.model.element.TypeElement;
import org.mapstruct.ap.internal.gem.DecoratedWithGem;
import org.mapstruct.ap.internal.model.common.Accessibility; import org.mapstruct.ap.internal.model.common.Accessibility;
import org.mapstruct.ap.internal.model.common.Type; import org.mapstruct.ap.internal.model.common.Type;
import org.mapstruct.ap.internal.model.common.TypeFactory; import org.mapstruct.ap.internal.model.common.TypeFactory;
import org.mapstruct.ap.internal.option.Options; import org.mapstruct.ap.internal.option.Options;
import org.mapstruct.ap.internal.gem.DecoratedWithGem;
import org.mapstruct.ap.internal.version.VersionInformation; import org.mapstruct.ap.internal.version.VersionInformation;
/** /**
@ -34,7 +33,6 @@ public class Decorator extends GeneratedType {
private String implName; private String implName;
private String implPackage; private String implPackage;
private boolean suppressGeneratorTimestamp; private boolean suppressGeneratorTimestamp;
private Set<Annotation> customAnnotations;
public Builder() { public Builder() {
super( Builder.class ); super( Builder.class );
@ -70,11 +68,6 @@ public class Decorator extends GeneratedType {
return this; return this;
} }
public Builder additionalAnnotations(Set<Annotation> customAnnotations) {
this.customAnnotations = customAnnotations;
return this;
}
public Decorator build() { public Decorator build() {
String implementationName = implName.replace( Mapper.CLASS_NAME_PLACEHOLDER, String implementationName = implName.replace( Mapper.CLASS_NAME_PLACEHOLDER,
Mapper.getFlatName( mapperElement ) ); Mapper.getFlatName( mapperElement ) );
@ -102,8 +95,7 @@ public class Decorator extends GeneratedType {
suppressGeneratorTimestamp, suppressGeneratorTimestamp,
Accessibility.fromModifiers( mapperElement.getModifiers() ), Accessibility.fromModifiers( mapperElement.getModifiers() ),
extraImportedTypes, extraImportedTypes,
decoratorConstructor, decoratorConstructor
customAnnotations
); );
} }
} }
@ -118,8 +110,7 @@ public class Decorator extends GeneratedType {
Options options, VersionInformation versionInformation, Options options, VersionInformation versionInformation,
boolean suppressGeneratorTimestamp, boolean suppressGeneratorTimestamp,
Accessibility accessibility, SortedSet<Type> extraImports, Accessibility accessibility, SortedSet<Type> extraImports,
DecoratorConstructor decoratorConstructor, DecoratorConstructor decoratorConstructor) {
Set<Annotation> customAnnotations) {
super( super(
typeFactory, typeFactory,
packageName, packageName,
@ -137,11 +128,6 @@ public class Decorator extends GeneratedType {
this.decoratorType = decoratorType; this.decoratorType = decoratorType;
this.mapperType = mapperType; this.mapperType = mapperType;
// Add custom annotations
if ( customAnnotations != null ) {
customAnnotations.forEach( this::addAnnotation );
}
} }
@Override @Override

View File

@ -133,7 +133,7 @@ public final class LifecycleMethodResolver {
MappingBuilderContext ctx, Set<String> existingVariableNames) { MappingBuilderContext ctx, Set<String> existingVariableNames) {
MethodSelectors selectors = MethodSelectors selectors =
new MethodSelectors( ctx.getTypeUtils(), ctx.getElementUtils(), ctx.getMessager(), ctx.getOptions() ); new MethodSelectors( ctx.getTypeUtils(), ctx.getElementUtils(), ctx.getMessager() );
List<SelectedMethod<SourceMethod>> matchingMethods = selectors.getMatchingMethods( List<SelectedMethod<SourceMethod>> matchingMethods = selectors.getMatchingMethods(
callbackMethods, callbackMethods,

View File

@ -259,7 +259,7 @@ public class MappingBuilderContext {
} }
/** /**
* @param type that MapStruct wants to use to generate an automatic sub-mapping for/from * @param type that MapStruct wants to use to genrate an autoamtic sub-mapping for/from
* *
* @return {@code true} if the type is not excluded from the {@link MappingExclusionProvider} * @return {@code true} if the type is not excluded from the {@link MappingExclusionProvider}
*/ */

View File

@ -64,7 +64,7 @@ public class NestedTargetPropertyMappingHolder {
} }
/** /**
* @return all the targets that were handled * @return all the targets that were hanled
*/ */
public Set<String> getHandledTargets() { public Set<String> getHandledTargets() {
return handledTargets; return handledTargets;
@ -226,7 +226,7 @@ public class NestedTargetPropertyMappingHolder {
handledTargets.add( entryByTP.getKey() ); handledTargets.add( entryByTP.getKey() );
} }
// For the nonNested mappings (asymmetric) Mappings we also forge mappings // For the nonNested mappings (assymetric) Mappings we also forge mappings
// However, here we do not forge name based mappings and we only // However, here we do not forge name based mappings and we only
// do update on the defined Mappings. // do update on the defined Mappings.
if ( !groupedSourceReferences.nonNested.isEmpty() ) { if ( !groupedSourceReferences.nonNested.isEmpty() ) {
@ -362,13 +362,7 @@ public class NestedTargetPropertyMappingHolder {
Map<String, Set<MappingReference>> singleTargetReferences = new LinkedHashMap<>(); Map<String, Set<MappingReference>> singleTargetReferences = new LinkedHashMap<>();
for ( MappingReference mapping : mappingReferences.getMappingReferences() ) { for ( MappingReference mapping : mappingReferences.getMappingReferences() ) {
TargetReference targetReference = mapping.getTargetReference(); TargetReference targetReference = mapping.getTargetReference();
List<String> propertyEntries = targetReference.getPropertyEntries(); String property = first( targetReference.getPropertyEntries() );
if ( propertyEntries.isEmpty() ) {
// This can happen if the target property is target = ".",
// this usually happens when doing a reverse mapping
continue;
}
String property = first( propertyEntries );
MappingReference newMapping = mapping.popTargetReference(); MappingReference newMapping = mapping.popTargetReference();
if ( newMapping != null ) { if ( newMapping != null ) {
// group properties on current name. // group properties on current name.
@ -755,7 +749,7 @@ public class NestedTargetPropertyMappingHolder {
} }
/** /**
* This class is used to group Source references in respected to the nesting that they have. * This class is used to group Source references in respected to the nestings that they have.
* *
* This class contains all groupings by Property Entries if they are nested, or a list of all the other options * This class contains all groupings by Property Entries if they are nested, or a list of all the other options
* that could not have been popped. * that could not have been popped.

View File

@ -5,9 +5,12 @@
*/ */
package org.mapstruct.ap.internal.model; package org.mapstruct.ap.internal.model;
import static org.mapstruct.ap.internal.util.Collections.first;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.lang.model.element.ElementKind; import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.ExecutableElement;
@ -23,8 +26,6 @@ import org.mapstruct.ap.internal.model.source.selector.SelectedMethod;
import org.mapstruct.ap.internal.model.source.selector.SelectionContext; import org.mapstruct.ap.internal.model.source.selector.SelectionContext;
import org.mapstruct.ap.internal.util.Message; import org.mapstruct.ap.internal.util.Message;
import static org.mapstruct.ap.internal.util.Collections.first;
/** /**
* *
* @author Sjaak Derksen * @author Sjaak Derksen
@ -125,7 +126,7 @@ public class ObjectFactoryMethodResolver {
MappingBuilderContext ctx) { MappingBuilderContext ctx) {
MethodSelectors selectors = MethodSelectors selectors =
new MethodSelectors( ctx.getTypeUtils(), ctx.getElementUtils(), ctx.getMessager(), null ); new MethodSelectors( ctx.getTypeUtils(), ctx.getElementUtils(), ctx.getMessager() );
return selectors.getMatchingMethods( return selectors.getMatchingMethods(
getAllAvailableMethods( method, ctx.getSourceModel() ), getAllAvailableMethods( method, ctx.getSourceModel() ),

View File

@ -119,8 +119,7 @@ public final class PresenceCheckMethodResolver {
MethodSelectors selectors = new MethodSelectors( MethodSelectors selectors = new MethodSelectors(
ctx.getTypeUtils(), ctx.getTypeUtils(),
ctx.getElementUtils(), ctx.getElementUtils(),
ctx.getMessager(), ctx.getMessager()
null
); );
return selectors.getMatchingMethods( return selectors.getMatchingMethods(

View File

@ -274,7 +274,7 @@ public class ValueMappingMethod extends MappingMethod {
return mappings; return mappings;
} }
// Start to fill the mappings with the defined valueMappings // Start to fill the mappings with the defined valuemappings
for ( ValueMappingOptions valueMapping : valueMappings.regularValueMappings ) { for ( ValueMappingOptions valueMapping : valueMappings.regularValueMappings ) {
mappings.add( new MappingEntry( valueMapping.getSource(), valueMapping.getTarget() ) ); mappings.add( new MappingEntry( valueMapping.getSource(), valueMapping.getTarget() ) );
unmappedSourceConstants.remove( valueMapping.getSource() ); unmappedSourceConstants.remove( valueMapping.getSource() );
@ -305,7 +305,7 @@ public class ValueMappingMethod extends MappingMethod {
} }
Set<String> mappedSources = new LinkedHashSet<>(); Set<String> mappedSources = new LinkedHashSet<>();
// Start to fill the mappings with the defined value mappings // Start to fill the mappings with the defined valuemappings
for ( ValueMappingOptions valueMapping : valueMappings.regularValueMappings ) { for ( ValueMappingOptions valueMapping : valueMappings.regularValueMappings ) {
mappedSources.add( valueMapping.getSource() ); mappedSources.add( valueMapping.getSource() );
mappings.add( new MappingEntry( valueMapping.getSource(), valueMapping.getTarget() ) ); mappings.add( new MappingEntry( valueMapping.getSource(), valueMapping.getTarget() ) );

View File

@ -9,12 +9,9 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import org.mapstruct.ap.internal.gem.NullValuePropertyMappingStrategyGem;
import org.mapstruct.ap.internal.model.common.Assignment; import org.mapstruct.ap.internal.model.common.Assignment;
import org.mapstruct.ap.internal.model.common.Type; import org.mapstruct.ap.internal.model.common.Type;
import static org.mapstruct.ap.internal.gem.NullValuePropertyMappingStrategyGem.IGNORE;
/** /**
* This wrapper handles the situation were an assignment must be done via a target getter method because there * This wrapper handles the situation were an assignment must be done via a target getter method because there
* is no setter available. * is no setter available.
@ -29,14 +26,6 @@ import static org.mapstruct.ap.internal.gem.NullValuePropertyMappingStrategyGem.
* @author Sjaak Derksen * @author Sjaak Derksen
*/ */
public class GetterWrapperForCollectionsAndMaps extends WrapperForCollectionsAndMaps { public class GetterWrapperForCollectionsAndMaps extends WrapperForCollectionsAndMaps {
private final boolean ignoreMapNull;
public GetterWrapperForCollectionsAndMaps(Assignment decoratedAssignment,
List<Type> thrownTypesToExclude,
Type targetType,
boolean fieldAssignment) {
this( decoratedAssignment, thrownTypesToExclude, targetType, null, fieldAssignment );
}
/** /**
* @param decoratedAssignment source RHS * @param decoratedAssignment source RHS
@ -47,7 +36,6 @@ public class GetterWrapperForCollectionsAndMaps extends WrapperForCollectionsAnd
public GetterWrapperForCollectionsAndMaps(Assignment decoratedAssignment, public GetterWrapperForCollectionsAndMaps(Assignment decoratedAssignment,
List<Type> thrownTypesToExclude, List<Type> thrownTypesToExclude,
Type targetType, Type targetType,
NullValuePropertyMappingStrategyGem nvpms,
boolean fieldAssignment) { boolean fieldAssignment) {
super( super(
@ -56,7 +44,6 @@ public class GetterWrapperForCollectionsAndMaps extends WrapperForCollectionsAnd
targetType, targetType,
fieldAssignment fieldAssignment
); );
this.ignoreMapNull = nvpms == IGNORE;
} }
@Override @Override
@ -67,8 +54,4 @@ public class GetterWrapperForCollectionsAndMaps extends WrapperForCollectionsAnd
} }
return imported; return imported;
} }
public boolean isIgnoreMapNull() {
return ignoreMapNull;
}
} }

View File

@ -71,37 +71,7 @@ public class MappingReference {
return false; return false;
} }
MappingReference that = (MappingReference) o; MappingReference that = (MappingReference) o;
if ( ".".equals( that.mapping.getTargetName() ) ) { return mapping.equals( that.mapping );
// target this will never be equal to any other target this or any other.
return false;
}
if (!Objects.equals( mapping.getTargetName(), that.mapping.getTargetName() ) ) {
return false;
}
if ( !Objects.equals( mapping.getConstant(), that.mapping.getConstant() ) ) {
return false;
}
if ( !Objects.equals( mapping.getJavaExpression(), that.mapping.getJavaExpression() ) ) {
return false;
}
if ( sourceReference == null ) {
return that.sourceReference == null;
}
if ( that.sourceReference == null ) {
return false;
}
if (!Objects.equals( sourceReference.getPropertyEntries(), that.sourceReference.getPropertyEntries() ) ) {
return false;
}
return true;
} }
@Override @Override

View File

@ -32,8 +32,6 @@ public interface ConversionContext {
String getNumberFormat(); String getNumberFormat();
String getLocale();
TypeFactory getTypeFactory(); TypeFactory getTypeFactory();
} }

View File

@ -21,7 +21,6 @@ public class DefaultConversionContext implements ConversionContext {
private final FormattingParameters formattingParameters; private final FormattingParameters formattingParameters;
private final String dateFormat; private final String dateFormat;
private final String numberFormat; private final String numberFormat;
private final String locale;
private final TypeFactory typeFactory; private final TypeFactory typeFactory;
public DefaultConversionContext(TypeFactory typeFactory, FormattingMessager messager, Type sourceType, public DefaultConversionContext(TypeFactory typeFactory, FormattingMessager messager, Type sourceType,
@ -33,7 +32,6 @@ public class DefaultConversionContext implements ConversionContext {
this.formattingParameters = formattingParameters; this.formattingParameters = formattingParameters;
this.dateFormat = this.formattingParameters.getDate(); this.dateFormat = this.formattingParameters.getDate();
this.numberFormat = this.formattingParameters.getNumber(); this.numberFormat = this.formattingParameters.getNumber();
this.locale = this.formattingParameters.getLocale();
validateDateFormat(); validateDateFormat();
} }
@ -66,11 +64,6 @@ public class DefaultConversionContext implements ConversionContext {
return numberFormat; return numberFormat;
} }
@Override
public String getLocale() {
return locale != null ? locale.toString() : null;
}
@Override @Override
public String getDateFormat() { public String getDateFormat() {
return dateFormat; return dateFormat;

View File

@ -15,23 +15,21 @@ import javax.lang.model.element.Element;
*/ */
public class FormattingParameters { public class FormattingParameters {
public static final FormattingParameters EMPTY = new FormattingParameters( null, null, null, null, null, null ); public static final FormattingParameters EMPTY = new FormattingParameters( null, null, null, null, null );
private final String date; private final String date;
private final String number; private final String number;
private final AnnotationMirror mirror; private final AnnotationMirror mirror;
private final AnnotationValue dateAnnotationValue; private final AnnotationValue dateAnnotationValue;
private final Element element; private final Element element;
private final String locale;
public FormattingParameters(String date, String number, AnnotationMirror mirror, public FormattingParameters(String date, String number, AnnotationMirror mirror,
AnnotationValue dateAnnotationValue, Element element, String locale) { AnnotationValue dateAnnotationValue, Element element) {
this.date = date; this.date = date;
this.number = number; this.number = number;
this.mirror = mirror; this.mirror = mirror;
this.dateAnnotationValue = dateAnnotationValue; this.dateAnnotationValue = dateAnnotationValue;
this.element = element; this.element = element;
this.locale = locale;
} }
public String getDate() { public String getDate() {
@ -53,8 +51,4 @@ public class FormattingParameters {
public Element getElement() { public Element getElement() {
return element; return element;
} }
public String getLocale() {
return locale;
}
} }

View File

@ -16,34 +16,23 @@ public class ImplementationType {
private final Type type; private final Type type;
private final boolean initialCapacityConstructor; private final boolean initialCapacityConstructor;
private final boolean loadFactorAdjustment; private final boolean loadFactorAdjustment;
private final String factoryMethodName;
private ImplementationType( private ImplementationType(Type type, boolean initialCapacityConstructor, boolean loadFactorAdjustment) {
Type type,
boolean initialCapacityConstructor,
boolean loadFactorAdjustment,
String factoryMethodName
) {
this.type = type; this.type = type;
this.initialCapacityConstructor = initialCapacityConstructor; this.initialCapacityConstructor = initialCapacityConstructor;
this.loadFactorAdjustment = loadFactorAdjustment; this.loadFactorAdjustment = loadFactorAdjustment;
this.factoryMethodName = factoryMethodName;
} }
public static ImplementationType withDefaultConstructor(Type type) { public static ImplementationType withDefaultConstructor(Type type) {
return new ImplementationType( type, false, false, null ); return new ImplementationType( type, false, false );
} }
public static ImplementationType withInitialCapacity(Type type) { public static ImplementationType withInitialCapacity(Type type) {
return new ImplementationType( type, true, false, null ); return new ImplementationType( type, true, false );
} }
public static ImplementationType withLoadFactorAdjustment(Type type) { public static ImplementationType withLoadFactorAdjustment(Type type) {
return new ImplementationType( type, true, true, null ); return new ImplementationType( type, true, true );
}
public static ImplementationType withFactoryMethod(Type type, String factoryMethodName) {
return new ImplementationType( type, true, false, factoryMethodName );
} }
/** /**
@ -55,7 +44,7 @@ public class ImplementationType {
* @return a new implementation type with the given {@code type} * @return a new implementation type with the given {@code type}
*/ */
public ImplementationType createNew(Type type) { public ImplementationType createNew(Type type) {
return new ImplementationType( type, initialCapacityConstructor, loadFactorAdjustment, factoryMethodName ); return new ImplementationType( type, initialCapacityConstructor, loadFactorAdjustment );
} }
/** /**
@ -82,8 +71,4 @@ public class ImplementationType {
public boolean isLoadFactorAdjustment() { public boolean isLoadFactorAdjustment() {
return loadFactorAdjustment; return loadFactorAdjustment;
} }
public String getFactoryMethodName() {
return factoryMethodName;
}
} }

View File

@ -17,10 +17,6 @@ import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Optional;
import java.util.OptionalDouble;
import java.util.OptionalInt;
import java.util.OptionalLong;
import java.util.Set; import java.util.Set;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -54,7 +50,7 @@ import org.mapstruct.ap.internal.util.Nouns;
import org.mapstruct.ap.internal.util.TypeUtils; import org.mapstruct.ap.internal.util.TypeUtils;
import org.mapstruct.ap.internal.util.accessor.Accessor; import org.mapstruct.ap.internal.util.accessor.Accessor;
import org.mapstruct.ap.internal.util.accessor.AccessorType; import org.mapstruct.ap.internal.util.accessor.AccessorType;
import org.mapstruct.ap.internal.util.accessor.ElementAccessor; import org.mapstruct.ap.internal.util.accessor.FieldElementAccessor;
import org.mapstruct.ap.internal.util.accessor.MapValueAccessor; import org.mapstruct.ap.internal.util.accessor.MapValueAccessor;
import org.mapstruct.ap.internal.util.accessor.PresenceCheckAccessor; import org.mapstruct.ap.internal.util.accessor.PresenceCheckAccessor;
import org.mapstruct.ap.internal.util.accessor.ReadAccessor; import org.mapstruct.ap.internal.util.accessor.ReadAccessor;
@ -371,15 +367,6 @@ public class Type extends ModelElement implements Comparable<Type> {
return componentType != null; return componentType != null;
} }
private boolean isType(Class<?> type) {
return type.getName().equals( getFullyQualifiedName() );
}
private boolean isOptionalType() {
return isType( Optional.class ) || isType( OptionalInt.class ) || isType( OptionalDouble.class ) ||
isType( OptionalLong.class );
}
public boolean isTypeVar() { public boolean isTypeVar() {
return (typeMirror.getKind() == TypeKind.TYPEVAR); return (typeMirror.getKind() == TypeKind.TYPEVAR);
} }
@ -796,10 +783,6 @@ public class Type extends ModelElement implements Comparable<Type> {
* @return an unmodifiable map of all write accessors indexed by property name * @return an unmodifiable map of all write accessors indexed by property name
*/ */
public Map<String, Accessor> getPropertyWriteAccessors( CollectionMappingStrategyGem cmStrategy ) { public Map<String, Accessor> getPropertyWriteAccessors( CollectionMappingStrategyGem cmStrategy ) {
if ( isRecord() ) {
// Records do not have setters, so we return an empty map
return Collections.emptyMap();
}
// collect all candidate target accessors // collect all candidate target accessors
List<Accessor> candidates = new ArrayList<>( getSetters() ); List<Accessor> candidates = new ArrayList<>( getSetters() );
candidates.addAll( getAlternativeTargetAccessors() ); candidates.addAll( getAlternativeTargetAccessors() );
@ -1064,7 +1047,7 @@ public class Type extends ModelElement implements Comparable<Type> {
List<Accessor> setterMethods = getSetters(); List<Accessor> setterMethods = getSetters();
List<Accessor> readAccessors = new ArrayList<>( getPropertyReadAccessors().values() ); List<Accessor> readAccessors = new ArrayList<>( getPropertyReadAccessors().values() );
// All the fields are also alternative accessors // All the fields are also alternative accessors
readAccessors.addAll( filters.fieldsIn( getAllFields(), ElementAccessor::new ) ); readAccessors.addAll( filters.fieldsIn( getAllFields(), FieldElementAccessor::new ) );
// there could be a read accessor (field or method) for a list/map that is not present as setter. // there could be a read accessor (field or method) for a list/map that is not present as setter.
// an accessor could substitute the setter in that case and act as setter. // an accessor could substitute the setter in that case and act as setter.
@ -1183,10 +1166,6 @@ public class Type extends ModelElement implements Comparable<Type> {
* FTL. * FTL.
*/ */
public String getNull() { public String getNull() {
if ( isOptionalType() ) {
return createReferenceName() + ".empty()";
}
if ( !isPrimitive() || isArrayType() ) { if ( !isPrimitive() || isArrayType() ) {
return "null"; return "null";
} }

View File

@ -38,29 +38,26 @@ import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror; import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVariable; import javax.lang.model.type.TypeVariable;
import javax.lang.model.type.WildcardType; import javax.lang.model.type.WildcardType;
import org.mapstruct.ap.internal.util.ElementUtils;
import org.mapstruct.ap.internal.util.TypeUtils;
import org.mapstruct.ap.internal.gem.BuilderGem; import org.mapstruct.ap.internal.gem.BuilderGem;
import org.mapstruct.ap.internal.util.AnnotationProcessingException; import org.mapstruct.ap.internal.util.AnnotationProcessingException;
import org.mapstruct.ap.internal.util.Collections; import org.mapstruct.ap.internal.util.Collections;
import org.mapstruct.ap.internal.util.ElementUtils;
import org.mapstruct.ap.internal.util.Extractor; import org.mapstruct.ap.internal.util.Extractor;
import org.mapstruct.ap.internal.util.FormattingMessager; import org.mapstruct.ap.internal.util.FormattingMessager;
import org.mapstruct.ap.internal.util.JavaCollectionConstants;
import org.mapstruct.ap.internal.util.JavaStreamConstants; import org.mapstruct.ap.internal.util.JavaStreamConstants;
import org.mapstruct.ap.internal.util.Message; import org.mapstruct.ap.internal.util.Message;
import org.mapstruct.ap.internal.util.NativeTypes; import org.mapstruct.ap.internal.util.NativeTypes;
import org.mapstruct.ap.internal.util.RoundContext; import org.mapstruct.ap.internal.util.RoundContext;
import org.mapstruct.ap.internal.util.Strings; import org.mapstruct.ap.internal.util.Strings;
import org.mapstruct.ap.internal.util.TypeUtils;
import org.mapstruct.ap.internal.util.accessor.Accessor; import org.mapstruct.ap.internal.util.accessor.Accessor;
import org.mapstruct.ap.internal.version.VersionInformation;
import org.mapstruct.ap.spi.AstModifyingAnnotationProcessor; import org.mapstruct.ap.spi.AstModifyingAnnotationProcessor;
import org.mapstruct.ap.spi.BuilderInfo; import org.mapstruct.ap.spi.BuilderInfo;
import org.mapstruct.ap.spi.MoreThanOneBuilderCreationMethodException; import org.mapstruct.ap.spi.MoreThanOneBuilderCreationMethodException;
import org.mapstruct.ap.spi.TypeHierarchyErroneousException; import org.mapstruct.ap.spi.TypeHierarchyErroneousException;
import static org.mapstruct.ap.internal.model.common.ImplementationType.withDefaultConstructor; import static org.mapstruct.ap.internal.model.common.ImplementationType.withDefaultConstructor;
import static org.mapstruct.ap.internal.model.common.ImplementationType.withFactoryMethod;
import static org.mapstruct.ap.internal.model.common.ImplementationType.withInitialCapacity; import static org.mapstruct.ap.internal.model.common.ImplementationType.withInitialCapacity;
import static org.mapstruct.ap.internal.model.common.ImplementationType.withLoadFactorAdjustment; import static org.mapstruct.ap.internal.model.common.ImplementationType.withLoadFactorAdjustment;
@ -85,8 +82,6 @@ public class TypeFactory {
sb.append( ')' ); sb.append( ')' );
return sb.toString(); return sb.toString();
}; };
private static final String LINKED_HASH_SET_FACTORY_METHOD_NAME = "newLinkedHashSet";
private static final String LINKED_HASH_MAP_FACTORY_METHOD_NAME = "newLinkedHashMap";
private final ElementUtils elementUtils; private final ElementUtils elementUtils;
private final TypeUtils typeUtils; private final TypeUtils typeUtils;
@ -105,8 +100,7 @@ public class TypeFactory {
private final boolean loggingVerbose; private final boolean loggingVerbose;
public TypeFactory(ElementUtils elementUtils, TypeUtils typeUtils, FormattingMessager messager, public TypeFactory(ElementUtils elementUtils, TypeUtils typeUtils, FormattingMessager messager,
RoundContext roundContext, Map<String, String> notToBeImportedTypes, boolean loggingVerbose, RoundContext roundContext, Map<String, String> notToBeImportedTypes, boolean loggingVerbose) {
VersionInformation versionInformation) {
this.elementUtils = elementUtils; this.elementUtils = elementUtils;
this.typeUtils = typeUtils; this.typeUtils = typeUtils;
this.messager = messager; this.messager = messager;
@ -124,22 +118,11 @@ public class TypeFactory {
implementationTypes.put( Collection.class.getName(), withInitialCapacity( getType( ArrayList.class ) ) ); implementationTypes.put( Collection.class.getName(), withInitialCapacity( getType( ArrayList.class ) ) );
implementationTypes.put( List.class.getName(), withInitialCapacity( getType( ArrayList.class ) ) ); implementationTypes.put( List.class.getName(), withInitialCapacity( getType( ArrayList.class ) ) );
boolean sourceVersionAtLeast19 = versionInformation.isSourceVersionAtLeast19(); implementationTypes.put( Set.class.getName(), withLoadFactorAdjustment( getType( LinkedHashSet.class ) ) );
implementationTypes.put(
Set.class.getName(),
sourceVersionAtLeast19 ?
withFactoryMethod( getType( LinkedHashSet.class ), LINKED_HASH_SET_FACTORY_METHOD_NAME ) :
withLoadFactorAdjustment( getType( LinkedHashSet.class ) )
);
implementationTypes.put( SortedSet.class.getName(), withDefaultConstructor( getType( TreeSet.class ) ) ); implementationTypes.put( SortedSet.class.getName(), withDefaultConstructor( getType( TreeSet.class ) ) );
implementationTypes.put( NavigableSet.class.getName(), withDefaultConstructor( getType( TreeSet.class ) ) ); implementationTypes.put( NavigableSet.class.getName(), withDefaultConstructor( getType( TreeSet.class ) ) );
implementationTypes.put( implementationTypes.put( Map.class.getName(), withLoadFactorAdjustment( getType( LinkedHashMap.class ) ) );
Map.class.getName(),
sourceVersionAtLeast19 ?
withFactoryMethod( getType( LinkedHashMap.class ), LINKED_HASH_MAP_FACTORY_METHOD_NAME ) :
withLoadFactorAdjustment( getType( LinkedHashMap.class ) )
);
implementationTypes.put( SortedMap.class.getName(), withDefaultConstructor( getType( TreeMap.class ) ) ); implementationTypes.put( SortedMap.class.getName(), withDefaultConstructor( getType( TreeMap.class ) ) );
implementationTypes.put( NavigableMap.class.getName(), withDefaultConstructor( getType( TreeMap.class ) ) ); implementationTypes.put( NavigableMap.class.getName(), withDefaultConstructor( getType( TreeMap.class ) ) );
implementationTypes.put( implementationTypes.put(
@ -150,18 +133,6 @@ public class TypeFactory {
ConcurrentNavigableMap.class.getName(), ConcurrentNavigableMap.class.getName(),
withDefaultConstructor( getType( ConcurrentSkipListMap.class ) ) withDefaultConstructor( getType( ConcurrentSkipListMap.class ) )
); );
implementationTypes.put(
JavaCollectionConstants.SEQUENCED_SET_FQN,
sourceVersionAtLeast19 ?
withFactoryMethod( getType( LinkedHashSet.class ), LINKED_HASH_SET_FACTORY_METHOD_NAME ) :
withLoadFactorAdjustment( getType( LinkedHashSet.class ) )
);
implementationTypes.put(
JavaCollectionConstants.SEQUENCED_MAP_FQN,
sourceVersionAtLeast19 ?
withFactoryMethod( getType( LinkedHashMap.class ), LINKED_HASH_MAP_FACTORY_METHOD_NAME ) :
withLoadFactorAdjustment( getType( LinkedHashMap.class ) )
);
this.loggingVerbose = loggingVerbose; this.loggingVerbose = loggingVerbose;
} }
@ -504,11 +475,7 @@ public class TypeFactory {
if (accessor.getAccessorType().isFieldAssignment()) { if (accessor.getAccessorType().isFieldAssignment()) {
return new ArrayList<>(); return new ArrayList<>();
} }
Element element = accessor.getElement(); return extractTypes( ( (ExecutableElement) accessor.getElement() ).getThrownTypes() );
if ( element instanceof ExecutableElement ) {
return extractTypes( ( (ExecutableElement) element ).getThrownTypes() );
}
return new ArrayList<>();
} }
private List<Type> extractTypes(List<? extends TypeMirror> typeMirrors) { private List<Type> extractTypes(List<? extends TypeMirror> typeMirrors) {

View File

@ -11,7 +11,6 @@ import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.ExecutableElement;
import javax.lang.model.type.TypeMirror;
import org.mapstruct.ap.internal.gem.BeanMappingGem; import org.mapstruct.ap.internal.gem.BeanMappingGem;
import org.mapstruct.ap.internal.gem.BuilderGem; import org.mapstruct.ap.internal.gem.BuilderGem;
@ -183,14 +182,6 @@ public class BeanMappingOptions extends DelegatingOptions {
.orElse( next().getSubclassExhaustiveStrategy() ); .orElse( next().getSubclassExhaustiveStrategy() );
} }
@Override
public TypeMirror getSubclassExhaustiveException() {
return Optional.ofNullable( beanMapping ).map( BeanMappingGem::subclassExhaustiveException )
.filter( GemValue::hasValue )
.map( GemValue::getValue )
.orElse( next().getSubclassExhaustiveException() );
}
@Override @Override
public ReportingPolicyGem unmappedTargetPolicy() { public ReportingPolicyGem unmappedTargetPolicy() {
return Optional.ofNullable( beanMapping ).map( BeanMappingGem::unmappedTargetPolicy ) return Optional.ofNullable( beanMapping ).map( BeanMappingGem::unmappedTargetPolicy )
@ -232,7 +223,7 @@ public class BeanMappingOptions extends DelegatingOptions {
return selectionParameters; return selectionParameters;
} }
public boolean isIgnoredByDefault() { public boolean isignoreByDefault() {
return Optional.ofNullable( beanMapping ).map( BeanMappingGem::ignoreByDefault ) return Optional.ofNullable( beanMapping ).map( BeanMappingGem::ignoreByDefault )
.map( GemValue::get ) .map( GemValue::get )
.orElse( false ); .orElse( false );

View File

@ -56,18 +56,16 @@ public class DefaultOptions extends DelegatingOptions {
@Override @Override
public ReportingPolicyGem unmappedTargetPolicy() { public ReportingPolicyGem unmappedTargetPolicy() {
ReportingPolicyGem unmappedTargetPolicy = options.getUnmappedTargetPolicy(); if ( options.getUnmappedTargetPolicy() != null ) {
if ( unmappedTargetPolicy != null ) { return options.getUnmappedTargetPolicy();
return unmappedTargetPolicy;
} }
return ReportingPolicyGem.valueOf( mapper.unmappedTargetPolicy().getDefaultValue() ); return ReportingPolicyGem.valueOf( mapper.unmappedTargetPolicy().getDefaultValue() );
} }
@Override @Override
public ReportingPolicyGem unmappedSourcePolicy() { public ReportingPolicyGem unmappedSourcePolicy() {
ReportingPolicyGem unmappedSourcePolicy = options.getUnmappedSourcePolicy(); if ( options.getUnmappedSourcePolicy() != null ) {
if ( unmappedSourcePolicy != null ) { return options.getUnmappedSourcePolicy();
return unmappedSourcePolicy;
} }
return ReportingPolicyGem.valueOf( mapper.unmappedSourcePolicy().getDefaultValue() ); return ReportingPolicyGem.valueOf( mapper.unmappedSourcePolicy().getDefaultValue() );
} }
@ -79,9 +77,8 @@ public class DefaultOptions extends DelegatingOptions {
@Override @Override
public String componentModel() { public String componentModel() {
String defaultComponentModel = options.getDefaultComponentModel(); if ( options.getDefaultComponentModel() != null ) {
if ( defaultComponentModel != null ) { return options.getDefaultComponentModel();
return defaultComponentModel;
} }
return mapper.componentModel().getDefaultValue(); return mapper.componentModel().getDefaultValue();
} }
@ -100,9 +97,8 @@ public class DefaultOptions extends DelegatingOptions {
@Override @Override
public InjectionStrategyGem getInjectionStrategy() { public InjectionStrategyGem getInjectionStrategy() {
String defaultInjectionStrategy = options.getDefaultInjectionStrategy(); if ( options.getDefaultInjectionStrategy() != null ) {
if ( defaultInjectionStrategy != null ) { return InjectionStrategyGem.valueOf( options.getDefaultInjectionStrategy().toUpperCase() );
return InjectionStrategyGem.valueOf( defaultInjectionStrategy.toUpperCase() );
} }
return InjectionStrategyGem.valueOf( mapper.injectionStrategy().getDefaultValue() ); return InjectionStrategyGem.valueOf( mapper.injectionStrategy().getDefaultValue() );
} }
@ -135,10 +131,6 @@ public class DefaultOptions extends DelegatingOptions {
return SubclassExhaustiveStrategyGem.valueOf( mapper.subclassExhaustiveStrategy().getDefaultValue() ); return SubclassExhaustiveStrategyGem.valueOf( mapper.subclassExhaustiveStrategy().getDefaultValue() );
} }
public TypeMirror getSubclassExhaustiveException() {
return mapper.subclassExhaustiveException().getDefaultValue();
}
public NullValueMappingStrategyGem getNullValueIterableMappingStrategy() { public NullValueMappingStrategyGem getNullValueIterableMappingStrategy() {
NullValueMappingStrategyGem nullValueIterableMappingStrategy = options.getNullValueIterableMappingStrategy(); NullValueMappingStrategyGem nullValueIterableMappingStrategy = options.getNullValueIterableMappingStrategy();
if ( nullValueIterableMappingStrategy != null ) { if ( nullValueIterableMappingStrategy != null ) {

View File

@ -106,10 +106,6 @@ public abstract class DelegatingOptions {
return next.getSubclassExhaustiveStrategy(); return next.getSubclassExhaustiveStrategy();
} }
public TypeMirror getSubclassExhaustiveException() {
return next.getSubclassExhaustiveException();
}
public NullValueMappingStrategyGem getNullValueIterableMappingStrategy() { public NullValueMappingStrategyGem getNullValueIterableMappingStrategy() {
return next.getNullValueIterableMappingStrategy(); return next.getNullValueIterableMappingStrategy();
} }

View File

@ -55,8 +55,7 @@ public class IterableMappingOptions extends DelegatingOptions {
iterableMapping.numberFormat().get(), iterableMapping.numberFormat().get(),
iterableMapping.mirror(), iterableMapping.mirror(),
iterableMapping.dateFormat().getAnnotationValue(), iterableMapping.dateFormat().getAnnotationValue(),
method, method
iterableMapping.locale().getValue()
); );
IterableMappingOptions options = IterableMappingOptions options =

View File

@ -8,14 +8,14 @@ package org.mapstruct.ap.internal.model.source;
import java.util.Optional; import java.util.Optional;
import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.ExecutableElement;
import org.mapstruct.ap.internal.util.ElementUtils;
import org.mapstruct.ap.internal.util.TypeUtils;
import org.mapstruct.ap.internal.model.common.FormattingParameters;
import org.mapstruct.ap.internal.gem.MapMappingGem; import org.mapstruct.ap.internal.gem.MapMappingGem;
import org.mapstruct.ap.internal.gem.NullValueMappingStrategyGem; import org.mapstruct.ap.internal.gem.NullValueMappingStrategyGem;
import org.mapstruct.ap.internal.model.common.FormattingParameters;
import org.mapstruct.ap.internal.util.ElementUtils;
import org.mapstruct.ap.internal.util.FormattingMessager; import org.mapstruct.ap.internal.util.FormattingMessager;
import org.mapstruct.ap.internal.util.Message; import org.mapstruct.ap.internal.util.Message;
import org.mapstruct.ap.internal.util.TypeUtils;
import org.mapstruct.tools.gem.GemValue; import org.mapstruct.tools.gem.GemValue;
/** /**
@ -47,8 +47,6 @@ public class MapMappingOptions extends DelegatingOptions {
return options; return options;
} }
String locale = mapMapping.locale().getValue();
SelectionParameters keySelection = new SelectionParameters( SelectionParameters keySelection = new SelectionParameters(
mapMapping.keyQualifiedBy().get(), mapMapping.keyQualifiedBy().get(),
mapMapping.keyQualifiedByName().get(), mapMapping.keyQualifiedByName().get(),
@ -68,8 +66,7 @@ public class MapMappingOptions extends DelegatingOptions {
mapMapping.keyNumberFormat().get(), mapMapping.keyNumberFormat().get(),
mapMapping.mirror(), mapMapping.mirror(),
mapMapping.keyDateFormat().getAnnotationValue(), mapMapping.keyDateFormat().getAnnotationValue(),
method, method
locale
); );
FormattingParameters valueFormatting = new FormattingParameters( FormattingParameters valueFormatting = new FormattingParameters(
@ -77,8 +74,7 @@ public class MapMappingOptions extends DelegatingOptions {
mapMapping.valueNumberFormat().get(), mapMapping.valueNumberFormat().get(),
mapMapping.mirror(), mapMapping.mirror(),
mapMapping.valueDateFormat().getAnnotationValue(), mapMapping.valueDateFormat().getAnnotationValue(),
method, method
locale
); );
MapMappingOptions options = new MapMappingOptions( MapMappingOptions options = new MapMappingOptions(

View File

@ -141,12 +141,6 @@ public class MapperConfigOptions extends DelegatingOptions {
next().getSubclassExhaustiveStrategy(); next().getSubclassExhaustiveStrategy();
} }
public TypeMirror getSubclassExhaustiveException() {
return mapperConfig.subclassExhaustiveException().hasValue() ?
mapperConfig.subclassExhaustiveException().get() :
next().getSubclassExhaustiveException();
}
@Override @Override
public NullValueMappingStrategyGem getNullValueIterableMappingStrategy() { public NullValueMappingStrategyGem getNullValueIterableMappingStrategy() {
if ( mapperConfig.nullValueIterableMappingStrategy().hasValue() ) { if ( mapperConfig.nullValueIterableMappingStrategy().hasValue() ) {

View File

@ -170,13 +170,6 @@ public class MapperOptions extends DelegatingOptions {
next().getSubclassExhaustiveStrategy(); next().getSubclassExhaustiveStrategy();
} }
@Override
public TypeMirror getSubclassExhaustiveException() {
return mapper.subclassExhaustiveException().hasValue() ?
mapper.subclassExhaustiveException().get() :
next().getSubclassExhaustiveException();
}
@Override @Override
public NullValueMappingStrategyGem getNullValueIterableMappingStrategy() { public NullValueMappingStrategyGem getNullValueIterableMappingStrategy() {
if ( mapper.nullValueIterableMappingStrategy().hasValue() ) { if ( mapper.nullValueIterableMappingStrategy().hasValue() ) {

View File

@ -18,16 +18,16 @@ import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue; import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.Element; import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.ExecutableElement;
import org.mapstruct.ap.internal.util.ElementUtils;
import org.mapstruct.ap.internal.util.TypeUtils;
import org.mapstruct.ap.internal.gem.MappingGem; import org.mapstruct.ap.internal.gem.MappingGem;
import org.mapstruct.ap.internal.gem.MappingsGem; import org.mapstruct.ap.internal.gem.MappingsGem;
import org.mapstruct.ap.internal.gem.NullValueCheckStrategyGem; import org.mapstruct.ap.internal.gem.NullValueCheckStrategyGem;
import org.mapstruct.ap.internal.gem.NullValuePropertyMappingStrategyGem; import org.mapstruct.ap.internal.gem.NullValuePropertyMappingStrategyGem;
import org.mapstruct.ap.internal.model.common.FormattingParameters; import org.mapstruct.ap.internal.model.common.FormattingParameters;
import org.mapstruct.ap.internal.util.ElementUtils;
import org.mapstruct.ap.internal.util.FormattingMessager; import org.mapstruct.ap.internal.util.FormattingMessager;
import org.mapstruct.ap.internal.util.Message; import org.mapstruct.ap.internal.util.Message;
import org.mapstruct.ap.internal.util.TypeUtils;
import org.mapstruct.tools.gem.GemValue; import org.mapstruct.tools.gem.GemValue;
/** /**
@ -118,8 +118,6 @@ public class MappingOptions extends DelegatingOptions {
String conditionExpression = getConditionExpression( mapping, method, messager ); String conditionExpression = getConditionExpression( mapping, method, messager );
String dateFormat = mapping.dateFormat().getValue(); String dateFormat = mapping.dateFormat().getValue();
String numberFormat = mapping.numberFormat().getValue(); String numberFormat = mapping.numberFormat().getValue();
String locale = mapping.locale().getValue();
String defaultValue = mapping.defaultValue().getValue(); String defaultValue = mapping.defaultValue().getValue();
Set<String> dependsOn = mapping.dependsOn().hasValue() ? Set<String> dependsOn = mapping.dependsOn().hasValue() ?
@ -131,8 +129,7 @@ public class MappingOptions extends DelegatingOptions {
numberFormat, numberFormat,
mapping.mirror(), mapping.mirror(),
mapping.dateFormat().getAnnotationValue(), mapping.dateFormat().getAnnotationValue(),
method, method
locale
); );
SelectionParameters selectionParams = new SelectionParameters( SelectionParameters selectionParams = new SelectionParameters(
mapping.qualifiedBy().get(), mapping.qualifiedBy().get(),
@ -482,12 +479,13 @@ public class MappingOptions extends DelegatingOptions {
} }
/** /**
* Mapping can only be inversed if the source was not a constant nor an expression * mapping can only be inversed if the source was not a constant nor an expression nor a nested property
* and the mapping is not a 'target-source-ignore' mapping
* *
* @return true when the above applies * @return true when the above applies
*/ */
public boolean canInverse() { public boolean canInverse() {
return constant == null && javaExpression == null; return constant == null && javaExpression == null && !( isIgnored && sourceName == null );
} }
public MappingOptions copyForInverseInheritance(SourceMethod templateMethod, public MappingOptions copyForInverseInheritance(SourceMethod templateMethod,

View File

@ -83,7 +83,7 @@ public interface Method {
Parameter getMappingTargetParameter(); Parameter getMappingTargetParameter();
/** /**
* Returns whether the method is designated as bean factory for * Returns whether the meethod is designated as bean factory for
* mapping target {@link org.mapstruct.ObjectFactory } * mapping target {@link org.mapstruct.ObjectFactory }
* *
* @return true if it is a target bean factory. * @return true if it is a target bean factory.

View File

@ -186,7 +186,7 @@ public class SourceMethod implements Method {
return this; return this;
} }
public Builder setDefiningType(Type definingType) { public Builder setDefininingType(Type definingType) {
this.definingType = definingType; this.definingType = definingType;
return this; return this;
} }

View File

@ -33,7 +33,7 @@ public class InheritanceSelector implements MethodSelector {
List<SelectedMethod<T>> candidatesWithBestMatchingSourceType = new ArrayList<>(); List<SelectedMethod<T>> candidatesWithBestMatchingSourceType = new ArrayList<>();
int bestMatchingSourceTypeDistance = Integer.MAX_VALUE; int bestMatchingSourceTypeDistance = Integer.MAX_VALUE;
// Find methods with the minimum inheritance distance from the source parameter type // find the methods with the minimum distance regarding getParameter getParameter type
for ( SelectedMethod<T> method : methods ) { for ( SelectedMethod<T> method : methods ) {
Parameter singleSourceParam = first( method.getMethod().getSourceParameters() ); Parameter singleSourceParam = first( method.getMethod().getSourceParameters() );
@ -49,17 +49,17 @@ public class InheritanceSelector implements MethodSelector {
return candidatesWithBestMatchingSourceType; return candidatesWithBestMatchingSourceType;
} }
private <T extends Method> int addToCandidateListIfMinimal(List<SelectedMethod<T>> candidatesWithBestMatchingType, private <T extends Method> int addToCandidateListIfMinimal(List<SelectedMethod<T>> candidatesWithBestMathingType,
int bestMatchingTypeDistance, SelectedMethod<T> method, int bestMatchingTypeDistance, SelectedMethod<T> method,
int currentTypeDistance) { int currentTypeDistance) {
if ( currentTypeDistance == bestMatchingTypeDistance ) { if ( currentTypeDistance == bestMatchingTypeDistance ) {
candidatesWithBestMatchingType.add( method ); candidatesWithBestMathingType.add( method );
} }
else if ( currentTypeDistance < bestMatchingTypeDistance ) { else if ( currentTypeDistance < bestMatchingTypeDistance ) {
bestMatchingTypeDistance = currentTypeDistance; bestMatchingTypeDistance = currentTypeDistance;
candidatesWithBestMatchingType.clear(); candidatesWithBestMathingType.clear();
candidatesWithBestMatchingType.add( method ); candidatesWithBestMathingType.add( method );
} }
return bestMatchingTypeDistance; return bestMatchingTypeDistance;
} }

View File

@ -1,129 +0,0 @@
/*
* 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 java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.stream.Collectors;
import org.mapstruct.ap.internal.model.common.Parameter;
import org.mapstruct.ap.internal.model.common.ParameterBinding;
import org.mapstruct.ap.internal.model.source.Method;
/**
* Selector for deduplicating overloaded lifecycle callback methods
* whose parameter signatures differ only by type hierarchy.
* <p>
* In the context of lifecycle callback method selection
* (such as @BeforeMapping or @AfterMapping), it is possible to have multiple overloaded methods
* whose parameter lists are structurally identical except for the specific types,
* where those types are related by inheritance (e.g., one parameter is a superclass or subclass of another).
* <p>
* This selector groups such methods by their effective parameter signature
* (ignoring differences only in type hierarchy), and, within each group,
* retains only the method whose parameter types have the closest inheritance distance
* to the actual invocation types.
* This ensures that, for each group of nearly identical overloads,
* only the most specific and appropriate method is selected.
* <p>
* <b>Example (see Issue3849Test):</b>
*
* <pre>{@code
* @AfterMapping
* default void afterMapping(Parent source, @MappingTarget ParentDto target) { ... }
* @AfterMapping
* default void afterMapping(Parent source, @MappingTarget ChildDto target) { ... }
* }</pre>
* When mapping a Child to a ChildDto,
* only the method with ChildDto is selected, even though both methods match by signature
* except for the target type's inheritance relationship.
*/
public class LifecycleOverloadDeduplicateSelector implements MethodSelector {
@Override
public <T extends Method> List<SelectedMethod<T>> getMatchingMethods(List<SelectedMethod<T>> methods,
SelectionContext context) {
if ( !context.getSelectionCriteria().isLifecycleCallbackRequired() || methods.size() <= 1 ) {
return methods;
}
Collection<List<SelectedMethod<T>>> methodSignatureGroups =
methods.stream()
.collect( Collectors.groupingBy(
LifecycleOverloadDeduplicateSelector::buildSignatureKey,
LinkedHashMap::new,
Collectors.toList()
) )
.values();
List<SelectedMethod<T>> deduplicatedMethods = new ArrayList<>( methods.size() );
for ( List<SelectedMethod<T>> signatureGroup : methodSignatureGroups ) {
if ( signatureGroup.size() == 1 ) {
deduplicatedMethods.add( signatureGroup.get( 0 ) );
continue;
}
SelectedMethod<T> bestInheritanceMethod = signatureGroup.get( 0 );
for ( int i = 1; i < signatureGroup.size(); i++ ) {
SelectedMethod<T> candidateMethod = signatureGroup.get( i );
if ( isInheritanceBetter( candidateMethod, bestInheritanceMethod ) ) {
bestInheritanceMethod = candidateMethod;
}
}
deduplicatedMethods.add( bestInheritanceMethod );
}
return deduplicatedMethods;
}
/**
* Builds a grouping key for a method based on its defining type,
* method name, and a detailed breakdown of each parameter binding.
* <p>
* The key consists of:
* <ul>
* <li>The type that defines the method</li>
* <li>The method name</li>
* <li>parameter bindings</li>
* </ul>
* This ensures that methods are grouped together only if all these aspects match,
* except for differences in type hierarchy, which are handled separately.
*/
private static <T extends Method> List<Object> buildSignatureKey(SelectedMethod<T> method) {
List<Object> key = new ArrayList<>();
key.add( method.getMethod().getDefiningType() );
key.add( method.getMethod().getName() );
for ( ParameterBinding binding : method.getParameterBindings() ) {
key.add( binding.getType() );
key.add( binding.getVariableName() );
}
return key;
}
/**
* Compare the inheritance distance of parameters between two methods to determine if candidateMethod is better.
* Compares parameters in order, returns as soon as a better one is found.
*/
private <T extends Method> boolean isInheritanceBetter(SelectedMethod<T> candidateMethod,
SelectedMethod<T> currentBestMethod) {
List<ParameterBinding> candidateBindings = candidateMethod.getParameterBindings();
List<ParameterBinding> bestBindings = currentBestMethod.getParameterBindings();
List<Parameter> candidateParams = candidateMethod.getMethod().getParameters();
List<Parameter> bestParams = currentBestMethod.getMethod().getParameters();
int paramCount = candidateBindings.size();
for ( int i = 0; i < paramCount; i++ ) {
int candidateDistance = candidateBindings.get( i )
.getType()
.distanceTo( candidateParams.get( i ).getType() );
int bestDistance = bestBindings.get( i ).getType().distanceTo( bestParams.get( i ).getType() );
if ( candidateDistance < bestDistance ) {
return true;
}
else if ( candidateDistance > bestDistance ) {
return false;
}
}
return false;
}
}

Some files were not shown because too many files have changed in this diff Show More