How to solve HHH000346 Error using hibernate 5 and mysql? - mysql

I'm studying restful service and views.
Regarding it, I use mysql and hibernate 5.
My data tables are two and have reference relation.
The problem occurs when I update the primary key.
When I add new one then update existing data in another table (they have reference relation), HHH000346: Error during managed flush occurs.
I already search on google, but I couldn't find the answer.
This is my Entity classes.
#Entity
#Table(name = "users")
#EntityListeners(AuditingEntityListener.class)
public class User {
private long serial;
private String username;
private String password;
public User() {
}
public User(long serial, String username, String password) {
setSerial(serial);
setUsername(username);
setPassword(password);
}
#Column(name = "serial", nullable = false)
#GeneratedValue(strategy = GenerationType.AUTO)
public long getSerial() {
return serial;
}
public void setSerial(long serial) {
this.serial = serial;
}
#Id
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
#Column(name = "password", nullable = false)
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
#Override
public String toString() {
return "serial: " + this.serial + ", username: " + this.username + ", password: " + this.password;
}
}
Entity
#Table(name = "sites")
#EntityListeners(AuditingEntityListener.class)
#IdClass(Site.class)
public class Site implements Serializable{
#ManyToOne
#JoinColumn(name="username",foreignKey=#ForeignKey(name="username"))
private String username;
private String siteURL;
#Id
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
#Id
public String getSiteURL() {
return siteURL;
}
public void setSiteURL(String siteName) {
this.siteURL = siteName;
}
}
And this is class had problem.
public class UserController {
#Autowired
private UserRepository userRepository;
#Autowired
private SiteRepository siteRepository;
private CryptoUtil passwordEncoder = new CryptoUtil();
...
#PutMapping("/users/{username}")
public User updateUser(#PathVariable(value = "username") String username, #Valid #RequestBody User userDetails)
throws ResourceNotFoundException {
User user = userRepository.findById(username)
.orElseThrow(() -> new ResourceNotFoundException("User not found on :: " + username));
List<Site> sites = siteRepository.findByUsername(user.getUsername());
userDetails.setPassword(passwordEncoder.encryptSHA256(userDetails.getPassword()));
final User updateUser = userRepository.save(userDetails);
for (Site site : sites)
{
site.setUsername(userDetails.getUsername());
site = siteRepository.save(site);
}
userRepository.delete(user);
return updateUser;
}
....
}
The for-each statement occurs error.
PLEASE HELP ME

Why did you do this?
#ManyToOne
#JoinColumn(name="username",foreignKey=#ForeignKey(name="username"))
private String username;
It should be:
#ManyToOne
#JoinColumn(name="username",foreignKey=#ForeignKey(name="username"))
private User user;
I'll also suggest you to use the primary key as foreign key.
And you can't have multiple #Id in an entity.

Related

Spring Boot: How to retrieve the username by user_id?

I have already connected my springboot to MySQL database. I want to display the username when user_id is specified in the HTTP request. e.g. http://8080/user/1 must display the name of the user with user_id 1.
The table contains attributes as:
| Integer user_id; | String username; | String fathername; | String mothername;
I have already tried this code in by Controller class but i does not seem to be working
#RequestMapping("/{userid}")
#ResponseBody
public String getById(Integer userid) {
String name="";
try {
Optional<Persondetails> persondetails=persondetailsRepository.findById(personid);
name = String.valueOf(userdetails.getName());
}
catch (Exception ex) {
return "Name not found";
}
return "The Name of the user is : " + name;
}
my repository code:
import java.util.List;
import java.util.Optional;
public interface UserdetailsRepository extends JpaRepository<Userdetails, Integer> {
public Optional<Userdetails> findById(Integer userid);
}
It says getName() is undefined for the type Optional
But i have defined it in Userdetails class
public class Userdetails {
#Id
#GeneratedValue
#Column(name="user_id")
private Integer userid;
#Column(name="name")
private String name;
#Column (name="fathers_name")
private String fathersname;
#Column(name="mothers_name")
private String mothersname;
public Userdetails() {
}
public Integer getUserid() {
return userid;
}
public void setUserid(Integer userid) {
this.userid = userid;
}
public String getName() {
return name;
}
public void setname(String name) {
this.name = name;
}
public String getFathersname() {
return fathersname;
}
public void setFathersname(String fathersname) {
this.fathersname = fathersname;
}
public void setMothersname(String mothersname) {
this.mothersname = mothersname;
}
public String getMothersname() {
return mothersname;
}
}
It's missing the method type GET, you can do by two options:
#RequestMapping(value = "/{id}", method = RequestMethod.GET)
public User findOne(#PathVariable("id") int id){
return userService.findById(id);
}
OR
#GetMapping("/{id}")
public String getString(#PathVariable("id") int id) {
return "Helloworld";
}
Spring boot Connect with Mysql and get Data.
application.properties
server.contextPath=/demo-user
spring.datasource.url=jdbc:mysql://localhost:3306/testdb
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
*Controller.Java
#RequestMapping({"/users"})
public class UserController {
#Autowired
private UserService userService;
#GetMapping(path = {"/{id}"})
public User findOne(#PathVariable("id") int id){
return userService.findById(id);
}
}
UserService.java
public interface UserService {
User findById(int id);
}
UserServiceImpl.java
#Service
public class UserServiceImpl implements UserService {
#Autowired
private UserRepository repository;
#Override
public User findById(int id) {
return repository.findOne(id);
}
}
UserRepository .java
public interface UserRepository extends Repository<User, Integer> {
User findOne(int id);
}
User.java
#Entity
#Table(name = "user")
public class User {
#Id
#Column
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column
private String firstName;
#Column
private String lastName;
#Column
private String email;
//setter and getter
}
Make request from browser or application.
http://localhost:8080/demo-user/users/1

Spring Boot: Saving a one to many json request, foreign key is not saved automatically

I have 2 entities, Role and Resource. A role can have many resources.
#Entity
public class Resource {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#Column(name="firstname")
private String firstName;
#Column(name="lastname")
private String lastName;
private String email;
#ManyToOne
#JoinColumn(name="roleId", nullable = false)
private Role role;
public int getId() {
return id;
}
public void setId(int 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 String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Role getRole() {
return role;
}
public void setRole(Role role) {
this.role = role;
}
}
#Entity
public class Role {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#Column(name = "rolename")
private String roleName;
#OneToMany(mappedBy = "role", cascade = CascadeType.ALL)
private List<Resource> resources;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public List<Resource> getResources() {
return resources;
}
public void setResources(List<Resource> resources) {
this.resources = resources;
}
}
I'm trying to save a Role object that has a resource in it. This is the body of my json in postman.
{
"roleName" : "Business Analyst",
"resources" : [{
"firstName" : "John",
"lastName" : "Doe",
"email" : "John#Doe.com"
}]
}
http post call in postman:
http://localhost:8080/app/admin/roles/role
Role Controller
#RestController
#RequestMapping(value="/admin/roles")
public class RoleController {
#Autowired
private RoleService roleService;
private static final Logger log = LoggerFactory.getLogger(RoleController.class);
#RequestMapping(value="/role", method = RequestMethod.POST)
public ResponseEntity<?> addRole(#RequestBody Role role, UriComponentsBuilder ucBuilder){
log.info("Adding Role {}" + role);
log.info("Adding Rolename:" + role.getRoleName());
roleService.addRole(role);
HttpHeaders headers = new HttpHeaders();
headers.setLocation(ucBuilder.path("/admin/roles/role/{id}").buildAndExpand(role.getId()).toUri());
return new ResponseEntity<String> (headers,HttpStatus.CREATED);
}
#RequestMapping(value="role", method = RequestMethod.GET)
public ResponseEntity<List<Role>> listAllRoles(){
List<Role> roles = roleService.getAllRoles();
return new ResponseEntity<List<Role>>(roles, HttpStatus.OK);
}
}
RoleRepository
public interface RoleRepository extends CrudRepository<Role, Integer> {
}
RoleService
public interface RoleService {
public void addRole(Role role);
}
RoleServiceImpl
#Service
public class RoleServiceImpl implements RoleService {
#Autowired
private RoleRepository roleRepository;
#Override
public void addRole(Role role) {
roleRepository.save(role);
}
}
Whats happening is, the role Business Analyst gets save in the roleName field of Role table. The id of the said row is auto generated. At the same time, the resource with firstName = John, lastName = Doe and email = John#Doe.com gets save in the Resource table.
However, the role_id is not being saved automatically in the Resource table so now it is null ( the table Resource has the role_id set to nullable ). I was expecting that when I do the json post, the data will be automatically saved in the Role table and also the Resource table. Both of these are happening except that the role_id is not being saved. What did I miss?
Change addRole like below :
public void addRole(Role role) {
for(Resource resource: role.getResources()){
resource.setRole(role);
}
roleRepository.save(role);
}

Output registered users as Json in spring mvc

I have a simple form for registration with generated id and then title, username and password. Once user is registered I want to go to Json page and be able to pull that data in there, is that even possible? if so how is it done? This is what I have at the moment but that doesn't work.
Model:
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String title;
#NotNull
#Size(min=2, max=30)
private String username;
#NotNull
#Size(min=6)
private String password;
public String getTitle() { return title; }
public String getUsername() { return username; }
public String getPassword() { return password; }
public Long getId() { return id; }
public void setId(Long id) {
this.id = id;
}
public void setUsername(String username) { this.username = username; }
public void setPassword(String password) { this.password = password; }
public void setTitle(String title) { this.title = title; }
public List<Note> getNotes() {
return notes;
}
#OneToMany
private List<Note> notes = new ArrayList<Note>();
}
Controller:
#RequestMapping(value = "/json", method = RequestMethod.GET)
#ResponseBody
public User json(){
User user = new User();
user.setId(id);
user.setTitle(title);
user.setUsername(username);
user.setPassword(password);
return user;
}
}

