Alternatives to finder methods for every property in Spring JpaRepository - spring-data

I use Spring Data JPA for my repository layer. I need to query entities by every possible property and combinations of its properties. So my typical repository looks like this.
public interface UserRepository extends JpaRepository<User, Long> {
User findByLogin(String login);
User findByEmail(String email);
User findByName(String name);
User findByLoginAndEmail(String login, String email);
User findByLoginAndName(String login, String name);
User findByLoginAndEmailAndName(String login, String email, String name);
//and so on
}
Even with three properties it looks ugly enough.
Are there any more flexible alternatives to this approach? Or this design is OK(at least I do not have to implements all of these methods)?

Found query by example. Seems it is what I was looking for.

Related

What is the best way to name REST resources when returning same resource but using different DTO?

I'm curious what is the best way of returning the same resource but using different DTOs.
For example, I have a user class:
public class User {
private String name;
private String surname;
private String age;
}
The list of users is available under url:
/users
Some other view needs list of users but without age, so, I would like to return list of UserDTO.
public class UserDTO {
private String name;
private String surname;
}
What is the proper way of defining url?
/userDtos - this is bad, because I can have more than one DTOs for representing users,
/users/dto - this is also bad
/users?name=true,surname=true - this one is also bad, it indicates that we are filtering the result, but we are not; we're just filtering fields.
For sure someone already had this problem before, but I couldn't find anything on the Internet.
A similar concept is called partial response which provide an option to let client to specify which fields to include in the response using the query parameters like:
:
/user?fields=name,surename
Basically you define a syntax for you own query language to represent a selection of fields. Here and Google Cloud API are some examples.
By taking this concept to a more coarse-grained level , you can use query parameter "view" to define different predefined combination of fields such as:
/users //default view if no "view" query parameter is specified
/users?view=admin //maybe this view will not show age field
/users?view=hr //maybe this view only show the fields that are accessible to HR

Define #DeclareRoles annotation programmatically

The JAVA EE #DeclareRoles annotation is a way to declare the list of possible roles of the users to match with the annotation #RolesAllowed.
But what if our roles are stored in database and if the list of the potential roles is long ?
I currently use roles to specify an atomic access to functionnalities on my website, so I have a long list of roles as some users can access functionnality-1 but not the 2, and some can on the 2 but not on the 1, etc...
I want to avoid editing the #DeclareRoles annotation every time I am creating a new role for a new functionnality, so the question is :
Is there any way to programmatically setup the #DeclareRoles annotation or to specify that it should load from a database ?
Since the introduction of the JavaEE 8 security API you have the ability to write your own identity store. This allows you to fetch users and user data from a custom location and a custom service. You asked about using a database - so here is an example using a database facade together with a custom identity store;
#ApplicationScoped
public class MyIdentityStore implements IdentityStore {
#EJB private UserFacade userFacade;
#Override
public int priority() {
return 50;
}
#Override
public Set<ValidationType> validationTypes() {
return EnumSet.of(ValidationType.PROVIDE_GROUPS, ValidationType.VALIDATE);
}
#Override
public Set<String> getCallerGroups(CredentialValidationResult validationResult) {
final String userName = validationResult.getCallerPrincipal().getName();
final User user= usersFacade.find(userName);
return user.getRoles();
}
public CredentialValidationResult validate(UsernamePasswordCredential credential) {
/* Handle validation/login of the user here */
}
}
To explain the above slightly more - the getCallerGroups() will return the roles that the user is part of - something you can then use throughout the JavaEE security API and lockdown methods such as #RolesAllowed. The validate() method handles the validation of the user when a check is requested by the container. Finally, the validationTypes() method simply specifies what this Identity store should be used for - in this case we have specified both the fetching of roles and handling of validation.
So since EE8 introduced this - it has become really flexible and easy to take advantage of the security features in the platform.
Here are some really great references on the subject;
https://www.ibm.com/developerworks/library/j-javaee8-security-api-1
https://www.ibm.com/developerworks/library/j-javaee8-security-api-2
https://www.ibm.com/developerworks/library/j-javaee8-security-api-3
https://www.baeldung.com/java-ee-8-security

Using POST to hide confidential data in Spring Data Rest #Query method

The below JPA Repository is exposed using Spring Data Rest via Http GET method - which in practice is correct, however, in my case it's revealing / sending password info via GET rather a Web Form. Is there a way to force use a POST instead?
The URL for below is:
http://localhost:8080/api/users/search/queryForLogin?email=myemail#xyz.com&password=myPass
public interface UserRepository extends JpaRepository<User, Long> {
#Query("select u from User u where lower(u.email) = lower(:email) and
u.password = :password")
User queryForLogin(
#Param("email") String email,
#Param("password") String password );
}

search phrase string using jpa queries

I have a search with JPA query using Spring Data like this :
My interface repository :
public interface AnnonceDao extends JpaRepository<Annonce, Integer> {
Page<Annonce> findByTitreContaining(String titre,Pageable page);
}
when I look for something like Hello Friend I get all entities that have Hello Friend concatened , I want something to get Friend Hello too or any entity that contains Hello or Friend. what I can use as Query, thanks for your help.
This should work:
public interface AnnonceDao extends JpaRepository<Annonce, Integer> {
Page<Annonce> findByTitreContainingAndTitreContaining(
String part1,
String part2,
Pageable page
);
}
If the number of terms you want to pass is unknown at compile time, as you explain in the comment you can use Specifications.
This leaves the task of creating the specification to the client of the repository. If you don't like that you can provide a custom method and dynamically create a query inside. Again you have the choice of multiple technologies:
SQL
JQL
QueryDsl
QueryDsl looks actually really nice and readable as you can see in the linke example.

Why do we use UserManager to acess user profile info when we can use application dbcontext?

When I am googling to find how to find UserProfile properties I get results and all of them use UserManager to access the UserProfile custom properties.
So if I have a custom ApplicationUser
public class ApplicationUser : IdentityUser
{
public int AccType { get; set; } //
}
And in my controller a simplified code looks like
ApplicationUser usr = _context.Users.SingleOrDefault(u => u.UserName == User.Identity.Name);
This method exposes the UserProfile properties to code. So why is everybody using UserManager???
UserManager includes validation rules and helper methods specific to tasks commonly performed for users, like creating a new user with a secure password, verifying an entered password, adding/removing from roles etc.
Yes, you could use ApplicationDbContext directly, but you'd need to write queries against your DbSet<ApplicationUIser>, when UserManager already has these queries already, with validation - and more.
For example, UserManager.FindByNameAsync is already defined, and additionally it normalizes the name before executing the search.
Take a look at the source and see what UserManager is offering over DbSet<ApplicationUser>.