英文:
Spring Boot Jackson date format
问题
I have a problem with Jackson in SpringBoot. My controller returns dates in format yyyy-MM-dd'T'HH:mm:ss'Z'
, but I need yyyy-MM-dd'T'HH:mm:ss.SSS'Z'
(for mwl-calendar in angular which uses date-fns library).
Controller:
@GetMapping(value = "/slots", produces = MediaType.APPLICATION_JSON_VALUE)
public Set<SlotResponse> timeSlots() {
return slotService.getSlots();
}
SlotResponse:
@Data
public class SlotResponse {
private Instant start;
private Instant end;
}
Additional dependency:
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
I tried:
- to use
@JsonFormat(pattern="yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
annotation - to use
spring.jackson.date-format=yyyyMMdd'T'HH:mm:ss.SSSZ
configuration - to create ObjectMapper manually:
@Bean
public ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"));
return mapper;
}
- to enable options
SerializationFeature.WRITE_DATES_WITH_ZONE_ID
andSerializationFeature.WRITE_DATES_WITH_CONTEXT_TIME_ZONE
But all of this didn't take effect. Every time I see this result:
[{"start":"2023-05-11T16:00:00Z","end":"2023-05-11T17:00:00Z"}]
I use Java 17, SpringBoot 2.7.0, Jackson 2.13.3
What is wrong?
英文:
I have a problem with Jackson in SpringBoot. My controller returns dates in format yyyy-MM-dd'T'HH:mm:ss'Z'
, but I need yyyy-MM-dd'T'HH:mm:ss.SSS'Z'
(for mwl-calendar in angular which uses date-fns library).
Controller:
@GetMapping(value = "/slots", produces = MediaType.APPLICATION_JSON_VALUE)
public Set<SlotResponse> timeSlots() {
return slotService.getSlots();
}
SlotResponse:
@Data
public class SlotResponse {
private Instant start;
private Instant end;
}
Additional dependency:
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
I tried:
- to use
@JsonFormat(pattern="yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
annotation - to use
spring.jackson.date-format=yyyyMMddTHH:mm:ss.SSSZ
configuration - to create ObjectMapper manually:
@Bean
public ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"));
return mapper;
}
- to enable options
SerializationFeature.WRITE_DATES_WITH_ZONE_ID
andSerializationFeature.WRITE_DATES_WITH_CONTEXT_TIME_ZONE
But all of this didn't take effect. Everytime I see this result:
[{"start":"2023-05-11T16:00:00Z","end":"2023-05-11T17:00:00Z"}]
I use Java 17, SpringBoot 2.7.0, Jackson 2.13.3
What is wrong?
答案1
得分: 3
你可以为Instant类型创建自定义的JSON序列化器:
```java
public static class InstantSerializer extends StdSerializer<Instant> {
public InstantSerializer() {
super(Instant.class);
}
@Override
public void serialize(
@Nullable final Instant value,
@NonNull final JsonGenerator jsonGenerator,
@NonNull final SerializerProvider serializerProvider
) throws IOException {
if (value != null) {
final DateTimeFormatter formatter = DateTimeFormatter
.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
.withZone(ZoneId.systemDefault());
final String text = formatter.format(value);
jsonGenerator.writeString(text);
}
}
}
然后在你想要按照这个格式处理的字段上使用它:
@Data
public class SlotResponse {
@JsonSerialize(using = InstantSerializer.class) // Add this
private Instant start;
@JsonSerialize(using = InstantSerializer.class) // Add this
private Instant end;
}
如果你想让这个适用于整个系统,你可以将这个序列化器添加到Jackson中:
@Bean
public ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
...
final SimpleModule module = new SimpleModule();
module.addSerializer(new InstantSerializer());
mapper.registerModule(module);
...
return mapper;
}
<details>
<summary>英文:</summary>
You can create custom json serializer for Instant type:
public static class InstantSerializer extends StdSerializer<Instant> {
public InstantSerializer() {
super(Instant.class);
}
@Override
public void serialize(
@Nullable final Instant value,
@NonNull final JsonGenerator jsonGenerator,
@NonNull final SerializerProvider serializerProvider
) throws IOException {
if (value != null) {
final DateTimeFormatter formatter = DateTimeFormatter
.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
.withZone(ZoneId.systemDefault());
final String text = formatter.format(value);
jsonGenerator.writeString(text);
}
}
}
Then use it on the field that you want to follow the format:
@Data
public class SlotResponse {
@JsonSerialize(using = InstantSerializer.class) // Add this
private Instant start;
@JsonSerialize(using = InstantSerializer.class) // Add this
private Instant end;
}
In case you want to make this apply for your whole system, you can add the serializer to jackson:
@Bean
public ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
...
final SimpleModule module = new SimpleModule();
module.addSerializer(new InstantSerializer());
mapper.registerModule(module);
...
return mapper;
}
</details>
# 答案2
**得分**: 1
I apologize, but the text you provided contains a mix of code, formatting, and explanations. It's challenging to provide a meaningful translation without context. If you have specific parts that need translation or if you'd like a summary of the content, please specify, and I'll be happy to assist.
<details>
<summary>英文:</summary>
### Sorry, cannot reproduce
With (*only*)
- spring-boot-starter-web:2.7.0
- lombok
- (dev tools, spring-boot-starter-test)
, (shortened) "dto":
package com.example.soq76225352;
import java.time.Instant;
import lombok.Data;
@Data
public class SomeResponse {
private Instant start = Instant.now();
}
and:
```lang-java
@RestController
class DemoController {
@GetMapping(value = "/slots")
public SomeResponse timeSlots() {
return new SomeResponse();
}
}
(no other settings, properties, only defaults..)
, we get:
{"start":"2023-05-11T09:08:23.569050400Z"}
which looks very like the desired format. (??)
As soon I add:
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
, I get:
2023-05-11 11:03:49.487 WARN 3732 --- [nio-8080-exec-3] .w.s.m.s.DefaultHandlerExceptionResolver :
Resolved [org.springframework.http.converter.HttpMessageNotWritableException:
Could not write JSON: Unsupported field: YearOfEra; nested exception is com.fasterxml.jackson.databind.JsonMappingException:
Unsupported field: YearOfEra (through reference chain:
com.example.soq76225352.SomeResponse["start"])
]
(-> /error
-> 404
) !?
Going deeper
- The format
'Z'
refers to a "literal Z" - Whereas
Z
refers to the "zone offset" (in form+HHMM
, see DateTimeFormatterBuilder + source documentation) - On the other hand:
X
is the "zone offset" (as described byZ
) or (literal)'Z'
in case of "zero offset"/UTC!DateTimeFormatter
To make it work:
-
in all cases (that's strange for the literal case!), we have to:
- or
@JsonFormat(timezone = "..." //,...
- or
spring.jackson.time-zone
... (explicitly) set the "config time zone", see https://stackoverflow.com/q/7556851/592355
- additionally we need to ensure (it is by default):
spring.jackson.serialization.WRITE_DATES_WITH_CONTEXT_TIME_ZONE=true
, see source code(your version)
- or
Given (e.g.)
spring.jackson.time-zone=UTC
When/Then
- When format is
'Z'
, then we get"...Z"
- When format is
Z
, then we get"...+0000"
- When format is
X
, then we get (also)"...Z"
Relevant, but old:
Relevant, but not deep/exact (milliseconds) enough:
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论