Reputation: 42967
I am working on a Spring Boot project using Spring Data JPA and Hibernate mapping. In my repository classes I am using a query by method name approach and I have the following question. I have this User entity class:
@Entity
@Table(name = "portal_user")
@Getter
@Setter
public class User implements Serializable {
private static final long serialVersionUID = 5062673109048808267L;
@Id
@Column(name = "id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
@Column(name = "first_name")
@NotNull(message = "{NotNull.User.firstName.Validation}")
private String firstName;
@Column(name = "middle_name")
private String middleName;
@Column(name = "surname")
@NotNull(message = "{NotNull.User.surname.Validation}")
private String surname;
@Column(name = "sex")
@NotNull(message = "{NotNull.User.sex.Validation}")
private char sex;
@Column(name = "birthdate")
@NotNull(message = "{NotNull.User.birthdate.Validation}")
private Date birthdate;
@Column(name = "tax_code")
@NotNull(message = "{NotNull.User.taxCode.Validation}")
private String taxCode;
@Column(name = "e_mail")
@NotNull(message = "{NotNull.User.email.Validation}")
private String email;
@Column(name = "pswd")
@NotNull(message = "{NotNull.User.pswd.Validation}")
private String pswd;
@Column(name = "contact_number")
@NotNull(message = "{NotNull.User.contactNumber.Validation}")
private String contactNumber;
@Temporal(TemporalType.DATE)
@Column(name = "created_at")
private Date createdAt;
@Column(name = "is_active")
private boolean is_active;
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "user", orphanRemoval = true)
@JsonManagedReference
private Set<Address> addressesList = new HashSet<>();
@ManyToMany(cascade = { CascadeType.MERGE })
@JoinTable(
name = "portal_user_user_type",
joinColumns = { @JoinColumn(name = "portal_user_id_fk") },
inverseJoinColumns = { @JoinColumn(name = "user_type_id_fk") }
)
Set<UserType> userTypes;
@ManyToOne(fetch = FetchType.EAGER)
@JsonProperty("subagent")
private User parent;
public User() {
super();
// TODO Auto-generated constructor stub
}
public User(String firstName, String middleName, String surname, char sex, Date birthdate, String taxCode,
String email, String pswd, String contactNumber, Date createdAt, boolean is_active) {
super();
this.firstName = firstName;
this.middleName = middleName;
this.surname = surname;
this.sex = sex;
this.birthdate = birthdate;
this.taxCode = taxCode;
this.email = email;
this.pswd = pswd;
this.contactNumber = contactNumber;
this.createdAt = createdAt;
this.is_active = is_active;
}
}
Then I have this repository interface:
public interface UsersRepository extends JpaRepository<User, Integer> {
/**
* Retrieve an user by its e-mail address:
* @param email is the e-mail of the user
* @return the user related to the specified e-mail
*/
User findByemail(String email);
/**
* Retrieve the list of users belonging to a specific user type
* @param typeName is the name of the user type
* @return the list of users belonging to a specific user type
*/
List<User> findByUserTypes_TypeName(String typeName);
/**
* Retrieve the list of users children of an user.
* Generally used to retrieve the client users of a specific sub-agent user
* @param id is the id of the parent user
* @return the list of children of a specific user (generally used to retrieve the client users of a specific sub-agent user)
*/
List<User> findByParent_Id(Integer id);
/**
* Retrieve an user starting from is id
* @param id of the user which you want to retrieve
* @return the retrieved object
*/
Optional<User> findById(Integer id);
}
Om my doubt is on the last method (intended to retrieve an User object by its own id field value, this one:
Optional<User> findById(Integer id);
Originally I tried to define it simply as:
User findById(Integer id);
But doing in this way Eclipse\STS give me the following error:
Multiple markers at this line
- implements org.springframework.data.repository.CrudRepository<com.easydefi.users.entity.User,java.lang.Integer>.
findById
- The return type is incompatible with CrudRepository<User,Integer>.findById(Integer)
- The return type is incompatible with CrudRepository<User,Integer>.findById(Integer)
Why this error? and why Eclipse force me to return Optional<User>
as returned type? What is this Optional? And why in the findByemail() allow me to return a simple User type?
Upvotes: 0
Views: 2003
Reputation: 81950
Alexy and Raul already gave good explanations why this doesn't work. But the options the offer for avoiding the problem is rather limited. Here are the most relevant options you have:
omit your findById
method and just use the one offered by the CrudRepository
. Works but it seems you don't want the Optional
so this isn't really satisfying.
You can modify the method name by using an alternative for find
, e.g. search
or query
. See https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repository-query-keywords for a list of possibly words to use.
You can also add anything between find
and By
. findUserById
would work just as well.
You can decide not to inherit from CrudRepository
. This of course will remove all the other methods of the CrudRepository
as well. But if you copy their declaration into your repository interface the will get their proper implementation. You may also use this variant to prune methods that you possibly don't want to have in your repository anyway.
Upvotes: 1
Reputation: 161
Your repository extends JpaRepository. JpaRepository extends PagingAndSortingRepository that extends CrudRepository. CrudRepository has the method: Optional<T> findById(ID var1);
.
https://docs.spring.io/spring-data/jpa/docs/current/api/org/springframework/data/jpa/repository/JpaRepository.html
When you define a method with this signature you are overriding the CrudRepository method. But if you define a different return type for this method created in your repository, your code won't compile.
Optional was created in Java 8, in resume, is used to indicate that the return data of method may be null. Is a good practice to use Optional for these scenarios. https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html
About another methods that you mentioned, they are just methods of your UsersRepository that you can create as you want.
Upvotes: 1
Reputation: 1242
As you can see in the JavaDoc of CrudRepository
interface which JpaRepository
extends, there is already a findById
method with the same signature.
Java overriding rules do not allow you to have a method with the same name and parameters and a return type that is not consistent with the parent class definition (in this case, Optional<User>
).
If you somehow change the method name, Spring Data JPA will be able to use a plain reference. In this case, null
will be returned if the entity hasn't been found. For you case however, you should just drop your findById
method.
Upvotes: 1