Search code examples
javaspring-bootjpacriteriapredicate

Spring Boot Jpa specification Set Enums IN Set Enums


Hi I want filter restaurant by type using Specification, but I get error:

Parameter value [SUSHI] did not match expected type [java.util.Set (n/a)]

How Can I comare List enums to list enums ? :/

My specification file:

if(Objects.nonNull(category)){
    predicates.add(root.get(Restaurant_.category).in(category));
}

Restaurant model:

@ElementCollection(targetClass = RestaurantCategory.class)
@Enumerated(EnumType.STRING)
@CollectionTable(name = "restaurant_category")
private Set<RestaurantCategory> category;

Restaurant category:

public enum RestaurantCategory {
    STREET_FOOD, SUSHI, PIZZA, BURGER
}

Solution

  • Had the same problem and this question helped me.

    In my case, I wanted to search my commissions by country. Here how I solved my issue.

    Domain:

    @Entity
    @Table(name = "commission")
    data class Commission(
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        var id: Long? = 0,
    
        @ElementCollection(fetch = FetchType.EAGER)
        @Enumerated(EnumType.STRING)
        var countries: MutableSet<CountryCode>? = null,
    
        @get: NotNull
        @Enumerated(EnumType.STRING)
        @Column(name = "type", nullable = false)
        var type: CommissionType? = null
    ) 
    

    Specification code (@see findByCountries part):

    object CommissionSpecifications {
    fun buildQuery(request: SearchCommissionRequest): Specification<Commission> {
    
        var query = Specification.where<Commission>(distinct())
    
        request.type?.also { query = query?.and(findByType(it)) }
        request.countries?.also { if (it.isNotEmpty()) query = query?.and(findByCountries(it)) }
    
        return query!!
    }
    
    private fun findByType(type: CommissionType): Specification<Commission> =
        Specification { root, _, cb -> cb.equal(root.get<Commission>(Commission::type.name), type) }
    
    private fun findByCountries(countries: Set<CountryCode>): Specification<Commission> =
        Specification { root, _, _ ->
            root.join<Commission, Set<CountryCode>>(Commission::countries.name).`in`(countries)
        }
    
    private fun distinct(): Specification<Commission?> {
        return Specification { root: Root<Commission?>?, query: CriteriaQuery<*>, cb: CriteriaBuilder? ->
            query.distinct(true)
            null
        }
    }
    

    }