【问题标题】:Jackson LocalDate/Time deserializationJackson LocalDate/Time 反序列化
【发布时间】:2018-09-29 23:21:12
【问题描述】:

我配置了 jackson,以便在 java.time.LocalDatejava.time.LocalDateTime 时给我一个简单的字符串表示。这可以在序列化过程中找到,例如当我在 REST api 上获取数据时。

但是反过来就不行了。当我尝试向服务器发送数据并且 JSON 应该被解析为 java 对象时,会抛出此异常:

javax.ws.rs.client.ResponseProcessingException:com.fasterxml.jackson.databind.JsonMappingException:无法构造 java.time.LocalDateTime 的实例:没有从字符串值反序列化的字符串参数构造函数/工厂方法('2018 -04-19T14:10:30.903')

经过几个小时的研究,我设法让它工作,但只使用了我分别用@JsonDeserialize(using = LocalDateDeserializer.class)@JsonDeserialize(using = LocalDateTimeDeserializer.class) 注释的属性。

在我看来,如果我可以在一个中心位置定义这些映射,那将是理想的。

ObjectMapper 配置:

@Provider
public class ObjectMapperContextResolver implements ContextResolver<ObjectMapper> {
    @Override
    public ObjectMapper getContext(Class<?> aClass) {
        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(new JavaTimeModule());
        mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);

        return mapper;
    }
}

我尝试将自定义反序列化器添加到 JavaTimeModule,但没有成功:

JavaTimeModule dateTimeModule = new JavaTimeModule();
dateTimeModule.addDeserializer(LocalDate.class, LocalDateDeserializer.INSTANCE);
dateTimeModule.addDeserializer(LocalDateTime.class, LocalDateTimeDeserializer.INSTANCE);

mapper.registerModule(dateTimeModule);

长话短说:有没有办法在全局范围内定义映射,这样我就不需要在每个字段上都添加这些注释。谢谢!

编辑:

好的:我用邮递员测试了它,没有注释,它按预期工作。但是,当我运行单元测试 (JerseyTest) 时,它会引发上述异常。我将ObjectMapperContextResolver 注册到测试应用程序,但可能我遗漏了一些东西。

很抱歉没有提到我参加了单元测试。

测试类:

import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;

import javax.ws.rs.core.Application;

import java.time.LocalDate;
import java.time.LocalDateTime;

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.*;


public class PocRestTest extends JerseyTest {

    private static PocService mockedPocService;

    @Override
    protected Application configure() {
        mockedPocService = Mockito.mock(PocService.class);
        ResourceConfig config = new ResourceConfig();
        config.register(new PocRest(mockedPocService));
        config.register(ObjectMapperContextResolver.class);
        return config;
    }

    private Poc dto;

    @Before
    public void init() {
        dto = new Poc();
        dto.setId(1);
        dto.setName("hi rest");
        dto.setDate(LocalDate.now());
        dto.setDateTime(LocalDateTime.now());

        doReturn(dto).when(mockedPocService).getPocById(1);
    }

    @Test
    public void test() {
        Poc response = target("poc/1").request().get(Poc.class);
        assertEquals(dto.getId(), response.getId());
        assertEquals(dto.getName(), response.getName());
        assertEquals(dto.getDate(), response.getDate());
        assertEquals(dto.getDateTime(), response.getDateTime());

        verify(mockedPocService).getPocById(1);
        verifyNoMoreInteractions(mockedPocService);
    }
}

【问题讨论】:

标签: java jersey jackson2 jersey-test-framework


【解决方案1】:

您通过JerseyTestconfigure() 方法向服务器注册了ContextResolver,但是如果您查看异常,您会发现这是一个客户端异常(注意client 在包裹名字)。所以问题出在客户端。您缺少的是反序列化也需要在客户端从 JSON 到 Poc 进行,因此您还需要在客户端上注册 ContextResolver。为此,您可以覆盖 JerseyTest 上的 configureClient() 并在那里注册 ContextResolver

@Override
public void configureClient(ClientConfig config) {
    config.register(ObjectMapperContextResolver.class);
}

【讨论】:

  • 我为此浪费了一整天的时间,解决了无数其他在使用 Jersey 测试框架时无法开箱即用的问题。最后,这是最后一个缺失的部分,非常感谢。
猜你喜欢
  • 2020-09-25
  • 2017-10-24
  • 2014-01-06
  • 1970-01-01
  • 1970-01-01
  • 2019-05-11
  • 1970-01-01
  • 1970-01-01
  • 2019-09-17
相关资源
最近更新 更多