当前位置: 首页 > 知识库问答 >
问题:

Jackson解析异常-(尽管至少存在一个创建者):没有字符串参数构造函数/工厂方法可以从字符串值反序列化

花烨
2023-03-14
  • Spring启动版本: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;
}
@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"));
}
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);
}

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

@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()));
}

共有1个答案

郎成龙
2023-03-14

最后我终于解决了这个问题。这个问题是在我的发布者代码中编写的错误代码造成的,首先,我通过将我的entried有效负载转换为json对象(使用jackson)来加密我的有效负载,然后,我再次将json有效负载存储在带有header的对象中,并试图将该对象转换为字符串(再次使用jackson转换器)。在这个过程中,我两次将整个有效负载转换为字符串,因此,我在通过Kafka发送的有效负载中引入了额外的\r\n。当从json到object转换回object时,这个额外的\r\n导致了我前面粘贴的问题。

作为解决方案,我将已经转换的json对象存储到另一个带有jackson注释@JSONRAWData的对象中。这样可以防止添加额外的\r\n

 类似资料: