Add rest-client-test module: @RestClientTest on Boot 4.1, Jackson 3 by default, and the RestClient-vs-RestTemplate root-URI matching trap (post #49)

This commit is contained in:
Claude
2026-10-08 16:40:51 +00:00
parent 4370ac7fdf
commit b9388053c4
23 changed files with 704 additions and 0 deletions
+92
View File
@@ -0,0 +1,92 @@
#!/usr/bin/env bash
# Regenerates every file in docs/output/ from a real build - nothing in there is hand-typed.
#
# 00-full-test-run.txt, 01-04: from the 4 committed test classes (mvn test).
# 05: from a scratch test class, recreated here, run once, captured, deleted again. It is not
# part of the committed suite - it exists only to show the real failure of a relative
# requestTo() against a RestClient built with an absolute baseUrl.
# 06: the real `mvn dependency:tree` subtree showing Jackson 3 (tools.jackson.core) resolving
# in place of classic Jackson 2.
set -euo pipefail
cd "$(dirname "$0")/.."
echo "== mvn test (4 committed classes) =="
mvn -q test
{
echo "# mvn test - full run, Spring Boot 4.1.1"
echo
mvn test 2>&1 | grep -E "^\[INFO\] Running |^\[INFO\] Tests run|^\[INFO\] Results:|^\[INFO\] BUILD"
} > docs/output/00-full-test-run.txt
echo "== scratch: relative requestTo() against an absolute RestClient baseUrl =="
SCRATCH=src/test/java/com/ankurm/restclienttest/ScratchRelativeRequestToFailsDemoTest.java
cat > "$SCRATCH" <<'EOF'
package com.ankurm.restclienttest;
import tools.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.restclient.test.autoconfigure.RestClientTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.client.MockRestServiceServer;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;
@RestClientTest(EmployeeClient.class)
class ScratchRelativeRequestToFailsDemoTest {
@Autowired
private MockRestServiceServer mockServer;
@Autowired
private EmployeeClient employeeClient;
@Autowired
private ObjectMapper objectMapper;
@org.springframework.test.context.bean.override.mockito.MockitoBean
private EmployeeAuditLogger auditLogger;
@Test
void whenRequestToIsRelative_thenMismatch() throws Exception {
Employee mockEmployee = new Employee(1, "Ankur", "M", "[email protected]");
String employeeJson = objectMapper.writeValueAsString(mockEmployee);
mockServer.expect(requestTo("/employees/1"))
.andRespond(withSuccess(employeeJson, MediaType.APPLICATION_JSON));
employeeClient.getEmployeeById(1);
}
}
EOF
# The scratch test's real, expected failure gives mvn a nonzero exit code - capture via command
# substitution with `|| true` rather than a raw pipe, which would abort this script under
# set -o pipefail even though the failure is exactly what we're here to capture.
raw_out="$(mvn test -Dtest=ScratchRelativeRequestToFailsDemoTest 2>&1 || true)"
rm "$SCRATCH"
{
echo "# ScratchRelativeRequestToFailsDemoTest - run once to capture this real failure, then deleted."
echo "# Reproduces EmployeeClient (RestClient.Builder.baseUrl(\"http://hr-api.example.com\")) with a"
echo "# relative mockServer.expect(requestTo(\"/employees/1\")) - the pattern that works fine for"
echo "# EmployeeTemplateClient's RestTemplateBuilder.rootUri(). See scripts/run-all.sh to regenerate."
echo
echo "$raw_out" | grep -A20 "AssertionError: Request URI expected"
} > docs/output/05-restclient-relative-requestto-fails.txt
echo "== dependency:tree subtree showing Jackson 3 resolving by default =="
{
echo "# mvn dependency:tree, trimmed to the spring-boot-starter-restclient / Jackson subtree."
echo "# Full raw output has an \"[INFO] \" prefix on every line, stripped here for quoting."
echo
mvn dependency:tree 2>&1 | grep -E "^\[INFO\]" | sed -E 's/^\[INFO\] //' \
| grep -A4 "spring-boot-starter-jackson:jar"
} > docs/output/06-dependency-tree-jackson3.txt
echo "== confirming the committed suite is still green after the scratch run =="
mvn -q test
echo "Done. docs/output/ regenerated."