Пользовательские типы данных с использованием EclipseLink и Querydsl

Я создал пользовательский тип данных для хранения действительных и нормализованных адресов электронной почты:

public class Email implements Serializable {

    private final String value;

    public Email(String emailAddress) {
        this.value = normalize(emailAddress);
        if (!isValid(value)) {
            throw new IllegalArgumentException("Email address format is not valid: " + value);
        }
    }
    ...
}

И его корреспондент JPA 2.1 для автоматического сохранения и извлечения из базы данных:

@Converter(autoApply = true)
public class EmailConverter implements AttributeConverter<Email, String> {

    @Override
    public String convertToDatabaseColumn(Email email) {
        return email == null ? null : email.toString();
    }

    @Override
    public Email convertToEntityAttribute(String email) {
        return email == null ? null : new Email(email);
    }

}

Теперь я могу использовать его как свойство лица:

public class Person extends BaseEntity {

    private String name;

    private LocalDate birthDate;

    @QueryType(PropertyType.STRING)
    private Email email;

    ...
}

И это прекрасно работает. Но у меня проблема, когда я пытаюсь найти всех людей, начиная с их адреса электронной почты, используя Querydsl. Я добавил объект электронной почты с помощью @QueryType как String. Таким образом, метамодель Querydsl создается таким образом, что я могу сделать запрос (используя .startsWith()) следующим образом:

private static final QPerson person = QPerson.person;

public List<Person> getEmailStartWith(String pattern) {
    pattern = Email.normalize(pattern);
    return new JPAQuery(getEntityManager())
        .from(person)
        .where(person.email.startsWith(pattern))
        .orderBy(person.email.asc())
        .list(person);
}

Но я получаю это исключение, когда я его запускаю:

java.lang.IllegalArgumentException: You have attempted to set a value of type class java.lang.String for parameter 1 with expected type of class xxx.Email from query string select person
from Person person
where person.email like ?1 escape '!'
order by person.email asc.
at org.eclipse.persistence.internal.jpa.QueryImpl.setParameterInternal(QueryImpl.java:932) ~[eclipselink-2.5.0.jar:2.5.0.v20130507-3faac2b]
at org.eclipse.persistence.internal.jpa.QueryImpl.setParameterInternal(QueryImpl.java:906) ~[eclipselink-2.5.0.jar:2.5.0.v20130507-3faac2b]
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.setParameter(EJBQueryImpl.java:469) ~[eclipselink-2.5.0.jar:2.5.0.v20130507-3faac2b]
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.setParameter(EJBQueryImpl.java:1) ~[eclipselink-2.5.0.jar:2.5.0.v20130507-3faac2b]
at com.mysema.query.jpa.impl.JPAUtil.setConstants(JPAUtil.java:44) ~[querydsl-jpa-3.2.1.jar:na]
at com.mysema.query.jpa.impl.AbstractJPAQuery.createQuery(AbstractJPAQuery.java:130) ~[querydsl-jpa-3.2.1.jar:na]
at com.mysema.query.jpa.impl.AbstractJPAQuery.createQuery(AbstractJPAQuery.java:97) ~[querydsl-jpa-3.2.1.jar:na]
at com.mysema.query.jpa.impl.AbstractJPAQuery.list(AbstractJPAQuery.java:240) ~[querydsl-jpa-3.2.1.jar:na]
...

Я могу получить правильный результат с помощью JPQL (и неэлегантного трюка, concat):

public List<Person> getEmailStartWith(String pattern) {
    pattern = Email.normalize(pattern);
    return getEntityManager()
        .createQuery("select p from Person p where p.email like concat(?1, '%')", Person.class)
        .setParameter(1, pattern)
        .getResultList();
}

Но, конечно, я предпочитаю безопасность типа Querydsl. Можно ли создать этот запрос с помощью этой библиотеки?

Ответ 1

В соответствии с Querydsl создателем Timo Westkämper этот issue больше связан с EclipseLink.