Encode the usage rules of Jackson in DDD4J projects. Jackson usage in LLM training data conflicts with project conventions.
Why this skill is needed
LLMs will serialize dates in ISO-8601 format 2024-03-15T10:30:00Z —DDD4J requires 2024-03-15 10:30:00. LLMs will not return []for null arrays—the DDD4J frontend expects null arrays to never appear. LLMs do not know these rules.
Capability Boundaries
✅ Strong Suits
- Date format rule — yyyy-MM-dd HH:mm:ss (non-ISO-8601)
- Null value rules — array→[], string→"", number→keep null, boolean→keep null
- @Sensitive masking — 5 strategies (phone/ID card/name/address/email)
- JacksonKit — independent ObjectMapper dedicated to Redis/cache (DefaultTyping.NON_FINAL)
- ToLongDeserializer — handles precision loss for large numbers in frontend JS
❌ Out of Scope
- Entity inheritance/return value conventions → ddd4j-core
- MyBatis JSON field handling → ddd4j-mybatis
- API signature/security → ddd4j-satoken
The most common LLM mistakes
| # | Wrong | Correct approach |
|---|---|---|
| 1 | Use ISO-8601 for dates 2024-03-15T10:30:00Z |
Use yyyy-MM-dd HH:mm:ss |
| 2 | null array returns null |
Return [] |
| 3 | null string returns null |
Return "" |
| 4 | Return 0 |
for a null number: numbers/booleans keep null, no conversion |
| 5 | Write masking logic manually | Use @Sensitive(strategy = SensitiveStrategy.PHONE) |
| 6 | Use Web ObjectMapper for cache | Use JacksonKit (DefaultTyping.NON_FINAL + ALL visibility) |
| 7 | Return Long directly for large numbers | Use ToLongDeserializer to handle precision loss |
Core rules quick reference
// ❌ 错误:LLM会这样写
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
private LocalDateTime createTime;
// ✅ 正确:DDD4J 已全局配置
private LocalDateTime createTime; // 序列化为 "2024-03-15 10:30:00"
// ✅ Null 处理:前端收到的 JSON
// null 数组 → [] (默认开启)
// null 字符串 → "" (默认开启)
// null 对象 → {} (默认开启)
// null 数字 → null (不转化)
// null 布尔 → null (不转化)
// ✅ 敏感数据脱敏
public class UserVO {
@Sensitive(strategy = SensitiveStrategy.PHONE)
private String phone; // 185****1653
@Sensitive(strategy = SensitiveStrategy.ID_CARD)
private String idCard; // 1234****5678
@Sensitive(strategy = SensitiveStrategy.USERNAME)
private String name; // 张*三
@Sensitive(strategy = SensitiveStrategy.EMAIL)
private String email; // r*****o@qq.com
@Sensitive(strategy = SensitiveStrategy.ADDRESS)
private String address; // 北京市****海淀区****
}
// ✅ 两个 ObjectMapper
// Web用:JacksonAutoConfiguration 自动配置的,用于 HTTP 请求响应
@Autowired private ObjectMapper objectMapper;
// 缓存用:JacksonKit 独立 ObjectMapper,带 DefaultTyping.NON_FINAL
JacksonKit.toJson(obj); // 序列化时写入类型信息
JacksonKit.fromJson(json, Type.class); // 反序列化时根据类型信息恢复
Gotchas
- Do not configure Jackson2ObjectMapperBuilderCustomizer yourself — DDD4J is already preconfigured; conflicts will cause date format corruption
- Storing objects in Redis must use JacksonKit, not ObjectMapper — Web ObjectMapper has no DefaultTyping, polymorphic deserialization will lose types
- A null number will not be converted to 0 — the frontend needs to handle the case where a number may be null (unlike arrays/strings)
- @Sensitive only takes effect on String type — other types are ignored
- ToLongDeserializer accepts strings and converts them to Long — the frontend passes
"1234567890123456789"and it can still be parsed correctly - The date format affects both serialization and deserialization — dates submitted by the frontend must also be
yyyy-MM-dd HH:mm:ss
Data Privacy
This skill does not collect, store, or transmit any user data. The @Sensitive annotation is only used to mask existing sensitive data during serialization.