According to Querydsl creator, Timo Westkämper, this issue is more related to EclipseLink.
Custom data types using EclipseLink and Querydsl
-
29-06-2022 - |
Question
I've created a custom data type for storing valid and normalized email addresses:
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);
}
}
...
}
And its correspondent JPA 2.1 converter for automatically storing to and retrieving from database:
@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);
}
}
Now, I can use it as a property of a person entity:
public class Person extends BaseEntity {
private String name;
private LocalDate birthDate;
@QueryType(PropertyType.STRING)
private Email email;
...
}
And this works perfectly. But I have a problem when I try to find all persons by the starting of their email address using Querydsl. I've annotated email property with @QueryType
as String. This way, Querydsl metamodel is created such ay I'm able to make a query (using .startsWith()
) like this:
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);
}
But I get this exception when I run it:
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]
...
I can get the correct result using JPQL (and an inelegant trick, 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();
}
But of course I prefer Querydsl's type safety. Is possible to create this query using this library?
Solution