fix: use the Jackson 3 mapper the persistence module actually has

JdbcProjectRepositoryAdapter asked for com.fasterxml.jackson.databind.ObjectMapper
— Jackson 2. This build is on Jackson 3 (tools.jackson.databind), so no bean
of that type exists and the context failed to refresh: the pod crash-looped
with 'Parameter 1 ... required a bean of type ObjectMapper that could not be
found'.

Compilation could not catch it. The Jackson 2 types are still on the classpath
through some transitive dependency, so the wrong import resolves and only the
container tells you. PublicJson in the sibling package was already on Jackson 3
and is the shape this now follows.

readTree/asString rather than readValue with a TypeReference: Jackson 3 does
not throw a checked exception here, so the surrounding try/catch narrows to
RuntimeException and the method keeps its contract of degrading to an empty
list rather than failing the whole edit screen.
This commit is contained in:
DongHyeonka
2026-08-20 23:54:18 +09:00
parent bb6d2330bb
commit 0da7c7e2db
@@ -1,7 +1,5 @@
package dev.caskeleton.adapter.outbound.persistence.techlog.management;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import dev.caskeleton.application.techlog.management.command.CreateProjectCommand;
import dev.caskeleton.application.techlog.management.command.UpdateProjectCommand;
import dev.caskeleton.application.techlog.management.model.ProjectEditView;
@@ -11,10 +9,13 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import org.springframework.jdbc.core.simple.JdbcClient;
import tools.jackson.databind.JsonNode;
import tools.jackson.databind.ObjectMapper;
import org.springframework.stereotype.Repository;
/**
@@ -36,8 +37,6 @@ public class JdbcProjectRepositoryAdapter implements ProjectRepositoryPort {
"id, name, phase, workflow_status, target_visibility, current_objective, next_step,"
+ " updated_at, version, first_published_at, last_published_at";
private static final TypeReference<List<String>> LABELS = new TypeReference<>() {};
private final JdbcClient jdbcClient;
private final ObjectMapper objectMapper;
@@ -54,20 +53,20 @@ public class JdbcProjectRepositoryAdapter implements ProjectRepositoryPort {
private List<String> labels(String json) {
if (json == null || json.isBlank()) return List.of();
try {
return objectMapper.readValue(json, LABELS);
} catch (Exception malformed) {
// 열 자체가 jsonb 배열로 제약돼 있으므로 여기 오면 데이터가 아니라 스키마가 어긋난 것이다.
JsonNode node = objectMapper.readTree(json);
if (!node.isArray()) return List.of();
List<String> out = new ArrayList<>();
for (JsonNode item : node) out.add(item.asString(""));
return List.copyOf(out);
} catch (RuntimeException malformed) {
// 열이 jsonb 배열로 제약돼 있으므로 여기 오면 데이터가 아니라 스키마가 어긋난 것이다.
// 편집 화면 전체를 막는 대신 빈 목록으로 두고 나머지 필드를 보여준다.
return List.of();
}
}
private String labelsJson(List<String> values) {
try {
return objectMapper.writeValueAsString(values == null ? List.of() : values);
} catch (Exception impossible) {
throw new IllegalStateException("technology labels are not serialisable", impossible);
}
return objectMapper.writeValueAsString(values == null ? List.of() : values);
}
private ProjectEditView mapEdit(ResultSet rs, int rowNum) throws SQLException {