I am developing REST application using spring boot and I am trying to optimize the performance of the queries. I am currently using findById from the repositories which is causing performance issues. Code is given below:
User Entity
@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
@Entity
@Table(name="user", uniqueConstraints = @UniqueConstraint(columnNames = "email"))
@JsonIgnoreProperties({"comments"})
public class User implements UserDetails {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@NotEmpty(message = "first name should not be empty")
@Column(name = "first_name")
private String firstName;
@NotEmpty(message = "last name should not be empty")
@Column(name = "last_name")
private String lastName;
@Email(message = "Not a valid email")
private String email;
@NotEmpty
// @Pattern(regexp = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[#$@!%&*?])[A-Za-z\d#$@!%&*?]{8,}$",
// message ="1 Uppercase, 1 Lowercase, 1 special character, 1 number, Min 8 characters ")
@Size(min = 8, message = "password should have at least 8 characters")
private String password;
@Enumerated(EnumType.STRING)
private Role role;
@OneToMany(mappedBy = "user",
cascade = CascadeType.ALL)
private Set<Comment> comments = new HashSet<>();
@ManyToMany(mappedBy = "assignees")
private Set<Issue> issues = new HashSet<>();
@ManyToMany(mappedBy = "voters")
private Set<Issue> votedIssues = new HashSet<>();
@ManyToMany(mappedBy = "members")
private Set<Community> communities = new HashSet<>();
@ManyToMany(mappedBy = "requestingMembers")
private Set<Community> requestedCommunities = new HashSet<>();
@OneToMany(mappedBy = "admin", cascade = CascadeType.ALL)
private Set<Community> communitiesCreated = new HashSet<>();
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return List.of(new SimpleGrantedAuthority(role.name()));
}
@Override
public String getUsername() {
return email;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
Issue Entity
@AllArgsConstructor
@Data
@Entity
@NoArgsConstructor
@Table(name="issue")
public class Issue {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String title;
private String description;
private LocalDate dateCreated;
private boolean isOpen;
@ManyToOne
private User user;
@OneToMany(mappedBy = "issue", cascade = CascadeType.ALL)
private List<Comment> comments = new ArrayList<>();
@ManyToMany(cascade = CascadeType.ALL)
private List<User> voters = new ArrayList<>();
@ManyToMany(cascade = CascadeType.ALL)
private List<User> assignees = new ArrayList<>();
@ManyToOne
@JoinColumn(name = "community_id")
private Community community;
}
Comment Entity
@AllArgsConstructor
@Data
@Entity
@NoArgsConstructor
@Table(name = "comment")
public class Comment {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String content;
@ManyToOne
private User user;
@ManyToOne
@JoinColumn(name = "issue_id")
private Issue issue;
private LocalDate dateCreated;
}
Role Enum
public enum Role {
CUSTOMER("CUSTOMER"),
EXPERT("EXPERT"),
ADMIN("ADMIN");
private String role;
Role(String role) {
this.role = role;
}
public String getRoleName() {
return role;
}
}
When I do a userRepository.findById(userId) there are so many select queries being fired. I am looking for a way to optimize the queries so that findById produces result in less queries. Currenlty it is making so many queries just for one api request for example :
2023-05-16T16:21:48.837+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL : select u1_0.id,u1_0.email,u1_0.first_name,u1_0.last_name,u1_0.password,u1_0.role from user u1_0 where u1_0.id=?
2023-05-16T16:21:48.911+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL : select i1_0.assignees_id,i1_1.id,c1_0.id,a1_0.id,a1_0.email,a1_0.first_name,a1_0.last_name,a1_0.password,a1_0.role,c1_0.description,c1_0.name,i1_1.date_created,i1_1.description,i1_1.is_open,i1_1.title,u1_0.id,u1_0.email,u1_0.first_name,u1_0.last_name,u1_0.password,u1_0.role from issue_assignees i1_0 join issue i1_1 on i1_1.id=i1_0.issues_id left join community c1_0 on c1_0.id=i1_1.community_id left join user a1_0 on a1_0.id=c1_0.user_id left join user u1_0 on u1_0.id=i1_1.user_id where i1_0.assignees_id=?
2023-05-16T16:21:48.921+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL : select c1_0.user_id,c1_0.id,c1_0.content,c1_0.date_created,i1_0.id,c2_0.id,c2_0.user_id,c2_0.description,c2_0.name,i1_0.date_created,i1_0.description,i1_0.is_open,i1_0.title,u1_0.id,u1_0.email,u1_0.first_name,u1_0.last_name,u1_0.password,u1_0.role from comment c1_0 left join issue i1_0 on i1_0.id=c1_0.issue_id left join community c2_0 on c2_0.id=i1_0.community_id left join user u1_0 on u1_0.id=i1_0.user_id where c1_0.user_id=?
2023-05-16T16:21:48.927+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL : select c1_0.user_id,c1_0.id,c1_0.content,c1_0.date_created,i1_0.id,c2_0.id,c2_0.user_id,c2_0.description,c2_0.name,i1_0.date_created,i1_0.description,i1_0.is_open,i1_0.title,u1_0.id,u1_0.email,u1_0.first_name,u1_0.last_name,u1_0.password,u1_0.role from comment c1_0 left join issue i1_0 on i1_0.id=c1_0.issue_id left join community c2_0 on c2_0.id=i1_0.community_id left join user u1_0 on u1_0.id=i1_0.user_id where c1_0.user_id=?
2023-05-16T16:21:48.930+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL : select i1_0.assignees_id,i1_1.id,c1_0.id,a1_0.id,a1_0.email,a1_0.first_name,a1_0.last_name,a1_0.password,a1_0.role,c1_0.description,c1_0.name,i1_1.date_created,i1_1.description,i1_1.is_open,i1_1.title,u1_0.id,u1_0.email,u1_0.first_name,u1_0.last_name,u1_0.password,u1_0.role from issue_assignees i1_0 join issue i1_1 on i1_1.id=i1_0.issues_id left join community c1_0 on c1_0.id=i1_1.community_id left join user a1_0 on a1_0.id=c1_0.user_id left join user u1_0 on u1_0.id=i1_1.user_id where i1_0.assignees_id=?
2023-05-16T16:21:48.932+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL : select v1_0.voters_id,v1_1.id,c1_0.id,a1_0.id,a1_0.email,a1_0.first_name,a1_0.last_name,a1_0.password,a1_0.role,c1_0.description,c1_0.name,v1_1.date_created,v1_1.description,v1_1.is_open,v1_1.title,u1_0.id,u1_0.email,u1_0.first_name,u1_0.last_name,u1_0.password,u1_0.role from issue_voters v1_0 join issue v1_1 on v1_1.id=v1_0.voted_issues_id left join community c1_0 on c1_0.id=v1_1.community_id left join user a1_0 on a1_0.id=c1_0.user_id left join user u1_0 on u1_0.id=v1_1.user_id where v1_0.voters_id=?
2023-05-16T16:21:48.933+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL : select c1_0.members_id,c1_1.id,a1_0.id,a1_0.email,a1_0.first_name,a1_0.last_name,a1_0.password,a1_0.role,c1_1.description,c1_1.name from community_members c1_0 join community c1_1 on c1_1.id=c1_0.communities_id left join user a1_0 on a1_0.id=c1_1.user_id where c1_0.members_id=?
2023-05-16T16:21:48.936+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL : select r1_0.requesting_members_id,r1_1.id,a1_0.id,a1_0.email,a1_0.first_name,a1_0.last_name,a1_0.password,a1_0.role,r1_1.description,r1_1.name from community_requesting_members r1_0 join community r1_1 on r1_1.id=r1_0.requested_communities_id left join user a1_0 on a1_0.id=r1_1.user_id where r1_0.requesting_members_id=?
2023-05-16T16:21:48.937+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL : select c1_0.user_id,c1_0.id,c1_0.description,c1_0.name from community c1_0 where c1_0.user_id=?
2023-05-16T16:21:48.938+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL : select m1_0.communities_id,m1_1.id,m1_1.email,m1_1.first_name,m1_1.last_name,m1_1.password,m1_1.role from community_members m1_0 join user m1_1 on m1_1.id=m1_0.members_id where m1_0.communities_id=?
2023-05-16T16:21:48.938+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL : select c1_0.user_id,c1_0.id,c1_0.content,c1_0.date_created,i1_0.id,c2_0.id,c2_0.user_id,c2_0.description,c2_0.name,i1_0.date_created,i1_0.description,i1_0.is_open,i1_0.title,u1_0.id,u1_0.email,u1_0.first_name,u1_0.last_name,u1_0.password,u1_0.role from comment c1_0 left join issue i1_0 on i1_0.id=c1_0.issue_id left join community c2_0 on c2_0.id=i1_0.community_id left join user u1_0 on u1_0.id=i1_0.user_id where c1_0.user_id=?
2023-05-16T16:21:48.940+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL : select c1_0.user_id,c1_0.id,c1_0.content,c1_0.date_created,i1_0.id,c2_0.id,c2_0.user_id,c2_0.description,c2_0.name,i1_0.date_created,i1_0.description,i1_0.is_open,i1_0.title,u1_0.id,u1_0.email,u1_0.first_name,u1_0.last_name,u1_0.password,u1_0.role from comment c1_0 left join issue i1_0 on i1_0.id=c1_0.issue_id left join community c2_0 on c2_0.id=i1_0.community_id left join user u1_0 on u1_0.id=i1_0.user_id where c1_0.user_id=?
2023-05-16T16:21:48.941+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL : select i1_0.assignees_id,i1_1.id,c1_0.id,a1_0.id,a1_0.email,a1_0.first_name,a1_0.last_name,a1_0.password,a1_0.role,c1_0.description,c1_0.name,i1_1.date_created,i1_1.description,i1_1.is_open,i1_1.title,u1_0.id,u1_0.email,u1_0.first_name,u1_0.last_name,u1_0.password,u1_0.role from issue_assignees i1_0 join issue i1_1 on i1_1.id=i1_0.issues_id left join community c1_0 on c1_0.id=i1_1.community_id left join user a1_0 on a1_0.id=c1_0.user_id left join user u1_0 on u1_0.id=i1_1.user_id where i1_0.assignees_id=?
2023-05-16T16:21:48.942+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL : select v1_0.voters_id,v1_1.id,c1_0.id,a1_0.id,a1_0.email,a1_0.first_name,a1_0.last_name,a1_0.password,a1_0.role,c1_0.description,c1_0.name,v1_1.date_created,v1_1.description,v1_1.is_open,v1_1.title,u1_0.id,u1_0.email,u1_0.first_name,u1_0.last_name,u1_0.password,u1_0.role from issue_voters v1_0 join issue v1_1 on v1_1.id=v1_0.voted_issues_id left join community c1_0 on c1_0.id=v1_1.community_id left join user a1_0 on a1_0.id=c1_0.user_id left join user u1_0 on u1_0.id=v1_1.user_id where v1_0.voters_id=?
2023-05-16T16:21:48.943+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL : select v1_0.voters_id,v1_1.id,c1_0.id,a1_0.id,a1_0.email,a1_0.first_name,a1_0.last_name,a1_0.password,a1_0.role,c1_0.description,c1_0.name,v1_1.date_created,v1_1.description,v1_1.is_open,v1_1.title,u1_0.id,u1_0.email,u1_0.first_name,u1_0.last_name,u1_0.password,u1_0.role from issue_voters v1_0 join issue v1_1 on v1_1.id=v1_0.voted_issues_id left join community c1_0 on c1_0.id=v1_1.community_id left join user a1_0 on a1_0.id=c1_0.user_id left join user u1_0 on u1_0.id=v1_1.user_id where v1_0.voters_id=?
2023-05-16T16:21:48.944+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL : select c1_0.members_id,c1_1.id,a1_0.id,a1_0.email,a1_0.first_name,a1_0.last_name,a1_0.password,a1_0.role,c1_1.description,c1_1.name from community_members c1_0 join community c1_1 on c1_1.id=c1_0.communities_id left join user a1_0 on a1_0.id=c1_1.user_id where c1_0.members_id=?
2023-05-16T16:21:48.945+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL : select m1_0.communities_id,m1_1.id,m1_1.email,m1_1.first_name,m1_1.last_name,m1_1.password,m1_1.role from community_members m1_0 join user m1_1 on m1_1.id=m1_0.members_id where m1_0.communities_id=?
2023-05-16T16:21:48.945+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL : select c1_0.user_id,c1_0.id,c1_0.description,c1_0.name from community c1_0 where c1_0.user_id=?
2023-05-16T16:21:48.946+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL : select i1_0.community_id,i1_0.id,i1_0.date_created,i1_0.description,i1_0.is_open,i1_0.title,u1_0.id,u1_0.email,u1_0.first_name,u1_0.last_name,u1_0.password,u1_0.role from issue i1_0 left join user u1_0 on u1_0.id=i1_0.user_id where i1_0.community_id=?
2023-05-16T16:21:48.947+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL : select r1_0.requesting_members_id,r1_1.id,a1_0.id,a1_0.email,a1_0.first_name,a1_0.last_name,a1_0.password,a1_0.role,r1_1.description,r1_1.name from community_requesting_members r1_0 join community r1_1 on r1_1.id=r1_0.requested_communities_id left join user a1_0 on a1_0.id=r1_1.user_id where r1_0.requesting_members_id=?
2023-05-16T16:21:48.947+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL : select c1_0.user_id,c1_0.id,c1_0.description,c1_0.name from community c1_0 where c1_0.user_id=?
2023-05-16T16:21:48.948+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL : select c1_0.user_id,c1_0.id,c1_0.content,c1_0.date_created,i1_0.id,c2_0.id,c2_0.user_id,c2_0.description,c2_0.name,i1_0.date_created,i1_0.description,i1_0.is_open,i1_0.title,u1_0.id,u1_0.email,u1_0.first_name,u1_0.last_name,u1_0.password,u1_0.role from comment c1_0 left join issue i1_0 on i1_0.id=c1_0.issue_id left join community c2_0 on c2_0.id=i1_0.community_id left join user u1_0 on u1_0.id=i1_0.user_id where c1_0.user_id=?
2023-05-16T16:21:48.949+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL : select i1_0.assignees_id,i1_1.id,c1_0.id,a1_0.id,a1_0.email,a1_0.first_name,a1_0.last_name,a1_0.password,a1_0.role,c1_0.description,c1_0.name,i1_1.date_created,i1_1.description,i1_1.is_open,i1_1.title,u1_0.id,u1_0.email,u1_0.first_name,u1_0.last_name,u1_0.password,u1_0.role from issue_assignees i1_0 join issue i1_1 on i1_1.id=i1_0.issues_id left join community c1_0 on c1_0.id=i1_1.community_id left join user a1_0 on a1_0.id=c1_0.user_id left join user u1_0 on u1_0.id=i1_1.user_id where i1_0.assignees_id=?
2023-05-16T16:21:48.950+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL : select v1_0.voters_id,v1_1.id,c1_0.id,a1_0.id,a1_0.email,a1_0.first_name,a1_0.last_name,a1_0.password,a1_0.role,c1_0.description,c1_0.name,v1_1.date_created,v1_1.description,v1_1.is_open,v1_1.title,u1_0.id,u1_0.email,u1_0.first_name,u1_0.last_name,u1_0.password,u1_0.role from issue_voters v1_0 join issue v1_1 on v1_1.id=v1_0.voted_issues_id left join community c1_0 on c1_0.id=v1_1.community_id left join user a1_0 on a1_0.id=c1_0.user_id left join user u1_0 on u1_0.id=v1_1.user_id where v1_0.voters_id=?
2023-05-16T16:21:48.951+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL : select c1_0.members_id,c1_1.id,a1_0.id,a1_0.email,a1_0.first_name,a1_0.last_name,a1_0.password,a1_0.role,c1_1.description,c1_1.name from community_members c1_0 join community c1_1 on c1_1.id=c1_0.communities_id left join user a1_0 on a1_0.id=c1_1.user_id where c1_0.members_id=?
2023-05-16T16:21:48.951+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL : select r1_0.requesting_members_id,r1_1.id,a1_0.id,a1_0.email,a1_0.first_name,a1_0.last_name,a1_0.password,a1_0.role,r1_1.description,r1_1.name from community_requesting_members r1_0 join community r1_1 on r1_1.id=r1_0.requested_communities_id left join user a1_0 on a1_0.id=r1_1.user_id where r1_0.requesting_members_id=?
2023-05-16T16:21:48.952+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL : select c1_0.user_id,c1_0.id,c1_0.description,c1_0.name from community c1_0 where c1_0.user_id=?
2023-05-16T16:21:48.953+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL : select c1_0.user_id,c1_0.id,c1_0.content,c1_0.date_created,i1_0.id,c2_0.id,c2_0.user_id,c2_0.description,c2_0.name,i1_0.date_created,i1_0.description,i1_0.is_open,i1_0.title,u1_0.id,u1_0.email,u1_0.first_name,u1_0.last_name,u1_0.password,u1_0.role from comment c1_0 left join issue i1_0 on i1_0.id=c1_0.issue_id left join community c2_0 on c2_0.id=i1_0.community_id left join user u1_0 on u1_0.id=i1_0.user_id where c1_0.user_id=?
2023-05-16T16:21:48.953+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL : select i1_0.assignees_id,i1_1.id,c1_0.id,a1_0.id,a1_0.email,a1_0.first_name,a1_0.last_name,a1_0.password,a1_0.role,c1_0.description,c1_0.name,i1_1.date_created,i1_1.description,i1_1.is_open,i1_1.title,u1_0.id,u1_0.email,u1_0.first_name,u1_0.last_name,u1_0.password,u1_0.role from issue_assignees i1_0 join issue i1_1 on i1_1.id=i1_0.issues_id left join community c1_0 on c1_0.id=i1_1.community_id left join user a1_0 on a1_0.id=c1_0.user_id left join user u1_0 on u1_0.id=i1_1.user_id where i1_0.assignees_id=?
2023-05-16T16:21:48.954+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL : select v1_0.voters_id,v1_1.id,c1_0.id,a1_0.id,a1_0.email,a1_0.first_name,a1_0.last_name,a1_0.password,a1_0.role,c1_0.description,c1_0.name,v1_1.date_created,v1_1.description,v1_1.is_open,v1_1.title,u1_0.id,u1_0.email,u1_0.first_name,u1_0.last_name,u1_0.password,u1_0.role from issue_voters v1_0 join issue v1_1 on v1_1.id=v1_0.voted_issues_id left join community c1_0 on c1_0.id=v1_1.community_id left join user a1_0 on a1_0.id=c1_0.user_id left join user u1_0 on u1_0.id=v1_1.user_id where v1_0.voters_id=?
2023-05-16T16:21:48.954+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL : select c1_0.members_id,c1_1.id,a1_0.id,a1_0.email,a1_0.first_name,a1_0.last_name,a1_0.password,a1_0.role,c1_1.description,c1_1.name from community_members c1_0 join community c1_1 on c1_1.id=c1_0.communities_id left join user a1_0 on a1_0.id=c1_1.user_id where c1_0.members_id=?
2023-05-16T16:21:48.955+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL : select r1_0.requesting_members_id,r1_1.id,a1_0.id,a1_0.email,a1_0.first_name,a1_0.last_name,a1_0.password,a1_0.role,r1_1.description,r1_1.name from community_requesting_members r1_0 join community r1_1 on r1_1.id=r1_0.requested_communities_id left join user a1_0 on a1_0.id=r1_1.user_id where r1_0.requesting_members_id=?
2023-05-16T16:21:48.955+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL : select c1_0.user_id,c1_0.id,c1_0.description,c1_0.name from community c1_0 where c1_0.user_id=?
I am expecting just one or two select queries.
2
Answers
First stop using
@Data
(or better Lombok all together) with JPA entities. When using@Data
it will generate anequals
/hashCode
/toString
method including all collections (which are lazy) in your entity. (I wrote a blog about it about 4 years ago and yet we still haven’t learned).Those
hashCode
andequals
method are important as those are used to determine if an object is already in the cache or not. Now to calculate thehashCode
what do you think will happen…. Exactly queries, queries and some more queries.I would suggest to create a
BaseEntity
which include a regularhashCode
,equals
and basictoString
method. Then let all your entities extend this base class.Next replace the
@Data
with only@Getter
/@Setter
to generate the getters/setters.Now for example let your
Comment
class extend this and drop the usage of@Data
.This should already reduce the number of queries that are being issued. Another optimization you could do is to use bytecode enhancements to lazy load the
Issue
in theComment
(the sample ofcourse applies to other fields that can be lazy loaded). But this requires bytecode enhancements.I recommend avoiding the use of @Data (or preferably Lombok altogether) when working with JPA entities. When you use @Data, it generates methods such as equals, hashCode, and toString, which include all collections (which are lazy) in your entity. I wrote a blog about this issue around four years ago, yet it seems we still haven’t learned from it.
These hashCode and equals methods are crucial as they are used to determine if an object is already present in the cache or not. Now, let’s consider what happens when calculating the hashCode… It results in queries, queries, and even more queries.
To address this, I suggest creating a BaseEntity that includes a regular hashCode, equals, and a basic toString method. Then, have all your entities extend this base class.
Additionally, replace @Data with only @Getter and @Setter annotations to generate the getters and setters.
Here’s an example implementation:
Now, for example, let your Comment class extend this base class and remove the usage of @Data.
This can help reduce the number of queries being issued. Another optimization option is to use bytecode enhancements for lazy loading specific fields, but it should be kept in mind that this approach requires bytecode enhancements.