Spring Boot testing with H2 - Table "OAUTH_ACCESS_TOKEN" not found - spring-boot

I'm thinking I need to setup the db testing environment (e.g. create tables, seed users so that token can be issued with credentials) before I can run tests but not sure how to.
#RunWith(SpringRunner.class)
#WebAppConfiguration
#SpringBootTest(classes = Application.class)
public class UsersControllerTest {
// ...
private MockMvc mockMvc;
#Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac)
.addFilter(springSecurityFilterChain).build();
}
private String obtainAccessToken(String username, String password) throws Exception {
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("client_id", CLIENTID);
params.add("grant_type", CLIENTPASSWORD);
params.add("username", username);
params.add("password", password);
ResultActions result = mockMvc.perform(post("/oauth/token")
.params(params)
.with(httpBasic(CLIENTID, CLIENTPASSWORD))
.accept("application/json;charset=UTF-8"))
.andExpect(status().isOk())
.andExpect(content().contentType("application/json;charset=UTF-8"));
String resultString = result.andReturn().getResponse().getContentAsString();
JacksonJsonParser jsonParser = new JacksonJsonParser();
return jsonParser.parseMap(resultString).get("access_token").toString();
}
#Test
public void givenNoToken_whenGetAllUsers_thenUnauthorized() throws Exception {
mockMvc.perform(
get("/users")
).andExpect(status().isUnauthorized());
}
#Test
public void givenToken_whenGetAllUsers_thenOk() throws Exception {
String accessToken = obtainAccessToken("martyn", "secret");
mockMvc.perform(
get("/users")
.header("Authorization", "Bearer " + accessToken)
).andExpect(status().isOk());
}
// ...
Here is a typical Entity for this app:
#Entity(name = "users")
public class User implements Serializable {
/**
*
*/
private static final long serialVersionUID = -8507204786382662588L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(nullable = false)
private String firstName;
#Column(nullable = false)
private String surname;
#Column(nullable = false, unique = true)
private String email;
#Column(nullable = false, unique = true)
private String username;
#Column(nullable = false)
#JsonIgnore
private String password;
#OneToMany
#JoinColumn(name="user_id") // cascade = CascadeType.ALL, orphanRemoval = true
private List<Fund> funds;
public Long getId() {
return 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;
}
// standard getters and setters
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public List<Fund> getFunds() {
return funds;
}
}
But also, as the error indicates, I'd need to generate these oauth* tables too.
Here is my src/test/resources/application.properties
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
spring.datasource.username=sa
spring.datasource.password=sa
So I guess I want to generate the tables (entities, and oauth*) in the H2 database prior to running tests and populate with a single user(?) but can't seem to figure how this is done in Spring Boot. Or should I not be hitting any database and mocking JDBC altogether? Could someone point me in the correct direction as to how to prepare a test environment here? I'm at a bit of a loss.
UPDATE
Here is how dataSource is configured:
#Configuration
public class JDBCTokenConfig {
#Value("${spring.datasource.url}")
private String datasourceUrl;
#Value("${spring.datasource.username}")
private String dbUsername;
#Value("${spring.datasource.password}")
private String dbPassword;
#Bean
public DataSource dataSource() {
final DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl(datasourceUrl);
dataSource.setUsername(dbUsername);
dataSource.setPassword(dbPassword);
return dataSource;
}
#Bean
public TokenStore tokenStore(DataSource dataSource) {
return new JdbcTokenStore(dataSource);
}
// #Bean
// public TokenStore tokenStore() {
// return new InMemoryTokenStore();
// }
}
pom.xml
<dependencies>
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
...
</dependencies>

