Two-jar starter (autoconfigure + starter), a demo app, and 17 captured transcripts covering AutoConfiguration.imports, @ConditionalOn*, ordering, optional Jackson 3 integration, configuration metadata and the Boot 4 module split. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Uu7q8vPeREyT4218EJPzz1
137 lines
7.5 KiB
Bash
Executable File
137 lines
7.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Facts that a test cannot show, read from the built jars and from deliberately failing builds:
|
|
# 07 @ConditionalOnClass on a @Bean method versus on a nested class, on classpaths with and without Jackson
|
|
# 12 what is in the starter jar and the auto-configuration jar, and what the starter pulls in
|
|
# 13 the generated configuration metadata and auto-configuration metadata, as they sit in the jar
|
|
# 14 Boot 4's split of spring-boot-autoconfigure, and the Boot 3 import that no longer compiles
|
|
# 15 the annotation-processor version trap when the module has its own parent pom
|
|
# 17 which Boot 4.1.1 jar holds each class the starter imports
|
|
set -euo pipefail
|
|
cd "$(dirname "$0")/.."
|
|
mkdir -p output
|
|
M2=~/.m2/repository/org/springframework/boot
|
|
AC=masker-spring-boot-autoconfigure
|
|
JP() { "$@" 2>&1 | grep -v -E '^(Picked up|WARNING)'; }
|
|
ROOT=$(pwd)
|
|
clean() { sed "s#$ROOT#<custom-starter>#g; s#$HOME#~#g"; }
|
|
|
|
echo "== build the jars"
|
|
mvn -B -q package -DskipTests dependency:tree -Dscope=compile -DoutputFile=target/tree.txt >/dev/null 2>&1 || mvn -B package -DskipTests dependency:tree -Dscope=compile -DoutputFile=target/tree.txt
|
|
|
|
echo "== 07"
|
|
mvn -B -q -pl "$AC" test-compile dependency:build-classpath -Dmdep.outputFile=/tmp/masker-cp.txt -Dmdep.includeScope=test >/dev/null 2>&1
|
|
FULL=$(cat /tmp/masker-cp.txt)
|
|
NOJACKSON=$(tr ':' '\n' < /tmp/masker-cp.txt | grep -v jackson | paste -sd:)
|
|
{
|
|
echo "# @ConditionalOnClass(JsonMapper.class) on a @Bean method, versus on a nested class, with and without Jackson"
|
|
echo
|
|
echo "--- condition on the @Bean method, classpath without any Jackson jar ---"
|
|
JP java -cp "$AC/target/test-classes:$AC/target/classes:$NOJACKSON" com.ankurm.traps.MethodLevelMain method | grep -v -E '^[0-9:.]+ \[main\]'
|
|
echo
|
|
echo "--- condition on a nested class, classpath without any Jackson jar ---"
|
|
JP java -cp "$AC/target/test-classes:$AC/target/classes:$NOJACKSON" com.ankurm.traps.MethodLevelMain nested | grep -v -E '^[0-9:.]+ \[main\]'
|
|
echo
|
|
echo "--- condition on the @Bean method, classpath with Jackson ---"
|
|
JP java -cp "$AC/target/test-classes:$AC/target/classes:$FULL" com.ankurm.traps.MethodLevelMain method | grep -v -E '^[0-9:.]+ \[main\]'
|
|
} | clean > output/07-conditional-on-class-on-a-bean-method.txt
|
|
|
|
echo "== 12"
|
|
{
|
|
echo "# What is inside the two jars, and what the starter drags in"
|
|
echo
|
|
echo "--- masker-spring-boot-starter-1.0.0.jar ---"
|
|
unzip -l masker-spring-boot-starter/target/masker-spring-boot-starter-1.0.0.jar | awk 'NR>3 && $4!="" {print $4}' | grep -v '/$'
|
|
echo
|
|
echo "--- masker-spring-boot-autoconfigure-1.0.0.jar (META-INF and the classes) ---"
|
|
unzip -l $AC/target/$AC-1.0.0.jar | awk 'NR>3 && $4!="" {print $4}' | grep -v '/$' | grep -v -E 'pom\.(xml|properties)|MANIFEST'
|
|
echo
|
|
echo "--- META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports ---"
|
|
unzip -p $AC/target/$AC-1.0.0.jar META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
|
|
echo
|
|
echo "--- dependency tree of masker-spring-boot-starter (Jackson is not in it) ---"
|
|
cat masker-spring-boot-starter/target/tree.txt
|
|
echo
|
|
echo "--- dependency tree of masker-spring-boot-autoconfigure (Jackson is there, marked optional in the pom) ---"
|
|
cat $AC/target/tree.txt
|
|
} | clean > output/12-jar-contents-and-dependency-trees.txt
|
|
|
|
echo "== 13"
|
|
{
|
|
echo "# Metadata the two annotation processors write into the auto-configuration jar"
|
|
echo
|
|
echo "--- META-INF/spring-configuration-metadata.json, written by spring-boot-configuration-processor ---"
|
|
echo
|
|
unzip -p $AC/target/$AC-1.0.0.jar META-INF/spring-configuration-metadata.json
|
|
echo
|
|
echo
|
|
echo "--- META-INF/additional-spring-configuration-metadata.json, hand-written and kept as is ---"
|
|
unzip -p $AC/target/$AC-1.0.0.jar META-INF/additional-spring-configuration-metadata.json
|
|
echo
|
|
echo
|
|
echo "--- META-INF/spring-autoconfigure-metadata.properties, written by spring-boot-autoconfigure-processor ---"
|
|
unzip -p $AC/target/$AC-1.0.0.jar META-INF/spring-autoconfigure-metadata.properties
|
|
} > output/13-configuration-metadata-in-the-jar.txt
|
|
|
|
echo "== 14"
|
|
BOOT_AC=$M2/spring-boot-autoconfigure/4.1.1/spring-boot-autoconfigure-4.1.1.jar
|
|
BOOT_JACKSON=$M2/spring-boot-jackson/4.1.1/spring-boot-jackson-4.1.1.jar
|
|
{
|
|
echo "# Boot 4.1.1: where the auto-configuration classes a starter refers to now live"
|
|
echo
|
|
echo "--- entries in spring-boot-autoconfigure's own AutoConfiguration.imports ---"
|
|
unzip -p "$BOOT_AC" META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports | grep -c .
|
|
echo
|
|
echo "--- JacksonAutoConfiguration: which jar, which package ---"
|
|
echo "spring-boot-autoconfigure-4.1.1.jar, classes named JacksonAutoConfiguration: $(unzip -l "$BOOT_AC" | grep -c 'JacksonAutoConfiguration' || true)"
|
|
unzip -l "$BOOT_JACKSON" | awk '/JacksonAutoConfiguration.class/ {print "spring-boot-jackson-4.1.1.jar: " $4}'
|
|
echo
|
|
X=$(mktemp -d)
|
|
unzip -q -o "$BOOT_AC" 'org/springframework/boot/autoconfigure/AutoConfiguration.class' \
|
|
'org/springframework/boot/autoconfigure/AutoConfigurationExcludeFilter.class' -d "$X"
|
|
echo "--- what @AutoConfiguration is made of (javap -v, class-level annotations) ---"
|
|
JP javap -v -cp "$X" org.springframework.boot.autoconfigure.AutoConfiguration \
|
|
| sed -n '/^RuntimeVisibleAnnotations/,$p' | grep -E '^ (org\.springframework)|proxyBeanMethods' | sed 's/^ *//'
|
|
echo
|
|
echo "--- AutoConfigurationExcludeFilter, the filter @SpringBootApplication's scan applies: the classes it tests for (javap -c) ---"
|
|
JP javap -p -c -cp "$X" org.springframework.boot.autoconfigure.AutoConfigurationExcludeFilter \
|
|
| grep -E 'ldc|ImportCandidates.load' | sed -E 's/^ *[0-9]+: //; s/ +/ /g'
|
|
rm -rf "$X"
|
|
echo
|
|
echo "--- the Boot 3 import, compiled against the 4.1.1 jars ---"
|
|
mkdir -p /tmp/masker-broken
|
|
JP javac -d /tmp/masker-broken -cp "$BOOT_AC:$BOOT_JACKSON" $AC/src/broken/OldJacksonImport.java | clean || true
|
|
} > output/14-boot4-autoconfiguration-locations.txt
|
|
|
|
echo "== 17"
|
|
{
|
|
echo "# Which 4.1.1 jar holds each Boot class this starter and its tests import (searched in every Boot jar the build resolved)"
|
|
echo
|
|
for c in AutoConfiguration AutoConfigureAfter AutoConfigurations ConditionalOnClass ConditionalOnBean ConditionalOnMissingBean ConditionalOnProperty \
|
|
ConditionEvaluationReportLoggingListener ImportCandidates Configurations JacksonAutoConfiguration ApplicationContextRunner FilteredClassLoader; do
|
|
for j in "$M2"/spring-boot*/4.1.1/spring-boot*-4.1.1.jar; do
|
|
unzip -l "$j" | awk -v c="/$c.class" -v j="$(basename "$j")" 'index($4, c) && $4 !~ /\$/ {printf "%-46s %s\n", j, $4}'
|
|
done
|
|
done
|
|
} > output/17-where-the-classes-live.txt
|
|
|
|
echo "== 15"
|
|
TMP=$(mktemp -d)
|
|
cp -r pom.xml "$AC" "$TMP/"
|
|
mkdir -p "$TMP/masker-spring-boot-starter" "$TMP/masker-demo"
|
|
cp masker-spring-boot-starter/pom.xml "$TMP/masker-spring-boot-starter/"; cp masker-demo/pom.xml "$TMP/masker-demo/"
|
|
rm -rf "$TMP/$AC/target"
|
|
python3 - "$TMP/$AC/pom.xml" <<'PY'
|
|
import sys
|
|
p=sys.argv[1]
|
|
s=open(p).read()
|
|
s=s.replace("<artifactId>spring-boot-configuration-processor</artifactId>","<artifactId>spring-boot-configuration-processor</artifactId>\n <version>${project.parent.version}</version>")
|
|
open(p,'w').write(s)
|
|
PY
|
|
{
|
|
echo "# The processor path with <version>\${project.parent.version}</version>, when the module's parent is not Spring Boot's"
|
|
echo
|
|
(cd "$TMP" && mvn -B -U -pl $AC compile 2>&1 | grep -E 'ERROR.*(annotationProcessorPath|Could not find artifact)' | head -1 | sed -E 's/^\[ERROR\] //; s/ -> \[Help 1\]//')
|
|
} > output/15-annotation-processor-version-trap.txt
|
|
rm -rf "$TMP"
|
|
echo "done"
|