I've recently tried to implement Spring Security into my web store project to distinguish between single users. Websites are working properly except there is one issue which I can't track to resolve. I have object called Customer within User class. Customer object has fields like id, balance, etc., and User has OneToOne relationship to Customer, so I can have single object for credentials and foreign key to specifics of user - his first name, last name, balance, owned products, etc.
I also have Product class which has ManyToOne relationship with Customer. It has its' own id, productCost, etc.
I'm using Spring MVC to take care of proper URL dispatching. When some action is taken, I'm using @AuthenticationPrincipal annotation to get currently logged Customer (through foreign key in User) and modify data regarding Customer linked with that foreign key.
When I modify Customer data through @AuthenticationPrincipal in controller, changes are immediate and they show up on website. But when I try to modify data through some DAO, for example by searching for Customer through id or try to get Customer that owns Product from Product getter (ManyToOne has reference to owning Customer), changes are not immediate. Database updates itself immediately and properly, like in first case, but collections in code and website state are not changed until I logout and login again - that's when data is updated. I suspect it may be due to fact that updating UserDetails updates data directly for currently logged user but then - how may I achieve same effect for Customer found by id?
Snippets of code: Users.java:
@Entity
@Table(name="users")
public class Users {
@Id
@Column(name="username")
private String username;
@Column(name="password")
private String password;
@Column(name="enabled")
private boolean isActive;
@OneToMany(mappedBy="user")
private Set<Authorities> authorities;
@OneToOne
@JoinColumn(name="customer_id")
private Customer customer;
Product.java:
@Entity
@Table(name="product")
public class Product {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="id")
private int id;
@Column(name="name")
private String productName;
@Column(name="description")
private String productDescription;
@Column(name="category")
private String productCategory;
@Column(name="cost")
private int productCost;
@ManyToOne(fetch=FetchType.EAGER)
@JoinColumn(name="owner_id")
private Customer productOwner;
Customer.java:
@Entity
@Table(name="customer")
public class Customer {
//Class fields
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="id")
private int id;
@Column(name="balance")
private int balance;
@Column(name="first_name")
private String firstName;
@Column(name="last_name")
private String lastName;
@Column(name="email")
private String email;
@OneToMany(mappedBy="productOwner", fetch=FetchType.EAGER)
private List<Product> ownedProducts;
Piece of controller code:
@Autowired
CustomerService customerService;
@Autowired
ProductService productService;
/*(...)*/
@GetMapping("/showOffer/{offerId}")
public String getOffer(@PathVariable int offerId, Model theModel, @AuthenticationPrincipal MyUserDetails user) {
Product retrievedProduct = productService.findById(offerId);
if (user.getCustomer().getBalance() >= retrievedProduct.getProductCost())
{
Customer retrievedProductOwner = retrievedProduct.getProductOwner();
/* This is where changes aren't applied immediately and I need to logout and login to process them. */
retrievedProductOwner.setBalance(1000);
/* This is where changes are immediately shown and Java collections are updated: */
user.getCustomer().setBalance(user.getCustomer().getBalance()-retrievedProduct.getProductCost());
/* Code below is an attempt to force immediate changes by updating collections directly from database - but that approach doesn't work */
productService.delete(retrievedProduct.getId());
retrievedProduct.getProductOwner().getOwnedProducts().clear();
retrievedProduct.getProductOwner().setOwnedProducts(productService.listOwnerProducts(retrievedProduct.getProductOwner()));
}
else {
System.out.println("Insufficient funds!");
}
return "redirect:/home";
TL:DR
I use UserDetails object in controller and I am also using DAO for Customer used as foreign key in UserDetails. Using UserDetails directly updates data and everything works fine, using DAO doesn't make changes until I logout and login.
