Search code examples
javaspringhibernatejpajpql

Migrating Spring application from Hibernate 4.3.1.Final to 5.4.27.Final


I am trying to migrate from hibernate 4.3.1.Final to 5.4.27.Final in an oldish Spring application (most Spring components are on version 4.3.13.Final). After updating the version fixing couple minor issues (class imports) and building the application with maven I get the following error while trying to deploy this web application on Tomcat 7.0.107 (part of the stack trace pointing to the root exception):

2121 Caused by: java.lang.IllegalArgumentException: Validation failed for query for method public abstract java.util.List hr.chus.plus.dao.repository.StatusUpdateRepository     .findAlarmLogsByZoneAndDatesAndNeedsAck(java.lang.Integer,java.lang.String,java.util.Date,java.util.Date)!
-- cut --
2150 Caused by: org.hibernate.QueryException: Could not resolve identifier `acks` as plural-attribute [FROM hr.chus.plus.dao.model.jpa.StatusUpdate WHERE updateType='ALARM'        AND relatedId=:alarmId   AND subtype='ZONE'   AND subtypeUuid=:zone   AND timestamp BETWEEN :start AND :end  AND needAck=true   AND size(acks)=0]
2151   at org.hibernate.QueryException.generateQueryException(QueryException.java:120) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]
2152   at org.hibernate.QueryException.wrapWithQueryString(QueryException.java:103) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]
2153   at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:220) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]
2154   at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:144) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]
2155   at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:113) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]
2156   at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:73) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]
2157   at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:162) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]
2158   at org.hibernate.internal.AbstractSharedSessionContract.getQueryPlan(AbstractSharedSessionContract.java:604) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]
2159   at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:716) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]
2160   ... 79 common frames omitted
2161 Caused by: org.hibernate.QueryException: Could not resolve identifier `acks` as plural-attribute
2162   at org.hibernate.hql.internal.ast.tree.CollectionPathNode.from(CollectionPathNode.java:123) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]

This JPQL was running and deploying fine with the previous version.

Pertinent parts of the mentioned entities are as follows:

AlarmLog:

@Entity
@Table(name = "z_alarm_log")
@SecondaryTable(name = "z_alarm_log_data", pkJoinColumns = { @PrimaryKeyJoinColumn(name = "id") })
@Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
public class AlarmLog extends AbstractLogEntity {

private static final int SUBTYPE_MAX_LENGTH = 10;

  @Column(name = "alarm_id")
  private Integer          alarmId;

  @Column(name = "trouble", columnDefinition = "TINYINT")
  private Boolean          trouble;

  @Lob
  @Basic(fetch = FetchType.EAGER)
  @Column(name = "data", columnDefinition = "BLOB", table = "z_alarm_log_data")
  private String           data;

  @Column(name = "need_ack", columnDefinition = "TINYINT")
  private Boolean          needAck            = false;

  @OneToMany(mappedBy = "log", fetch = FetchType.LAZY, cascade = { CascadeType.ALL })
  private Set<AlarmLogAck> acks               = new HashSet<>();

  @Column(name = "code", nullable = false)
  private int              code               = 0;

  @Column(name = "subtype", length = SUBTYPE_MAX_LENGTH)
  private String           subtype;

  @Column(name = "subtype_id")
  private Integer          subtypeId;

  @Column(name = "subtype_uuid", nullable = true, columnDefinition = "CHAR")
  private String           subtypeUuid;

AlarmLogAck:

@Entity
@Table(name = "z_alarm_log_ack")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class AlarmLogAck extends AbstractLongIdEntity {
  private static final int MESSAGE_MAX_LENGTH = 200;

  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "zipato_id")
  private Zipato           zipato;

  @ManyToOne(fetch = FetchType.LAZY, optional = false)
  @JoinColumn(name = "log_id")
  private AlarmLog         log;

  @ManyToOne(fetch = FetchType.LAZY, optional = false)
  @JoinColumn(name = "user_id")
  private User             user;

  @Column(name = "show_date", nullable = false, columnDefinition = "DATETIME")
  private Date             showDate;

  @Column(name = "ack_date", nullable = true, columnDefinition = "DATETIME")
  private Date             ackDate;

  @Column(name = "message", length = MESSAGE_MAX_LENGTH, nullable = true)
  private String           message;

AlarmLogRepository:

  @Transactional(readOnly = true)
  public interface AlarmLogRepository extends JpaRepository<AlarmLog, Long>, JpaSpecificationExecutor<AlarmLog> {

    @Query("FROM AlarmLog " + //
        "WHERE zipato=:zipato " + //
        "  AND alarmId=:alarmId " + //
        "  AND subtype='ZONE' " + //
        "  AND subtypeUuid=:zone " + //
        "  AND timestamp BETWEEN :start AND :end" + //
        "  AND needAck=true " + //
        "  AND size(AlarmLog.acks)=0")
    List<AlarmLog> findAlarmLogsByZoneAndDatesAndNeedsAck(@Param("zipato") Zipato p_zipato,
                                                          @Param("alarmId") Integer p_alarmId,
                                                          @Param("zone") String p_zone,
                                                          @Param("start") Date p_start,
                                                          @Param("end") Date p_end);

I have tried googling this error and I could not find this exact combination of plural-attribute not being recognized. I also tried debugging to a certain level and found out that this Set is not being recognized as a Collection type or to be more precise that the acks Set is not in the list and therefore could not be recognized as a plural-attribute.

I am at a loss how to fix this...

Any ideas?


Solution

  • For that query you should set identifier for entity AlarmLog and use that identifier in where conditions in following way:

    ...
    @Query("FROM AlarmLog al " +
            "WHERE zipato=:zipato " +
            "  AND alarmId=:alarmId " +
            "  AND subtype='ZONE' " +
            "  AND subtypeUuid=:zone " + 
            "  AND timestamp BETWEEN :start AND :end" +
            "  AND needAck=true " + 
            "  AND size(al.acks)=0")
    ...