querydsl: Collection .contains() not working anymore

Observed vs. expected behavior

The query that I wrote in the past previously was working with older Hibernate, now is not working.

Steps to reproduce

In the repository classes there are 3 methods and none of those is working:

[UserRepositoryImpl] findByUserRole_1()

org.hibernate.query.SemanticException: Operand of 'member of' operator must be a plural path

[UserRepositoryImpl] findByUserRole_2() Alternate where clause also throws exception:

org.hibernate.query.QueryArgumentException:
Argument [ROLE_ADMIN] of type [com.thevegcat.app.config.UserRole]
did not match parameter type [java.util.Set (n/a)]

[UserRepository] findByUserRole_3() This one also used to work and now throws exception:

java.lang.ClassCastException:
class org.hibernate.metamodel.mapping.internal.BasicAttributeMapping cannot be cast to class
org.hibernate.sql.ast.tree.from.TableGroupJoinProducer
(org.hibernate.metamodel.mapping.internal.BasicAttributeMapping and
org.hibernate.sql.ast.tree.from.TableGroupJoinProducer are in unnamed module of loader 'app')

UserRole.java

public enum UserRole {
    ROLE_ADMIN,
    ROLE_ADVANCED,
    ROLE_EDITOR,
    ROLE_USER,
    ROLE_ANONYMOUS
}

User.java

@Entity 
public class User {
    // ...

	@Convert( converter = UserRolesConverter.class )
	@Column( columnDefinition = "TEXT" )
	private Set<UserRole> roles;

    // ...
}


UserRepositoryImpl.java

public class UserRepositoryImpl 
    // ...

    // case #1 - using user.roles.contains( userRole )
    public List<User> findByUserRole_1( final UserRole userRole ) {
        final QUser user = QUser.user;
        return 
            new JPAQueryFactory( this.entityManager )
                .selectFrom( user )
                .where(
                    new BooleanBuilder().and( user.roles.contains( userRole ) ).getValue()
                )
                .fetch();
    }

    // case #2 - using user.roles.any().eq( userRole )
    public List<User> findByUserRole_2( final UserRole userRole ) {
        final QUser user = QUser.user;
        return 
            new JPAQueryFactory( this.entityManager )
                .selectFrom( user )
                .where(
                    new BooleanBuilder().and( user.roles.any().eq( userRole ) ).getValue()
                )
                .fetch();
    }

    // ...
}

UserRepository.java

public interface UserRepository extends
    PagingAndSortingRepository<User, Integer>,
    CrudRepository<User, Integer>
{
    // ...

    @Query( "SELECT u FROM User u LEFT JOIN FETCH u.roles r WHERE :role IN ( r )" )
    List<User> findByUserRole_3( UserRole role );

    // ...
}

UserRolesConverter.java

public class UserRolesConverter implements AttributeConverter<Set<UserRole>, String>, Serializable {

	@Serial private static final long serialVersionUID = -6105356555706277280L;

	public static final TypeReference<Set<UserRole>> TYPE_REFERENCE = new TypeReference<>() { /**/ };

	@Override
	public String convertToDatabaseColumn( final Set<UserRole> attribute ) {
		if( attribute == null || attribute.isEmpty() ) {
			return null;
		}
		try {
			return new ObjectMapper().writeValueAsString( attribute );
		}
		catch( final JsonProcessingException e ) {
			return null;
		}
	}

	@Override
	public Set<UserRole> convertToEntityAttribute( final String dbData ) {
		if( dbData == null ) {
			return Collections.emptySet();
		}
		try {
			final Set<UserRole> result = new ObjectMapper().readValue( dbData, TYPE_REFERENCE );
			if( result == null ) {
				throw new IllegalStateException( "This should never happen" );
			}
			return result;
		}
		catch( final JsonProcessingException e ) {
			throw new IllegalStateException( "JsonProcessingException: " + e.getMessage() );
		}
	}

}

Environment

OS: Windows 11 Pro 23H2 22631.2506 Windows Feature Experience Pack 1000.22677.1000.0 IDE: Eclipse STS Version: 4.20.1.RELEASE Build Id: 202310260003 Revision: b4f357cb0399519f520df4fc968315d5735367da Spring: Spring Boot 3.1.5 Hibernate: Hibernate ORM 6.3.1.Final Querydsl version: 5.0.0 Querydsl module: querydsl-apt, querydsl-jpa, com.querydsl.apt.jpa.JPAAnnotationProcessor Database: mysql Ver 8.0.16 for Win64 on x86_64 (MySQL Community Server - GPL) JDK: openjdk version “17.0.7” 2023-04-18 OpenJDK Runtime Environment Temurin-17.0.7+7 (build 17.0.7+7) OpenJDK 64-Bit Server VM Temurin-17.0.7+7 (build 17.0.7+7, mixed mode, sharing)

See also

https://stackoverflow.com/questions/77409442/querydsl-collection-contains

About this issue

  • Original URL
  • State: open
  • Created 8 months ago
  • Comments: 27 (8 by maintainers)

Most upvoted comments

I cloned the repository and had a look at the errors. It doesn’t seem straightforward to fix. I will try to reproduce the errors in the querydsl repository as some unit tests and fix it there. Hibernate 6 changed the way the types of the query parameters get validated, I believe this is what is causing the issues now.

@H-Lo New release out with plenty of fixes on java.time territory, give it a shot

https://github.com/OpenFeign/querydsl/releases/tag/6.0.0.M2

migrate to jpa specifications. This project is abandonware.

@H-Lo doubt you will get any help here.

I tried to volunteer… but what the present team is looking for is NOT someone to keep the project active https://querydsl.slack.com/archives/C06KLG1BP/p1698220668765159

Since there is a conscientious choice to get this project on a death spiral, I forked it and start my own release cycles

https://github.com/OpenFeign/querydsl

There are 3 releases out already, latest one with first contributions from opensource.

5.1.1 at the very least contain fair less extremely old dependencies and was tested with java 21.

@danielvion and myself are preparing for a major push towards querydsl 6.0 with hibernate 6 support.

At this stage, we are looking for volunteer to try it out.