oscerd opened a new pull request, #29215: URL: https://github.com/apache/camel/pull/29215
Fixes the camel-jackson family (Jackson 2 and 3, with their Avro and Protobuf modules) part of [CAMEL-26300](https://issues.apache.org/jira/browse/CAMEL-26300), found by the runtime tests of the body types of the data type transformers (CAMEL-25928). CAMEL-26300 is fixed with one PR per component. Fixes the camel-jackson items of [CAMEL-26300](https://issues.apache.org/jira/browse/CAMEL-26300), found by the runtime tests of the body types of the data type transformers (CAMEL-25928). Each fix is made in the Jackson 2 and the Jackson 3 module alike: camel-jackson and camel-jackson3, camel-jackson-avro and camel-jackson3-avro, camel-jackson-protobuf and camel-jackson3-protobuf. ## 1. application-json rejects a Map, a List, plain text, bytes or a stream without a content class **Was:** `JsonDataTypeTransformer` kept a JSON object or array given as a String, and wrote any other body with Jackson, for the class of the `X-Content-Class` exchange property, else the class of a POJO body, else `JsonNode`. A `Map`, a `List`, other text, bytes or a stream has no class of its own (they are `java.*` classes), so it was written with the root type `JsonNode`, and Jackson refused it ("Incompatible types: declared root type JsonNode"). The stream cache of Camel is taken for a POJO, so Jackson tried to write the stream itself as a bean, which fails. **Now:** without the `X-Content-Class` exchange property: - a `Map` is written as a JSON object, and a `List` (or another `Collection`) as a JSON array, by Jackson without a root type; - text, bytes or a stream (an `InputStream`, a `Reader` or the stream cache) is read as text with the type converters: a JSON object or array is kept as it is, as a String body was before, and other text becomes a JSON string (`Hello` gives `"Hello"`). These bodies are not given to Jackson as they are, so bytes do not become Base64 and a stream is not written as a bean. A JSON object or array as a String, a `JsonNode`, a POJO and a null body give the same JSON as before, and with the `X-Content-Class` exchange property set the transformer still writes only a body of that class (or JSON object or array text). ## 2. application-x-java-object, avro-x-java-object and protobuf-x-java-object throw a NullPointerException on a null body **Was:** with the `X-Content-Class` exchange property set, `JsonPojoDataTypeTransformer` checked whether the body is already of that class with `message.getBody().getClass()`, which threw a `NullPointerException` for a null body. The Avro and Protobuf transformers extend it. **Now:** the check is `contentType.isInstance(body)`, so a null body goes on to be read, and fails as other bodies without JSON (or Avro or Protobuf binary) do: a `CamelExecutionException` whose cause is an `InvalidPayloadException` ("No body available"). The body types already said that a null body fails, and are unchanged for this. ## 3. Jackson 2 avro-x-java-object and protobuf-x-java-object fail on a JsonNode body **Was:** with the Avro or Protobuf schema set, the Jackson 2 `AvroPojoDataTypeTransformer` and `ProtobufPojoDataTypeTransformer` read a `JsonNode` body with a reader that has the schema. Jackson 2 gives the schema to the parser of the tree, which does not take one, so they failed with an `UnsupportedOperationException` ("TreeTraversingParser does not support schema of type 'avro'"), not wrapped in a `CamelExecutionException`. With Jackson 3 the same call reads the node, so camel-jackson3 worked. **Now:** the Jackson 2 transformers read the `JsonNode` with a reader without the schema, so the node is read into the class of the `X-Content-Class` exchange property, as with camel-jackson3. The body types of both versions now name the `JsonNode` among the bodies read into that class. ## 4. camel-jackson3-avro and camel-jackson3-protobuf let JacksonException through unwrapped **Was:** `AvroBinaryDataTypeTransformer`, `AvroStructDataTypeTransformer`, `ProtobufBinaryDataTypeTransformer` and `ProtobufStructDataTypeTransformer` of camel-jackson3-avro and camel-jackson3-protobuf caught `IOException` (and `InvalidPayloadException`), as their Jackson 2 counterparts do. The errors of Jackson 3 are `JacksonException`, a `RuntimeException`, so they went through unwrapped, for example for malformed JSON text. **Now:** these four transformers also catch `JacksonException` and wrap it in a `CamelExecutionException`, as the camel-jackson3 JSON transformers do since CAMEL-24064. The `x-java-object` transformers inherit the `transform` of camel-jackson3, which wraps it already. ## 5. avro-x-struct does not take JSON text, but protobuf-x-struct does **Was:** `AvroStructDataTypeTransformer` read every body without the `X-Content-Class` exchange property as Avro binary with the schema, so JSON text was decoded as Avro: it failed, or gave a wrong `JsonNode` (the existing `shouldHandleJsonString` test only checked the class of the result). `ProtobufStructDataTypeTransformer` reads a JSON object or array given as a String as JSON. **Now:** `AvroStructDataTypeTransformer` reads a JSON object or array given as a String as JSON, with the same check and in the same place as `ProtobufStructDataTypeTransformer`, in both versions. Its body types now list text, as those of `protobuf-x-struct` do. ## Tests New or changed tests, the same in the Jackson 2 and the Jackson 3 module of each pair: - `JsonDataTypeTransformerTest`: a `Map` and a `List` (with a POJO and a `Map` in it) give a JSON object and array; JSON as bytes, an `InputStream`, a `Reader` and the stream cache is kept as it is; other text, as a String and as bytes, becomes a JSON string; `theBodyTypesSayTheBody` checks the new carriers with each of these bodies, and that with the `X-Content-Class` property a `Map` still fails. - `JsonPojoDataTypeTransformerTest`, and the `x-java-object` tests of Avro and Protobuf: a null body with the `X-Content-Class` property fails with a `CamelExecutionException` caused by an `InvalidPayloadException`. - `AvroPojoDataTypeTransformerTest` and `ProtobufPojoDataTypeTransformerTest`: a `JsonNode` body with the schema set is read into the class, also in `theBodyTypesSayTheBody`. - `AvroStructDataTypeTransformerTest`: `shouldHandleJsonString` now checks the values read from the JSON text (in camel-jackson3-avro it sends JSON text again, instead of Avro binary), `theBodyTypesSayTheBody` takes JSON text, and malformed JSON fails with a `CamelExecutionException`. - The camel-jackson3 `avro-binary`, `protobuf-binary` and `protobuf-x-struct` tests: malformed JSON fails with a `CamelExecutionException`. Without the fix, 26 of these 31 tests fail: with the old "Incompatible types" error of `application-json`, a `NullPointerException`, the `UnsupportedOperationException` of the Jackson 2 tree parser, a wrong name read from the JSON text by Jackson 2 Avro (or an unwrapped `MismatchedInputException` by Jackson 3), an unwrapped `StreamReadException`, or the old carriers. The 5 that pass are the Jackson 2 `avro-x-struct` malformed JSON test (Jackson 2 already wrapped this error) and the two `JsonNode` cases of each of the Jackson 3 `avro-x-java-object` and `protobuf-x-java-object` tests, which Jackson 3 already read and which keep both versions alike. Module tests: camel-jackson 113, camel-jackson3 123, camel-jackson-avro 33, camel-jackson3-avro 33, camel-jackson-protobuf 31 and camel-jackson3-protobuf 32, all passing. ## Docs and generated files - The body types of `application-json` (both versions) now list text, bytes, a stream, a Map, a List, a POJO and a null body, and say what each gives; those of `avro-x-struct` list text; those of `avro-x-java-object` and `protobuf-x-java-object` name the `JsonNode`. The regenerated transformer JSON of the six modules and the catalog copies of `application-json`, `avro-x-java-object`, `avro-x-struct` and `protobuf-x-java-object` (which the catalog takes from the Jackson 2 modules) have the new body types. - The components have no doc page for the transformers: their body types are what the catalog shows. - Upgrade guide entry for 4.24, as more bodies now give JSON and some failures change their exception. ## Not changed - A file (a `java.io.File`, a `Path` or the `GenericFile` of the file consumers) is not read by `application-json`: the issue names text, bytes and a stream, and a `Path` is written today by Jackson as its URI, which is left as it is. Numbers, booleans and other values without a content class also still fail, as before. - Text that is no JSON object or array becomes a JSON string even when it is a JSON number, boolean or `null`, as the transformer only recognises an object or an array as JSON text, as it did before for a String body. - A `Map` entry with a null or empty value is left out of the JSON, as the mapper of the transformer already does for the properties of a POJO (`NON_EMPTY` inclusion), and a `Map` holding `java.time` values fails with Jackson 2, as a POJO with such fields does. - A null body still fails in the `x-java-object` transformers, as their body types say, rather than being kept as null: there is no JSON to read into the class. - The Jackson 3 `x-java-object` transformers still pass the schema when they read a `JsonNode`; Jackson 3 does not use it for a tree. For main only, as the other CAMEL-26300 fixes. Main only, as the other fixes of the CAMEL-24961 follow-ups. _Claude Code on behalf of Andrea Cosentino (oscerd)_ 🤖 Generated with [Claude Code](https://claude.com/claude-code) -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
