├── .github
└── workflows
│ └── main.yml
├── .gitignore
├── .mvn
└── wrapper
│ ├── MavenWrapperDownloader.java
│ ├── maven-wrapper.jar
│ └── maven-wrapper.properties
├── benchmark.plt
├── model.png
├── model.uml
├── mvnw
├── mvnw.cmd
├── pom.xml
├── readme.md
├── results.csv
├── results.png
└── src
├── main
├── java
│ └── com
│ │ └── javaetmoi
│ │ └── benchmark
│ │ ├── MapperBenchmark.java
│ │ └── mapping
│ │ ├── mapper
│ │ ├── OrderMapper.java
│ │ ├── bull
│ │ │ └── BullMapper.java
│ │ ├── datus
│ │ │ └── DatusMapper.java
│ │ ├── dozer
│ │ │ └── DozerMapper.java
│ │ ├── jmapper
│ │ │ └── JMapperMapper.java
│ │ ├── manual
│ │ │ └── ManualMapper.java
│ │ ├── mapstruct
│ │ │ ├── MapStructMapper.java
│ │ │ └── MapStructOrderMapper.java
│ │ ├── modelmapper
│ │ │ └── ModelMapper.java
│ │ ├── orika
│ │ │ └── OrikaMapper.java
│ │ ├── remappe
│ │ │ └── ReMappeMapper.java
│ │ └── selma
│ │ │ ├── SelmaMapper.java
│ │ │ └── SelmaOrderMapper.java
│ │ └── model
│ │ ├── dto
│ │ ├── OrderDTO.java
│ │ └── ProductDTO.java
│ │ └── entity
│ │ ├── Address.java
│ │ ├── Customer.java
│ │ ├── Order.java
│ │ ├── OrderFactory.java
│ │ └── Product.java
└── resources
│ └── com
│ └── javaetmoi
│ └── benchmark
│ └── mapping
│ └── mapper
│ └── dozer
│ └── dozer.xml
└── test
└── java
└── com
└── javaetmoi
└── benchmark
└── mapping
└── mapper
├── AbstractMapperTest.java
├── BullMapperTest.java
├── DatusMapperTest.java
├── DozerMapperTest.java
├── JMapperMapperTest.java
├── ManualMapperTest.java
├── MapStructMapperTest.java
├── ModelMapperTest.java
├── OrikaMapperTest.java
├── ReMapMapperTest.java
└── SelmaMapperTest.java
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | - 'releases/*'
8 | pull_request:
9 | branches:
10 | - '*'
11 |
12 | jobs:
13 | linux:
14 | name: 'Linux (JDK 8)'
15 | runs-on: ubuntu-latest
16 | steps:
17 | - uses: actions/checkout@v4.1.1
18 | - name: 'Set up JDK 8'
19 | uses: actions/setup-java@v1
20 | with:
21 | java-version: 8
22 | - name: 'Test'
23 | shell: bash
24 | run: ./mvnw clean install
25 | benchmark:
26 | name: ${{ matrix.mapper }} Benchmark
27 | needs: linux
28 | runs-on: ubuntu-latest
29 | strategy:
30 | matrix:
31 | mapper: [Manual, MapStruct, Selma, JMapper, datus, Orika, ModelMapper, BULL, Dozer, ReMap]
32 | steps:
33 | - uses: actions/checkout@v4.1.1
34 | - name: 'Set up JDK 8'
35 | uses: actions/setup-java@v1
36 | with:
37 | java-version: 8
38 | - name: 'Install'
39 | shell: bash
40 | run: ./mvnw clean install -DskipTests
41 | - name: 'Benchmark'
42 | shell: bash
43 | run: java -jar target/benchmarks.jar -p type=${{ matrix.mapper }} -rff results_${{ matrix.mapper }}.csv -rf csv
44 | - uses: actions/upload-artifact@v4
45 | name: Upload Benchmark Results
46 | with:
47 | name: benchmark_results_${{ matrix.mapper }}
48 | path: results_${{ matrix.mapper }}.csv
49 | collect_benchmark:
50 | name: Collect benchmarks
51 | needs: benchmark
52 | runs-on: ubuntu-latest
53 | steps:
54 | - uses: actions/checkout@v4.1.1
55 | - uses: actions/download-artifact@v4.1.8
56 | name: Download benchmarks
57 | with:
58 | pattern: benchmark_results_*
59 | merge-multiple: true
60 | - shell: bash
61 | name: Prepare CSV Results
62 | run: |
63 | head -1 results_Manual.csv > results.csv
64 | for mapper in Manual MapStruct Selma JMapper datus Orika ModelMapper BULL Dozer ReMap; do sed 1d results_${mapper}.csv >> results.csv; done
65 | less results.csv
66 | - uses: actions/upload-artifact@v4
67 | name: Upload CSV Results
68 | with:
69 | name: results-csv
70 | path: results.csv
71 | - shell: bash
72 | name: Install gnuplot
73 | run: |
74 | sudo apt-get update
75 | sudo apt-get install gnuplot
76 | - shell: bash
77 | name: Plot Results
78 | run: |
79 | gnuplot -c benchmark.plt
80 | - uses: actions/upload-artifact@v4
81 | name: Upload Plot
82 | with:
83 | name: results-plot
84 | path: results.png
85 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | .project
3 | .classpath
4 | .settings/
5 | .idea/
6 | *.iml
--------------------------------------------------------------------------------
/.mvn/wrapper/MavenWrapperDownloader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2007-present the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | import java.net.*;
17 | import java.io.*;
18 | import java.nio.channels.*;
19 | import java.util.Properties;
20 |
21 | public class MavenWrapperDownloader {
22 |
23 | private static final String WRAPPER_VERSION = "0.5.5";
24 | /**
25 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
26 | */
27 | private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
28 | + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
29 |
30 | /**
31 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
32 | * use instead of the default one.
33 | */
34 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
35 | ".mvn/wrapper/maven-wrapper.properties";
36 |
37 | /**
38 | * Path where the maven-wrapper.jar will be saved to.
39 | */
40 | private static final String MAVEN_WRAPPER_JAR_PATH =
41 | ".mvn/wrapper/maven-wrapper.jar";
42 |
43 | /**
44 | * Name of the property which should be used to override the default download url for the wrapper.
45 | */
46 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
47 |
48 | public static void main(String args[]) {
49 | System.out.println("- Downloader started");
50 | File baseDirectory = new File(args[0]);
51 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
52 |
53 | // If the maven-wrapper.properties exists, read it and check if it contains a custom
54 | // wrapperUrl parameter.
55 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
56 | String url = DEFAULT_DOWNLOAD_URL;
57 | if(mavenWrapperPropertyFile.exists()) {
58 | FileInputStream mavenWrapperPropertyFileInputStream = null;
59 | try {
60 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
61 | Properties mavenWrapperProperties = new Properties();
62 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
63 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
64 | } catch (IOException e) {
65 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
66 | } finally {
67 | try {
68 | if(mavenWrapperPropertyFileInputStream != null) {
69 | mavenWrapperPropertyFileInputStream.close();
70 | }
71 | } catch (IOException e) {
72 | // Ignore ...
73 | }
74 | }
75 | }
76 | System.out.println("- Downloading from: " + url);
77 |
78 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
79 | if(!outputFile.getParentFile().exists()) {
80 | if(!outputFile.getParentFile().mkdirs()) {
81 | System.out.println(
82 | "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
83 | }
84 | }
85 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
86 | try {
87 | downloadFileFromURL(url, outputFile);
88 | System.out.println("Done");
89 | System.exit(0);
90 | } catch (Throwable e) {
91 | System.out.println("- Error downloading");
92 | e.printStackTrace();
93 | System.exit(1);
94 | }
95 | }
96 |
97 | private static void downloadFileFromURL(String urlString, File destination) throws Exception {
98 | if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
99 | String username = System.getenv("MVNW_USERNAME");
100 | char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
101 | Authenticator.setDefault(new Authenticator() {
102 | @Override
103 | protected PasswordAuthentication getPasswordAuthentication() {
104 | return new PasswordAuthentication(username, password);
105 | }
106 | });
107 | }
108 | URL website = new URL(urlString);
109 | ReadableByteChannel rbc;
110 | rbc = Channels.newChannel(website.openStream());
111 | FileOutputStream fos = new FileOutputStream(destination);
112 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
113 | fos.close();
114 | rbc.close();
115 | }
116 |
117 | }
118 |
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arey/java-object-mapper-benchmark/d2d94b4b91e71b9d37ceab3950c85c87a05f338b/.mvn/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.2/apache-maven-3.6.2-bin.zip
2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar
3 |
--------------------------------------------------------------------------------
/benchmark.plt:
--------------------------------------------------------------------------------
1 | # Labels
2 | set title 'Java Object-to-Object mapping frameworks Performance Comparison'
3 | set ylabel 'Object graph mapped per second'
4 | set xlabel 'Mapping Framework'
5 | set xtics nomirror rotate by -45
6 |
7 |
8 | # Ranges
9 | set autoscale
10 |
11 | # Input
12 | set datafile separator ','
13 |
14 | # Output
15 | set terminal png enhanced font "Verdana,9"
16 | set output 'results.png'
17 | set grid
18 | set key off
19 | set boxwidth 0.8 relative
20 |
21 |
22 | # box style
23 | set style line 1 lc rgb '#5C91CD' lt 1
24 | set style fill solid
25 |
26 | # remove top and right borders
27 | set style line 2 lc rgb '#808080' lt 1
28 | set border 3 back ls 2
29 | set tics nomirror
30 |
31 | plot 'results.csv' every ::1 using 0:5:xticlabels(8) with boxes ls 1,\
32 | 'results.csv' every ::1 using 0:($5 + 1500):(sprintf("%d",$5)) with labels offset char 0,1
--------------------------------------------------------------------------------
/model.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arey/java-object-mapper-benchmark/d2d94b4b91e71b9d37ceab3950c85c87a05f338b/model.png
--------------------------------------------------------------------------------
/model.uml:
--------------------------------------------------------------------------------
1 |
2 |
3 | JAVA
4 |
5 |
6 | com.javaetmoi.benchmark.mapping.model.dto.OrderDTO
7 | com.javaetmoi.benchmark.mapping.model.entity.Address
8 | com.javaetmoi.benchmark.mapping.model.entity.Customer
9 | com.javaetmoi.benchmark.mapping.model.entity.Order
10 | com.javaetmoi.benchmark.mapping.model.entity.Product
11 | com.javaetmoi.benchmark.mapping.model.dto.ProductDTO
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | Properties
40 |
41 | All
42 | private
43 |
44 |
45 |
--------------------------------------------------------------------------------
/mvnw:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # ----------------------------------------------------------------------------
3 | # Licensed to the Apache Software Foundation (ASF) under one
4 | # or more contributor license agreements. See the NOTICE file
5 | # distributed with this work for additional information
6 | # regarding copyright ownership. The ASF licenses this file
7 | # to you under the Apache License, Version 2.0 (the
8 | # "License"); you may not use this file except in compliance
9 | # with the License. You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing,
14 | # software distributed under the License is distributed on an
15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | # KIND, either express or implied. See the License for the
17 | # specific language governing permissions and limitations
18 | # under the License.
19 | # ----------------------------------------------------------------------------
20 |
21 | # ----------------------------------------------------------------------------
22 | # Maven2 Start Up Batch script
23 | #
24 | # Required ENV vars:
25 | # ------------------
26 | # JAVA_HOME - location of a JDK home dir
27 | #
28 | # Optional ENV vars
29 | # -----------------
30 | # M2_HOME - location of maven2's installed home dir
31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven
32 | # e.g. to debug Maven itself, use
33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files
35 | # ----------------------------------------------------------------------------
36 |
37 | if [ -z "$MAVEN_SKIP_RC" ] ; then
38 |
39 | if [ -f /etc/mavenrc ] ; then
40 | . /etc/mavenrc
41 | fi
42 |
43 | if [ -f "$HOME/.mavenrc" ] ; then
44 | . "$HOME/.mavenrc"
45 | fi
46 |
47 | fi
48 |
49 | # OS specific support. $var _must_ be set to either true or false.
50 | cygwin=false;
51 | darwin=false;
52 | mingw=false
53 | case "`uname`" in
54 | CYGWIN*) cygwin=true ;;
55 | MINGW*) mingw=true;;
56 | Darwin*) darwin=true
57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
59 | if [ -z "$JAVA_HOME" ]; then
60 | if [ -x "/usr/libexec/java_home" ]; then
61 | export JAVA_HOME="`/usr/libexec/java_home`"
62 | else
63 | export JAVA_HOME="/Library/Java/Home"
64 | fi
65 | fi
66 | ;;
67 | esac
68 |
69 | if [ -z "$JAVA_HOME" ] ; then
70 | if [ -r /etc/gentoo-release ] ; then
71 | JAVA_HOME=`java-config --jre-home`
72 | fi
73 | fi
74 |
75 | if [ -z "$M2_HOME" ] ; then
76 | ## resolve links - $0 may be a link to maven's home
77 | PRG="$0"
78 |
79 | # need this for relative symlinks
80 | while [ -h "$PRG" ] ; do
81 | ls=`ls -ld "$PRG"`
82 | link=`expr "$ls" : '.*-> \(.*\)$'`
83 | if expr "$link" : '/.*' > /dev/null; then
84 | PRG="$link"
85 | else
86 | PRG="`dirname "$PRG"`/$link"
87 | fi
88 | done
89 |
90 | saveddir=`pwd`
91 |
92 | M2_HOME=`dirname "$PRG"`/..
93 |
94 | # make it fully qualified
95 | M2_HOME=`cd "$M2_HOME" && pwd`
96 |
97 | cd "$saveddir"
98 | # echo Using m2 at $M2_HOME
99 | fi
100 |
101 | # For Cygwin, ensure paths are in UNIX format before anything is touched
102 | if $cygwin ; then
103 | [ -n "$M2_HOME" ] &&
104 | M2_HOME=`cygpath --unix "$M2_HOME"`
105 | [ -n "$JAVA_HOME" ] &&
106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
107 | [ -n "$CLASSPATH" ] &&
108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
109 | fi
110 |
111 | # For Mingw, ensure paths are in UNIX format before anything is touched
112 | if $mingw ; then
113 | [ -n "$M2_HOME" ] &&
114 | M2_HOME="`(cd "$M2_HOME"; pwd)`"
115 | [ -n "$JAVA_HOME" ] &&
116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
117 | fi
118 |
119 | if [ -z "$JAVA_HOME" ]; then
120 | javaExecutable="`which javac`"
121 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
122 | # readlink(1) is not available as standard on Solaris 10.
123 | readLink=`which readlink`
124 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
125 | if $darwin ; then
126 | javaHome="`dirname \"$javaExecutable\"`"
127 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
128 | else
129 | javaExecutable="`readlink -f \"$javaExecutable\"`"
130 | fi
131 | javaHome="`dirname \"$javaExecutable\"`"
132 | javaHome=`expr "$javaHome" : '\(.*\)/bin'`
133 | JAVA_HOME="$javaHome"
134 | export JAVA_HOME
135 | fi
136 | fi
137 | fi
138 |
139 | if [ -z "$JAVACMD" ] ; then
140 | if [ -n "$JAVA_HOME" ] ; then
141 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
142 | # IBM's JDK on AIX uses strange locations for the executables
143 | JAVACMD="$JAVA_HOME/jre/sh/java"
144 | else
145 | JAVACMD="$JAVA_HOME/bin/java"
146 | fi
147 | else
148 | JAVACMD="`which java`"
149 | fi
150 | fi
151 |
152 | if [ ! -x "$JAVACMD" ] ; then
153 | echo "Error: JAVA_HOME is not defined correctly." >&2
154 | echo " We cannot execute $JAVACMD" >&2
155 | exit 1
156 | fi
157 |
158 | if [ -z "$JAVA_HOME" ] ; then
159 | echo "Warning: JAVA_HOME environment variable is not set."
160 | fi
161 |
162 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
163 |
164 | # traverses directory structure from process work directory to filesystem root
165 | # first directory with .mvn subdirectory is considered project base directory
166 | find_maven_basedir() {
167 |
168 | if [ -z "$1" ]
169 | then
170 | echo "Path not specified to find_maven_basedir"
171 | return 1
172 | fi
173 |
174 | basedir="$1"
175 | wdir="$1"
176 | while [ "$wdir" != '/' ] ; do
177 | if [ -d "$wdir"/.mvn ] ; then
178 | basedir=$wdir
179 | break
180 | fi
181 | # workaround for JBEAP-8937 (on Solaris 10/Sparc)
182 | if [ -d "${wdir}" ]; then
183 | wdir=`cd "$wdir/.."; pwd`
184 | fi
185 | # end of workaround
186 | done
187 | echo "${basedir}"
188 | }
189 |
190 | # concatenates all lines of a file
191 | concat_lines() {
192 | if [ -f "$1" ]; then
193 | echo "$(tr -s '\n' ' ' < "$1")"
194 | fi
195 | }
196 |
197 | BASE_DIR=`find_maven_basedir "$(pwd)"`
198 | if [ -z "$BASE_DIR" ]; then
199 | exit 1;
200 | fi
201 |
202 | ##########################################################################################
203 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
204 | # This allows using the maven wrapper in projects that prohibit checking in binary data.
205 | ##########################################################################################
206 | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
207 | if [ "$MVNW_VERBOSE" = true ]; then
208 | echo "Found .mvn/wrapper/maven-wrapper.jar"
209 | fi
210 | else
211 | if [ "$MVNW_VERBOSE" = true ]; then
212 | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
213 | fi
214 | if [ -n "$MVNW_REPOURL" ]; then
215 | jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
216 | else
217 | jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
218 | fi
219 | while IFS="=" read key value; do
220 | case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
221 | esac
222 | done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
223 | if [ "$MVNW_VERBOSE" = true ]; then
224 | echo "Downloading from: $jarUrl"
225 | fi
226 | wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
227 | if $cygwin; then
228 | wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
229 | fi
230 |
231 | if command -v wget > /dev/null; then
232 | if [ "$MVNW_VERBOSE" = true ]; then
233 | echo "Found wget ... using wget"
234 | fi
235 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
236 | wget "$jarUrl" -O "$wrapperJarPath"
237 | else
238 | wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
239 | fi
240 | elif command -v curl > /dev/null; then
241 | if [ "$MVNW_VERBOSE" = true ]; then
242 | echo "Found curl ... using curl"
243 | fi
244 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
245 | curl -o "$wrapperJarPath" "$jarUrl" -f
246 | else
247 | curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
248 | fi
249 |
250 | else
251 | if [ "$MVNW_VERBOSE" = true ]; then
252 | echo "Falling back to using Java to download"
253 | fi
254 | javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
255 | # For Cygwin, switch paths to Windows format before running javac
256 | if $cygwin; then
257 | javaClass=`cygpath --path --windows "$javaClass"`
258 | fi
259 | if [ -e "$javaClass" ]; then
260 | if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
261 | if [ "$MVNW_VERBOSE" = true ]; then
262 | echo " - Compiling MavenWrapperDownloader.java ..."
263 | fi
264 | # Compiling the Java class
265 | ("$JAVA_HOME/bin/javac" "$javaClass")
266 | fi
267 | if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
268 | # Running the downloader
269 | if [ "$MVNW_VERBOSE" = true ]; then
270 | echo " - Running MavenWrapperDownloader.java ..."
271 | fi
272 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
273 | fi
274 | fi
275 | fi
276 | fi
277 | ##########################################################################################
278 | # End of extension
279 | ##########################################################################################
280 |
281 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
282 | if [ "$MVNW_VERBOSE" = true ]; then
283 | echo $MAVEN_PROJECTBASEDIR
284 | fi
285 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
286 |
287 | # For Cygwin, switch paths to Windows format before running java
288 | if $cygwin; then
289 | [ -n "$M2_HOME" ] &&
290 | M2_HOME=`cygpath --path --windows "$M2_HOME"`
291 | [ -n "$JAVA_HOME" ] &&
292 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
293 | [ -n "$CLASSPATH" ] &&
294 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
295 | [ -n "$MAVEN_PROJECTBASEDIR" ] &&
296 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
297 | fi
298 |
299 | # Provide a "standardized" way to retrieve the CLI args that will
300 | # work with both Windows and non-Windows executions.
301 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
302 | export MAVEN_CMD_LINE_ARGS
303 |
304 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
305 |
306 | exec "$JAVACMD" \
307 | $MAVEN_OPTS \
308 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
309 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
310 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
311 |
--------------------------------------------------------------------------------
/mvnw.cmd:
--------------------------------------------------------------------------------
1 | @REM ----------------------------------------------------------------------------
2 | @REM Licensed to the Apache Software Foundation (ASF) under one
3 | @REM or more contributor license agreements. See the NOTICE file
4 | @REM distributed with this work for additional information
5 | @REM regarding copyright ownership. The ASF licenses this file
6 | @REM to you under the Apache License, Version 2.0 (the
7 | @REM "License"); you may not use this file except in compliance
8 | @REM with the License. You may obtain a copy of the License at
9 | @REM
10 | @REM http://www.apache.org/licenses/LICENSE-2.0
11 | @REM
12 | @REM Unless required by applicable law or agreed to in writing,
13 | @REM software distributed under the License is distributed on an
14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | @REM KIND, either express or implied. See the License for the
16 | @REM specific language governing permissions and limitations
17 | @REM under the License.
18 | @REM ----------------------------------------------------------------------------
19 |
20 | @REM ----------------------------------------------------------------------------
21 | @REM Maven2 Start Up Batch script
22 | @REM
23 | @REM Required ENV vars:
24 | @REM JAVA_HOME - location of a JDK home dir
25 | @REM
26 | @REM Optional ENV vars
27 | @REM M2_HOME - location of maven2's installed home dir
28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
31 | @REM e.g. to debug Maven itself, use
32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
34 | @REM ----------------------------------------------------------------------------
35 |
36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
37 | @echo off
38 | @REM set title of command window
39 | title %0
40 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
42 |
43 | @REM set %HOME% to equivalent of $HOME
44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
45 |
46 | @REM Execute a user defined script before this one
47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending
49 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
50 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
51 | :skipRcPre
52 |
53 | @setlocal
54 |
55 | set ERROR_CODE=0
56 |
57 | @REM To isolate internal variables from possible post scripts, we use another setlocal
58 | @setlocal
59 |
60 | @REM ==== START VALIDATION ====
61 | if not "%JAVA_HOME%" == "" goto OkJHome
62 |
63 | echo.
64 | echo Error: JAVA_HOME not found in your environment. >&2
65 | echo Please set the JAVA_HOME variable in your environment to match the >&2
66 | echo location of your Java installation. >&2
67 | echo.
68 | goto error
69 |
70 | :OkJHome
71 | if exist "%JAVA_HOME%\bin\java.exe" goto init
72 |
73 | echo.
74 | echo Error: JAVA_HOME is set to an invalid directory. >&2
75 | echo JAVA_HOME = "%JAVA_HOME%" >&2
76 | echo Please set the JAVA_HOME variable in your environment to match the >&2
77 | echo location of your Java installation. >&2
78 | echo.
79 | goto error
80 |
81 | @REM ==== END VALIDATION ====
82 |
83 | :init
84 |
85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
86 | @REM Fallback to current working directory if not found.
87 |
88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
90 |
91 | set EXEC_DIR=%CD%
92 | set WDIR=%EXEC_DIR%
93 | :findBaseDir
94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound
95 | cd ..
96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound
97 | set WDIR=%CD%
98 | goto findBaseDir
99 |
100 | :baseDirFound
101 | set MAVEN_PROJECTBASEDIR=%WDIR%
102 | cd "%EXEC_DIR%"
103 | goto endDetectBaseDir
104 |
105 | :baseDirNotFound
106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
107 | cd "%EXEC_DIR%"
108 |
109 | :endDetectBaseDir
110 |
111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
112 |
113 | @setlocal EnableExtensions EnableDelayedExpansion
114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
116 |
117 | :endReadAdditionalConfig
118 |
119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
122 |
123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
124 |
125 | FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
126 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
127 | )
128 |
129 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
130 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data.
131 | if exist %WRAPPER_JAR% (
132 | if "%MVNW_VERBOSE%" == "true" (
133 | echo Found %WRAPPER_JAR%
134 | )
135 | ) else (
136 | if not "%MVNW_REPOURL%" == "" (
137 | SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
138 | )
139 | if "%MVNW_VERBOSE%" == "true" (
140 | echo Couldn't find %WRAPPER_JAR%, downloading it ...
141 | echo Downloading from: %DOWNLOAD_URL%
142 | )
143 |
144 | powershell -Command "&{"^
145 | "$webclient = new-object System.Net.WebClient;"^
146 | "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
147 | "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
148 | "}"^
149 | "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
150 | "}"
151 | if "%MVNW_VERBOSE%" == "true" (
152 | echo Finished downloading %WRAPPER_JAR%
153 | )
154 | )
155 | @REM End of extension
156 |
157 | @REM Provide a "standardized" way to retrieve the CLI args that will
158 | @REM work with both Windows and non-Windows executions.
159 | set MAVEN_CMD_LINE_ARGS=%*
160 |
161 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
162 | if ERRORLEVEL 1 goto error
163 | goto end
164 |
165 | :error
166 | set ERROR_CODE=1
167 |
168 | :end
169 | @endlocal & set ERROR_CODE=%ERROR_CODE%
170 |
171 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
172 | @REM check for post script, once with legacy .bat ending and once with .cmd ending
173 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
174 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
175 | :skipRcPost
176 |
177 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
178 | if "%MAVEN_BATCH_PAUSE%" == "on" pause
179 |
180 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
181 |
182 | exit /B %ERROR_CODE%
183 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 | com.javaetmoi.benchmark
6 | java-object-mapper-benchmark
7 | 1.0.0-SNAPSHOT
8 | jar
9 |
10 | JMH benchmark of Object-to-Object mapping frameworks/
11 |
12 |
13 | 3.0
14 |
15 |
16 |
17 | 1.5.4
18 | 6.5.2
19 | 3.2.0
20 | 1.5.5.Final
21 | 1.0
22 | 1.6.1.CR2
23 | 1.37
24 | 1.7.3-jdk8
25 | 1.5.0
26 | 4.3.2
27 | 5.9.2
28 | 2.0.9
29 |
30 | UTF-8
31 | 1.8
32 | benchmarks
33 |
34 |
35 |
36 |
37 | org.openjdk.jmh
38 | jmh-core
39 | ${version.jmh}
40 |
41 |
42 | org.openjdk.jmh
43 | jmh-generator-annprocess
44 | ${version.jmh}
45 | provided
46 |
47 |
48 |
49 | ma.glasnost.orika
50 | orika-core
51 | ${version.orika}
52 |
53 |
54 |
55 | com.github.dozermapper
56 | dozer-core
57 | ${version.dozer}
58 |
59 |
60 |
61 | org.modelmapper
62 | modelmapper
63 | ${version.modelmapper}
64 |
65 |
66 |
67 | org.mapstruct
68 | mapstruct
69 | ${version.mapstruct}
70 |
71 |
72 | org.mapstruct
73 | mapstruct-processor
74 | ${version.mapstruct}
75 |
76 |
77 |
78 | fr.xebia.extras
79 | selma
80 | ${version.selma}
81 |
82 |
83 |
84 | com.hotels.beans
85 | bull-bean-transformer
86 | ${version.bull}
87 |
88 |
89 |
90 | com.github.roookeee
91 | datus
92 | ${version.datus}
93 |
94 |
95 |
96 | fr.xebia.extras
97 | selma-processor
98 | ${version.selma}
99 | provided
100 |
101 |
102 |
103 | com.googlecode.jmapper-framework
104 | jmapper-core
105 | ${version.jmapper}
106 |
107 |
108 |
109 | com.remondis
110 | remap
111 | ${version.remap}
112 |
113 |
114 |
115 | org.junit.jupiter
116 | junit-jupiter-engine
117 | ${version.junit}
118 | test
119 |
120 |
121 |
122 | org.slf4j
123 | slf4j-nop
124 | ${version.slf4j}
125 |
126 |
127 |
128 | org.slf4j
129 | jcl-over-slf4j
130 | ${version.slf4j}
131 |
132 |
133 |
134 | javax.xml.bind
135 | jaxb-api
136 | 2.2.8
137 |
138 |
139 |
140 |
141 |
142 |
143 | org.apache.maven.plugins
144 | maven-compiler-plugin
145 | 3.11.0
146 |
147 | ${javac.target}
148 | ${javac.target}
149 | ${javac.target}
150 |
151 |
152 |
153 | org.apache.maven.plugins
154 | maven-shade-plugin
155 | 3.5.1
156 |
157 |
158 | package
159 |
160 | shade
161 |
162 |
163 | ${uberjar.name}
164 |
165 |
167 | org.openjdk.jmh.Main
168 |
169 |
170 |
171 |
172 |
176 | *:*
177 |
178 | META-INF/*.SF
179 | META-INF/*.DSA
180 | META-INF/*.RSA
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 | maven-clean-plugin
193 | 3.3.2
194 |
195 |
196 | maven-deploy-plugin
197 | 3.1.1
198 |
199 |
200 | maven-install-plugin
201 | 3.1.1
202 |
203 |
204 | maven-jar-plugin
205 | 3.3.0
206 |
207 |
208 | maven-javadoc-plugin
209 | 3.6.2
210 |
211 |
212 | maven-resources-plugin
213 | 3.3.1
214 |
215 |
216 | maven-site-plugin
217 | 3.7.1
218 |
219 |
220 | maven-source-plugin
221 | 3.3.0
222 |
223 |
224 | maven-surefire-plugin
225 | 3.2.3
226 |
227 |
228 |
229 |
230 |
231 |
232 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # Object-to-object mapping framework microbenchmark
2 | 
3 |
4 | Multi-layered applications often require to map between different object models (e.g. DTOs and entities).
5 | Writing such boiler plate mapping code is a tedious and error-prone task.
6 | A lot of object-to-object mapping Java frameworks aims to simplify this work and automate it.
7 | Some uses code instrospection (eg. Dozer). Other uses code generation (ex: MapStruct).
8 | This micro-benchmark compares performance of 9 frameworks. Results could be compared to the benchmark of a code written manually.
9 |
10 | Benchmark are powered by a tool called [JMH](http://openjdk.java.net/projects/code-tools/jmh/) or also known as "Java Microbenchmarking Harness".
11 | JMH is developed by the OpenJDK team.
12 |
13 | ## Benchmarked object to object mapper frameworks
14 |
15 | - [Dozer](https://github.com/DozerMapper/dozer)
16 | - [MapStruct](http://mapstruct.org/)
17 | - [ModelMapper](http://modelmapper.org/)
18 | - [Selma](http://www.selma-java.org/)
19 | - [Orika](https://github.com/orika-mapper/orika)
20 | - [JMapper](https://github.com/jmapper-framework/jmapper-core)
21 | - [BULL](https://github.com/HotelsDotCom/bull)
22 | - [datus](https://github.com/roookeee/datus)
23 | - [ReMap](https://github.com/remondis-it/remap)
24 |
25 | ## Contributing to benchmark
26 |
27 |
28 | Github is for social coding platform: if you want to add another mapping framework or optimize an existing one, we encourage contributions
29 | through pull requests from [forks of this repository](http://help.github.com/forking/).
30 | If you want to contribute code this way, please reference a GitHub ticket as well covering the specific issue you are addressing.
31 | To add a new mapper, please add a unit test that extends the `AbstractMapperTest` class and declare your mapper into the `MapperBenchmark` class.
32 |
33 |
34 | ## Data model
35 |
36 | The data model used by this benchmark is very basic. It comes from the [Comparison](https://github.com/jhalterman/modelmapper/blob/master/core/src/test/java/org/modelmapper/performance/Comparison.java) class from the ModelMapper framework.
37 | It includes combinations which usually appear in Java Beans, such as:
38 |
39 | * Object types
40 | * Collections
41 |
42 | 
43 |
44 | ## Launch the benchmark
45 |
46 | _Pre-requisites: Maven 3.x and a JDK 8 (or above)_
47 |
48 | ``git clone git://github.com/arey/java-object-mapper-benchmark.git``
49 |
50 | ``mvn clean install``
51 |
52 | ``java -jar target/benchmarks.jar``
53 |
54 | Optional: To run a single benchmark, such as MapStruct, use `java -jar target/benchmarks.jar -p type=MapStruct`
55 |
56 | ## Interpreting the Results
57 |
58 | The benchmarks measure throughput, given in "ops/time". The time unit used is seconds.
59 | Generally, the score represents the number of graph object mapped per second; the higher the score, the better.
60 |
61 | ## Results
62 |
63 | Tests has been performed on:
64 |
65 | * OS: macOS High Sierra
66 | * CPU: 3.1 GHz Intel Core i7, 2 cores, L2 Cache (per Core): 256 KB, L3 Cache: 4 MB
67 | * RAM: 16 GB 1867 MHz DDR3
68 | * JVM: Oracle 1.8.0_74-b02 64 bits
69 |
70 | | Benchmark | Mode | Samples | Score | Margin error (+/-) | Units |
71 | |----------------|-------|---------|-------------|--------------------|-------|
72 | | Manual | thrpt | 200 | 26 978 437 | 615 002 | ops/s |
73 | | MapStruct | thrpt | 200 | 28 039 597 | 199 255 | ops/s |
74 | | Selma | thrpt | 200 | 27 518 789 | 238 602 | ops/s |
75 | | JMapper | thrpt | 200 | 24 531 754 | 123 945 | ops/s |
76 | | Orika | thrpt | 200 | 4 565 378 | 24 947 | ops/s |
77 | | ModelMapper | thrpt | 200 | 184 304 | 12 777 | ops/s |
78 | | Dozer | thrpt | 200 | 89 860 | 462 | ops/s |
79 | | BULL | thrpt | 200 | 178 027 | 679 | ops/s |
80 | | datus | thrpt | 200 | 8 230 775 | 59 673 | ops/s |
81 |
82 |
83 | 
84 |
85 |
86 | ## Documentation
87 |
88 | * [Micro-benchmark of Java mapping object frameworks](http://javaetmoi.com/2015/09/benchmark-frameworks-java-mapping-objet/) (french article)
89 |
90 | ## Generating plot
91 |
92 | 1. Run benchmark while exporting results to csv with `java -jar target/benchmarks.jar -rff results.csv -rf csv`
93 | 2. Use gnuplot to generate plot with `gnuplot benchmark.plt`. This will output `results.png`.
94 |
95 | ## Credits
96 |
97 | * Uses [Maven](http://maven.apache.org/) as a build tool
98 | * Uses [JMH](http://openjdk.java.net/projects/code-tools/jmh/) for Java Microbenchmarking Harness
99 |
--------------------------------------------------------------------------------
/results.csv:
--------------------------------------------------------------------------------
1 | "Benchmark","Mode","Threads","Samples","Score","Score Error (99,9%)","Unit","Param: type"
2 | "com.javaetmoi.benchmark.MapperBenchmark.mapper","thrpt",1,200,"26978437,866517","615002,224893","ops/s",Manual
3 | "com.javaetmoi.benchmark.MapperBenchmark.mapper","thrpt",1,200,"28039597,815878","199255,230955","ops/s",MapStruct
4 | "com.javaetmoi.benchmark.MapperBenchmark.mapper","thrpt",1,200,"27518789,645248","238602,253918","ops/s",Selma
5 | "com.javaetmoi.benchmark.MapperBenchmark.mapper","thrpt",1,200,"24531754,377299","123945,801129","ops/s",JMapper
6 | "com.javaetmoi.benchmark.MapperBenchmark.mapper","thrpt",1,200,"8230775,891415","59673,825530","ops/s",datus
7 | "com.javaetmoi.benchmark.MapperBenchmark.mapper","thrpt",1,200,"4565378,535779","24947,644996","ops/s",Orika
8 | "com.javaetmoi.benchmark.MapperBenchmark.mapper","thrpt",1,200,"184304,271986","1277,567799","ops/s",ModelMapper
9 | "com.javaetmoi.benchmark.MapperBenchmark.mapper","thrpt",1,200,"178027,846","679,915001","ops/s",BULL
10 | "com.javaetmoi.benchmark.MapperBenchmark.mapper","thrpt",1,200,"89860,325285","462,290433","ops/s",Dozer
11 |
12 |
13 |
--------------------------------------------------------------------------------
/results.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arey/java-object-mapper-benchmark/d2d94b4b91e71b9d37ceab3950c85c87a05f338b/results.png
--------------------------------------------------------------------------------
/src/main/java/com/javaetmoi/benchmark/MapperBenchmark.java:
--------------------------------------------------------------------------------
1 | package com.javaetmoi.benchmark;
2 |
3 | import com.javaetmoi.benchmark.mapping.mapper.OrderMapper;
4 | import com.javaetmoi.benchmark.mapping.mapper.bull.BullMapper;
5 | import com.javaetmoi.benchmark.mapping.mapper.datus.DatusMapper;
6 | import com.javaetmoi.benchmark.mapping.mapper.dozer.DozerMapper;
7 | import com.javaetmoi.benchmark.mapping.mapper.jmapper.JMapperMapper;
8 | import com.javaetmoi.benchmark.mapping.mapper.manual.ManualMapper;
9 | import com.javaetmoi.benchmark.mapping.mapper.mapstruct.MapStructMapper;
10 | import com.javaetmoi.benchmark.mapping.mapper.modelmapper.ModelMapper;
11 | import com.javaetmoi.benchmark.mapping.mapper.orika.OrikaMapper;
12 | import com.javaetmoi.benchmark.mapping.mapper.remappe.ReMappeMapper;
13 | import com.javaetmoi.benchmark.mapping.mapper.selma.SelmaMapper;
14 | import com.javaetmoi.benchmark.mapping.model.dto.OrderDTO;
15 | import com.javaetmoi.benchmark.mapping.model.entity.Order;
16 | import com.javaetmoi.benchmark.mapping.model.entity.OrderFactory;
17 | import org.openjdk.jmh.annotations.*;
18 | import org.openjdk.jmh.results.Result;
19 | import org.openjdk.jmh.results.RunResult;
20 | import org.openjdk.jmh.results.format.ResultFormatType;
21 | import org.openjdk.jmh.runner.Runner;
22 | import org.openjdk.jmh.runner.options.Options;
23 | import org.openjdk.jmh.runner.options.OptionsBuilder;
24 |
25 | import java.util.Collection;
26 |
27 | @State(Scope.Benchmark)
28 | public class MapperBenchmark {
29 |
30 | @Param({"Manual", "MapStruct", "Selma", "JMapper", "datus", "Orika", "ModelMapper", "BULL", "Dozer", "ReMap"})
31 | private String type;
32 |
33 | private OrderMapper mapper;
34 | private Order order;
35 |
36 | @Setup(Level.Trial)
37 | public void setup() {
38 | switch (type) {
39 | case "Dozer":
40 | mapper = new DozerMapper();
41 | break;
42 | case "Orika":
43 | mapper = new OrikaMapper();
44 | break;
45 | case "ModelMapper":
46 | mapper = new ModelMapper();
47 | break;
48 | case "MapStruct":
49 | mapper = new MapStructMapper();
50 | break;
51 | case "Selma":
52 | mapper = new SelmaMapper();
53 | break;
54 | case "JMapper":
55 | mapper = new JMapperMapper();
56 | break;
57 | case "Manual":
58 | mapper = new ManualMapper();
59 | break;
60 | case "BULL":
61 | mapper = new BullMapper();
62 | break;
63 | case "datus":
64 | mapper = new DatusMapper();
65 | break;
66 | case "ReMap":
67 | mapper = new ReMappeMapper();
68 | break;
69 | default:
70 | throw new IllegalStateException("Unknown type: " + type);
71 | }
72 | }
73 |
74 | @Setup(Level.Iteration)
75 | public void preInit() {
76 | order = OrderFactory.buildOrder();
77 | }
78 |
79 | @Benchmark
80 | public OrderDTO mapper() {
81 | return mapper.map(order);
82 | }
83 |
84 | public static void main(String... args) throws Exception {
85 | Options opts = new OptionsBuilder()
86 | .include(MapperBenchmark.class.getSimpleName())
87 | .warmupIterations(5)
88 | .measurementIterations(5)
89 | .jvmArgs("-server")
90 | .forks(1)
91 | .resultFormat(ResultFormatType.TEXT)
92 | .build();
93 |
94 | Collection results = new Runner(opts).run();
95 | for (RunResult result : results) {
96 | Result> r = result.getPrimaryResult();
97 | System.out.println("API replied benchmark score: "
98 | + r.getScore() + " "
99 | + r.getScoreUnit() + " over "
100 | + r.getStatistics().getN() + " iterations");
101 | }
102 | }
103 |
104 | }
105 |
--------------------------------------------------------------------------------
/src/main/java/com/javaetmoi/benchmark/mapping/mapper/OrderMapper.java:
--------------------------------------------------------------------------------
1 | package com.javaetmoi.benchmark.mapping.mapper;
2 |
3 | import com.javaetmoi.benchmark.mapping.model.dto.OrderDTO;
4 | import com.javaetmoi.benchmark.mapping.model.entity.Order;
5 |
6 | public interface OrderMapper {
7 | OrderDTO map(Order source);
8 | }
--------------------------------------------------------------------------------
/src/main/java/com/javaetmoi/benchmark/mapping/mapper/bull/BullMapper.java:
--------------------------------------------------------------------------------
1 | package com.javaetmoi.benchmark.mapping.mapper.bull;
2 |
3 | import com.hotels.beans.BeanUtils;
4 | import com.hotels.beans.transformer.BeanTransformer;
5 | import com.hotels.transformer.model.FieldMapping;
6 | import com.javaetmoi.benchmark.mapping.mapper.OrderMapper;
7 | import com.javaetmoi.benchmark.mapping.model.dto.OrderDTO;
8 | import com.javaetmoi.benchmark.mapping.model.entity.Order;
9 |
10 | /**
11 | * BULL mapper.
12 | * For more details see: https://github.com/HotelsDotCom/bull.
13 | */
14 | public class BullMapper implements OrderMapper {
15 | private final BeanTransformer transformer;
16 |
17 | public BullMapper() {
18 | FieldMapping[] fieldMappings = new FieldMapping[] {
19 | new FieldMapping("customer.name", "customerName"),
20 | new FieldMapping("customer.billingAddress.city", "billingCity"),
21 | new FieldMapping("customer.billingAddress.street", "billingStreetAddress"),
22 | new FieldMapping("customer.shippingAddress.city", "shippingCity"),
23 | new FieldMapping("customer.shippingAddress.street", "shippingStreetAddress")
24 | };
25 | this.transformer = new BeanUtils().getTransformer().withFieldMapping(fieldMappings);
26 | }
27 |
28 | @Override
29 | public OrderDTO map(Order source) {
30 | return transformer.transform(source, OrderDTO.class);
31 | }
32 | }
--------------------------------------------------------------------------------
/src/main/java/com/javaetmoi/benchmark/mapping/mapper/datus/DatusMapper.java:
--------------------------------------------------------------------------------
1 | package com.javaetmoi.benchmark.mapping.mapper.datus;
2 |
3 | import com.github.roookeee.datus.api.Datus;
4 | import com.github.roookeee.datus.api.Mapper;
5 | import com.github.roookeee.datus.immutable.ConstructorParameter;
6 | import com.javaetmoi.benchmark.mapping.mapper.OrderMapper;
7 | import com.javaetmoi.benchmark.mapping.model.dto.OrderDTO;
8 | import com.javaetmoi.benchmark.mapping.model.dto.ProductDTO;
9 | import com.javaetmoi.benchmark.mapping.model.entity.Address;
10 | import com.javaetmoi.benchmark.mapping.model.entity.Customer;
11 | import com.javaetmoi.benchmark.mapping.model.entity.Order;
12 | import com.javaetmoi.benchmark.mapping.model.entity.Product;
13 |
14 | public class DatusMapper implements OrderMapper {
15 | private static final Mapper productMapper = Datus.forTypes(Product.class, ProductDTO.class)
16 | .immutable((String name) -> new ProductDTO(name))
17 | .from(Product::getName).to(ConstructorParameter::bind)
18 | .build();
19 |
20 | private static final Mapper orderMapper = Datus.forTypes(Order.class, OrderDTO.class)
21 | .mutable(OrderDTO::new)
22 | .from(Order::getCustomer).nullsafe()
23 | .map(Customer::getName).into(OrderDTO::setCustomerName)
24 | .from(Order::getCustomer).nullsafe()
25 | .map(Customer::getBillingAddress).map(Address::getCity).into(OrderDTO::setBillingCity)
26 | .from(Order::getCustomer).nullsafe()
27 | .map(Customer::getBillingAddress).map(Address::getStreet).into(OrderDTO::setBillingStreetAddress)
28 | .from(Order::getCustomer).nullsafe()
29 | .map(Customer::getShippingAddress).map(Address::getCity).into(OrderDTO::setShippingCity)
30 | .from(Order::getCustomer).nullsafe()
31 | .map(Customer::getShippingAddress).map(Address::getStreet).into(OrderDTO::setShippingStreetAddress)
32 | .from(Order::getProducts).nullsafe()
33 | .map(productMapper::convert).into(OrderDTO::setProducts)
34 | .build();
35 |
36 | @Override
37 | public OrderDTO map(Order source) {
38 | return orderMapper.convert(source);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/com/javaetmoi/benchmark/mapping/mapper/dozer/DozerMapper.java:
--------------------------------------------------------------------------------
1 | package com.javaetmoi.benchmark.mapping.mapper.dozer;
2 |
3 | import com.github.dozermapper.core.DozerBeanMapperBuilder;
4 | import com.github.dozermapper.core.Mapper;
5 | import com.javaetmoi.benchmark.mapping.mapper.OrderMapper;
6 | import com.javaetmoi.benchmark.mapping.model.dto.OrderDTO;
7 | import com.javaetmoi.benchmark.mapping.model.entity.Order;
8 |
9 | import java.util.Collections;
10 |
11 | public class DozerMapper implements OrderMapper {
12 |
13 | private Mapper beanMapper;
14 |
15 | public DozerMapper() {
16 | beanMapper = DozerBeanMapperBuilder
17 | .create()
18 | .withMappingFiles(Collections.singletonList("com/javaetmoi/benchmark/mapping/mapper/dozer/dozer.xml"))
19 | .build();
20 | }
21 |
22 | @Override
23 | public OrderDTO map(Order source) {
24 | return beanMapper.map(source, OrderDTO.class);
25 | }
26 | }
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/src/main/java/com/javaetmoi/benchmark/mapping/mapper/jmapper/JMapperMapper.java:
--------------------------------------------------------------------------------
1 | package com.javaetmoi.benchmark.mapping.mapper.jmapper;
2 |
3 | import com.googlecode.jmapper.JMapper;
4 | import com.googlecode.jmapper.api.JMapperAPI;
5 | import com.javaetmoi.benchmark.mapping.mapper.OrderMapper;
6 | import com.javaetmoi.benchmark.mapping.model.dto.OrderDTO;
7 | import com.javaetmoi.benchmark.mapping.model.dto.ProductDTO;
8 | import com.javaetmoi.benchmark.mapping.model.entity.Address;
9 | import com.javaetmoi.benchmark.mapping.model.entity.Customer;
10 | import com.javaetmoi.benchmark.mapping.model.entity.Order;
11 |
12 | import static com.googlecode.jmapper.api.JMapperAPI.attribute;
13 | import static com.googlecode.jmapper.api.JMapperAPI.mappedClass;
14 |
15 | public class JMapperMapper implements OrderMapper {
16 |
17 | JMapper mapper;
18 |
19 | public JMapperMapper() {
20 |
21 | JMapperAPI api = new JMapperAPI()
22 | .add(mappedClass(OrderDTO.class)
23 | .add(attribute("shippingStreetAddress").value("${customer.shippingAddress.street}"))
24 | .add(attribute("shippingCity").value("${customer.shippingAddress.city}"))
25 | .add(attribute("billingStreetAddress").value("${customer.billingAddress.street}"))
26 | .add(attribute("billingCity").value("${customer.billingAddress.city}"))
27 | .add(attribute("products").value("products"))
28 | .add(attribute("customerName").value("${customer.name}")))
29 | .add(mappedClass(ProductDTO.class)
30 | .add(attribute("name").value("name")));
31 |
32 | mapper = new JMapper(OrderDTO.class, Order.class, api);
33 | }
34 |
35 | @Override
36 | public OrderDTO map(Order source) {
37 | // Waiting https://github.com/jmapper-framework/jmapper-core/issues/43
38 | // By waiting: hand mapping with by practice 'cause we are changing the source object.
39 | if (source.getCustomer() == null) {
40 | source.setCustomer(new Customer());
41 | }
42 | if (source.getCustomer().getShippingAddress() == null) {
43 | source.getCustomer().setShippingAddress(new Address());
44 | }
45 | if (source.getCustomer().getBillingAddress() == null) {
46 | source.getCustomer().setBillingAddress(new Address());
47 | }
48 | return mapper.getDestination(source);
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/com/javaetmoi/benchmark/mapping/mapper/manual/ManualMapper.java:
--------------------------------------------------------------------------------
1 | package com.javaetmoi.benchmark.mapping.mapper.manual;
2 |
3 | import com.javaetmoi.benchmark.mapping.mapper.OrderMapper;
4 | import com.javaetmoi.benchmark.mapping.model.dto.OrderDTO;
5 | import com.javaetmoi.benchmark.mapping.model.dto.ProductDTO;
6 | import com.javaetmoi.benchmark.mapping.model.entity.Address;
7 | import com.javaetmoi.benchmark.mapping.model.entity.Customer;
8 | import com.javaetmoi.benchmark.mapping.model.entity.Order;
9 | import com.javaetmoi.benchmark.mapping.model.entity.Product;
10 |
11 | import java.util.ArrayList;
12 | import java.util.List;
13 |
14 |
15 | public final class ManualMapper implements OrderMapper {
16 |
17 | @Override
18 | public OrderDTO map(Order source) {
19 | OrderDTO target = new OrderDTO();
20 | Customer customer = source.getCustomer();
21 | if (customer != null) {
22 | target.setCustomerName(customer.getName());
23 | if (customer.getBillingAddress() != null) {
24 | target.setBillingCity(customer.getBillingAddress().getCity());
25 | target.setBillingStreetAddress(customer.getBillingAddress().getStreet());
26 | }
27 | if (customer.getShippingAddress() != null) {
28 | target.setShippingCity(customer.getShippingAddress().getCity());
29 | target.setShippingStreetAddress(customer.getShippingAddress().getStreet());
30 | }
31 | }
32 | if (source.getProducts() != null) {
33 | List targetProducts = new ArrayList(source.getProducts().size());
34 | for (Product product : source.getProducts()) {
35 | targetProducts.add(new ProductDTO(product.getName()));
36 | }
37 | target.setProducts(targetProducts);
38 | }
39 | return target;
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/com/javaetmoi/benchmark/mapping/mapper/mapstruct/MapStructMapper.java:
--------------------------------------------------------------------------------
1 | package com.javaetmoi.benchmark.mapping.mapper.mapstruct;
2 |
3 | import com.javaetmoi.benchmark.mapping.mapper.OrderMapper;
4 | import com.javaetmoi.benchmark.mapping.model.dto.OrderDTO;
5 | import com.javaetmoi.benchmark.mapping.model.entity.Order;
6 | import org.mapstruct.factory.Mappers;
7 |
8 |
9 | public class MapStructMapper implements OrderMapper {
10 |
11 | MapStructOrderMapper mapper = Mappers.getMapper(MapStructOrderMapper.class);
12 |
13 | @Override
14 | public OrderDTO map(Order source) {
15 | return mapper.map(source);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/com/javaetmoi/benchmark/mapping/mapper/mapstruct/MapStructOrderMapper.java:
--------------------------------------------------------------------------------
1 | package com.javaetmoi.benchmark.mapping.mapper.mapstruct;
2 |
3 | import com.javaetmoi.benchmark.mapping.mapper.OrderMapper;
4 | import com.javaetmoi.benchmark.mapping.model.dto.OrderDTO;
5 | import com.javaetmoi.benchmark.mapping.model.dto.ProductDTO;
6 | import com.javaetmoi.benchmark.mapping.model.entity.Order;
7 | import com.javaetmoi.benchmark.mapping.model.entity.Product;
8 | import org.mapstruct.Mapper;
9 | import org.mapstruct.Mapping;
10 | import org.mapstruct.Mappings;
11 |
12 | @Mapper
13 | public interface MapStructOrderMapper extends OrderMapper {
14 |
15 | @Mappings({
16 | @Mapping(source = "customer.name", target = "customerName"),
17 | @Mapping(source = "customer.billingAddress.street", target = "billingStreetAddress"),
18 | @Mapping(source = "customer.billingAddress.city", target = "billingCity"),
19 | @Mapping(source = "customer.shippingAddress.street", target = "shippingStreetAddress"),
20 | @Mapping(source = "customer.shippingAddress.city", target = "shippingCity"),
21 | })
22 | OrderDTO map(Order source);
23 |
24 | @Mapping(source = "name", target = "name")
25 | ProductDTO productToProductDTO(Product product);
26 | }
--------------------------------------------------------------------------------
/src/main/java/com/javaetmoi/benchmark/mapping/mapper/modelmapper/ModelMapper.java:
--------------------------------------------------------------------------------
1 | package com.javaetmoi.benchmark.mapping.mapper.modelmapper;
2 |
3 | import com.javaetmoi.benchmark.mapping.mapper.OrderMapper;
4 | import com.javaetmoi.benchmark.mapping.model.dto.OrderDTO;
5 | import com.javaetmoi.benchmark.mapping.model.entity.Order;
6 | import org.modelmapper.PropertyMap;
7 |
8 | public class ModelMapper implements OrderMapper {
9 |
10 | private org.modelmapper.ModelMapper modelMapper;
11 |
12 | public ModelMapper() {
13 | modelMapper = new org.modelmapper.ModelMapper();
14 | modelMapper.addMappings(new PropertyMap() {
15 | @Override
16 | protected void configure() {
17 | map().setBillingStreetAddress(source.getCustomer().getBillingAddress().getStreet());
18 | map().setBillingCity(source.getCustomer().getBillingAddress().getCity());
19 | map().setShippingStreetAddress(source.getCustomer().getShippingAddress().getStreet());
20 | map().setShippingCity(source.getCustomer().getShippingAddress().getCity());
21 | }
22 | });
23 | }
24 |
25 | @Override
26 | public OrderDTO map(Order source) {
27 | return modelMapper.map(source, OrderDTO.class);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/com/javaetmoi/benchmark/mapping/mapper/orika/OrikaMapper.java:
--------------------------------------------------------------------------------
1 | package com.javaetmoi.benchmark.mapping.mapper.orika;
2 |
3 | import com.javaetmoi.benchmark.mapping.mapper.OrderMapper;
4 | import com.javaetmoi.benchmark.mapping.model.dto.OrderDTO;
5 | import com.javaetmoi.benchmark.mapping.model.entity.Order;
6 | import ma.glasnost.orika.BoundMapperFacade;
7 | import ma.glasnost.orika.MapperFactory;
8 | import ma.glasnost.orika.impl.DefaultMapperFactory;
9 |
10 | /**
11 | * Using custom BoundMapperFacade with no object graph cycles.
12 | *
13 | * @see http://orika-mapper.github.io/orika-docs/performance-tuning.html
14 | */
15 | public class OrikaMapper implements OrderMapper {
16 |
17 | private BoundMapperFacade orderMapper;
18 |
19 | public OrikaMapper() {
20 | MapperFactory factory = new DefaultMapperFactory.Builder().build();
21 | factory.registerClassMap(factory.classMap(Order.class, OrderDTO.class)
22 | .field("customer.name", "customerName")
23 | .field("customer.billingAddress.street",
24 | "billingStreetAddress")
25 | .field("customer.billingAddress.city", "billingCity")
26 | .field("customer.shippingAddress.street",
27 | "shippingStreetAddress")
28 | .field("customer.shippingAddress.city",
29 | "shippingCity")
30 | .field("products", "products")
31 | .toClassMap());
32 | orderMapper = factory.getMapperFacade(Order.class, OrderDTO.class, false);
33 | }
34 |
35 | @Override
36 | public OrderDTO map(Order source) {
37 | return orderMapper.map(source);
38 | }
39 | };
40 |
41 |
--------------------------------------------------------------------------------
/src/main/java/com/javaetmoi/benchmark/mapping/mapper/remappe/ReMappeMapper.java:
--------------------------------------------------------------------------------
1 | package com.javaetmoi.benchmark.mapping.mapper.remappe;
2 |
3 | import com.javaetmoi.benchmark.mapping.mapper.OrderMapper;
4 | import com.javaetmoi.benchmark.mapping.model.dto.OrderDTO;
5 | import com.javaetmoi.benchmark.mapping.model.dto.ProductDTO;
6 | import com.javaetmoi.benchmark.mapping.model.entity.Address;
7 | import com.javaetmoi.benchmark.mapping.model.entity.Customer;
8 | import com.javaetmoi.benchmark.mapping.model.entity.Order;
9 | import com.javaetmoi.benchmark.mapping.model.entity.Product;
10 | import com.remondis.remap.Mapper;
11 | import com.remondis.remap.Mapping;
12 |
13 | import java.util.ArrayList;
14 | import java.util.List;
15 | import java.util.Objects;
16 |
17 |
18 | public final class ReMappeMapper implements OrderMapper {
19 |
20 | private final Mapper mapperToDtoProduct = Mapping
21 | .from(Product.class)
22 | .to(ProductDTO.class)
23 | .mapper();
24 |
25 | private final Mapper mapperToDto = Mapping
26 | .from(Order.class)
27 | .to(OrderDTO.class)
28 | .replace(Order::getCustomer, OrderDTO::getCustomerName).withSkipWhenNull(customer -> customer.getName())
29 | .replace(Order::getCustomer, OrderDTO::getBillingStreetAddress).withSkipWhenNull(customer -> {
30 | Address billingAddress = customer.getBillingAddress();
31 | return Objects.nonNull(billingAddress)
32 | ? billingAddress.getStreet()
33 | : null;
34 | })
35 | .replace(Order::getCustomer, OrderDTO::getBillingCity).withSkipWhenNull(customer -> {
36 | Address billingAddress = customer.getBillingAddress();
37 | return Objects.nonNull(billingAddress)
38 | ? billingAddress.getCity()
39 | : null;
40 | })
41 | .replace(Order::getCustomer, OrderDTO::getShippingStreetAddress).withSkipWhenNull(customer -> {
42 | Address shippingAddress = customer.getShippingAddress();
43 | return Objects.nonNull(shippingAddress)
44 | ? shippingAddress.getStreet()
45 | : null;
46 | })
47 | .replace(Order::getCustomer, OrderDTO::getShippingCity).withSkipWhenNull(customer -> {
48 | Address shippingAddress = customer.getShippingAddress();
49 | return Objects.nonNull(shippingAddress)
50 | ? shippingAddress.getCity()
51 | : null;
52 | })
53 | .useMapper(mapperToDtoProduct)
54 | .mapper();
55 |
56 | @Override
57 | public OrderDTO map(Order source) {
58 | return mapperToDto.map(source);
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/src/main/java/com/javaetmoi/benchmark/mapping/mapper/selma/SelmaMapper.java:
--------------------------------------------------------------------------------
1 | package com.javaetmoi.benchmark.mapping.mapper.selma;
2 |
3 | import com.javaetmoi.benchmark.mapping.mapper.OrderMapper;
4 | import com.javaetmoi.benchmark.mapping.model.dto.OrderDTO;
5 | import com.javaetmoi.benchmark.mapping.model.entity.Order;
6 | import fr.xebia.extras.selma.Selma;
7 |
8 | public class SelmaMapper implements OrderMapper {
9 |
10 | private SelmaOrderMapper mapper = Selma.builder(SelmaOrderMapper.class).build();
11 |
12 | @Override
13 | public OrderDTO map(Order source) {
14 | return mapper.map(source);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/com/javaetmoi/benchmark/mapping/mapper/selma/SelmaOrderMapper.java:
--------------------------------------------------------------------------------
1 | package com.javaetmoi.benchmark.mapping.mapper.selma;
2 |
3 | import com.javaetmoi.benchmark.mapping.model.dto.OrderDTO;
4 | import com.javaetmoi.benchmark.mapping.model.dto.ProductDTO;
5 | import com.javaetmoi.benchmark.mapping.model.entity.Order;
6 | import com.javaetmoi.benchmark.mapping.model.entity.Product;
7 | import fr.xebia.extras.selma.Field;
8 | import fr.xebia.extras.selma.Mapper;
9 |
10 | @Mapper(
11 | withCustomFields = {
12 | @Field({"customer.name", "customerName"}),
13 | @Field({"customer.billingAddress.street", "billingStreetAddress"}),
14 | @Field({"customer.billingAddress.city", "billingCity"}),
15 | @Field({"customer.shippingAddress.street", "shippingStreetAddress"}),
16 | @Field({"customer.shippingAddress.city", "shippingCity"})
17 | }
18 | )
19 | public interface SelmaOrderMapper {
20 |
21 | OrderDTO map(Order source);
22 |
23 | ProductDTO map(Product product);
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/com/javaetmoi/benchmark/mapping/model/dto/OrderDTO.java:
--------------------------------------------------------------------------------
1 | package com.javaetmoi.benchmark.mapping.model.dto;
2 |
3 | import java.util.List;
4 |
5 | public class OrderDTO {
6 |
7 | private List products;
8 | String customerName;
9 | private String shippingStreetAddress;
10 | private String shippingCity;
11 | private String billingStreetAddress;
12 | private String billingCity;
13 |
14 | public String getCustomerName() {
15 | return customerName;
16 | }
17 |
18 | public void setCustomerName(String customerName) {
19 | this.customerName = customerName;
20 | }
21 |
22 | public String getShippingStreetAddress() {
23 | return shippingStreetAddress;
24 | }
25 |
26 | public void setShippingStreetAddress(String shippingStreetAddress) {
27 | this.shippingStreetAddress = shippingStreetAddress;
28 | }
29 |
30 | public String getShippingCity() {
31 | return shippingCity;
32 | }
33 |
34 | public void setShippingCity(String shippingCity) {
35 | this.shippingCity = shippingCity;
36 | }
37 |
38 | public String getBillingStreetAddress() {
39 | return billingStreetAddress;
40 | }
41 |
42 | public void setBillingStreetAddress(String billingStreetAddress) {
43 | this.billingStreetAddress = billingStreetAddress;
44 | }
45 |
46 | public String getBillingCity() {
47 | return billingCity;
48 | }
49 |
50 | public void setBillingCity(String billingCity) {
51 | this.billingCity = billingCity;
52 | }
53 |
54 | public List getProducts() {
55 | return products;
56 | }
57 |
58 | public void setProducts(List products) {
59 | this.products = products;
60 | }
61 | }
--------------------------------------------------------------------------------
/src/main/java/com/javaetmoi/benchmark/mapping/model/dto/ProductDTO.java:
--------------------------------------------------------------------------------
1 | package com.javaetmoi.benchmark.mapping.model.dto;
2 |
3 | public class ProductDTO {
4 |
5 | private String name;
6 |
7 | public ProductDTO() {
8 |
9 | }
10 |
11 | public ProductDTO(String name) {
12 | this.name = name;
13 | }
14 |
15 | public String getName() {
16 | return name;
17 | }
18 |
19 | public void setName(String name) {
20 | this.name = name;
21 | }
22 | }
--------------------------------------------------------------------------------
/src/main/java/com/javaetmoi/benchmark/mapping/model/entity/Address.java:
--------------------------------------------------------------------------------
1 | package com.javaetmoi.benchmark.mapping.model.entity;
2 |
3 | public class Address {
4 | String street;
5 | String city;
6 |
7 | public String getStreet() {
8 | return street;
9 | }
10 |
11 | public void setStreet(String street) {
12 | this.street = street;
13 | }
14 |
15 | public String getCity() {
16 | return city;
17 | }
18 |
19 | public void setCity(String city) {
20 | this.city = city;
21 | }
22 | }
--------------------------------------------------------------------------------
/src/main/java/com/javaetmoi/benchmark/mapping/model/entity/Customer.java:
--------------------------------------------------------------------------------
1 | package com.javaetmoi.benchmark.mapping.model.entity;
2 |
3 | public class Customer {
4 | String name;
5 | Address shippingAddress;
6 | Address billingAddress;
7 |
8 | public Address getShippingAddress() {
9 | return shippingAddress;
10 | }
11 |
12 | public void setShippingAddress(Address shippingAddress) {
13 | this.shippingAddress = shippingAddress;
14 | }
15 |
16 | public Address getBillingAddress() {
17 | return billingAddress;
18 | }
19 |
20 | public void setBillingAddress(Address billingAddress) {
21 | this.billingAddress = billingAddress;
22 | }
23 |
24 | public String getName() {
25 | return name;
26 | }
27 |
28 | public void setName(String name) {
29 | this.name = name;
30 | }
31 | }
--------------------------------------------------------------------------------
/src/main/java/com/javaetmoi/benchmark/mapping/model/entity/Order.java:
--------------------------------------------------------------------------------
1 | package com.javaetmoi.benchmark.mapping.model.entity;
2 |
3 | import java.util.List;
4 |
5 | public class Order {
6 | private Customer customer;
7 | private List products;
8 |
9 | public Customer getCustomer() {
10 | return customer;
11 | }
12 |
13 | public void setCustomer(Customer customer) {
14 | this.customer = customer;
15 | }
16 |
17 | public List getProducts() {
18 | return products;
19 | }
20 |
21 | public void setProducts(List products) {
22 | this.products = products;
23 | }
24 | }
--------------------------------------------------------------------------------
/src/main/java/com/javaetmoi/benchmark/mapping/model/entity/OrderFactory.java:
--------------------------------------------------------------------------------
1 | package com.javaetmoi.benchmark.mapping.model.entity;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Collections;
5 | import java.util.List;
6 |
7 | public class OrderFactory {
8 |
9 | public static Order buildOrder() {
10 | Order order = new Order();
11 | Customer customer = new Customer();
12 | order.setCustomer(customer);
13 | customer.setName("Joe Smith");
14 | Address billingAddress = new Address();
15 | customer.setBillingAddress(billingAddress);
16 | billingAddress.setStreet("1234 Market Street");
17 | billingAddress.setCity("San Fran");
18 | Address shippingAddress = new Address();
19 | customer.setShippingAddress(shippingAddress);
20 | shippingAddress.setStreet("1234 West Townsend");
21 | shippingAddress.setCity("Boston");
22 | List products = new ArrayList(2);
23 | order.setProducts(products);
24 | products.add(new Product("socks"));
25 | products.add(new Product("shoes"));
26 | return order;
27 | }
28 |
29 | public static Order buildPartialOrder() {
30 | Order order = new Order();
31 | Customer customer = new Customer();
32 | order.setCustomer(customer);
33 | customer.setName("John Doe");
34 | Address billingAddress = new Address();
35 | customer.setBillingAddress(billingAddress);
36 | billingAddress.setStreet("93 Newcastle Dr.");
37 | order.setProducts(Collections.emptyList());
38 | return order;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/com/javaetmoi/benchmark/mapping/model/entity/Product.java:
--------------------------------------------------------------------------------
1 | package com.javaetmoi.benchmark.mapping.model.entity;
2 |
3 | public class Product {
4 | private String name;
5 |
6 | public Product(String name) {
7 | this.name = name;
8 | }
9 |
10 | public String getName() {
11 | return name;
12 | }
13 |
14 | public void setName(String name) {
15 | this.name = name;
16 | }
17 | }
--------------------------------------------------------------------------------
/src/main/resources/com/javaetmoi/benchmark/mapping/mapper/dozer/dozer.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | com.javaetmoi.benchmark.mapping.model.entity.Order
7 | com.javaetmoi.benchmark.mapping.model.dto.OrderDTO
8 |
9 | customer.name
10 | customerName
11 |
12 |
13 | customer.billingAddress.street
14 | billingStreetAddress
15 |
16 |
17 | customer.billingAddress.city
18 | billingCity
19 |
20 |
21 | customer.shippingAddress.street
22 | shippingStreetAddress
23 |
24 |
25 | customer.shippingAddress.city
26 | shippingCity
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/src/test/java/com/javaetmoi/benchmark/mapping/mapper/AbstractMapperTest.java:
--------------------------------------------------------------------------------
1 | package com.javaetmoi.benchmark.mapping.mapper;
2 |
3 |
4 | import com.javaetmoi.benchmark.mapping.model.dto.OrderDTO;
5 | import com.javaetmoi.benchmark.mapping.model.entity.Order;
6 | import com.javaetmoi.benchmark.mapping.model.entity.OrderFactory;
7 | import org.junit.jupiter.api.Test;
8 |
9 | import static org.junit.jupiter.api.Assertions.*;
10 |
11 | public abstract class AbstractMapperTest {
12 |
13 | @Test
14 | public void map_with_all_fields() {
15 | Order order = OrderFactory.buildOrder();
16 | OrderDTO orderDTO = testedOrderMapper().map(order);
17 | assertEquals(orderDTO.getCustomerName(), "Joe Smith");
18 | assertEquals(orderDTO.getBillingStreetAddress(), "1234 Market Street");
19 | assertEquals(orderDTO.getBillingCity(), "San Fran");
20 | assertEquals(orderDTO.getShippingStreetAddress(), "1234 West Townsend");
21 | assertEquals(orderDTO.getShippingCity(), "Boston");
22 | assertEquals(orderDTO.getProducts().get(0).getName(), "socks");
23 | assertEquals(orderDTO.getProducts().get(1).getName(), "shoes");
24 | }
25 |
26 | @Test
27 | public void map_with_partial_order() {
28 | Order order = OrderFactory.buildPartialOrder();
29 | OrderDTO orderDTO = testedOrderMapper().map(order);
30 | assertEquals(orderDTO.getCustomerName(), "John Doe");
31 | assertEquals(orderDTO.getBillingStreetAddress(), "93 Newcastle Dr.");
32 | assertTrue(orderDTO.getProducts().isEmpty());
33 | }
34 |
35 | @Test
36 | public void map_with_empty_order() {
37 | Order order = new Order();
38 | OrderDTO orderDTO = testedOrderMapper().map(order);
39 | assertNotNull(orderDTO);
40 | }
41 |
42 | protected abstract OrderMapper testedOrderMapper();
43 | }
44 |
--------------------------------------------------------------------------------
/src/test/java/com/javaetmoi/benchmark/mapping/mapper/BullMapperTest.java:
--------------------------------------------------------------------------------
1 | package com.javaetmoi.benchmark.mapping.mapper;
2 |
3 | import com.javaetmoi.benchmark.mapping.mapper.bull.BullMapper;
4 |
5 | public class BullMapperTest extends AbstractMapperTest {
6 | @Override
7 | protected OrderMapper testedOrderMapper() {
8 | return new BullMapper();
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/test/java/com/javaetmoi/benchmark/mapping/mapper/DatusMapperTest.java:
--------------------------------------------------------------------------------
1 | package com.javaetmoi.benchmark.mapping.mapper;
2 |
3 | import com.javaetmoi.benchmark.mapping.mapper.datus.DatusMapper;
4 |
5 | public class DatusMapperTest extends AbstractMapperTest {
6 | @Override
7 | protected OrderMapper testedOrderMapper() {
8 | return new DatusMapper();
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/test/java/com/javaetmoi/benchmark/mapping/mapper/DozerMapperTest.java:
--------------------------------------------------------------------------------
1 | package com.javaetmoi.benchmark.mapping.mapper;
2 |
3 | import com.javaetmoi.benchmark.mapping.mapper.dozer.DozerMapper;
4 |
5 | public class DozerMapperTest extends AbstractMapperTest {
6 |
7 | @Override
8 | protected OrderMapper testedOrderMapper() {
9 | return new DozerMapper();
10 | }
11 | }
--------------------------------------------------------------------------------
/src/test/java/com/javaetmoi/benchmark/mapping/mapper/JMapperMapperTest.java:
--------------------------------------------------------------------------------
1 | package com.javaetmoi.benchmark.mapping.mapper;
2 |
3 | import com.javaetmoi.benchmark.mapping.mapper.jmapper.JMapperMapper;
4 |
5 | public class JMapperMapperTest extends AbstractMapperTest {
6 |
7 | @Override
8 | protected OrderMapper testedOrderMapper() {
9 | return new JMapperMapper();
10 | }
11 | }
--------------------------------------------------------------------------------
/src/test/java/com/javaetmoi/benchmark/mapping/mapper/ManualMapperTest.java:
--------------------------------------------------------------------------------
1 | package com.javaetmoi.benchmark.mapping.mapper;
2 |
3 | import com.javaetmoi.benchmark.mapping.mapper.manual.ManualMapper;
4 |
5 | public class ManualMapperTest extends AbstractMapperTest {
6 | @Override
7 | protected OrderMapper testedOrderMapper() {
8 | return new ManualMapper();
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/test/java/com/javaetmoi/benchmark/mapping/mapper/MapStructMapperTest.java:
--------------------------------------------------------------------------------
1 | package com.javaetmoi.benchmark.mapping.mapper;
2 |
3 | import com.javaetmoi.benchmark.mapping.mapper.mapstruct.MapStructMapper;
4 |
5 | public class MapStructMapperTest extends AbstractMapperTest {
6 | @Override
7 | protected OrderMapper testedOrderMapper() {
8 | return new MapStructMapper();
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/test/java/com/javaetmoi/benchmark/mapping/mapper/ModelMapperTest.java:
--------------------------------------------------------------------------------
1 | package com.javaetmoi.benchmark.mapping.mapper;
2 |
3 | import com.javaetmoi.benchmark.mapping.mapper.modelmapper.ModelMapper;
4 |
5 |
6 | public class ModelMapperTest extends AbstractMapperTest {
7 | @Override
8 | protected OrderMapper testedOrderMapper() {
9 | return new ModelMapper();
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/test/java/com/javaetmoi/benchmark/mapping/mapper/OrikaMapperTest.java:
--------------------------------------------------------------------------------
1 | package com.javaetmoi.benchmark.mapping.mapper;
2 |
3 | import com.javaetmoi.benchmark.mapping.mapper.orika.OrikaMapper;
4 |
5 | public class OrikaMapperTest extends AbstractMapperTest {
6 | @Override
7 | protected OrderMapper testedOrderMapper() {
8 | return new OrikaMapper();
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/test/java/com/javaetmoi/benchmark/mapping/mapper/ReMapMapperTest.java:
--------------------------------------------------------------------------------
1 | package com.javaetmoi.benchmark.mapping.mapper;
2 |
3 | import com.javaetmoi.benchmark.mapping.mapper.remappe.ReMappeMapper;
4 |
5 | public class ReMapMapperTest extends AbstractMapperTest {
6 | @Override
7 | protected OrderMapper testedOrderMapper() {
8 | return new ReMappeMapper();
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/test/java/com/javaetmoi/benchmark/mapping/mapper/SelmaMapperTest.java:
--------------------------------------------------------------------------------
1 | package com.javaetmoi.benchmark.mapping.mapper;
2 |
3 | import com.javaetmoi.benchmark.mapping.mapper.selma.SelmaMapper;
4 |
5 | public class SelmaMapperTest extends AbstractMapperTest {
6 | @Override
7 | protected OrderMapper testedOrderMapper() {
8 | return new SelmaMapper();
9 | }
10 | }
11 |
--------------------------------------------------------------------------------