Spring Data: запрос по примеру и конвертер - PullRequest
1 голос
/ 26 марта 2020

У меня есть сущность:

import javax.persistence.Convert;

@Entity(name = "my_entity")
public class MyEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @Convert(converter = StringListConverter.class)
    private List<String> emails;

    // next fields omitted...

}

Конвертер, который используется полем emails в сущности (типичная реализация, например LocalDateTimeConverter):

import javax.persistence.Converter;

@Converter
public class StringListConverter implements AttributeConverter<List<String>, String> {
    private static final String SPLIT_CHAR = ";";

    @Override
    public String convertToDatabaseColumn(List<String> stringList) {
        if (CollectionUtils.isNotEmpty(stringList)) {
            return String.join(SPLIT_CHAR, stringList);
        } else {
            return null;
        }
    }

    @Override
    public List<String> convertToEntityAttribute(String string) {
        if (StringUtils.isNotBlank(string)) {
            return Arrays.asList(string.split(SPLIT_CHAR));
        } else {
            return Collections.emptyList();
        }
    }

}

(я храню электронные письма разделенные точкой с запятой в одном столбце. StringListConverter выполните это преобразование.)

И хранилище данных Spring:

import org.springframework.data.domain.Example;

public interface MyRepository extends JpaRepository<MyEntity, Long> {

    default List<MyEntity> findMatchingMyEntity(MyEntity myEntity) {
        Example<MyEntity> example = Example.of(myEntity);
        return findAll(example);
    }

}

Я использую механизм Query by Example из Spring Data. Когда у меня есть поля без @Convert (например, String name), это работает. Но когда у меня есть поле с @Convert (AttributeConverter), например List<String> emails, это вызывает InvalidDataAccessApiUsageException.

org.springframework.dao.InvalidDataAccessApiUsageException: Parameter value [abc@company.com] did not match expected type [java.util.List (n/a)]; nested exception is java.lang.IllegalArgumentException: Parameter value [abc@company.com] did not match expected type [java.util.List (n/a)]
    at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:374) ~[spring-orm-5.2.1.RELEASE.jar:5.2.1.RELEASE]
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:257) ~[spring-orm-5.2.1.RELEASE.jar:5.2.1.RELEASE]
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:528) ~[spring-orm-5.2.1.RELEASE.jar:5.2.1.RELEASE]
    at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61) ~[spring-tx-5.2.1.RELEASE.jar:5.2.1.RELEASE]
    ...
Caused by: java.lang.IllegalArgumentException: Parameter value [abc@company.com] did not match expected type [java.util.List (n/a)]
    at org.hibernate.query.spi.QueryParameterBindingValidator.validate(QueryParameterBindingValidator.java:54) ~[hibernate-core-5.4.8.Final.jar:5.4.8.Final]
    at org.hibernate.query.spi.QueryParameterBindingValidator.validate(QueryParameterBindingValidator.java:27) ~[hibernate-core-5.4.8.Final.jar:5.4.8.Final]
    at org.hibernate.query.internal.QueryParameterBindingImpl.validate(QueryParameterBindingImpl.java:90) ~[hibernate-core-5.4.8.Final.jar:5.4.8.Final]
    ... 146 common frames omitted

(сообщение странное, потому что я пробовал поиск по этому списку: ["abc@company.com", "def@company.com"] , но в сообщении только одно электронное письмо)


Я пытался реализовать transform в ExampleMatcher:

import org.springframework.data.domain.Example;
import org.springframework.data.domain.ExampleMatcher;

public interface MyRepository extends JpaRepository<MyEntity, Long> {

    default List<MyEntity> findMatchingMyEntity(MyEntity myEntity) {
        ExampleMatcher matcher = ExampleMatcher.matching()
                .withMatcher("emails",
                        match -> match.transform(emailsOptional -> {
                            if (emailsOptional.isPresent()) {
                                List<String> emails = (List<String>) emailsOptional.get();
                                return Optional.ofNullable(new StringListConverter().convertToDatabaseColumn(emails));
                            }
                            return emailsOptional;
                        }));
        Example<MyEntity> example = Example.of(myEntity, matcher);
        return findAll(example);
    }

}

Но это тоже причины InvalidDataAccessApiUsageException, но с сообщением, отличным от предыдущего (я установил два электронных письма):

org.springframework.dao.InvalidDataAccessApiUsageException: Parameter value [abc@company.com;def@company.com] did not match expected type [java.util.List (n/a)]; nested exception is java.lang.IllegalArgumentException: Parameter value [abc@company.com;def@company.com] did not match expected type [java.util.List (n/a)]
    at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:374) ~[spring-orm-5.2.1.RELEASE.jar:5.2.1.RELEASE]
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:257) ~[spring-orm-5.2.1.RELEASE.jar:5.2.1.RELEASE]
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:528) ~[spring-orm-5.2.1.RELEASE.jar:5.2.1.RELEASE]
Caused by: java.lang.IllegalArgumentException: Parameter value [abc@company.com;def@company.com] did not match expected type [java.util.List (n/a)]
    at org.hibernate.query.spi.QueryParameterBindingValidator.validate(QueryParameterBindingValidator.java:54) ~[hibernate-core-5.4.8.Final.jar:5.4.8.Final]
    at org.hibernate.query.spi.QueryParameterBindingValidator.validate(QueryParameterBindingValidator.java:27) ~[hibernate-core-5.4.8.Final.jar:5.4.8.Final]
    ... 146 common frames omitted
...