I think it is a good thing to reach your in memory database without mocking. Honestly, you will need more time to configure rather than creating the correct schema needed for your database.
Using Spring-boot, it is very easy to configure to test your application:
Declare using spring-boot-starter-jpa
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
Add the in memory DB for your tests
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
Delete your spring.datasource properties in application.properties
Thanks to #SpringBootApplication, the datasource will be automatically configured to connect to your H2 in memory database.
Create the SQL schema
By default, spring-boot-starter-jpa configures automatically the datasource to execute scripts classpath:/schema.sql and if you need also, classpath:/data.sql.
Create a schema.sql in src/test/resources, and create the tables (copy the following content, I think this is what you need: https://github.com/spring-projects/spring-security-oauth/blob/master/spring-security-oauth2/src/test/resources/schema.sql) (I am not sure for this, maybe hibernate creates your schema on his own).
Create your schema in src/test/resources/schema.sql and seed the users in src/test/resources/data.sql
Check also the spring documentation to know how you can configure hibernate :
https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-application-properties.html#data-properties
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#reference
Now I understand, which is everybody, that you need to have your configuration different dependending on your environment. The best to do that is to rely on profiles.
In your situation, you have a prod profile, and a test profile.
Declare the profile and keep your spring.datasource properties in your src/test/resources/application.properties (the easier in your case I think)
I suggest you to read this Configure specific in memory database for testing purpose in Spring, and let me know if you have troubles configuring your environment.
With this, you will need to:
Add an annotation at the top of your Test class #ActiveProfiles('test')
Restore the spring.datasource properties you previously deleted an put them in src/test/resources/application-test.properties
Let me know

Related

Spring security configuration in spring boot not working as expected [duplicate]

This question already has answers here:
Springboot Security hasRole not working
(3 answers)
Closed 1 year ago.
I am using spring security with spring boot. But my spring security configuration is now working as expected.
Note : H2 database is running as a separate database in server mode ( Not in embedded mode ).
Here are my project details :
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
Application.properties
server.port=8085
spring.datasource.url=jdbc:h2:tcp://localhost:9092/mem:testdb
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driverClassName=org.h2.Driver
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
EmployeeeResource.java
#RestController
#RequestMapping("/employee")
#Slf4j
public class EmployeeResource {
#Autowired
EmployeeRepository employeeRepository;
#GetMapping(path = "/greetEmployee", produces = MediaType.TEXT_PLAIN_VALUE)
public String sayHello() {
return "Hello Employee !!!";
}
#GetMapping(path = "/getAllEmployees", produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})
public ResponseEntity<List<Employee>> getAllEmployee() {
List<Employee> employeeList = employeeRepository.findAll();
return new ResponseEntity<>(employeeList, HttpStatus.OK);
}
#GetMapping(path = "/getEmployee/{employeeId}", produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})
public ResponseEntity<Employee> getEmployee(#PathVariable("employeeId") int employeeId) {
Optional<Employee> optionalEmployee = employeeRepository.findByEmployeeId(employeeId);
if (optionalEmployee.isEmpty()) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
return new ResponseEntity<>(optionalEmployee.get(), HttpStatus.FOUND);
}
#PostMapping(path = "/createEmployee", consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})
public ResponseEntity<HttpStatus> createEmployee(#RequestBody Employee employee) {
Random random = new Random();
employee.setEmployeeId(random.nextInt(9999));
employeeRepository.save(employee);
log.info("Created employee with Id : {}", employee.getEmployeeId());
return new ResponseEntity<>(HttpStatus.CREATED);
}
#PostMapping(path = "/createEmployees", consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})
public ResponseEntity<String> createEmployees(#RequestBody List<Employee> employeeList) {
int count = 0;
Random random = new Random();
for (Employee employee : employeeList) {
employee.setEmployeeId(random.nextInt(999999));
employeeRepository.save(employee);
log.info("Created employee with Id : {}", employee.getEmployeeId());
count++;
}
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.set("countOfObjectCreated", String.valueOf(count));
return ResponseEntity.status(HttpStatus.CREATED).headers(responseHeaders).build();
}
#PutMapping(path = "/updateEmployee/{employeeId}", consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})
public ResponseEntity<HttpStatus> updateCustomer(#PathVariable("employeeId") int employeeId, #RequestBody Employee employee) {
Optional<Employee> optionalDbEmployee = employeeRepository.findByEmployeeId(employeeId);
if (optionalDbEmployee.isEmpty()) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
Employee dbEmployee = optionalDbEmployee.get();
dbEmployee.setFirstName(employee.getFirstName());
dbEmployee.setLastName(employee.getLastName());
dbEmployee.setExtension(employee.getExtension());
dbEmployee.setEmail(employee.getEmail());
dbEmployee.setOfficeCode(employee.getOfficeCode());
dbEmployee.setReportsTo(employee.getReportsTo());
dbEmployee.setJobTitle(employee.getJobTitle());
return new ResponseEntity<>(HttpStatus.OK);
}
#DeleteMapping(path = "/deleteEmployee/{employeeId}")
public ResponseEntity<HttpStatus> deleteCustomer(#PathVariable("employeeId") int employeeId) {
employeeRepository.deleteById(employeeId);
log.info("Employee with employee id {} Deleted successfully.", employeeId);
return new ResponseEntity<>(HttpStatus.OK);
}
}
Employee.java
#NoArgsConstructor
#AllArgsConstructor
#Getter
#Setter
#Builder
#Entity
#Table(name = "EMPLOYEE")
public class Employee {
#Id
#Column(name = "EMPLOYEE_ID")
int employeeId;
#Column(name = "LAST_NAME")
String lastName;
#Column(name = "FIRST_NAME")
String firstName;
#Column(name = "EXTENSION")
String extension;
#Column(name = "EMAIL")
String email;
#Column(name = "OFFICE_CODE")
int officeCode;
#Column(name = "REPORTS_TO")
Integer reportsTo;
#Column(name = "JOB_TITLE")
String jobTitle;
}
OfficeResource.java
#RestController
#RequestMapping("/office")
#Slf4j
public class OfficeResource {
#Autowired
OfficeRepository officeRepository;
#GetMapping(path = "/greetOffice", produces = MediaType.TEXT_PLAIN_VALUE)
public String sayHello() {
return "Hello Office !!!";
}
#GetMapping(path = "/getAllOffices", produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})
public ResponseEntity<List<Office>> getAllOffices() {
List<Office> officeList = officeRepository.findAll();
return new ResponseEntity<>(officeList, HttpStatus.OK);
}
#GetMapping(path = "/getOffice/{officeCode}", produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})
public ResponseEntity<Office> getOffice(#PathVariable("officeCode") int officeCode) {
Optional<Office> optionalOffice = officeRepository.findByOfficeCode(officeCode);
if (optionalOffice.isEmpty()) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
return new ResponseEntity<>(optionalOffice.get(), HttpStatus.FOUND);
}
#PostMapping(path = "/createOffice", consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})
public ResponseEntity<HttpStatus> createOffice(#RequestBody Office office) {
Random random = new Random();
office.setOfficeCode(random.nextInt(999));
officeRepository.save(office);
log.info("Created office with office code : {}", office.getOfficeCode());
return new ResponseEntity<>(HttpStatus.CREATED);
}
#PostMapping(path = "/createOffices", consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})
public ResponseEntity<String> createOffices(#RequestBody List<Office> officeList) {
int count = 0;
Random random = new Random();
for (Office office : officeList) {
office.setOfficeCode(random.nextInt(999));
officeRepository.save(office);
log.info("Created office with office code : {}", office.getOfficeCode());
count++;
}
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.set("countOfObjectCreated", String.valueOf(count));
return ResponseEntity.status(HttpStatus.CREATED).headers(responseHeaders).build();
}
#PutMapping(path = "/updateOffice/{officeCode}", consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})
public ResponseEntity<HttpStatus> updateOffice(#PathVariable("officeCode") int officeCode, #RequestBody Office office) {
Optional<Office> optionalDbOffice = officeRepository.findByOfficeCode(officeCode);
if (optionalDbOffice.isEmpty()) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
Office dbOffice = optionalDbOffice.get();
dbOffice.setCity(office.getCity());
dbOffice.setPhone(office.getPhone());
dbOffice.setAddressLine1(office.getAddressLine1());
dbOffice.setAddressLine2(office.getAddressLine2());
dbOffice.setState(office.getState());
dbOffice.setCountry(office.getCountry());
dbOffice.setPostalCode(office.getPostalCode());
dbOffice.setTerritory(office.getTerritory());
return new ResponseEntity<>(HttpStatus.OK);
}
#DeleteMapping(path = "/deleteOffice/{officeCode}")
public ResponseEntity<HttpStatus> deleteOffice(#PathVariable("officeCode") int officeCode) {
officeRepository.deleteById(officeCode);
log.info("Office with office code {} Deleted successfully.", officeCode);
return new ResponseEntity<>(HttpStatus.OK);
}
}
Office.java
#NoArgsConstructor
#AllArgsConstructor
#Getter
#Setter
#Builder
#Entity
#Table(name = "OFFICE")
public class Office {
#Id
#Column(name = "OFFICE_CODE")
int officeCode;
#Column(name = "CITY")
String city;
#Column(name = "PHONE")
String phone;
#Column(name = "ADDRESS_LINE1")
String addressLine1;
#Column(name = "ADDRESS_LINE2")
String addressLine2;
#Column(name = "STATE")
String state;
#Column(name = "COUNTRY")
String country;
#Column(name = "POSTAL_CODE")
String postalCode;
#Column(name = "TERRITORY")
String territory;
}
SecurityConfiguration.java
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
DataSource dataSource;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication()
.dataSource(dataSource)
.usersByUsernameQuery("select username,password,enabled from users where username = ?")
.authoritiesByUsernameQuery("select username,authority from authorities where username = ?")
.passwordEncoder(NoOpPasswordEncoder.getInstance());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/employee/createEmployee", "/employee/createEmployees", "/employee/updateEmployee/**", "/employee/deleteEmployee/**").hasRole("Admin")
.antMatchers("/office/createOffice", "/office/createOffices", "/office/updateOffice/**", "/office/deleteOffice/**").hasRole("Admin")
.antMatchers("/employee/getEmployee/**", "/employee/getAllEmployees").hasAnyRole("Admin","User")
.antMatchers("/office/getOffice/**", "/office/getAllOffices").hasAnyRole("Admin","User")
.and().formLogin();
}
After hitting the url "http://localhost:8085/employee/getEmployee/1002" from browser i am getting login form and after enter the credentials for "User1" who is "Admin" user and am getting "Forbidden, status=403" error.
Need Help.
hasRole and hasAnyRole prefix your strings with ROLE_. Use hasAuthoritiy or hasAnyAuthority instead. See spring docs

Spring Data JPA Redis : Cannot write custom method based query

I have configured Spring Data JPA with Redis and using RedisRepositories with provides methods like find(), findAll() etc. All these methods seem to be working just fine, but I am not able to write my custom method like.
RedisEntity findByGenderAndGrade(String gender, String grade);
RedisEntity is a simple POJO Entity class. If you want any more info, please let me know in messages.
Following is my entity:
#Data
#RedisHash("test1")
public class RedisEntity implements Serializable {
#Id
#GeneratedValue
private String id;
private String name;
private String gender;
private Integer grade;
}
Repository:
#Repository
public interface TestRepository extends JpaRepository<RedisEntity, String> {
List<RedisEntity> findAllByGender(String gender);
List<RedisEntity> findAllByGrade(Integer grade);
}
Service/Controller:
#Override
public List<RedisEntity> getById(String id) {
return testRepository.findById(id); //returns data perfectly.
}
#Override
public List<RedisEntity> getAllByGender(String gender) {
return testRepository.findAllByGender(gender); //returns []
}
#Override
public void saveEntity(RedisEntity redisEntity) {
testRepository.save(redisEntity); // saves it in redis perfectly.
}
Also,
findByGender and findAllByGender both give [], although I can see data in my redis database and save it as well.
As requested by FrançoisDupire,
#Configuration
public class RedisConfig {
#Autowired
private DeploymentProperties deploymentProperties;
private static Logger logger = LoggerFactory.getLogger(RedisConfig.class);
#Bean
JedisConnectionFactory jedisConnectionFactory() {
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration("localhost", 6379);
redisStandaloneConfiguration.setPassword(RedisPassword.of("root"));
return new JedisConnectionFactory(redisStandaloneConfiguration);
}
#Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(jedisConnectionFactory());
return template;
}
}
Also, I had referred this article: Baeldung article on Spring data redis
As mentioned by #JoshJ and verified by myself and others,
The solution to the problem is:
Adding #Indexed annotation
to all those columns/fields which need to be used with all finds.
#Data
#RedisHash("EmployeeDetails")
public class RedisEntity {
#Id
private String employeeId;
private String firstName;
private String lastName;
#Indexed
private String gender;
#Indexed
private String grade;
}
We have the Spring Data Redis Library which provides the scope to write the custom method.Attaching Sample code.
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>2.0.8.RELEASE</version>
</dependency>
Entity Definition
#Data
#RedisHash("EmployeeDetails")
public class RedisEntity {
#Id
private String employeeId;
private String firstName;
private String lastName;
private String gender;
private String grade;
}
Repository Definition
#Repository
public interface RedisEntityRepository extends CrudRepository<RedisEntity, String>{
List<RedisEntity> findAllByGenderAndGrade(String gender, String grade);
}
Implementation
#Component
public class RedisEntityImpl implements RedisEntityService {
#Autowired
private RedisEntityRepository redisEntityRepository;
#Override
public List<RedisEntity> getAllByGenderAndGrade(String gender, String grade) {
return redisEntityRepository.findAllByGenderAndGrade(gender,grade);
}
}
Properties
spring.cache.type = redis
spring.redis.host = localhost
spring.redis.port = 6379

SpringBoot with JPA in IntelliJ

I'm just starting with Spring, and actually I'm step by step tutorial so everything would work well, but somehow I've got problem with running spring boot after adding JPA elements.
Earlier I had problem with Database type NONE, so I manually added depedency:
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derby</artifactId>
<version>10.12.1.1</version>
<scope>runtime</scope>
</dependency>
But I feel that still something is missing in pom file which looks like this:
Pom.XML
Consol output with an error looks like this:
Console output
Implementation:
1.
class Topic
2.
class TopicController
3.
class TopicRepository
4.
class: TopicService
5.
run class
You need to annotate Topic class:
package defaultpackage.topic;
/**
* Created by zales on 02.03.2017.
*/
#Entity
public class Topic {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private String id;
private String name;
private String discription;
public Topic() {
}
public Topic(String id, String name, String discription) {
super();
this.id = id;
this.name = name;
this.discription = discription;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDiscription() {
return discription;
}
public void setDiscription(String discription) {
this.discription = discription;
}
}
You can see a similar sample with Entities and Repositories in here:
https://github.com/ccoloradoc/HibernateFilePermissionSample
Also make sure all your entities are in same package(or subpackage) as your SpringBootApplication.

cassandra-driver-mapping: InvalidTypeException: Invalid 32-bits float value, expecting 4 bytes but got 6

As I got issues with spring-data-cassandra with docker as describer here I switched to use com.datastax.cassandra library for cassandra operations but I am getting issues while mapping the resulted object using entity mapper as per this link
Here is my code ...
public String getUser(String userName) {
Mapper<User> mapper = manager.mapper(User.class);
User result = mapper.get(userName); // no issue getting User
String accountNum = result.getAccountId();
return accountNum ;
}
public Account getAccount(String accountNum){
Mapper<Account> mapper = manager.mapper(Account.class);
Account account = mapper.get(accountNum); // getting error here
return account;
}
Account.java
#Table(name = "account")
public class Account {
#PartitionKey
private String accountNum;
private String accountsubtype;
private float currentbalance;
private String customertype;
private String firstname;
private boolean isactive;
private String payments;
private String status;
....
//Getters & Setters
}
pom.xml dependecies
<dependency>
<groupId>com.datastax.cassandra</groupId>
<artifactId>cassandra-driver-core</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>com.datastax.cassandra</groupId>
<artifactId>cassandra-driver-mapping</artifactId>
<version>3.0.0</version>
</dependency>

Trying CrudRepository - H2 - TableNotFound

Below, my configs
Pom.xml
`<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>`
Controller
#RestController
public class SendSmsController {
#Autowired
private DataBaseService dataBaseService;
#Autowired
private SendSmsService sendSmsService;
#RequestMapping(value="/sendSms", method=RequestMethod.POST)
public ResponseEntity<Sms> sendSms(#RequestBody Sms sms,#RequestParam(required=false) String expirationDate) {
if(sms.getBody().length() > 160){
return new ResponseEntity<Sms>(HttpStatus.UNPROCESSABLE_ENTITY);
}
dataBaseService.saveSms(sms);
return sendSmsService.sendRequest(sms);
}
}
DataBaseService
#Data
#Service
public class DataBaseService {
#Autowired
private SmsRepository smsRepository;
public void saveSms(Sms sms) {
//I try smsRepository.save(sms) too
smsRepository.save(new Sms(sms.getTo(),sms.getTo(),sms.getBody()));
}
}
SmsRepository
public interface SmsRepository extends CrudRepository<Sms, Long> {
}
Sms Class
#Data
#Entity
#JsonIgnoreProperties(ignoreUnknown = true)
public class Sms {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
#JsonProperty
private String from;
#JsonProperty
private String to;
#JsonProperty
private String body;
public Sms(String from, String to, String body){
this.from = from;
this.to = to;
this.body = body;
};
public Sms(){
}
}
Config
#Configuration
public class Config {
#Bean
public SendSmsService sendSmsService(){
return new SendSmsService();
}
#Bean
public DataBaseService dataBaseService(){
return new DataBaseService();
}
This issue occurs when the code reaches "smsRepository.save(sms)". I follow this tutorial https://spring.io/guides/gs/accessing-data-jpa/ but i think i missing configs. Thank you for any help!
The error again: org.springframework.dao.InvalidDataAccessResourceUsageException: could not prepare statement; SQL [insert into sms (id, body, from, to) values (null, ?, ?, ?)]; nested exception is org.hibernate.exception.SQLGrammarException: could not prepare statement
Caused by: org.h2.jdbc.JdbcSQLException: Table "SMS" not found; SQL statement:
insert into sms (id, body, from, to) values (null, ?, ?, ?) [42102-187]
The Problem was in my class.
After this work
public class Sms {
#Id
private String id;
#JsonProperty
#Column(name="fromNumber")
private String from;
#JsonProperty
#Column(name="toNumber")
private String to;
#JsonProperty
#Column(name="bodyMessage")
private String body;

Resources