131 lines
7.4 KiB
Bash
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
|