Jackson解析异常 - (尽管至少存在一个Creator):没有String-argument构造函数/工厂方法从String值反序列化

SUM*_*MIT 6 java parsing json jackson jackson-databind

  • Spring Boot版本:1.5.10
  • 杰克逊版本:2.9.5
  • 龙目岛版本:1.18.0

我有一个场景,我使用kafka发送有效负载.在收到该有效载荷时,我试图断言接收器和发送器端的有效载荷是否相同.

首先,我创建了一个将作为有效负载传递的类.该课程的结构如下.使用的lombok插件版本是1.18.0.

@Builder
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public class MyDummyClass implements Serializable{

    private static final long serialVersionUID = -4181985100899233094L;
    private String data;
    private String id;
}
Run Code Online (Sandbox Code Playgroud)

对于上面的pojo,我创建了一个单元测试,我传递一个字符串并尝试将其从String转换为对象,该工作没有任何问题.

@Test
public void shouldBeAbleToConvertStringToDesiredObjectType() throws IOException {
    String s = "{\r\n  \"data\" : \"foo\",\r\n  \"id\" : \"xyz\"\r\n}";
    MyDummyClass myDummyClass = convertValue(s, MyDummyClass.class);
    assertThat(myDummyClass.getData(), is("foo"));
}
Run Code Online (Sandbox Code Playgroud)

杰克逊映射器配置也在下面给出.

private static final ObjectMapper mapper = new ObjectMapper();

static {
    mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
    mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
    mapper.disable(FAIL_ON_UNKNOWN_PROPERTIES);
    mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
    mapper.enable(ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    mapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
    mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
    // Skip the Null Values
    mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
    mapper.disableDefaultTyping();

    DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX"); //YYYY-MM-DDThh:mm:ss.sTZD (e.g. 1997-07-16T19:20:30.45.003+01:00)
    dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
    mapper.setDateFormat(dateFormat);
}
Run Code Online (Sandbox Code Playgroud)

现在来到主要问题陈述.所以在我的另一个测试用例中,我通过kafka发送有效负载,并在收到kafka主题的响应后,我试图将传入的String数据转换为所需的MyDummyClass类类型.在我的测试用例中,我已经使用logger语句来查看我收到的值.我可以看到我得到的是上面测试用例中提到的完全相同的字符串值.但在将该文本解析为所需的MyDummyClass类型时,我收到错误(尽管至少存在一个Creator):没有String-argument构造函数/工厂方法从String值反序列化.

@Test
public void messageWithAnyContractObjectCanBeConvertedToSameObjectAtTheListenerEnd() throws InterruptedException, IOException, JSONException {
    String correlationID = UUID.randomUUID().toString();
    String id = UUID.randomUUID().toString();
    MyDummyClass actualPayload = MyDummyClass.builder().data("foo").id("xyz").build();
    Message message = MessageBuilder.withAnyMessage()
            .withNoHeader(BaseHeader.builder().ID(id).correlationID(correlationID).sendToDestination("my-topic").build())
            .payload(actualPayload)
            .build();
    messagePublisher.publishMessage(message, DEFAULT_PUBLISHER_OPTIONS);

    String recordedString = records.poll(10, TimeUnit.SECONDS).value();
    LOGGER.info("Receiving Response {}", recordedString);
    MyDummyClass recordedValue = convertValue(recordedString, MyDummyClass.class);

    assertThat(recordedValue.getData(), is(actualPayload.getData()));
}
Run Code Online (Sandbox Code Playgroud)

详细错误日志: 在此输入图像描述

SUM*_*MIT 7

终于我能够解决这个问题了。此问题是由于在发布者代码中编写的代码错误导致的,首先,我通过将输入的有效负载转换为json对象(使用jackson)来加密我的有效负载,后来我再次将该json有效负载存储在带有标头的对象中,并试图将该对象转换为字符串(再次使用杰克逊转换器)。在此过程中,我将整个有效负载两次转换为字符串,结果将多余的\r\n东西引入了我通过kafka发送的有效负载。在将对象从json转换回对象的同时,这些额外\r\n的问题导致了我之前粘贴的问题。

作为解决方案,我将已经转换的json对象存储到另一个具有jackson批注@JsonRawData的对象中。这样可以防止添加多余的内容\r\n

  • 解决了多少天?出于纯粹的好奇心 (7认同)