Federico Mariani created CAMEL-24131:
----------------------------------------

             Summary: camel-jpa: consumer with nativeQuery (no resultClass) and 
default consumeDelete fails to delete rows, causing endless reprocessing
                 Key: CAMEL-24131
                 URL: https://issues.apache.org/jira/browse/CAMEL-24131
             Project: Camel
          Issue Type: Bug
          Components: camel-jpa
            Reporter: Federico Mariani


h3. Problem

When a JPA consumer is configured with {{nativeQuery}} and no {{resultClass}}, 
results are returned as {{Object[]}} rows (see 
{{QueryBuilder.nativeQuery(String)}}). {{consumeDelete}} defaults to {{true}}, 
so {{JpaConsumer.createDeleteHandler()}} (JpaConsumer.java:451-480) returns:

{code:java}
(EntityManager em, Object entityBean, Exchange exchange) -> 
em.remove(entityBean);
{code}

{{EntityManager#remove}} requires a managed entity instance; calling it with an 
{{Object[]}} throws {{IllegalArgumentException}}. Unlike the 
{{@PreConsumed}}/{{@Consumed}} handlers, which guard with 
{{entityType.isInstance(entityBean)}} (JpaConsumer.java:435, 463), the 
{{consumeDelete}} handler has no such guard. {{lockEntity()}} even anticipates 
this exact case -- it treats a lock failure on an array as expected 
(JpaConsumer.java:374-376) -- but the delete path does not.

h3. Impact

The exchange is processed successfully by the route (the 
{{Processor.process(exchange)}} call succeeds), but the subsequent 
{{getDeleteHandler().deleteObject(...)}} call throws. Because this happens 
*after* successful processing, the row is never deleted from the database. On 
the next poll, the same native-query result set (same rows) is selected and 
reprocessed -- a poison-poll loop: duplicate downstream processing plus a 
logged/thrown error on every single poll, indefinitely.

h3. How to reproduce

{code:java}
from("jpa://com.foo.MyEntity?nativeQuery=select * from MY_ENTITY where 
processed = false")
    .to("mock:result");
{code}

against a table with at least one matching row and no {{resultClass}} 
configured: the row is delivered to {{mock:result}} on every poll, and 
{{em.remove(Object[])}} throws each time.

h3. Suggested fix

Guard the default {{consumeDelete}} handler the same way the annotation-based 
handlers are guarded (e.g. skip/log when the result is not an instance of the 
configured entity type), or fail endpoint validation eagerly when 
{{nativeQuery}} is set without {{resultClass}} and {{consumeDelete=true}}.

Found during a broader camel-jpa code review (July 2026).

_Claude Code on behalf of Croway_



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

Reply via email to