sdk-java icon indicating copy to clipboard operation
sdk-java copied to clipboard

Bug: Deserialization of event without data produces null.

Open alexec opened this issue 2 years ago • 5 comments

If you serialize an event that does not have a data field using CloudEventSerializer using default setting, and then try to deserialize using CloudEventDeserializer you get a null value.

This is a bug surely.

alexec avatar Mar 23 '23 19:03 alexec

Work-around:

.withData("text/plain", "".getBytes(StandardCharsets.UTF_8))

alexec avatar Mar 23 '23 20:03 alexec

...This is a bug surely....

Not according to that class' contract [emphasis mine]:

——

deserialize

T deserialize(String topic, byte[] data)

Deserialize a record value from a byte array into a value or object.

Parameters:

topic - topic associated with the data

data - serialized bytes; may be null; implementations are recommended to handle null by returning a value or null rather than throwing an exception.

Returns:

deserialized typed data; may be null

——

skepticoitusInteruptus avatar Mar 24 '23 07:03 skepticoitusInteruptus

The Kafka contract does not apply here. The bug is simply that no CloudEvent is returned, even though the record clearly contains a CloudEvent.

If this was not the case, I could not work-around the bug by putting some dummy data into the event.

I believe it is likely to do with the code that auto-detects whether binary or structured deserialization was used.

alexec avatar Mar 24 '23 14:03 alexec

Example of record that fail:

ProducerRecord(topic=api-logs-local, partition=null, headers=RecordHeaders(headers = [], isReadOnly = false), key=urn:assetalias:External.asset.alias:prd, value=CloudEvent{id='7e139926-6b86-4cf3-9e77-aa11ba2e1f78', source=xxx.asset.alias, type='http_transaction.created.v1', time=2023-03-24T08:03:14.957447-07:00, extensions={endpoint=https://foo.api.xxx.com/v1/bar/{id}, method=GET, requestid=b5d1ad97-9da6-4134-81f5-eca830a72185, clientip=196.128.0.1, useragent=curl, status=200}}, timestamp=null)

alexec avatar Mar 24 '23 15:03 alexec

…The bug is simply that no CloudEvent is returned, even though the record clearly contains a CloudEvent…

That IS interesting. For sure, @alexec.

Especially given this precondition…

If you serialize an event that does not have a data field

Let me ask you this…

  1. How closely does the following reproduce what you've described in your original report?
  2. Is my understanding correct that you would expect the assertions at 3, 4 and 5 in the code below to all fail?
import io.cloudevents.CloudEvent;
import io.cloudevents.core.message.Encoding;
import io.cloudevents.core.message.MessageReader;
import io.cloudevents.core.test.Data;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;

public class CloudEventIssue540ReproducerTest {

   private final CloudEvent eventHasNoDataField = CloudEventBuilder.v1()
        .withId(…)
        .withType(…)
        .withSource(…)
        .withoutData() // (0) An event that does not have a data field
        .withSubject(…)
        .build();

    @Test
    public void ceIssue540DeserializerShouldWork() {
        String topic = "test";
        CloudEventMessageDeserializer deserializer = new CloudEventMessageDeserializer();

        ProducerRecord<Void, byte[]> inRecord = KafkaMessageFactory.createWriter(topic)
            .writeBinary(eventHasNoDataField); // (1) "…serialize an event that does not have a data field…" — @alexec 
        MessageReader outMessage = deserializer
            .deserialize(topic, inRecord.headers(), inRecord.value()); // (2) "…then try to deserialize…" — @alexec 
        assertThat(eventHasNoDataField.getData())
            .isNotNull(); // (3) "…you get a null value…" — @alexec 
        assertThat(outMessage.toEvent())
            .isNotNull(); // (4) "…no CloudEvent is returned…" — @alexec
        assertThat(outMessage.toEvent())
            .isEqualTo(eventHasNoDataField );
        assertThat(outMessage.toEvent().getData())
            .isNotNull(); // (5) "…you get a null value…" — @alexec 
    }
}

TIA.

skepticoitusInteruptus avatar Mar 24 '23 18:03 skepticoitusInteruptus