I am totally new to spring, and making a social media app, where User and Follow are Entity classes. Follow entity is having two fields of type User, one for follower and another for following, mapping is ManyToOne from Follow to User.
There is an use-case where I am requiring follower and following objects from a Follow object. And the place is where I want to get these in FollowService.java. My service class is having a method to save the Follow record into the database. In that function, I want to get follower and following from that saved Follow record, which I have just inserted.
Note:- I have got an idea from this answer to set only Ids for mapped classes instead of supplying whole object. So, I am just setting the followerId and followingId in my Follow record and save it to database. Further understanding you can get from the code...
Follow.java
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(uniqueConstraints = @UniqueConstraint(name = "uniqueIdForFollow", columnNames = {"fk_followerId", "fk_followingId"}))
public class Follow {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int followId;
@ManyToOne(targetEntity = User.class, fetch=FetchType.EAGER)
@JoinColumn(name = "fk_followerId", insertable=false, updatable=false)
@OnDelete(action = OnDeleteAction.CASCADE)
private User follower;
@Column(name = "fk_followerId")
private int followerId;
@ManyToOne(targetEntity = User.class, fetch=FetchType.EAGER)
@JoinColumn(name = "fk_followingId", insertable=false, updatable=false)
@OnDelete(action = OnDeleteAction.CASCADE)
private User following;
@Column(name = "fk_followingId")
private int followingId;
@CreationTimestamp
@Temporal(TemporalType.TIMESTAMP)
private Date createdAt;
public int getFollowId() {
return followId;
}
public int getFollowerId() {
return followerId;
}
public void setFollowerId(int followerId) {
this.followerId = followerId;
}
public int getFollowingId() {
return followingId;
}
public void setFollowingId(int followingId) {
this.followingId = followingId;
}
public User getFollower() {
return follower;
}
public void setFollower(User follower) {
this.follower = follower;
}
public User getFollowing() {
return following;
}
public void setFollowing(User following) {
this.following = following;
}
}
User.java
@NoArgsConstructor
@AllArgsConstructor
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int userId;
@NotNull
private String username;
@Email(message = "entered email is not valid.", regexp = "[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,3}", flags = Pattern.Flag.CASE_INSENSITIVE)
@NotNull
private String email;
@NotNull
private String password;
public int getUserId() {
return userId;
}
public @NotNull String getUsername() {
return username;
}
public void setUsername(@NotNull String username) {
this.username = username;
}
public @NotNull String getEmail() {
return email;
}
public void setEmail(@NotNull String email) {
this.email = email;
}
public @NotNull String getPassword() {
return password;
}
public void setPassword(@NotNull String password) {
this.password = password;
}
}
FollowController.java
@RestController
@RequestMapping("/users/{userId}/follow")
public class FollowController {
@Autowired
FollowService fs;
@PostMapping
public ResponseEntity<Map<String, Object>> followThisUser(@PathVariable("userId") int userId, @RequestBody Follow follow, HttpServletRequest request) throws Exception {
Follow newFollow = fs.followUser(userId, follow);
return ResponseHandler
.generateResponse(newFollow, HttpStatus.CREATED, "user with userId "+follow.getFollowerId()+" followed the user with userId "+userId, request.getRequestURI());
}
}
FollowService.java
@Service
public class FollowService {
@Autowired
FollowRepo fr;
public Follow followUser(int userId, Follow follow) {
follow.setFollowingId(userId);
Follow savedFollow = fr.save(follow);
// record saved to the database
// Now I fetch it using Id
// Here I want to get the follower and following fields
/*
Follow follow = getByFollowId(savedFollow.getFollowId());
System.out.println(follow.getFollower()); // I am getting null
System.out.println(follow.getFollowing()); // I am getting null
*/
return savedFollow;
}
public Follow getByFollowId(int followId) throws Exception {
Follow follow = fr.findByFollowId(followId);
if(follow == null){
throw new Exception("Follow not found with followId "+followId);
}
return follow;
}
}
FollowRepo.java
public interface FollowRepo extends JpaRepository<Follow, Integer> {
Follow findByFollowerIdAndFollowingId(int followerId, int followindId);
Follow findByFollowId(int followId);
}
What I tried?
What I have done in service class(in comment section), Same thing I had tried in method followThisUser()
in controller also to get the follower and following fields. But I am getting null there also.
Strange Thing
But If I created another separate controller TestController
there I am trying to do the same and I am getting what I had expected.
TestController.java
@RestController
public class TestController {
@Autowired
FollowService fs;
@GetMapping("/test/{followId}")
public ResponseEntity<Map<String, Object>> display(@PathVariable("followId") int followId, HttpServletRequest request) throws Exception {
System.out.println(followId);
Follow follow = fs.getByFollowId(followId);
System.out.println(follow.getFollower()); // not null, fine
System.out.println(follow.getFollowing()); // not null, fine
System.out.println(follow.getFollower().getUsername()); // also fine
return ResponseHandler
.generateResponse(follow, HttpStatus.OK, "fetched", request.getRequestURI());
}
}
Expectation
I just want to know the reason of above happening and what to do to meet the expectation?