DTO query rewriting renders invalid queries
Closed this issue ยท 11 comments
I am seeing this error with spring-data 3.5.0:
INFO [2025-05-19 17:36:30,602] [] [kafka-producer-network-thread | producer-2] org.apache.kafka.clients.producer.internals.TransactionManager: [Producer clientId=producer-2] ProducerId set to 1 with epoch 0
java.lang.IllegalArgumentException: org.hibernate.query.SyntaxException: At 1:50 and token ')', no viable alternative at input 'SELECT new com.adswizz.domain.entity.CampaignDeal(*) FROM CampaignDeal cd LEFT JOIN FETCH cd.dealLibrary d LEFT JOIN FETCH d.publisher p WHERE cd.campaignId = :campaignId' [SELECT new com.adswizz.domain.entity.CampaignDeal() FROM CampaignDeal cd LEFT JOIN FETCH cd.dealLibrary d LEFT JOIN FETCH d.publisher p WHERE cd.campaignId = :campaignId]
when running the following query:
@Query("SELECT cd FROM CampaignDeal cd "
+ "LEFT JOIN FETCH cd.dealLibrary d "
+ "LEFT JOIN FETCH d.publisher p "
+ "WHERE cd.campaignId = :campaignId")`
List<CampaignDeal> findCampaignDealsForCampaign(Integer campaignId);
The entity definition is:
@Entity
@Table(name = "campaign_deals")
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class CampaignDeal {
@EmbeddedId
private CampaignDealId campaignDealId;
@Column(name = "campaign_id", insertable = false, updatable = false)
private Integer campaignId;
@Column(name = "deal_library_id")
private Integer dealLibraryId;
@ToString.Exclude
@EqualsAndHashCode.Exclude
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "deal_library_id", updatable = false, insertable = false, referencedColumnName = "id")
private Deal dealLibrary;
@Column(name = "publisher_id")
private Integer publisherId;
@ToString.Exclude
@EqualsAndHashCode.Exclude
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "publisher_id", updatable = false, referencedColumnName = "affiliateid", insertable = false)
private Publisher publisher;
@Column(name = "type")
@Enumerated(EnumType.STRING)
private Type type;
@Embeddable
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public static class CampaignDealId implements Serializable {
private static final long serialVersionUID = 5373763488252554888L;
@ManyToOne(fetch = FetchType.LAZY, targetEntity = Campaign.class)
@JoinColumn(name = "campaign_id")
@ToString.Exclude
@EqualsAndHashCode.Exclude
private Campaign campaign;
@Column(name = "deal_id") //the dealID string, not the fk to deal_library
private String dealId;
}
public enum Type {
STRING,
LIBRARY
}
}
This used to work just fine until upgrading to the 3.5.0 version.
Same issue after upgrading from 3.5.0
thank you for reporting - we'll have a look
I faced the same problem and solved it by changing the query in your case from
@Query("SELECT cd FROM CampaignDeal cd ")
to
@Query("FROM CampaignDeal cd ")
I faced the same problem and solved it by changing the query in your case from
@Query("SELECT cd FROM CampaignDeal cd ")to@Query("FROM CampaignDeal cd ")
Thanks @Jackpad - indeed, seems to work in my case as well.
For the time being, we've identified two issues:
- When using classes with multiple constructors, we back off from determining projection properties and therefore we render an invalid empty constructor (
SELECT new com.adswizz.domain.entity.CampaignDeal(), the asterisk marks the unexpected parts in the query) - Additionally, when returning JPA entities in a query that does not match the repository type (e.g.
CampaignRepository extends Repositor<Campaign, โฆ>,List<CampaignDeal> findCampaignDealsForCampaign(Integer campaignId);), then the returned type is considered a projection. In that case, we also rewrite the query to a DTO projection.
While the second case is technically a projection, I think we should back off if the returned type is a JPA-managed type.
I've pushed a bugfix branch and our CI has published artifacts containing that change with the version 3.5.x-GH-3895-SNAPSHOT.
Care to upgrade to version 3.5.x-GH-3895-SNAPSHOT, available from https://repo.spring.io/snapshot/?
<dependencies>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>3.5.x-GH-3895-SNAPSHOT</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>spring-snapshot</id>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>