i am new to spring boot, having basic knowledge of java. i am trying to build a micro-service to retrieve data from mySQL database. below are the code details.
i am able to retrieve data from the same table using standalone JDBC class. request to help.
- Entity class
package com.studentProject.entity;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import org.springframework.stereotype.Component;
#Entity
#Component
#Table(name="students", schema="test_schema")
public class StudentEntity implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
#Column(name="id")
private Integer id;
#Column(name="name")
private String name;
#Column(name="course")
private String course;
#Column(name="country")
private String country;
#Column(name="phone")
private String phone;
public StudentEntity(Integer id, String name, String course, String country, String phone) {
super();
this.id = id;
this.name = name;
this.course = course;
this.country = country;
this.phone = phone;
}
public StudentEntity() {
super();
// TODO Auto-generated constructor stub
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCourse() {
return course;
}
public void setCourse(String course) {
this.course = course;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
-Repository Class
package com.studentProject.repository;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import com.studentProject.entity.StudentEntity;
#Repository
public interface StudentRepository extends CrudRepository<StudentEntity, Integer> {
StudentEntity findByName(String name);
StudentEntity findByCourse(String course);
}
-Controller class
package com.studentProject.controller;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.studentProject.entity.StudentEntity;
import com.studentProject.repository.StudentRepository;
#RestController
public class StudentController {
#Autowired
private StudentRepository studentRepository;
#Autowired
List<StudentEntity> studentList;
public StudentController(StudentRepository studentRepository, StudentEntity studentEntity,
List<StudentEntity> studentList) {
super();
this.studentRepository = studentRepository;
this.studentList = studentList;
}
#GetMapping("/getStudentDetails")
public Iterable<StudentEntity> getAllStudents(){
return studentRepository.findAll();
}
#GetMapping("/getStudentDetails/getByName")
public StudentEntity findByName(#RequestParam(value="name") String name) {
return studentRepository.findByName(name);
}
#GetMapping("/getStudentDetails/getById/{id}")
public Optional<StudentEntity> findById(#PathVariable(value="id") Integer id) {
return studentRepository.findById(id);
}
#GetMapping("/getStudentDetails/welcome")
public String welcome() {
return "hi brother welcome";
}
}
-Properties File
server.port = 8080
spring.datasource.driver-class-name = com.mysql.cj.jdbc.Driver
spring.datasource.url = jdbc:mysql://localhost:3306/
spring.datasource.username = root
spring.datasource.password = root
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
spring.data.jpa.repositories.enabled=true
spring.jpa.show-sql = true
spring.jpa.hibernate.ddl-auto = none
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
--Pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.StudentProject</groupId>
<artifactId>StudentProject-1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>StudentProject-1</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
-main application
package com.studentProject;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class StudentProject1Application {
public static void main(String[] args) {
SpringApplication.run(StudentProject1Application.class, args);
}
}
-mysql table details
schema=test_schema and table=students
error details
From the error log
Caused by: java.sql.SQLException: No database selected
it is clear that spring is not able to find database so select database by following below.
change the spring.datasource.url value to below by adding database name.
spring.datasource.url = jdbc:mysql://localhost:3306/test_schema
Caused by: java.sql.SQLException: No database selected at
This tells that you must select the database name, so you must add it in your config. I saw you already got an answer!
spring.datasource.url = jdbc:mysql://localhost:3306/YOUR_DB_SCHEMA
Related
I am trying to build a basic CRUD application in Spring Boot.
Made a Model class as below :
Employee.java
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
#Entity
public class Employee implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(nullable = false, updatable = false)
private Long id;
private String name;
private String email;
private String jobTitle;
private String phone;
private String imageUrl;
#Column(nullable = false, updatable = false)
private String employeeCode;
public Employee() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getJobTitle() {
return jobTitle;
}
public void setJobTitle(String jobTitle) {
this.jobTitle = jobTitle;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getImageUrl() {
return imageUrl;
}
public void setImageUrl(String imageUrl) {
this.imageUrl = imageUrl;
}
public String getEmployeeCode() {
return employeeCode;
}
public void setEmployeeCode(String employeeCode) {
this.employeeCode = employeeCode;
}
public Employee(String name, String email, String jobTitle, String phone, String imageUrl, String employeeCode) {
this.name = name;
this.email = email;
this.jobTitle = jobTitle;
this.phone = phone;
this.imageUrl = imageUrl;
this.employeeCode = employeeCode;
}
#Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + ", email=" + email + ", jobTitle=" + jobTitle + ", phone="
+ phone + ", imageUrl=" + imageUrl + ", employeeCode=" + employeeCode + "]";
}
}
This is my application.properties file.
#MYSQL Configuration
spring.datasource.url=jdbc:mysql://localhost:3306/employeemanager
spring.datasource.data-username=myusername
spring.datasource.password=mypassword
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
debug= true
My Pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.sood1</groupId>
<artifactId>EmployeeManager</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>EmployeeManager</name>
<description>Employee Manager App</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Below is the logs for the error.
java.sql.SQLException: Access denied for user ''#'localhost' (using password: YES)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:129) ~[mysql-connector-java-8.0.23.jar:8.0.23]
at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122) ~[mysql-connector-java-8.0.23.jar:8.0.23]
I tried establishing connection in sql command line interface with same credentials and it's working fine.
Can anyone help why this issue is coming up and what's the walk around for this.
Thank you in Advance
There is mistake in your configurations
spring.datasource.data-username=myusername change it to spring.datasource.username=myusername
I am trying to build a simple Spring Boot CRUD application that also has login and signup options with spring boot security. I'm already working with a MySQL database and its working fine to persist the data for my application. I also have the signup working.
I'm having some problems with my Spring Security log-in implementation.
org.springframework.security.authentication.InternalAuthenticationServiceException: PreparedStatementCallback; bad SQL grammar [select username,authority from authorities where username = ?]; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'cheesedb.authorities' doesn't exist
Obviously, I dont have an authorities class. I'm trying to authorize with email and password (I'll put in encryption once I have it working). I have two main models/classes, Cheese and Customer, but for this problem, I think Customer is the only model relevant.
Test2Application.java
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class Test2Application {
public static void main(String[] args) {
SpringApplication.run(Test2Application.class, args);
}
}
SecurityConfig.java
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
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 javax.sql.DataSource;
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
DataSource dataSource;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().dataSource(dataSource)
.usersByUsernameQuery("select email as principal, password as credentials, true from customer where email=?");
}
#Override
protected void configure(HttpSecurity http) throws Exception{
http
.csrf().disable()
.authorizeRequests()
.antMatchers(
// "/cheese/index",
// "/cheese/",
"/**/webjars/**",
"/cheese/signup",
"/cheese/login",
// "/cheese/account",
// "/cheese/add",
// "/cheese/remove",
"/cheese/success").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().loginPage("/cheese/login")
.defaultSuccessUrl("/cheese/account")
.permitAll();
}
}
Customer
package com.example.demo.models;
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;
#Entity
public class Customer {
#NotNull
#Size(min=2, max=25)
private String name;
#GeneratedValue
#Id
private int accountNumber;
#NotNull
#Size(min=2, max=25)
private String password;
#NotNull
#Size(min=2, max=25)
#Email
private String email;
public Customer(String name, String password, String email) {
this.name = name;
this.password = password;
this.email = email;
}
public Customer() {}
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 getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAccountNumber() {
return accountNumber;
}
}
UserController
package com.example.demo.controllers;
import com.example.demo.models.Customer;
import com.example.demo.models.data.CustomerDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
#Controller
#RequestMapping("cheese")
public class UserController {
#Autowired
private CustomerDao customerDao;
#RequestMapping(value = "login")
public String loginPage(Model model) {
model.addAttribute("title", "Login Page");
return "cheese/login";
}
#RequestMapping(value = "account")
public String accountInfo(Model model) {
model.addAttribute("title", "Account Page");
return "cheese/account";
}
#GetMapping("signup")
public String displaySignUpForm(Model model) {
model.addAttribute("title", "Sign Up");
model.addAttribute("customer", new Customer());
return "cheese/signup";
}
#PostMapping(value = "signup")
public String processSignUp(Model model, #ModelAttribute Customer customer, Errors errors) {
if (errors.hasErrors()) {
return "cheese/signup";
}
customerDao.save(customer);
return "cheese/success";
}
}
login.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{fragments/main_layout}">
<head th:replace="fragments :: head"></head>
<body>
<nav th:replace="fragments :: navigation"></nav>
<div th:if="${param.error}">
Invalid username and password.
</div>
<div th:if="${param.logout}">
You have been logged out.
</div>
<div class="mx-auto" style="width: 400px;">
<br>
<h1 th:text="${title}">Log in</h1>
<br>
<br>
<form th:action="#{/cheese/login}" method="post">
<div class="form-group">
<label for="email" class="form-control-label">Email</label> <input
type="text" class="form-control" id="email" name="username" />
</div>
<div class="form-group">
<label for="password" class="form-control-label">Password</label> <input
type="password" class="form-control"
id="password" name="password"/>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</body>
</html>
Pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>test2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>test2</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>webjars-locator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<addResources>true</addResources>
</configuration>
</plugin>
</plugins>
</build>
</project>
I've got configuration like this (using Maven):
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>springbootPlural</groupId>
<artifactId>das-boot</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>das-boot</name>
<url>http://maven.apache.org</url>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
<relativePath/>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.39</version>
</dependency>
</dependencies>
</project>
application.properties:
server.port=0 #(for random port)
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.datasource.url=jdbc:mysql://localhost:3306/mojabaza
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
User.class
package com.test.testowa.model;
import org.springframework.data.jpa.domain.AbstractPersistable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
#Entity
public class User extends AbstractPersistable<Long> {
private String userId;
private String userName;
private String password;
public User() {
}
public User(String userId, String userName, String password) {
this.userId = userId;
this.userName = userName;
this.password = password;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
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;
}
}
UserController.class
package com.test.testowa.controller;
import com.test.testowa.Service.UserService;
import com.test.testowa.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
#RestController
#RequestMapping("/user")
public class UserController {
private UserService userService;
#Autowired
public UserController(UserService userService) {
this.userService = userService;
}
#RequestMapping("/delete/{id}")
public String deleteUser(#PathVariable Long id)
{
return userService.deleteUser(id);
}
#RequestMapping("/add")
public User addUser(User user)
{
return userService.addUser(user);
}
#RequestMapping("/list/{id}")
public User findOne(#PathVariable Long id)
{
return userService.findOne(id);
}
#RequestMapping("/list")
public List<User> userList()
{
return userService.userList();
}
}
UserServiceImpl.class
package com.test.testowa.Service.impl;
import com.test.testowa.Service.UserService;
import com.test.testowa.model.User;
import com.test.testowa.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
#Service
public class UserServiceImpl implements UserService {
private UserRepository userRepository;
#Autowired
public UserServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}
#Override
public List<User> userList() {
return userRepository.findAll();
}
#Override
public User findOne(Long id) {
return userRepository.findOne(id);
}
#Override
public User addUser(User user) {
return userRepository.save(user);
}
#Override
public String deleteUser(Long id) {
userRepository.delete(id);
return "{'message':'User deleted'}";
}
}
UserRepository.class
package com.test.testowa.repository;
import com.test.testowa.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Long> {
}
UserService.class
package com.test.testowa.Service;
import com.test.testowa.model.User;
import java.util.List;
public interface UserService {
List<User> userList();
User findOne(Long id);
User addUser(User user);
String deleteUser(Long id);
}
Hibernate creates table "user" flawlessly, but when I'm inserting some values in Postman e.g POST -> localhost:43441/shipwrecks/add, with application/json header and body:
{
"id2":1,
"name":"name1",
"description":"desc1"
}
And I'm getting: Hibernate: insert into shipwreck (description, id2, name) values (?, ?, ?) in console. When I'm inserting data in mysql manually everything go well. Also GET ->localhost:43563/shipwrecks/list works well. Did I make a mistake in this code? Maybe wrong version of Spring Boot?
You need to specify the POST method for the add method in the Controller. I assume your User object is null and the data that you put in your request body does not reach your service.
I realize a very similar question was asked and closed because it wasn't specific enough and didn't specify outcomes. Closed Off Topic
Problem: JSON being returned from REST controller is empty. Verified data exists and is in the Iterable.
Expected Outcome: A JSON Array containing objects would be returned.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.codeexcursion</groupId>
<organization>
<name>Chris Lynch</name>
</organization>
<version>1.00.000</version>
<artifactId>work-tracking</artifactId>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.10.RELEASE</version>
</parent>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<name>Work Tracking</name>
<inceptionYear>2017</inceptionYear>
<developers>
<developer>
<id />
<name>Chris Lynch</name>
<email>chrislynch42#yahoo.com</email>
<timezone>-4</timezone>
<roles>
<role>Chief cook and bottle washer.</role>
</roles>
</developer>
</developers>
<dependencies>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.10.19</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>1.5.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>1.5.10.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>1.5.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
<version>1.5.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derby</artifactId>
<version>10.13.1.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.codeexcursion.Application</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
Entity
//Package and import Omitted
#Entity
public class Category {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private Long parentId;
private String title;
private String description;
protected Category() {
}
public Category(final String title, String description) {
this(0L, title, description);
}
public Category(Long parentId, final String title, String description) {
if (parentId == null) {
parentId = 0L;
}
if (title == null || title.trim().isEmpty()) {
throw new IllegalArgumentException("Title may not be null or empty.");
}
if (description == null) {
description = "";
}
this.parentId = parentId;
this.title = title;
this.description = description;
}
#Override
public String toString() {
return "id = " + id + "; parentId=" + parentId + "; title=" + title + "; description=" + description;
}
}
Resource
//Package and import Omitted
#Repository
public interface CategoryCRUD extends CrudRepository<Category, Long> {
List<Category> findByTitle(String title);
}
Rest Controller
//Package and import Omitted
#RestController
#RequestMapping("/categories")
public class CategoryController {
#Autowired
private CategoryCRUD categoryCRUD;
#RequestMapping(value = "", method = RequestMethod.GET)
public #ResponseBody Iterable<Category> list() {
System.out.println("findAll");
categoryCRUD.findAll().forEach((category) -> {
System.out.println("category=" + category);
});
return categoryCRUD.findAll();
}
private List<Category> findAll() {
final Iterable<Category> data = categoryCRUD.findAll();
List<Category> returnList = new ArrayList<>();
data.forEach(returnList::add);
return returnList;
}
}
I found an answer that was hinted on the closed post but wasn't detailed. I needed to add getters to my entity. I expected JPA/Spring to automagically add the getters and setters. The below fixed my problem.
Entity
//Package and imports omitted
#Entity
public class Category {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private Long parentId;
private String title;
private String description;
protected Category() {
}
public Category(final String title, String description) {
this(0L, title, description);
}
public Category(Long parentId, final String title, String description) {
if (parentId == null) {
parentId = 0L;
}
if (title == null || title.trim().isEmpty()) {
throw new IllegalArgumentException("Title may not be null or empty.");
}
if (description == null) {
description = "";
}
this.parentId = parentId;
this.title = title;
this.description = description;
}
#Override
public String toString() {
return "id = " + id + "; parentId=" + parentId + "; title=" + title + "; description=" + description;
}
public Long getId() {
return id;
}
public Long getParentId() {
return parentId;
}
public String getTitle() {
return title;
}
public String getDescription() {
return description;
}
}
Better answers are welcome.
In my case, the getters to the fields of the entity were not public.
Making them public fixed the issue for me.
You have to include the lombok dependency in your pom.xml file and you have to setup the lombok jar in the IDE you are using (Can be Intellij or Eclipse). if you want to use the annotations #Data, it automatically generates the getters, setters and toString() method inside a Java Bean or Pojo class.
You can use #Getter, #Setter, #AllArgsConstructor, #NoArgsConstructor javadoc annotation from lombok will generate the getters and setters and constructors for your fields.
Please have a look at this http://www.baeldung.com/intro-to-project-lombok for more information.
Thanks!
I would like to know if anyone else has used hibernate-envers with mysql in a Spring-boot application using the interface CrudRepository and has had trouble deleting entities with collections. I put together an example application with a test that demonstrates the exception that is generated.
The example can be cloned from https://github.com/LindesRoets/test-delete.git
You will need mysql running with a database called test_delete
CREATE DATABASE IF NOT EXISTS `test_delete` DEFAULT CHARACTER SET utf8;
Run the test
mvn test
You should see the following exception:
2015-08-11 21:36:28.725 ERROR 3855 --- [ main] org.hibernate.AssertionFailure : HHH000099: an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session): java.lang.NullPointerException
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 4.926 sec <<< FAILURE! - in com.dcp.test.AuthorRepositoryTest
testAuthorCRUD(com.dcp.test.AuthorRepositoryTest) Time elapsed: 0.163 sec <<< ERROR!
org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction
at org.hibernate.engine.internal.StatefulPersistenceContext.getLoadedCollectionOwnerOrNull(StatefulPersistenceContext.java:756)
at org.hibernate.event.spi.AbstractCollectionEvent.getLoadedOwnerOrNull(AbstractCollectionEvent.java:75)
at org.hibernate.event.spi.InitializeCollectionEvent.<init>(InitializeCollectionEvent.java:36)
at org.hibernate.internal.SessionImpl.initializeCollection(SessionImpl.java:1931)
at org.hibernate.collection.internal.AbstractPersistentCollection$4.doWork(AbstractPersistentCollection.java:558)
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:260)
at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:554)
at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:142)
at org.hibernate.collection.internal.PersistentBag.iterator(PersistentBag.java:294)
at java.util.AbstractCollection.addAll(AbstractCollection.java:343)
at org.hibernate.envers.internal.entities.mapper.relation.AbstractCollectionMapper.mapCollectionChanges(AbstractCollectionMapper.java:162)
at org.hibernate.envers.internal.entities.mapper.relation.AbstractCollectionMapper.mapModifiedFlagsToMapFromEntity(AbstractCollectionMapper.java:212)
at org.hibernate.envers.internal.entities.mapper.MultiPropertyMapper.map(MultiPropertyMapper.java:105)
at org.hibernate.envers.internal.synchronization.work.DelWorkUnit.generateData(DelWorkUnit.java:66)
at org.hibernate.envers.internal.synchronization.work.AbstractAuditWorkUnit.perform(AbstractAuditWorkUnit.java:76)
at org.hibernate.envers.internal.synchronization.AuditProcess.executeInSession(AuditProcess.java:119)
Below is all the source code as it appears in the sample application.
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.test</groupId>
<artifactId>test</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>test-delete</name>
<description></description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.5.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<start-class>com.test.Application</start-class>
<java.version>1.8</java.version>
<spring-boot-version>1.2.5.RELEASE</spring-boot-version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
<configuration>
<includes>
<include>**/*Test*.java</include>
</includes>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.3</version>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>${spring-boot-version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${spring-boot-version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>${spring-boot-version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.35</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-envers</artifactId>
</dependency>
</dependencies>
</project>
application.properties
spring.datasource.url = jdbc:mysql://localhost:3306/test_delete
spring.datasource.username =
spring.datasource.password =
# Specify the DBMS
spring.jpa.database = MYSQL
spring.datasource.driverClassName = com.mysql.jdbc.Driver
# Show or not log for each sql query
spring.jpa.show-sql = true
spring.jpa.hibernate.ddl-auto = create
# Naming strategy
spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
#envers
spring.jpa.properties.org.hibernate.envers.global_with_modified_flag=true
spring.jpa.properties.org.hibernate.envers.store_data_at_delete=true
Application.java
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
BaseEntity.java
#MappedSuperclass
#Audited
public abstract class BaseEntity implements Serializable {
#GeneratedValue(generator = "guid")
#GenericGenerator(name = "guid", strategy = "guid")
#Column(columnDefinition = "CHAR(36)")
#Id
protected String id;
#Temporal(TemporalType.TIMESTAMP)
protected Date dateCreated = new Date();
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Date getDateCreated() {
return dateCreated;
}
public void setDateCreated(Date dateCreated) {
this.dateCreated = dateCreated;
}
private static final long serialVersionUID = -8371628134270930829L;
}
Author.java
#Entity
#Audited
public class Author extends BaseEntity{
private String email;
private String name;
#OneToMany(mappedBy = "author")
private List<Book> books = new ArrayList<>();
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Book> getBooks() {
return books;
}
public void setBooks(List<Book> books) {
this.books = books;
}
}
Book.java
#Entity
#Audited
public class Book extends BaseEntity {
private String title;
private String genre;
#ManyToOne
private Author author;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getGenre() {
return genre;
}
public void setGenre(String genre) {
this.genre = genre;
}
public Author getAuthor() {
return author;
}
public void setAuthor(Author author) {
this.author = author;
}
}
AuthorRepository.java
#Transactional
public interface AuthorRepository extends CrudRepository<Author, String> {
}
AuthorRepositoryTest.java
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
public class AuthorRepositoryTest {
#Autowired
private AuthorRepository authorRepo;
#Test
public void testAuthorCRUD() {
Author author = new Author();
author.setName("Test Name");
author.setEmail("test#mail.com");
Author savedAuthor = authorRepo.save(author);
Assert.assertNotNull(savedAuthor);
authorRepo.delete(savedAuthor);
}
}
If you comment out the #Audited from the entity classes Book, Author and BaseEntity the test pass just fine.
Does anyone know how to make the delete functionality work with envers?
There are two ways that I found through trial and error to make the delete operation work as specified in the problem.
You can either specify the collection to load eagerly
#OneToMany(mappedBy = "author", fetch = FetchType.EAGER)
Or you can cascade the delete operation
#OneToMany(mappedBy = "author", cascade = CascadeType.REMOVE)
This is the minimum configuration that you will need to make the test pass as specified in the problem.
Had the same issue, fixed by doing an explicit join to the relationship in question, also I think it's a common thing to delete child relationships first as well so it might be a thing you will have to do anyways.
I think in the context of envers you have to use repository delete methods to be able to save the revisions on delete.