web-dev-qa-db-ja.com

ジャクソンの解析例外-(少なくとも1つのCreatorが存在しますが):文字列値からデシリアライズする文字列引数コンストラクター/ファクトリーメソッドがありません

  • スプリングブートバージョン:1.5.10
  • ジャクソンバージョン:2.9.5
  • ロンボクバージョン:1.18.0

Kafkaを使用してペイロードを送信するシナリオがあります。そのペイロードを受信すると、受信側と送信側の両方のペイロードが同じかどうかをアサートしようとしています。

最初に、ペイロードとして渡されるクラスを作成しました。クラスの構造は以下のgievnです。使用されているロンボクプラグインのバージョンは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;
}

上記のpojoについては、文字列を渡し、それを文字列からオブジェクトに変換しようとする単体テストを作成しました 問題なく動作

@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トピックから応答を受信した後、着信を変換しようとしています。 ひも 希望するデータ MyDummyClass クラスタイプ。私のテストケースでは、ロガーステートメントを入力して、受け取っている値を確認しました。上記のテストケースで述べたのとまったく同じ文字列値を取得していることがわかります。しかし、そのテキストの解析中に希望する MyDummyClass タイプエラーが発生しています(少なくとも1人のCreatorが存在します):文字列値からデシリアライズする文字列引数コンストラクタ/ファクトリメソッドがありません。

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

詳細なエラーログ: enter image description here

6
SUMIT

最後に、この問題を解決することができました。この問題は、パブリッシャーコードの横に記述された間違ったコードの結果であり、最初に、入力されたペイロードをjsonオブジェクトとして変換して(jacksonを使用して)ペイロードを暗号化し、後でそのJSONペイロードをヘッダー付きのオブジェクト内に格納して、そのオブジェクトを文字列に変換します(再びジャクソンコンバーターを使用)。このプロセスでは、ペイロード全体を2回文字列に変換していたため、余分な\r\n kafkaを介して送信していたペイロードに。 jsonからオブジェクトへのオブジェクトへの変換中に、この余分な\r\nは、以前貼り付けた問題を引き起こしていました。

解決策として、すでに変換されたjsonオブジェクトをjackson注釈@ JsonRawDataで別のオブジェクトに保存しました。これにより、余分な\r\n

7
SUMIT