Dropwizard Hibernate Configuration

I am new to Dropwizard and so far everything was going well till I started messing with Hibernate and MySQL. My problem is: Hibernate won't create tables and consequently no columns in my DB.
The only warning I get when running my jar file is:
org.hibernate.cfg.environment hibernate.properties not found
But do I need it at all? As I am having all configuration and mapping already.
Here is my application class:
public class LibraryApplication extends Application<LibraryConfiguration> {
public static void main(String[] args) throws Exception {
new LibraryApplication().run(args);
}
#Override
public String getName() {
return "hello backend";
}
private final HibernateBundle<LibraryConfiguration> hibernate = new HibernateBundle<LibraryConfiguration>(Book.class){ //more entities can be added separated with a coma
public DataSourceFactory getDataSourceFactory(LibraryConfiguration configuration) {
return configuration.getDataSourceFactory();
}
};
#Override
public void initialize(Bootstrap<LibraryConfiguration> bootstrap) {
bootstrap.addBundle(new AssetsBundle("/webapp", "/", "index.html", "static"));
bootstrap.addBundle(hibernate);
}
#Override
public void run(LibraryConfiguration configuration,
Environment environment) {
final BookDAO dao = new BookDAO(hibernate.getSessionFactory());
final TestResource resource = new TestResource(
configuration.getTemplate(), configuration.getDefaultName());
final TemplateHealthCheck healthCheck = new TemplateHealthCheck(
configuration.getTemplate());
environment.healthChecks().register("template", healthCheck); //register the health check
environment.jersey().register(resource); //register the resource class
environment.jersey().register(new BookResource(dao));
}
}
YAML file:
server:
type: simple
rootPath: '/api/*'
applicationContextPath: /
connector:
type: http
port: 8080
template: Hello, %s!
defaultName: back-end
database:
# the name of your JDBC driver
driverClass: com.mysql.jdbc.Driver
# the JDBC URL
url: jdbc:mysql://localhost:3306/books
# the username
user: root
# the password
password: root
# any properties specific to your JDBC driver:
properties:
charSet: UTF-8
hibernate.dialect: org.hibernate.dialect.MySQLDialect #org.hibernate.dialect.MySQL5InnoDBDialect
hibernate.hbm2ddl.auto: create
Configurtion class:
public class LibraryConfiguration extends Configuration{
#Valid
#NotNull
#JsonProperty
private DataSourceFactory database = new DataSourceFactory();
#JsonProperty("database")
public DataSourceFactory getDataSourceFactory() {
return database;
}
#NotEmpty
private String template;
#NotEmpty
private String defaultName = "";
#JsonProperty
public String getTemplate() {
return template;
}
#JsonProperty
public void setTemplate(String template) {
this.template = template;
}
#JsonProperty
public String getDefaultName() {
return defaultName;
}
#JsonProperty
public void setDefaultName(String name) {
this.defaultName = name;
}
}
and my entity:
#Entity
#Table(name = "book")
#NamedQueries({
#NamedQuery(
name = "library.core.Book.findAll",
query = "SELECT b FROM book b"
)
})
public class Book{
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column
private Long id;
#Column(name = "title")
#NotNull
private String title;
#Column(name = "author")
#NotNull
private String author;
#Column(name = "date")
private long date;
#Column(name = "description")
private String description;
#Column(name = "image")
private String image;
public Book(String title, String author){
this.title = title;
this.author = author;
}
#JsonProperty
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
#JsonProperty
public Long getId() {
return id;
}
#JsonProperty
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
#JsonProperty
public long getDate() {
return date;
}
public void setDate(long date) {
this.date = date;
}
#JsonProperty
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
#JsonProperty
public String getImage() {
return image;
}
public void setImage(String image) {
this.image = image;
}
public void setId(Long id) {
this.id = id;
}
}
I have already been to many tutorials but none of them really explains how to configure hibernate. Thank you in advance.
I have finally solved this problem, which was not a big deal actually. Just a small mistake as it was expected.
My problem was a Book class, IDE automatically imported the java library called Book in the LibraryApplication class, so DB was not mapping it.
On the other hand, in the Book class the named query should be as follows:
#NamedQuery(
name = "library.core.Book.findAll",
query = "SELECT b FROM Book b"
)
My mistake: I was writing Book with small letter.

