4

I am trying to use Spring JPA's projection to filter out unnecessary data from query result. However, I have multiple projections that will need to be used on the same interface method.

The problem is, I am trying to query data from the same method with a different returning object but java doesn't allowed this.

The query are auto generated by JPA based on method name, so I cannot make changes to method name.

Is there a alternative, other than creating a new interface, since I think it's a hassle and unnecessary

here is a sample code, of what I am trying to do.

Auto-Generated Query

public interface UserRepository extends CrudRepository<UserAccount, Long> {

    AuthenticateProjection getByUsername(String username);

    UserDetailsProjection getByUsername(String username);

}

Projections

public interface AuthenticateProjection {

    @Value("#{target.username}")
    String getUsername();

    @Value("#{target.credentail.token}")
    String getHashPassword();
}

public interface UserDetailsProjection {

    @Value("#{target.username}")
    String getUsername();

    @Value("#{target.firstname}")
    String getFirstName();

    @Value("#{target.lastname}")
    String getLastName();
}
2
  • Why are you wanting to "filter" the information--is this for returning from a controller, or for internal use? Commented Apr 11, 2017 at 17:55
  • @chrylis it will be return to the controller Commented Apr 11, 2017 at 18:12

2 Answers 2

7

So I've managed to figure out how to use multiple projections with a single query.

<T> T getByUsername(String username, Class<T> projection)

This allows the method caller to specified the type of projection to be applied to the query.

To further improve this so it is less prone to error, I made a blank interface that the projection will have to extend in order to be able to insert class into the parameter.

public interface JPAProjection {
}

public interface UserRepository extends CrudRepository<UserAccount, Long> {
    <T extends JPAProjection > T getByUsername(String username, Class<? extends JPAProjection> projection);
}

Projection Interface

public interface UserDetailsProjection extends JPAProjection{
    @Value("#{target.username}")
    String getUsername();

    @Value("#{target.firstname}")
    String getFirstname();

    @Value("#{target.lastname}")
    String getLastname();
}

Then I can call the query method by

getByUsername("...", UserDetailsProjection.class)
Sign up to request clarification or add additional context in comments.

2 Comments

I tried to use your same solution, but it does not work for me. In the Eclipse console I see an error: Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token: from near line 1, column 9 [select from com.app.company.domain.organization.Organization as generatedAlias0 where generatedAlias0.deletedAt is null]. Look at the "select" statement: there is not any column. Maybe did you have the same problem? It seems that the repository does not receive the correct projection type.....any idea? Thanks a lot!
hmm this is odd. I did not have any problem. Would you mind attaching your impl? Pastebin maybe? @AndreaBevilacqua
3

Just add something between get (or e.g. find) and By starting with an upper case character. It is ignored in the query generation.

public interface UserRepository extends CrudRepository<UserAccount, Long> {

   AuthenticateProjection getByUsername(String username);

   UserDetailsProjection getAnotherByUsername(String username);

}

1 Comment

Best answer ! No code to write, you may only write the "mode" of the data you want to retrieve, like : getByUsername, getFullByUsername, getLightByUsername.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.