2
votes

I'm using this awesome library, but I have a problem.

I'm implementing a DTO pattern, so I use another project to convert automaticaly an EJB to a DTO using naming conventions.

Then, I want to query the DTO and getting the real result (EJB query).

I implemented QueryDSL with JPAAnnotationProcessor on my ENTITIES, and the QuerydslAnnotationProcessor on my DTOs.

For example :

  • An entity User(Long Id, String username, Site site)
  • A DTO UserDto(Long id, String username, String siteName)

Converting objects is good, "siteName" automatically match "site.name".

And so, I put a QueryDSL Query like: userDto.id.gt(20).and(userDto.username.like("a%")).and(userDto.siteName.like("%b"));

I'm looking for a way to build the corresponding entity query

The only idea I got is to :

  • Clone the Query
  • Change the path "userDto" to "user"
  • Verify each predicate to know if the property exists and if the type is matching

Any way to do that or to reach my goal?

Thanks

2

2 Answers

1
votes

You will need to convert expressions in general. With a custom ReplaceVisitor you can for example override visit(Path expr, @Nullable Void context)

A generic way to do the path replacements would be to use a Map map to define the replacements:

if (map.contains(path)) {
    return map.get(path);
} else {
    return super.visit(path, context);
}

You can use your visitor like this:

Expression transformedExpression = expr.accept(visitor, null);
1
votes

Since this is still relevant and undocumented functionality, and since Timo's answer, while helpful, is very cryptic, here's how to do it:

First, extend ReplaceVisitor:

private class CustomReplaceVisior extends ReplaceVisitor<Void> {
    @Override
    public Expression<?> visit(Path<?> path, @Nullable Void context) {
        // The map Timo mentioned to transform paths:
        Map<Path<?>, Path<?>> map = Map.of(
            QUser.user.id, QUserDto.userDto.id,
            QUser.user.name, QUserDto.userDto.name
        );
        if (map.contains(path)) {
            return map.get(path);
        } else {
            return super.visit(path, context);
        }
    }
}

Then use it like this:

CustomReplaceVisior replaceVisitor = new CustomReplaceVisior();
Predicate userPredicate = QUser.user.id.eq(2).and(QUser.user.name.eq("Somename"));
Predicate userDtoPredicate = (Predicate) userPredicate.accept(replaceVisitor, null);