Files
spring-boot-demo/mapstruct/scripts/compile-errors.sh
T

131 lines
7.4 KiB
Bash

#!/usr/bin/env bash
# Compiles the deliberately broken sources under src/broken/ with javac and commits the compiler's own words:
# 17 unmapped target property 18 ambiguous mapping methods 19 missing source property
# 20 @MappingTarget on a record (compiles!) 21 no way to map one type to another
# 22 @DecoratedWith + constructor 23 processor on the plain classpath (JDK 23+)
# 24 Lombok before/after MapStruct, with and without lombok-mapstruct-binding
# Each step also greps for the expected message and fails the script if it is not there, so a MapStruct
# upgrade that rewords an error is noticed. Needs a JDK 25 and the jars from one `mvn test` (they come from ~/.m2).
set -uo pipefail
cd "$(dirname "$0")/.."
mkdir -p output target/broken
M2=${M2_REPO:-$HOME/.m2/repository}
MS=${MAPSTRUCT_VERSION:-1.6.3}
LOMBOK=${LOMBOK_VERSION:-1.18.48}
SPRING=${SPRING_VERSION:-7.0.10}
native() { if command -v cygpath >/dev/null 2>&1; then cygpath -m "$1"; else echo "$1"; fi; }
case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) SEP=';' ;; *) SEP=':' ;; esac
MSJ=$(native "$M2/org/mapstruct/mapstruct/$MS/mapstruct-$MS.jar")
MSP=$(native "$M2/org/mapstruct/mapstruct-processor/$MS/mapstruct-processor-$MS.jar")
LOM=$(native "$M2/org/projectlombok/lombok/$LOMBOK/lombok-$LOMBOK.jar")
BIND=$(native "$M2/org/projectlombok/lombok-mapstruct-binding/0.2.0/lombok-mapstruct-binding-0.2.0.jar")
SPR="$(native "$M2/org/springframework/spring-context/$SPRING/spring-context-$SPRING.jar")$SEP$(native "$M2/org/springframework/spring-beans/$SPRING/spring-beans-$SPRING.jar")$SEP$(native "$M2/org/springframework/spring-core/$SPRING/spring-core-$SPRING.jar")"
fail=0
# capture <file> <title> <expected text or ''> <display command> -- <real command...>
capture() {
local file=$1 title=$2 expect=$3 shown=$4; shift 5
local out
out=$("$@" 2>&1 | sed 's/\r$//; s#\\#/#g')
{
echo "# $title"
echo
echo "\$ $shown"
printf '%s\n' "$out"
} > "output/$file"
if [ -n "$expect" ] && ! grep -qF -- "$expect" "output/$file"; then
echo "MISSING in output/$file: $expect" >&2
fail=1
fi
echo "wrote output/$file"
}
javac_case() { # <case dir> -> real javac invocation with the processor on -processorpath
local c=$1; rm -rf "target/broken/$c"; mkdir -p "target/broken/$c"
echo "javac -d target/broken/$c -cp \$MAPSTRUCT_JAR -processorpath \$MAPSTRUCT_PROCESSOR_JAR src/broken/$c/*.java"
}
for spec in \
"17-error-unmapped-target.txt|unmapped-target|Unmapped target property: \"note\"|A record target component nobody mapped (unmappedTargetPolicy = ERROR)" \
"18-error-ambiguous-mapping-methods.txt|ambiguous|Ambiguous mapping methods found for mapping property|Two methods can produce the same property" \
"19-error-missing-source-property.txt|missing-source|No property named \"nmae\" exists in source parameter(s)|A typo in @Mapping(source = ...)" \
"21-error-cannot-map-type.txt|cannot-map|Can't map property|No way to turn one type into another"; do
IFS='|' read -r file case expect title <<<"$spec"
shown=$(javac_case "$case")
capture "$file" "$title" "$expect" "$shown" -- \
javac -d "target/broken/$case" -cp "$MSJ" -processorpath "$MSP" src/broken/$case/*.java
done
# 20: @MappingTarget on a record is NOT a compile error: read what was generated
c=update-record; rm -rf "target/broken/$c"; mkdir -p "target/broken/$c"
{
echo "# @MappingTarget on a record compiles, with unmappedTargetPolicy = ERROR, and generates this"
echo
echo "\$ javac -d target/broken/$c -s target/broken/$c -cp \$MAPSTRUCT_JAR -processorpath \$MAPSTRUCT_PROCESSOR_JAR src/broken/$c/*.java"
javac -d "target/broken/$c" -s "target/broken/$c" -cp "$MSJ" -processorpath "$MSP" src/broken/$c/*.java 2>&1 | sed 's/
$//'
echo "(exit status: ${PIPESTATUS[0]})"
echo
echo "\$ cat target/broken/$c/BrokenMapperImpl.java (header and imports trimmed)"
sed -n '/^public class/,$p' "target/broken/$c/BrokenMapperImpl.java" | sed 's/
$//'
} > output/20-update-method-on-a-record-compiles-to-a-no-op.txt
echo "wrote output/20-update-method-on-a-record-compiles-to-a-no-op.txt"
grep -q 'public void update' output/20-update-method-on-a-record-compiles-to-a-no-op.txt || { echo "MISSING update in 20" >&2; fail=1; }
# 22: the decorator needs the Spring annotations on the classpath
c=decorator-constructor; rm -rf "target/broken/$c"; mkdir -p "target/broken/$c"
capture 22-error-decorator-constructor.txt "@DecoratedWith with a constructor-injected delegate (componentModel = spring)" \
"constructor BrokenMapperDecorator in class BrokenMapperDecorator cannot be applied to given types" \
"javac -d target/broken/$c -cp \$MAPSTRUCT_JAR:\$SPRING_JARS -processorpath \$MAPSTRUCT_PROCESSOR_JAR src/broken/$c/*.java" -- \
javac -d "target/broken/$c" -cp "$MSJ$SEP$SPR" -processorpath "$MSP" src/broken/$c/*.java
# 23: processor jar on the plain classpath, no -processorpath, no -proc:full
c=processor-not-run; rm -rf "target/broken/$c"; mkdir -p "target/broken/$c"
{
echo "# The processor jar on the plain classpath: javac $(javac -version 2>&1 | awk '{print $2}') compiles without generating anything"
echo
echo "\$ javac -d target/broken/$c -cp \$MAPSTRUCT_JAR:\$MAPSTRUCT_PROCESSOR_JAR src/broken/$c/UsesMapper.java"
javac -d "target/broken/$c" -cp "$MSJ$SEP$MSP" src/broken/$c/UsesMapper.java 2>&1 | sed 's/\r$//'
echo "(exit status: ${PIPESTATUS[0]})"
echo
echo "\$ ls target/broken/$c"
ls "target/broken/$c" | sed 's/\r$//'
echo
echo "\$ java -cp \$MAPSTRUCT_JAR:target/broken/$c UsesMapper"
java -cp "$MSJ$SEP""target/broken/$c" UsesMapper 2>&1 | sed 's/\r$//' | head -4
echo
rm -rf "target/broken/$c"; mkdir -p "target/broken/$c"
echo "\$ javac -proc:full -d target/broken/$c -cp \$MAPSTRUCT_JAR:\$MAPSTRUCT_PROCESSOR_JAR src/broken/$c/UsesMapper.java"
javac -proc:full -d "target/broken/$c" -cp "$MSJ$SEP$MSP" src/broken/$c/UsesMapper.java 2>&1 | sed 's/\r$//'
echo "(exit status: ${PIPESTATUS[0]})"
echo "\$ ls target/broken/$c"
ls "target/broken/$c" | sed 's/\r$//'
} > output/23-processor-on-the-plain-classpath.txt
echo "wrote output/23-processor-on-the-plain-classpath.txt"
grep -q 'UsesMapperImpl.class' output/23-processor-on-the-plain-classpath.txt || { echo "MISSING UsesMapperImpl in 23" >&2; fail=1; }
# 24: Lombok and MapStruct ordering
c=lombok
run_lombok() { # <label> <processorpath>
rm -rf "target/broken/$c"; mkdir -p "target/broken/$c"
echo
echo "--- $1 ---"
echo "\$ javac -d target/broken/$c -cp \$MAPSTRUCT_JAR:\$LOMBOK_JAR -processorpath $3 src/broken/$c/LombokMapper.java"
javac -d "target/broken/$c" -cp "$MSJ$SEP$LOM" -processorpath "$2" src/broken/$c/LombokMapper.java 2>&1 | sed 's/\r$//; s#\\#/#g' | grep -v '^WARNING:'
echo "(exit status: ${PIPESTATUS[0]})"
echo "LombokMapperImpl generated: $([ -f target/broken/$c/LombokMapperImpl.class ] && echo yes || echo no)"
}
{
echo "# Lombok + MapStruct + a record target: what the processor path order and lombok-mapstruct-binding change"
run_lombok "MapStruct first, Lombok second, no binding" "$MSP$SEP$LOM" '$MAPSTRUCT_PROCESSOR_JAR:$LOMBOK_JAR'
run_lombok "Lombok first, MapStruct second, no binding" "$LOM$SEP$MSP" '$LOMBOK_JAR:$MAPSTRUCT_PROCESSOR_JAR'
run_lombok "MapStruct first, then Lombok and lombok-mapstruct-binding" "$MSP$SEP$LOM$SEP$BIND" '$MAPSTRUCT_PROCESSOR_JAR:$LOMBOK_JAR:$BINDING_JAR'
run_lombok "Lombok, binding, then MapStruct" "$LOM$SEP$BIND$SEP$MSP" '$LOMBOK_JAR:$BINDING_JAR:$MAPSTRUCT_PROCESSOR_JAR'
} > output/24-lombok-processor-order.txt
echo "wrote output/24-lombok-processor-order.txt"
exit $fail