Here is a sample entity and a repository in a Spring Boot application. I'm trying to test it. I need to commit all changes inside each test and rollback them after the test is finished.
If I remove #Transactional(propagation = Propagation.NOT_SUPPORTED) then the changes not commited at all. And I don't get an exception when insert users with the same email and emailIsUnique is failed. If I add this annotation, then changes are commited and emailIsUnique is passed. But userIsCreatedAndRead is failed, because user John Doe is already created in emailIsUnique and not rollbacked.
How to fix it?
package com.example.springdata.entities;
import java.util.UUID;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import org.hibernate.annotations.NaturalId;
#Entity(name = "Users")
public class UserEntity {
#Id
#GeneratedValue
private UUID id;
#NaturalId
#Column(length = 100, unique = true)
#NotNull
#Size(min = 3, max = 100)
private String login;
#Column(length = 100, unique = true)
#Email
private String email;
#Column(length = 100)
private String firstName;
#Column(length = 100)
private String lastName;
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
package com.example.springdata.repositories;
import java.util.UUID;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import com.example.springdata.entities.UserEntity;
#RepositoryRestResource(path = "users", collectionResourceRel = "users")
public interface UserRepository extends CrudRepository<UserEntity, UUID> {
}
package com.example.springdata.repositories;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import java.util.Optional;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.test.annotation.Rollback;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.example.springdata.entities.UserEntity;
import io.zonky.test.db.AutoConfigureEmbeddedDatabase;
import io.zonky.test.db.AutoConfigureEmbeddedDatabase.DatabaseProvider;
#DataJpaTest
#AutoConfigureEmbeddedDatabase(provider = DatabaseProvider.ZONKY)
#Transactional(propagation = Propagation.NOT_SUPPORTED)
class UserRepositoryIntegrationTests {
#Autowired
private UserRepository userRepository;
#Test
void userIsCreatedAndRead() {
UserEntity user = createEntity1();
userRepository.save(user);
assertThat(user.getId()).isNotNull();
Optional<UserEntity> optionalUser = userRepository.findById(user.getId());
assertThat(optionalUser).isPresent();
optionalUser.ifPresent(foundUser -> assertThat(foundUser).usingRecursiveComparison().isEqualTo(user));
}
#Test
void emailIsUnique() {
UserEntity user1 = createEntity1();
userRepository.save(user1);
UserEntity user2 = createEntity2();
user2.setEmail(user1.getEmail());
assertThrows(DataIntegrityViolationException.class, () -> userRepository.save(user2));
}
private UserEntity createEntity1() {
UserEntity user = new UserEntity();
user.setLogin("john"); //$NON-NLS-1$
user.setFirstName("John"); //$NON-NLS-1$
user.setLastName("Doe"); //$NON-NLS-1$
user.setEmail("john.doe#example.com"); //$NON-NLS-1$
return user;
}
private UserEntity createEntity2() {
UserEntity user = new UserEntity();
user.setLogin("jane"); //$NON-NLS-1$
user.setFirstName("Jane"); //$NON-NLS-1$
user.setLastName("Smith"); //$NON-NLS-1$
user.setEmail("jane.smith#example.com"); //$NON-NLS-1$
return user;
}
}
Related
The contact class as an entity that would be linked with address class
package asmt1.demo.entity;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import asmt1.demo.dto.UserStatus;
//#Entity annotation specifies that the class is an entity and is mapped to a database table.
//#Table annotation specifies the name of the database table to be used for mapping
#Entity
#Table(name="Contactdetail")
public class Contact {
//#Id is used to specify the primary key
#Id
//Generated value is used to generate pk value ie. id to be autogenerated and assign identity column(id)
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
//#column is used to specify the column condition
//#Column( unique = true)
private String firstName;
private String lastName;
//#Column(unique = true)
private long contactNo;
private String mailId;
//list of named constant ie. status
#Enumerated(EnumType.STRING)
private UserStatus status;
//it is used to create one-to-one relationship between the contact and address table
//fetch type.lazy tells Hibernate to only fetch the related entities from the database when you use the relationship
#ManyToMany(fetch = FetchType.LAZY,cascade = CascadeType.ALL)
#JoinTable(name="conadd",
joinColumns = {#JoinColumn(name="id")},
inverseJoinColumns = {#JoinColumn(name="addid")})
//To handle the problem related to the serialization of the model using Jackson API when the model attributes have a lazy loading defined,
//we have to tell the serializer to ignore the chain or helpful garbage that Hibernate adds to classes, so it can manage lazy loading of data by declaring #JsonIgnoreProperties
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
private Set<Address> address=new HashSet<>();
//generate getters,setters, toString() and constructor using fields
public Contact() {}
public Contact(String firstName, String lastName, long contactNo, String mailId, UserStatus status,
Set<Address> address) {
super();
this.firstName = firstName;
this.lastName = lastName;
this.contactNo = contactNo;
this.mailId = mailId;
this.status = status;
this.address = address;
}
public Set<Address> getAddress() {
return address;
}
public void setAddress(Set<Address> address) {
this.address = address;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public long getContactNo() {
return contactNo;
}
public void setContactNo(long contactNo) {
this.contactNo = contactNo;
}
public String getMailId() {
return mailId;
}
public void setMailId(String mailId) {
this.mailId = mailId;
}
public UserStatus getStatus() {
return status;
}
public void setStatus(UserStatus status) {
this.status = status;
}
#Override
public String toString() {
return "Contact [id=" + id + ", firstName=" + firstName + ", lastName=" + lastName + ", contactNo=" + contactNo
+ ", mailId=" + mailId + "]";
}
}
the address class which is the entity
package asmt1.demo.entity;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
//#Entity annotation specifies that the class is an entity and is mapped to a database table.
//#Table annotation specifies the name of the database table to be used for mapping
#Entity
#Table(name="addressDetail")
public class Address {
//#Id is used to specify the primarykey
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long addid;
private String street1;
private String street2;
private long zipcode;
private String city;
private String state;
private String Country;
//mappedby is used to specify to relationship
#ManyToMany(fetch = FetchType.LAZY,cascade = CascadeType.ALL,mappedBy = "address")
private Set<Contact> contact=new HashSet<>();
//generate getters,setters, toString() and constructor using fields
public long getId() {
return addid;
}
public Set<Contact> getContact() {
return contact;
}
public void setContact(Set<Contact> contact) {
this.contact = contact;
}
public void setId(long id) {
this.addid = id;
}
public String getStreet1() {
return street1;
}
public void setStreet1(String street1) {
this.street1 = street1;
}
public String getStreet2() {
return street2;
}
public void setStreet2(String street2) {
this.street2 = street2;
}
public long getZipcode() {
return zipcode;
}
public void setZipcode(long zipcode) {
this.zipcode = zipcode;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getCountry() {
return Country;
}
public void setCountry(String country) {
Country = country;
}
public Address(String street1, String street2, long zipcode, String city, String state, String country) {
super();
this.street1 = street1;
this.street2 = street2;
this.zipcode = zipcode;
this.city = city;
this.state = state;
Country = country;
}
public Address() {}
}
a request class where I was calling both for data uploading
package asmt1.demo.dto;
import java.util.HashSet;
import java.util.Set;
import asmt1.demo.entity.Address;
import asmt1.demo.entity.Contact;
public class AddressReq {
private Set<Address> address=new HashSet<>();
private Set<Contact> contact=new HashSet<>();
public Set<Address> getAddress() {
return address;
}
public void setAddress(Set<Address> address) {
this.address = address;
}
public Set<Contact> getContact() {
return contact;
}
public void setContact(Set<Contact> contact) {
this.contact = contact;
}
public AddressReq(Set<Address> address, Set<Contact> contact) {
super();
this.address = address;
this.contact = contact;
}
public AddressReq() {}
#Override
public String toString() {
return "AddressReq [address=" + address + ", contact=" + contact + "]";
}
}
enum class for status
package asmt1.demo.dto;
//constant value for userstatus class
public enum UserStatus {
ACTIVE,INACTIVE
}
controller class
package asmt1.demo.controller;
import java.util.List;
import java.util.NoSuchElementException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import asmt1.demo.converter.ContactConverter;
import asmt1.demo.dto.AddressReq;
import asmt1.demo.dto.ContactDto;
import asmt1.demo.entity.Contact;
import asmt1.demo.repository.AddressRepo;
import asmt1.demo.repository.ContactRepo;
//#restcontroller is used for restful services
#RestController
//#RequestMapping is used for creating baseurl for controller will be used
#RequestMapping("/contact")
public class ContactController {
//#Autowired will search the object of class
#Autowired
private ContactRepo ctrepo;
#Autowired
private AddressRepo addrepo;;
#Autowired
private ContactConverter converter;
//#Requestbody is used to map/bind methods with pojo pr value to return value to the web
//#postmapping is used to add data to database from web
#PostMapping("/add")
public List<Contact> newcontact(#RequestBody AddressReq req) {
return ctrepo.saveAll(req.getContact());
}
//#getmapping is used to get the details/records from database on web page
#GetMapping("/contactlist")
public List<Contact> getcontactlist(){
return ctrepo.findAll(Sort.by(Sort.Direction.ASC, "firstName","lastName"));
}
#GetMapping("/contactdto")
public List<ContactDto> getcontactlistdto(){
List<Contact> findAll=ctrepo.findAll();
return converter.entitytodto(findAll);
}
#GetMapping("/contactlist/{id}")
public ResponseEntity<Contact> get(#PathVariable Long id) {
try {
Contact contact = ctrepo.getOne(id);
return new ResponseEntity<Contact>(contact, HttpStatus.OK);
} catch (NoSuchElementException e) {
return new ResponseEntity<Contact>(HttpStatus.NOT_FOUND);
}
}
#GetMapping("/contactdto/{id}")
public ContactDto getbyid(#PathVariable Long id) {
Contact orElse=ctrepo.findById(id).orElse(null);
return converter.entitytodto(orElse);
}
#GetMapping("/orderlist")
public List<Contact> getcontactlistbyorder(){
return ctrepo.findAllByOrderByIdDesc();
}
#PostMapping("/save")
public ContactDto savedto(#RequestBody ContactDto dto) {
Contact contact=converter.dtotoentity(dto);
contact=ctrepo.save(contact);
return converter.entitytodto(contact);
}
//#deletemapping is used to delete the records/details from database by web page
#DeleteMapping("/delete/{id}")
public String deletebyid(#PathVariable long id){
if (ctrepo.findById(id)==null) {
return "Id not found.....Please enter correct id";
}
ctrepo.deleteById(id);
return "Successfully deleted "+id;
}
//#putmapping is used to change/update the records/details in database by web page
#PutMapping("/edit")
public List<Contact> editcontactbyid(#RequestBody AddressReq req ){
return ctrepo.saveAll(req.getContact());
}
}
here is the Json format which I was uploading the data but its showing me error that
at [Source: (PushbackInputStream); line: 1, column: 2]]
2021-05-04 12:57:07.799 WARN 876 --- [nio-9090-exec-4] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize instance of java.util.HashSet<asmt1.demo.entity.Contact> out of START_OBJECT token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of java.util.HashSet<asmt1.demo.entity.Contact> out of START_OBJECT token
at [Source: (PushbackInputStream); line: 1, column: 13] (through reference chain: asmt1.demo.dto.AddressReq["contact"])]
{"contact":{
"firstName":"tomu",
"lastName":"shawn",
"contactNo":9124245,
"mailId":"ggia#gmail.com",
"status":"INACTIVE",
"address":{
"street1":"A/wing-24",
"street2":"plotno-4",
"city":"Mumbai",
"state":"Maharashtra",
"country":"India",
"zipcode":705
}}}
In your AddressReq class contact is set that is collection but in your pay load you are sending an object which should be collection of object.
Based on the AddressReq class the pay load should be
{["contact":{
"firstName":"tomu",
"lastName":"shawn",
"contactNo":9124245,
"mailId":"ggia#gmail.com",
"status":"INACTIVE",
"address":{
"street1":"A/wing-24",
"street2":"plotno-4",
"city":"Mumbai",
"state":"Maharashtra",
"country":"India",
"zipcode":705
}
}]
}
or if your request is always single entry of contact then you can change the contact property to single instance not the collection of Contact instance.
I read the Spring Security documentation to learn how to create a basic authentication system for my web application but I don't understand what architecture to pick.
Link : https://docs.spring.io/spring-security/site/docs/5.1.5.RELEASE/reference/htmlsingle/#preface
Currently I'm using the class WebSecurityConfigurerAdapter with this code :
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/css/**", "/index", "/user/**").permitAll()
//.antMatchers("/user/**").hasRole("USER")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login").failureUrl("/login-error")
.and()
.logout()
.permitAll();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password(passwordEncoder().encode("password")).roles("USER");
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
But in the documentation they recommand 3 alternative solutions.
1) WebMvcConfigurer :
https://docs.spring.io/spring-security/site/docs/5.1.5.RELEASE/reference/htmlsingle/#hello-web-security-java-configuration
2) AuthenticationManager :
https://docs.spring.io/spring-security/site/docs/5.1.5.RELEASE/reference/htmlsingle/#tech-intro-authentication
3) With another classes designed for Web Application (?)
https://docs.spring.io/spring-security/site/docs/5.1.5.RELEASE/reference/htmlsingle/#tech-intro-web-authentication
So, it's currently a big mess in my head and I don't know at all how to create my authentication system.
What architecture am I supposed to choose ?
Here my other classes in addition to understand my project :
UserService
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import app.shellx.dao.AuthorityRepository;
import app.shellx.dao.RoleRepository;
import app.shellx.dao.UserRepository;
import app.shellx.model.Authority;
import app.shellx.model.Role;
import app.shellx.model.User;
#Service
public class UserService implements UserDetailsService {
#Autowired
private UserRepository userRepository;
#Autowired
private RoleService roleService;
#Transactional(readOnly=true)
public User loadUserByUsername(final String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username);
//List<GrantedAuthority> authorities = buildUserAuthority(user.getAuthorities());
//if you're implementing UserDetails you wouldn't need to call this method and instead return the User as it is
//return buildUserForAuthentication(user, authorities);
return user;
}
/*public User login() {
try {
Authentication request = new UsernamePasswordAuthenticationToken(name, password);
Authentication result = am.authenticate(request);
SecurityContextHolder.getContext().setAuthentication(result);
break;
} catch(AuthenticationException e) {
System.out.println("Authentication failed: " + e.getMessage());
}
}
System.out.println("Successfully authenticated. Security context contains: " +
SecurityContextHolder.getContext().getAuthentication());
}
}*/
/* // Converts user to spring.springframework.security.core.userdetails.User
private User buildUserForAuthentication(User user, List<GrantedAuthority> authorities) {
return new User(user.getUsername(), user.getEmail(), user.getPassword(), authorities, user.isAccountNonExpired(), user.getAvatar());
}
private List<GrantedAuthority> buildUserAuthority(Set<Authority> userRoles) {
Set<GrantedAuthority> setAuths = new HashSet<GrantedAuthority>();
// add user's authorities
for (Authority userRole : userRoles) {
setAuths.add(new SimpleGrantedAuthority(userRole.getRole()));
}
List<GrantedAuthority> Result = new ArrayList()<GrantedAuthority>(setAuths);
return Result;
}*/
public void add(User user, String role) {
user.setRole(roleService.findByRole(role));
this.userRepository.save(user);
/*role.setAuthorities(authorities);
this.roleRepository.save(role);
for (Authority auth : authorities) {
auth.setRoles(role);
this.authorityRepository.save(auth);
}*/
}
public void update(User user) {
this.userRepository.save(user);
}
public String getCurrentUser() {
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
String username;
if (principal instanceof UserDetails) {
username = ((User)principal).getUsername();
} else {
username = principal.toString();
}
return username;
}
}
User
import java.time.LocalDate;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinTable;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
#Entity
#Table(name="users")
public class User implements UserDetails {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name = "id")
private long id;
#Column(name = "users_username", nullable = false, unique = true)
private String username;
#Column(name = "users_email", nullable = false, unique = true)
private String email;
#Column(name = "users_password")
private String password;
#Column(name = "users_enabled")
private boolean enabled;
#Column(name = "users_avatar")
private String avatar;
#Column(name = "users_date")
private LocalDate date;
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
//#JoinTable(name = "authorities", joinColumns = #JoinColumn(name = "users_username"), inverseJoinColumns = #JoinColumn(name = "roles_username"))
private Role role;
public User() {
}
public User(String username, String email, String password, boolean enabled, String avatar) {
this.username = username;
this.email = email;
this.password = password;
this.enabled = enabled;
this.avatar = avatar;
}
public User(String username, String email, String password, Role role, boolean enabled, String avatar) {
this.username = username;
this.email = email;
this.password = password;
this.role = role;
this.enabled = enabled;
this.avatar = avatar;
}
public Collection<? extends GrantedAuthority> getAuthorities() {
Set<Authority> authorities = new HashSet<Authority>();
authorities = role.getAuthorities();
return authorities;
}
public void setName(String username) {
this.username = username;
}
public String getUsername() {
return username;
}
public boolean isEnabled() {
return enabled;
}
public boolean isAccountNonExpired() {
return false;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public boolean isAccountNonLocked() {
// TODO Auto-generated method stub
return false;
}
public boolean isCredentialsNonExpired() {
// TODO Auto-generated method stub
return false;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getAvatar() {
return avatar;
}
public void setAvatar(String avatar) {
this.avatar = avatar;
}
public Role getRole() {
return role;
}
public void setRole(Role role) {
this.role = role;
}
public String getRoleRole() {
return role.getRole();
}
}
EDIT : I'm using SPRING BOOT and Hibernate
I have data model like below
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorType;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Table;
import org.hibernate.annotations.DiscriminatorOptions;
#SuppressWarnings("deprecation")
#Entity
#Table
#Inheritance(strategy = InheritanceType.JOINED)
#DiscriminatorColumn(name="DTYPE", discriminatorType=DiscriminatorType.INTEGER)
#DiscriminatorValue("0")
#DiscriminatorOptions(force=true)
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
public Employee() {
}
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "EMPLOYEE_ID")
private int empID;
private String firstName;
private String lastName;
private Integer age;
private String email;
private String city;
private String phNum;
public String getPhNum() {
return phNum;
}
public void setPhNum(String phNum) {
this.phNum = phNum;
}
public int getEmpID() {
return empID;
}
public void setEmpID(int empID) {
this.empID = empID;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
}
Patient.java
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.OneToMany;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.Table;
import org.hibernate.annotations.DiscriminatorOptions;
import org.hibernate.validator.constraints.NotEmpty;
#SuppressWarnings("deprecation")
#Entity
#Table
#PrimaryKeyJoinColumn(name = "EMPLOYEE_ID")
#DiscriminatorValue("6")
public class Patient extends Employee {
private static final long serialVersionUID = 1L;
#NotEmpty(message = "DOJ cannot be null")
private String doj;
private String primaryDoctor;
public String getPrimaryDoctor() {
return primaryDoctor;
}
public void setPrimaryDoctor(String primaryDoctor) {
this.primaryDoctor = primaryDoctor;
}
public String getDoj() {
return doj;
}
public void setDoj(String doj) {
this.doj = doj;
}
#OneToMany(cascade = CascadeType.ALL, mappedBy = "patient", fetch = FetchType.LAZY)
private List<Encounter> encounterList;
public List<Encounter> getEncounterList() {
return encounterList;
}
public void setEncounterList(List<Encounter> encounterList) {
this.encounterList = encounterList;
}
}
Hibernate query at runtime
select useraccoun0_.empID as empID1_13_2_, useraccoun0_.EMPLOYEE_ID as EMPLOYEE6_13_2_,
useraccoun0_.fullName as fullName2_13_2_, useraccoun0_.password as password3_13_2_,
useraccoun0_.role as role4_13_2_, useraccoun0_.userName as userName5_13_2_,
employee1_.EMPLOYEE_ID as EMPLOYEE2_2_0_, employee1_.age as age3_2_0_,
employee1_.city as city4_2_0_, employee1_.email as email5_2_0_, employee1_.firstName as firstNam6_2_0_,
employee1_.lastName as lastName7_2_0_, employee1_.phNum as phNum8_2_0_, employee1_4_.doj as doj1_11_0_,
employee1_4_.primaryDoctor as primaryD2_11_0_, employee1_5_.specialization as speciali1_0_0_,
employee1_.DTYPE as DTYPE1_2_0_, encounterl2_.EMPLOYEE_ID as EMPLOYEE4_3_4_,
encounterl2_.EID as EID1_3_4_, encounterl2_.EID as EID1_3_1_, encounterl2_.labTest_testID as labTest_2_3_1_,
encounterl2_.medication_mid as medicati3_3_1_, encounterl2_.EMPLOYEE_ID as EMPLOYEE4_3_1_,
encounterl2_.vitalSign_EID as vitalSig5_3_1_ from UserAccount useraccoun0_
left outer join Employee employee1_ on useraccoun0_.EMPLOYEE_ID=employee1_.EMPLOYEE_ID
left outer join Pharmacist employee1_1_ on employee1_.EMPLOYEE_ID=employee1_1_.EMPLOYEE_ID
left outer join Nurse employee1_2_ on employee1_.EMPLOYEE_ID=employee1_2_.EMPLOYEE_ID
left outer join LabAssistant employee1_3_ on employee1_.EMPLOYEE_ID=employee1_3_.EMPLOYEE_ID
left outer join Patient employee1_4_ on employee1_.EMPLOYEE_ID=employee1_4_.EMPLOYEE_ID
left outer join Doctor employee1_5_ on employee1_.EMPLOYEE_ID=employee1_5_.EMPLOYEE_ID
left outer join Encounter encounterl2_ on employee1_.EMPLOYEE_ID=encounterl2_.EMPLOYEE_ID
where useraccoun0_.empID=4
In this query Discriminator column(DTYPE) is coming and its value is coming as 6. But it is giving me below exception
org.hibernate.WrongClassException: Object [id=null] was not of the specified subclass [com.*.*.Employee]: the class of the given object did not match the class of persistent copy
So not sure why it is giving me this exception and why id is coming as null.
User.java
package com.spring.demo.model;
import java.util.Date;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.Lob;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.Transient;
#Entity
#Table(name="user")
public class User {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="user_id")
private int id;
private String fName;
private String lName;
#Column(unique=true,nullable=true)
private String email;
#Column(unique=true,nullable=true)
private long mobile;
private Date dob;
#Lob
private byte[] image;
#Transient
private String base64Image;
#OneToOne(cascade=CascadeType.ALL,fetch =FetchType.EAGER)
#JoinColumn(name="userCredential_id")
private UserCredential userCredential;
#OneToOne(cascade=CascadeType.ALL,fetch =FetchType.EAGER)
#JoinColumn(name="add_id")
private Address address;
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getfName() {
return fName;
}
public void setfName(String fName) {
this.fName = fName;
}
public String getlName() {
return lName;
}
public void setlName(String lName) {
this.lName = lName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public long getMobile() {
return mobile;
}
public void setMobile(long mobile) {
this.mobile = mobile;
}
public Date getDob() {
return dob;
}
public void setDob(Date dob) {
this.dob = dob;
}
public byte[] getImage() {
return image;
}
public void setImage(byte[] image) {
this.image = image;
}
public UserCredential getUserCredential() {
return userCredential;
}
public void setUserCredential(UserCredential userCredential) {
this.userCredential = userCredential;
}
}
UserCredential.java
package com.spring.demo.model;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import com.fasterxml.jackson.annotation.JsonIgnore;
#Entity
#Table(name="usercredential")
public class UserCredential {
#Id
#Column(name="credential_id")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
#Column(unique=true,nullable=true)
private String username;
private String password;
private String cnfrmpassword;
#JsonIgnore
#OneToOne(cascade=CascadeType.ALL,fetch =FetchType.EAGER)
#JoinColumn(name="user_id",nullable=true)
private User user;
public UserCredential() {
super();
// TODO Auto-generated constructor stub
}
public UserCredential(int id, String username, String password, String cnfrmpassword, User user) {
super();
this.id = id;
this.username = username;
this.password = password;
this.cnfrmpassword = cnfrmpassword;
this.user = user;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getCnfrmpassword() {
return cnfrmpassword;
}
public void setCnfrmpassword(String cnfrmpassword) {
this.cnfrmpassword = cnfrmpassword;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
Address.java
package com.spring.demo.model;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import com.fasterxml.jackson.annotation.JsonIgnore;
#Entity
#Table(name="address")
public class Address {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="add_id")
private int id;
#Column(name="city")
private String city;
#Column(name="state")
private String state;
#Column(name="house_no")
private String h_no;
#JsonIgnore
#OneToOne(cascade=CascadeType.ALL,fetch =FetchType.EAGER)
#JoinColumn(name="user_id", nullable=true)
private User user;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getH_no() {
return h_no;
}
public void setH_no(String h_no) {
this.h_no = h_no;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
Here we have user as a parent table and (usercredential and address) are child classes in a relationship. When I insert data into tables then every primary key automatically incremented and get the appropriate value while the foreign key (user_id) always remains zero.
https://i.stack.imgur.com/Pivlm.jpg
https://i.stack.imgur.com/fAPth.jpg
https://i.stack.imgur.com/l37mr.jpg
My concern is user_id(foreign key) in child tables should not be null and equals to primary key(user_id) in parent table. Please look for every cascading(delete, update) operation should be implemented well on table.
Further information I am using Json for inserting data into tables.
{
"fName":"sur kumst",
"lName":"adfdf",
"mobile":45106,
"email":"ksusjasd1sd#gmail.com",
"dob":"2012-04-23T18:25:43.511Z",
"address":{
"city":"noida",
"state":"up",
"h_no":"1243"
},
"userCredential":{
"username":"kr0302",
"password":"12345",
"cnfrmpassword":"12345"
}
}
The issue is with the back reference. Hibernate cannot maintain this for you. Say you save your user object. it creates a credential row and generates id. it creates address and id. it updates the cred_id and add_id on the user object and then creates a row for it and generates id and returns that value. at this point you need to add your user object to credential and address and save those again.
It seems you are trying to model two bidirectional relationships:
User <-> UserCredentials and:
User <-> UserAddress.
But what you are really creating the following four relationships:
User -> UserCredentials
User <- UserCredentials
User -> UserAddress
User <- UserAddress
In order to fix this you need to use mappedBy. See this question for reference.
-
I am trying to create mapped cart entity.but shows 404 error associated with Injection of autowired dependencies failed
Check my source and help me ro solve it..
Mapping plan:
Customer-----one to one------>Cart--------onetomany--->Product
Customer
package com.model;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import org.hibernate.validator.constraints.NotEmpty;
#Entity
public class Customer {
#Id #GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="Cid")
private int customerId;
#Column(name="password")
#NotEmpty(message="Name is mandatory")
private String password;
#Column(name="Email")
#NotEmpty(message="Name is mandatory")
private String email;
#NotEmpty(message="First Name is mandatory")
#Column(name="firstname")
private String firstName;
#NotEmpty(message="Last Name is mandatory")
#Column(name="lastname")
private String lastName;
#Column(name="Mobile")
#Size(min = 10)
#NotEmpty(message="Mobile is mandatory")
private String mobile;
#ManyToOne(cascade=CascadeType.ALL)
#JoinColumn(name="address_id")
private Address delAdderss;
private boolean enabled;
private String role;
#OneToOne(cascade=CascadeType.ALL)
#JoinColumn(name="cart_id")
private Cart cart;
public int getCustomerId() {
return customerId;
}
public void setCustomerId(int customerId) {
this.customerId = customerId;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
public Address getDelAdderss() {
return delAdderss;
}
public void setDelAdderss(Address delAdderss) {
this.delAdderss = delAdderss;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
public Cart getCart() {
return cart;
}
public void setCart(Cart cart) {
this.cart = cart;
}
}
Cart
package com.model;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
#Entity
public class Cart {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int cart_id;
#Column
private double total;
#OneToOne(cascade=CascadeType.ALL)
#JoinColumn(name="CID")
private Customer customer;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name="id")
private List<Product> product;
public int getCart_id() {
return cart_id;
}
public void setCart_id(int cart_id) {
this.cart_id = cart_id;
}
public double getTotal() {
return total;
}
public void setTotal(double total) {
this.total = total;
}
public List<Product> getProduct() {
return product;
}
public void setProduct(List<Product> product) {
this.product = product;
}
}
Product
package com.model;
import java.util.Date;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.Transient;
import org.springframework.web.multipart.MultipartFile;
#Entity
public class Product {
#Id #GeneratedValue(strategy=GenerationType.AUTO)
private int id;
#Column
private String product_Name;
#Column
private String descripction;
#Column
private int price;
#Column
private Date mfg_Date;
#Transient
private MultipartFile image;
#ManyToOne(cascade = CascadeType.ALL)
private List<Cart> cart;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getProduct_Name() {
return product_Name;
}
public void setProduct_Name(String product_Name) {
this.product_Name = product_Name;
}
public String getDescripction() {
return descripction;
}
public void setDescripction(String descripction) {
this.descripction = descripction;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public Date getMfg_Date() {
return mfg_Date;
}
public void setMfg_Date(Date mfg_Date) {
this.mfg_Date = mfg_Date;
}
public MultipartFile getImage() {
return image;
}
public void setImage(MultipartFile image) {
this.image = image;
}
public List<Cart> getCarts() {
return cart;
}
public void setCarts(List<Cart> carts) {
this.cart= carts;
}
}