ResponseBody get object list from object. #JsonIgnore not working

Ok i have class User
#Entity
#Table(name = "users")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
private Long id_user;
#Column(nullable = false)
private String email;
#Column(nullable = true)
private String password;
private String firstname;
private String lastname;
private Boolean enabled;
private String phone;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id_company")
private Company company;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id_rank")
#JsonBackReference
private Authority authorities;
#OneToMany(mappedBy = "create_by")
private List<Cms> create_by;
#OneToMany(mappedBy = "modified_by")
private List<Cms> modified_by;
#OneToMany(mappedBy = "id_issuer")
private List<Ticket> id_issuer;
#OneToMany(mappedBy = "id_responsible")
private List<Ticket> id_responsible;
#OneToMany(mappedBy = "id_author")
private List<IssueMsg> id_author;
public User() {
}
public User(String email, String password, String firstname, String lastname, String phone, Company company, Authority authority) {
this.email = email;
this.password = password;
this.firstname = firstname;
this.lastname = lastname;
this.enabled = true;
this.phone = phone;
this.authorities = authority;
}
#Override
public String toString() {
return "User [id_user=" + id_user + ", email=" + email + ", password="
+ password + ", firstname=" + firstname + ", lastname="
+ lastname + ", enabled=" + enabled + ", phone=" + phone
+ "]";
}
public Long getId_user() {
return id_user;
}
public void setId_user(Long id_user) {
this.id_user = id_user;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
#JsonIgnore
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
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 Boolean getEnabled() {
return enabled;
}
public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public Company getCompany() {
return company;
}
public void setCompany(Company company) {
this.company = company;
}
/**
* #return the authorities
*/
public Authority getAuthorities() {
return authorities;
}
/**
* #param authorities the authorities to set
*/
public void setAuthorities(Authority authority) {
this.authorities = authority;
}
#JsonIgnore
public List<Cms> getCreate_by() {
return create_by;
}
public void setCreate_by(List<Cms> create_by) {
this.create_by = create_by;
}
#JsonIgnore
public List<Cms> getModified_by() {
return modified_by;
}
public void setModified_by(List<Cms> modified_by) {
this.modified_by = modified_by;
}
#JsonIgnore
public List<Ticket> getId_issuer() {
return id_issuer;
}
public void setId_issuer(List<Ticket> id_issuer) {
this.id_issuer = id_issuer;
}
#JsonIgnore
public List<Ticket> getId_responsible() {
return id_responsible;
}
public void setId_responsible(List<Ticket> id_responsible) {
this.id_responsible = id_responsible;
}
#JsonIgnore
public List<IssueMsg> getId_author() {
return id_author;
}
public void setId_author(List<IssueMsg> id_author) {
this.id_author = id_author;
}
}
And class Company
#Entity
#Table(name = "companies")
public class Company implements Serializable {
private static final long serialVersionUID = 6255059577246367312L;
#Id
#GeneratedValue
private Long id_company;
private String name;
private String adress;
private String email;
private String phone;
#OneToMany(mappedBy = "company")
#JsonManagedReference
private List<User> user;
#Override
public String toString() {
return "Company [id_company=" + id_company + ", name=" + name
+ ", adress=" + adress + ", email=" + email + ", phone="
+ phone + "]";
}
public Company() {
}
public Company(Long id_company, String name, String adress, String email,
String phone) {
this.id_company = id_company;
this.name = name;
this.adress = adress;
this.email = email;
this.phone = phone;
}
public Long getId_company() {
return id_company;
}
public void setId_company(Long id_company) {
this.id_company = id_company;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAdress() {
return adress;
}
public void setAdress(String adress) {
this.adress = adress;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public List<User> getUser() {
return user;
}
public void setUser(List<User> user) {
this.user = user;
}
}
I getting all result from database, and returning this as response body.
My JSON response get user.company.user list and i don't need what. I was try add on getter company user #JsonIgnore but i getting error
com.fasterxml.jackson.databind.JsonMappingException: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: java.util.ArrayList[1]->projektzespolowy.model.User["company"]->projektzespolowy.model.Company_$$_jvstcb8_2["handler"])
I read many post about fix thix but no one help. This is possible to ignore this user list in company?
I think you are getting this exception because User#company is lazy fetched so jackson tries to serialize a hibernate proxy. Try with fetch = FetchType.EAGER on the mapping, or call user.getCompany() in the controller prior to returning the results.