Andrea Cosentino created CAMEL-24442:
----------------------------------------

             Summary: camel-thrift - unmarshal deserializes into and returns a 
single shared instance
                 Key: CAMEL-24442
                 URL: https://issues.apache.org/jira/browse/CAMEL-24442
             Project: Camel
          Issue Type: Bug
            Reporter: Andrea Cosentino
            Assignee: Andrea Cosentino
             Fix For: 4.23.0


{{ThriftDataFormat.unmarshal()}} deserializes into the {{defaultInstance}} 
field and returns that same object:

{code:java}
if (contentTypeFormat.equals(CONTENT_TYPE_FORMAT_JSON)) {
    deserializer = new TDeserializer(new TJSONProtocol.Factory());
    deserializer.deserialize(defaultInstance, IOUtils.toByteArray(inputStream));
} else if (contentTypeFormat.equals(CONTENT_TYPE_FORMAT_BINARY)) {
    ...
}
return defaultInstance;
{code}

The data format is a singleton shared by every exchange on the route, and 
{{TBase.read()}} sets only the fields present in the incoming bytes without 
clearing the object first. Three consequences:

* A message that omits an optional field keeps the value left there by the 
*previous* message. This happens even with a single thread.
* Concurrent unmarshals interleave field writes into the one object.
* Every in-flight body is literally the same reference, so mutating one 
downstream changes the others.

{{ProtobufDataFormat}} handles this correctly - it builds a new instance per 
unmarshal. Proposal: do the same here, using {{defaultInstance.deepCopy()}} (or 
{{instanceClass.getDeclaredConstructor().newInstance()}}) as the 
deserialization target, and create the {{TDeserializer}} per call or make it a 
thread-local.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to