我有以下物件:
@Validated
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
@ToString
@Schema(description = "Request")
public final class Request implements Serializable {
private static final long serialVersionUID = 1L;
@JsonProperty("date")
@Schema(description = "Date")
private OffsetDateTime date;
}
我將此物件作為休息控制器的回應發送:
@RestController
public class RequestController {
@RequestMapping(
value = "/requests",
produces = {"application/json;charset=UTF-8"},
consumes = {"application/json"},
method = RequestMethod.POST)
public ResponseEntity<Request> get() {
LocalDate date = LocalDate.of(2021, Month.OCTOBER, 22);
OffsetDateTime dateTime = date.atTime(OffsetTime.MAX);
Request request = new Request(dateTime);
return ResponseEntity.ok(request);
}
}
然而我有配置:
@Configuration
public class WebConfiguration implements ServletContextInitializer, WebMvcConfigurer {
private final List<FilterRegistration> filterRegistrations;
private final ApplicationContext applicationContext;
public WebConfiguration(List<RestApplicationInstaller> restApplicationInstallers,
List<MonitoringRestApplicationInstaller> monitoringRestApplicationInstallers,
List<FilterRegistration> filterRegistrations,
ApplicationContext applicationContext) {
this.filterRegistrations = filterRegistrations;
this.applicationContext = applicationContext;
}
@Override
public void onStartup(ServletContext servletContext) {
VersionServletInstaller.installServlets(servletContext, getRegisterAsyncService(servletContext));
filterRegistrations.forEach(filterRegistration -> filterRegistration.onApplicationEvent(new ContextRefreshedEvent(applicationContext)));
}
private RegisterAsyncService getRegisterAsyncService(final ServletContext servletContext) {
final WebApplicationContext ctx = getWebApplicationContext(servletContext);
final RegisterAsyncService registerAsyncService = Objects.requireNonNull(ctx).getBean(RegisterAsyncService.class);
registerAsyncService.exec();
return registerAsyncService;
}
@Bean
public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer(CustomAnnotationIntrospector customAnnotationIntrospector) {
return builder -> builder.serializationInclusion(NON_NULL)
.annotationIntrospector(customAnnotationIntrospector);
}
}
好的。所以......我得到的date領域回應為:
2021-10-21T23:59:59.999999999-18:00
當我測驗我的控制器時,我嘗試獲得回應,將其反序列化為Request物件并檢查匹配:
@DirtiesContext
@SpringBootTest(
classes = {WebConfiguration.class, JacksonAutoConfiguration.class},
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ExtendWith(SpringExtension.class)
@EnableWebMvc
class RequestControllerTest {
private static final CharacterEncodingFilter
CHARACTER_ENCODING_FILTER = new CharacterEncodingFilter();
static {
CHARACTER_ENCODING_FILTER.setEncoding(DEFAULT_ENCODING);
CHARACTER_ENCODING_FILTER.setForceEncoding(true);
}
protected MockMvc mockMvc;
@Autowired
protected ObjectMapper objectMapper;
@Autowired
private WebApplicationContext context;
@PostConstruct
private void postConstruct() {
this.mockMvc =
MockMvcBuilders
.webAppContextSetup(this.context)
.addFilters(CHARACTER_ENCODING_FILTER)
.build();
}
@Test
void requestByIdTest() throws Exception {
mockMvc.perform(
MockMvcRequestBuilders.post("/requests")
.characterEncoding(CHARACTER_ENCODING_FILTER)
.contentType(MediaType.APPLICATION_JSON))
.andDo(print())
.andExpect(status().isOk())
.andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON))
.andExpect(
result -> Assertions.assertEquals(mapToObject(result.getResponse().getContentAsString(Charset.forName(CHARACTER_ENCODING_FILTER)), Request.class), getExpectedRequest()));
}
private WebComplianceRequest getExpectedRequest() {
LocalDate date = LocalDate.of(2021, Month.OCTOBER, 22);
OffsetDateTime dateTime = date.atTime(OffsetTime.MAX);
Request request = new Request(dateTime);
}
private <T> T mapToObject(String json, Class<T> targetClass) {
try {
return getReaderForClass(targetClass).readValue(json);
} catch (IOException e) {
throw new RuntimeExsception(e);
}
}
private <T> ObjectReader getReaderForClass(Class<T> targetClass) {
return objectMapper.readerFor(targetClass);
}
}
但我得到一個例外,因為date預期物件和得到物件中的欄位不同:
Date in response: 2021-10-22T17:59:59.999999999Z
Expected date: 2021-10-21T23:59:59.999999999-18:00
為什么會這樣?
為什么Z出現而不是時區?為什么日期從 更改2021-10-21為2021-10-22?我該如何解決?
我沒有得到任何例外,我匹配失敗,因為當我匹配回應和預期物件時日期不同。我只是用標準反序列化物件ObjectMapper并檢查與equals().
uj5u.com熱心網友回復:
到目前為止我們所知道的
- 您正在
OffsetDateTime通過LocalDate添加可用的最大偏移量(恰好是-18:00小時)來創建 - 這
OffsetDateTime被正確序列化為 JSON 值2021-10-21T23:59:59.999999999-18:00 - 反序列化時,值(as
String)是2021-10-22T17:59:59.999999999Z
關鍵部分目前還沒有包括:2. 和 3. 之間會發生什么?
請考慮用您所知道的一切來更新您的問題。
我們可以得出什么
出現不一致的值基本上是同一時刻 ( Instant),但以-18:00at 序列化的偏移量表示并以 UTC ( 00:00或簡稱Z) 表示。由于這些時刻之間存在 18 小時的差異,并且由于您創建了一個OffsetDateTimewith OffsetTime.MAX(即23:59:59.999999999-18:00,偏移量為 的一天中的最長時間-18:00)。
這就是為什么你在反序列化后得到的結果沒有錯,但它的表示可能不是你想要的。
我的猜測是 anInstant用于 2. 和 3. 之間的子步驟,反序列化僅提供 UTC 中的日期和時間。
如果沒有明確要求,我不會將最大偏移量傳遞給任何 API。在你的情況下嗎?也可以考慮添加相關資訊。
我們可以做些什么來使時間String相等
您可以使用不同的可能性OffsetDateTime從中創建LocalDate,即使用一天中的最大時間而沒有在 UTC 顯式偏移:
OffsetDateTime dateTime = OffsetDateTime.of(date, LocalTime.MAX, ZoneOffset.UTC);
這將序列化為2021-10-21T23:59:59.999999999Z,您也可以將其表示為2021-10-21T23:59:59.999999999 00:00或類似的(我會堅持使用Z)并且反序列化應該回傳相同的值。
如果您收到StringUTC格式的表示并且您對它沒有任何影響,您將必須決議它并通過應用最小偏移量 ( -18:00) 來更改表示,可能是這樣的:
String atMinOffset = OffsetDateTime.parse("2021-10-22T17:59:59.999999999Z")
.withOffsetSameInstant(ZoneOffset.MIN)
.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME);
System.out.println(atMinOffset);
輸出:
2021-10-21T23:59:59.999999999-18:00
如果您收到一個OffsetDateTime作為回應并且只想檢查它是否是同一時間點,請考慮:
public static void main(String[] args) throws IOException {
OffsetDateTime utcOdt = OffsetDateTime.parse("2021-10-22T17:59:59.999999999Z");
OffsetDateTime minOffsetOdt = OffsetDateTime.parse("2021-10-21T23:59:59.999999999-18:00");
System.out.println("OffsetDateTimes equal? --> " utcOdt.equals(minOffsetOdt));
System.out.println("Instants equal? --> " utcOdt.toInstant().equals(minOffsetOdt.toInstant()));
}
它的輸出是
OffsetDateTimes equal? --> false
Instants equal? --> true
為什么?
AnOffsetDateTime是某個時刻的表示,而 anInstant實際上是那個時刻。
這意味著您應該及時比較真實時刻,而不是基于背景關系的表示。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/370510.html
上一篇:在Pandas中合并日期和時間
