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)