Claus Ibsen created CAMEL-26025:
-----------------------------------
Summary: camel-support - API components do not convert the inBody
body, and an unknown operation of a header-selected producer does nothing
Key: CAMEL-26025
URL: https://issues.apache.org/jira/browse/CAMEL-26025
Project: Camel
Issue Type: Bug
Components: camel-support
Affects Versions: 4.18.0, 4.22.0, 4.23.0
Reporter: Claus Ibsen
Fix For: 4.24.0
Found while checking the body types of the spring-redis and fhir components for
the catalog (CAMEL-24961).
h4. 1. API components do not convert the body to the type of the inBody
parameter
An API component passes the message body to the method parameter that
{{inBody}} names. {{AbstractApiProducer.processInBody}} converts the body to
the type of that parameter only when the endpoint configurer of the component
knows the type ({{AbstractApiProducer}}, main 07d2e7a987bc, lines 178-183). The
configurer knows only the shared options, not the parameters of the API
methods, so it returns null and the body is passed as it is; the reflection
fallback (lines 184-189) is never reached. A body of another type then fails in
{{Method.invoke}} with "argument type mismatch". This is since 96034dd0f964
(2020, "Api component avoid using reflection in api producer"), and applies to
all 13 API components: as2, box, braintree, dhis2, fhir, google-calendar,
google-drive, google-mail, google-sheets, olingo2, olingo4, twilio and zendesk.
Checked on 4.24.0-SNAPSHOT with {{camel run}} against {{camel infra run fhir}}:
{{fhir://create/resource?inBody=resourceAsString}} with the JSON of a Patient
as a byte array failed with "Error invoking resource with {...
resourceAsString=[B@635d54e6 ...}: argument type mismatch"; a stream and a file
failed the same way, and the same JSON as a String created the Patient.
*Proposed change*: take the type of the inBody parameter from the method helper
of the endpoint (the argument types of its methods), and convert the body to it.
h4. 2. A producer that picks its method by a header does nothing for an unknown
value
A producer that extends {{HeaderSelectorProducer}} picks its method by a header
or an option, through a generated {{InvokeOnHeaderStrategy}}. For a value that
has no method, the generated strategy returns null ({{default: return null;}}),
which is also what a void method returns, so {{HeaderSelectorProducer.process}}
cannot tell them apart ({{HeaderSelectorProducer}}, main 07d2e7a987bc, lines
145-155): the exchange completes with no error and the body as it was. This
applies to caffeine, consul, dynamic-router, ehcache, infinispan, servicenow,
spring-redis and web3j.
Checked on 4.24.0-SNAPSHOT with {{camel run}}: {{CamelCaffeineAction=NOSUCH}}
before {{caffeine-cache:survey}}, and {{CamelRedis.Command=NOSUCH}} before
{{spring-redis:localhost:6379}}, both completed with no error and the body
unchanged.
*Proposed change*: let the generated strategy tell an unknown value from a void
method (a marker value, or an exception), so the producer fails with an error
that names the value and the ones it supports.
h4. 3. A header named as the prefix of an API component fails every call
A header named exactly as the camel case prefix of an API component, such as
{{CamelFhir}}, makes every call of that producer fail with
{{StringIndexOutOfBoundsException: Index 9 out of bounds for length 9}}:
{{ApiMethodPropertiesHelper}} reads the character after the prefix with
{{key.charAt(prefixLength - 1)}} ({{ApiMethodPropertiesHelper}}, main
07d2e7a987bc, line 97) without checking the length of the key.
Checked on 4.24.0-SNAPSHOT with {{camel run}}: a {{CamelFhir}} header before
{{fhir://read/resourceById}} gave that exception.
*Proposed change*: skip a header that is not longer than the prefix.
h4. Also read in the code, not run
* {{AbstractApiConfiguration.splitResult}} is documented with {{defaultValue =
"true"}}, but the field is false ({{AbstractApiConfiguration}}, lines 22-26);
google-sheets, whose configuration extends it, does not split results by
default.
* {{BodyFacts.kindOf}} checks for an Iterable before a Map ({{BodyFacts}},
lines 417 and 439-441), so a Map that is also Iterable, such as the response of
solr (a {{SimpleOrderedMap}}), is recorded as a collection, while
{{BodyFacts.describe}} calls it a Map.
_Claude Code on behalf of davsclaus_
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)