Search code examples
spring-data-jpaspring-data

Hibernate @Query throw syntax error at or near "."


I try to get field tags from the entity Article:

@Getter
@Setter
@Entity
@ToString
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "articles")
public class Article {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Embedded
    private Author author;

    @Column(unique = true)
    private String title;

    private String content;

    @ElementCollection(targetClass = String.class,
            fetch = FetchType.EAGER
    )
    @CollectionTable(name = "tags",
            joinColumns = @JoinColumn(name = "article_id")
    )
    @Column(name = "tag")
    private List<String> tags = new ArrayList<>();
}

With ArticleRepository extends JpaRepository<Article, Long>, JpaSpecificationExecutor<Article> and @Query:

@Query("SELECT " +
        " new java.util.ArrayList(a.tags) " +
        " FROM Article a " +
        " WHERE a.title = :title")
List<String> findAllTagsOfArticle(String title);

And get a result:

Hibernate: 
    select
        . as col_0_0_ 
    from
        articles article0_ 
    inner join
        tags tags1_ 
            on article0_.id=tags1_.article_id 
    where
        article0_.title=?
2022-07-21 15:17:24.666  WARN 2196 --- [   scheduling-1] o.h.engine.jdbc.spi.SqlExceptionHelper   : SQL Error: 0, SQLState: 42601
2022-07-21 15:17:24.666 ERROR 2196 --- [   scheduling-1] o.h.engine.jdbc.spi.SqlExceptionHelper   : ERROR: syntax error at or near "."

Generated SQL query looks correct but after SELECT hibernate generate .

Why does it happens and how to fix it?


Solution

  • You cannot pass a collection (a.tags) like that. The idea is that the constructor will receive a single row from the query result. But also, there's no need to use new ArrayList.

    This should work:

    @Query("select t from Article a join a.tags t where a.title = :title")
    List<String> findAllTagsOfArticle(String title);
    

    You can also simplify a bit the mapping:

        @ElementCollection
        @CollectionTable(name = "tags",
                joinColumns = @JoinColumn(name = "article_id")
        )
        @Column(name = "tag")
        private List<String> tags = new ArrayList<>();
    

    There is no need to specify EAGER and the target class in this case.