You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@camel.apache.org by "Claus Ibsen (Jira)" <ji...@apache.org> on 2026/07/16 12:08:00 UTC

[jira] [Updated] (CAMEL-24131) camel-jpa: consumer with nativeQuery (no resultClass) and default consumeDelete fails to delete rows, causing endless reprocessing

     [ https://issues.apache.org/jira/browse/CAMEL-24131?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Claus Ibsen updated CAMEL-24131:
--------------------------------
    Fix Version/s: 4.22.0

> 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
>            Assignee: Claus Ibsen
>            Priority: Major
>             Fix For: 4.22.0
>
>
> 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)