Support non-JSON content types and fix multi-placeholder replacement #12

Merged
stne3960 merged 1 commits from fixes into main 2026-05-12 11:40:06 +02:00
2 changed files with 51 additions and 33 deletions
Showing only changes of commit 985fa8ce2f - Show all commits

View File

@@ -135,11 +135,21 @@ public class MockRequestInterceptor implements HandlerInterceptor {
// Replace placeholders in the mock response body with path/global values // Replace placeholders in the mock response body with path/global values
Object body = mockService.replacePlaceholders(selected.body(), pathVars); Object body = mockService.replacePlaceholders(selected.body(), pathVars);
// Write the mock response: headers, status, and JSON body // Write the mock response: headers, status, and body
selected.headers().forEach(response::setHeader); selected.headers().forEach(response::setHeader);
response.setStatus(selected.status()); response.setStatus(selected.status());
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
// Respect Content-Type from YAML headers; default to application/json
String contentType = selected.headers().getOrDefault("Content-Type",
MediaType.APPLICATION_JSON_VALUE);
response.setContentType(contentType);
// For non-JSON content types with a string body, write the raw string directly
if (!contentType.contains("json") && body instanceof String rawBody) {
response.getWriter().write(rawBody);
} else {
response.getWriter().write(mockService.toJson(body)); response.getWriter().write(mockService.toJson(body));
}
return false; // Request has been fully handled return false; // Request has been fully handled
} }

View File

@@ -215,28 +215,24 @@ public class MockService {
String result = input; String result = input;
// Process datetime with offset (e.g., {datetime+2d4h30m} or {datetime+2d4h30m:rfc3339}) // Process datetime with offset (e.g., {datetime+2d4h30m} or {datetime+2d4h30m:rfc3339})
Matcher dateTimeOffsetMatcher = DATETIME_OFFSET_PATTERN.matcher(result); result = replaceAllMatches(result, DATETIME_OFFSET_PATTERN, matcher -> {
if (dateTimeOffsetMatcher.find()) { String sign = matcher.group("sign");
String sign = dateTimeOffsetMatcher.group("sign"); String daysStr = matcher.group("days");
String daysStr = dateTimeOffsetMatcher.group("days"); String hoursStr = matcher.group("hours");
String hoursStr = dateTimeOffsetMatcher.group("hours"); String minutesStr = matcher.group("minutes");
String minutesStr = dateTimeOffsetMatcher.group("minutes"); String format = matcher.group("format");
String format = dateTimeOffsetMatcher.group("format");
LocalDateTime now = LocalDateTime.now(); LocalDateTime now = LocalDateTime.now();
LocalDateTime target = calculateDateTimeWithOffset(now, sign, daysStr, hoursStr, minutesStr); LocalDateTime target = calculateDateTimeWithOffset(now, sign, daysStr, hoursStr, minutesStr);
return formatDateTime(target, format);
String replacement = formatDateTime(target, format); });
result = dateTimeOffsetMatcher.replaceFirst(replacement);
}
// Process datetime with days at specific time (e.g., {datetime+2d@13:00} or {datetime+2d@13:00:rfc3339}) // Process datetime with days at specific time (e.g., {datetime+2d@13:00} or {datetime+2d@13:00:rfc3339})
Matcher dateTimeAtTimeMatcher = DATETIME_AT_TIME_PATTERN.matcher(result); result = replaceAllMatches(result, DATETIME_AT_TIME_PATTERN, matcher -> {
if (dateTimeAtTimeMatcher.find()) { String sign = matcher.group("sign");
String sign = dateTimeAtTimeMatcher.group("sign"); int days = Integer.parseInt(matcher.group("days"));
int days = Integer.parseInt(dateTimeAtTimeMatcher.group("days")); String timeStr = matcher.group("time");
String timeStr = dateTimeAtTimeMatcher.group("time"); String format = matcher.group("format");
String format = dateTimeAtTimeMatcher.group("format");
LocalDate targetDate = LocalDate.now(); LocalDate targetDate = LocalDate.now();
if ("+".equals(sign)) { if ("+".equals(sign)) {
@@ -247,17 +243,14 @@ public class MockService {
LocalTime time = LocalTime.parse(timeStr); LocalTime time = LocalTime.parse(timeStr);
LocalDateTime target = LocalDateTime.of(targetDate, time); LocalDateTime target = LocalDateTime.of(targetDate, time);
return formatDateTime(target, format);
String replacement = formatDateTime(target, format); });
result = dateTimeAtTimeMatcher.replaceFirst(replacement);
}
// Process date with offset (e.g., {date-4d} or {date-4d:MMM dd, yyyy}) // Process date with offset (e.g., {date-4d} or {date-4d:MMM dd, yyyy})
Matcher dateOffsetMatcher = DATE_OFFSET_PATTERN.matcher(result); result = replaceAllMatches(result, DATE_OFFSET_PATTERN, matcher -> {
if (dateOffsetMatcher.find()) { String sign = matcher.group("sign");
String sign = dateOffsetMatcher.group("sign"); int days = Integer.parseInt(matcher.group("days"));
int days = Integer.parseInt(dateOffsetMatcher.group("days")); String format = matcher.group("format");
String format = dateOffsetMatcher.group("format");
LocalDate target = LocalDate.now(); LocalDate target = LocalDate.now();
if ("+".equals(sign)) { if ("+".equals(sign)) {
@@ -265,14 +258,29 @@ public class MockService {
} else { } else {
target = target.minusDays(days); target = target.minusDays(days);
} }
return formatDate(target, format);
String replacement = formatDate(target, format); });
result = dateOffsetMatcher.replaceFirst(replacement);
}
return result; return result;
} }
/**
* Replaces all matches of a pattern in the input string, using a function
* to compute the replacement for each match.
*/
private String replaceAllMatches(String input, Pattern pattern,
java.util.function.Function<Matcher, String> replacer)
{
Matcher matcher = pattern.matcher(input);
StringBuilder sb = new StringBuilder();
while (matcher.find()) {
String replacement = replacer.apply(matcher);
matcher.appendReplacement(sb, Matcher.quoteReplacement(replacement));
}
matcher.appendTail(sb);
return sb.toString();
}
/** /**
* Calculates a LocalDateTime with the given offset components. * Calculates a LocalDateTime with the given offset components.
* @param base the base datetime to start from * @param base the base datetime to start from