Fix Content-Type mismatch in publishEvent call
Description
Please reference the issue #779
If contentType is set as ""text/plain" serialization will be skipped.
Hi @artursouza , if I modify the serialization method of the serializer (to exclude quotation marks when serializing a string), I will also need to modify the deserialization method and its corresponding tests, otherwise I may fail to pass most of the tests.
I will need to think this through. It is not a simple change without breaking existing apps.
I will need to think this through. It is not a simple change without breaking existing apps.
After I debugged step by step, it is found that this bug is not directly related to the java-sdk serializer. The reason can be divided into the following two parts:
- When publishing data, in addition to using the serializer, the data will be encapsulated into a cloudenent envelop in dapr runtime, and the data will be further encapsulated according to the dataContentType set by the user:
// NewCloudEventsEnvelope returns a map representation of a cloudevents JSON.
func NewCloudEventsEnvelope(id, source, eventType, subject string, topic string, pubsubName string,
dataContentType string, data []byte, traceParent string, traceState string,
) map[string]interface{} {
....
var ceData interface{}
ceDataField := DataField
var err error
if contribContenttype.IsJSONContentType(dataContentType) {
err = unmarshalPrecise(data, &ceData)
} else if contribContenttype.IsBinaryContentType(dataContentType) || contribContenttype.IsCloudEventProtobuf(dataContentType, data) {
ceData = base64.StdEncoding.EncodeToString(data)
ceDataField = DataBase64Field
} else {
ceData = string(data)
}
if err != nil {
ceData = string(data)
}
....
}
And there are similar operations when using gRPC protocal. Can find more details in dapr/pkg/runtime/runtime.go publishMessageGRPC()
So the string "This is message #0" will store differently in this envelop if user set the dataContentType as text/plain instead of application/json .
- But when subscribe there is no further process of the data according to the dataContentType.
As http subscriber controller for example, it uses the annotation @RequsetBody to parse the data to CloudEvent in default way. But there is no further process of the data according to the dataContentType
...
@Topic(...)
@PostMapping(...)
public Mono<ResponseEntity> getCheckout(@RequestBody(required = false) CloudEvent<Order> cloudEvent) {
return Mono.fromSupplier(() -> {
try {
logger.info("Subscriber received: " + cloudEvent.getData().getOrderId());
return ResponseEntity.ok("SUCCESS");
} catch (Exception e) {
throw new RuntimeException(e);
}
});
}
...
gPRC subscriber is the same. User always use the data directly but not porcess it according dataContentType.
So we need to add more data processing instead of modifying the java-sdk serizer when implementing subscriber. Or directly add new methods to CloudEvent (for http subscriber) and TopicEventRequest (for gRPC subscriber) to parse data according to dataContentType.
Those are great insights. I think there is a way for CloudEvent to declare a custom serializer for Jackson. I think it is acceptable to have an indirect dependency on Jackson as long as people can still deserialize it without it if they decide to.
gentle ping @MregXN, any updates?
I am closing this PR due inactivity @cicoyle