H2 Schema Empty in Spring Boot Application - spring

I'm setting up a barebones Spring Boot project described here and I'm running into issues with the basic setup.
It seems that the DatabaseLoader does not get invoked, and when I open the H2 Console for this project I see no schema containing an Employee table.
Here's the relevant part of my pom.xml:
<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-data-rest</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<!--
<scope>runtime</scope>
-->
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
my domain:
#Data
#Entity
public class Employee {
private #Id #GeneratedValue Long id;
private String firstName;
private String lastName;
private String description;
public Employee() {}
public Employee(String firstName, String lastName, String description) {
this.firstName = firstName;
this.lastName = lastName;
this.description = description;
}
}
And the database loader:
public class DatabaseLoader implements CommandLineRunner {
private final EmployeeRepository repository;
#Autowired
public DatabaseLoader(EmployeeRepository repository) {
this.repository = repository;
}
#Override
public void run(String... strings) throws Exception {
this.repository.save(new Employee("duke", "earl", "dude"));
}
}
Navigating to the console after application startup at localhost:8080/console shows jdbc:h2:~/test with only an INFORMATION_SCHEMA and users menu. I also set this up as a CRUD repository and, though I can post to it, none of the attribute data seems to be saved, but the Employees resource is recognized.
POST:{"firstName": "Bilbo", "lastName": "Baggxins", "description": "burglar"}
Comes back with:
{
"_links": {
"self": {
"href": "http://localhost:8080/api/employees/4"
},
"employee": {
"href": "http://localhost:8080/api/employees/4"
}
}
}

The default h2 url with Spring Boot is: jdbc:h2:mem:testdb
To use jdbc:h2:~/test you must add this to your application.properties:
spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:~/test
What's happening is, you are writing the Employee in spring-boot's memory database (testdb). Then, you open the h2-console to jdbc:h2:~/test, which creates it on the fly, and let you browse emptiness.
With spring.h2.console.enabled=true you may open a browser to http://localhost:8080/h2-console and view the database content. Use the following settings:
Saved Settings: Generic H2 (Embedded)
Driver Class: org.h2.Driver
URL: jdbc:h2:mem:testdb
username: sa
password:

This is shamelessly borrowed from Josh Long. This is a working CommandLineRunner implementation. Github full code
#Component
class SampleRecordsCLR implements CommandLineRunner {
private final ReservationRepository reservationRepository;
#Autowired
public SampleRecordsCLR(ReservationRepository reservationRepository) {
this.reservationRepository = reservationRepository;
}
#Override
public void run(String... args) throws Exception {
Stream.of("Josh", "Jungryeol", "Nosung", "Hyobeom",
"Soeun", "Seunghue", "Peter", "Jooyong")
.forEach(name -> reservationRepository.save(new Reservation(name)));
reservationRepository.findAll().forEach(System.out::println);
}
}

Related

How to validate Data in Service Layer?

I've got a problem which I haven't been able to solve.
I am currently building a Rest Api with Spring Boot and I want to validate my User Entity inside of the service layer. I have tried different approaches, but nothing worked out for now. In my Test no Exception gets thrown when it gets to the create method.
Here is my current code:
User Entity
#Entity
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotBlank
#Email(message = "User needs a valid Mail.")
#Column(unique = true, nullable = false)
private String mail;
#NotBlank
#Column(nullable = false)
private String lastName;
#NotBlank
#Column(nullable = false)
private String firstName;
}
User Service
#Service
#RequiredArgsConstructor
public class UserService implements IUserService {
private final UserRepository userRepository;
#Override
public User create(#Valid User user) {
user.setId(null);
User createdUser = userRepository.save(user);
return createdUser;
}
My Test
#SpringBootTest
class UserServiceTest {
#Mock
UserRepository userRepository;
#InjectMocks
UserService userService;
#Test
void createUserFailsBecauseNoFirstName() {
User testUser = new User("test#mail.de", "LastName", "FirstName");
when(userRepository.save(any(User.class))).thenReturn(testUser);
testUser.setFirstName(null);
Assertions.assertThrows(ConstraintViolationException.class,
() -> userService.create(testUser));
}
pom.xml
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.rest</groupId>
<artifactId>test</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<java.version>11</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-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</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>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.9</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
What I tried:
#Validated for the Service Class (tutorial I followed)
#Validated additionally at Method Level
removing #Validated & #Validate and use Validator instead, but it doesn't get injected (followed that tutorial)
Because you are using #InjectMocks to get the UserService , it is not a bean that is managed by Spring since #InjectMocks is a Mockito annotation and know nothing about Spring and does not know how to get a bean from Spring container. So you are actually testing a non-spring UserService bean now and hence the validation does not takes place.
Change to use #Autowired to get the UserService bean from Spring container , and use #MockBean to replace the UserRepository bean in the Spring container with a mocked version. Also you need to add #Validated on the UserService too :
#Service
#Validated
public class UserService implements IUserService {
}
#SpringBootTest
class UserServiceTest {
#MockBean
UserRepository userRepository;
#Autowired
UserService userService;
#Test
void createUserFailsBecauseNoFirstName() {
User testUser = new User("test#mail.de", "LastName", "FirstName");
when(userRepository.save(any(User.class))).thenReturn(testUser);
testUser.setFirstName(null);
Assertions.assertThrows(ConstraintViolationException.class,
() -> userService.create(testUser));
}
}
Not really the solution that I was searching for, but I couldn't get it to work with Annotations even in a new Spring Boot Project. So I now used a Validator in my Service and let it validate my User.
Service
#Service
#RequiredArgsConstructor
public class UserService implements IUserService {
private final Validator validator;
private final UserRepository userRepository;
#Override
public User create(User user) {
user.setId(null);
// new Validation
Set<ConstraintViolation<T>> violations = validator.validate(objectToValidate);
if (!violations.isEmpty()) {
StringBuilder sb = new StringBuilder();
for (ConstraintViolation<T> constraintViolation : violations) {
sb.append(constraintViolation.getMessage());
}
throw new ResourceValidationException("Error occurred: " + sb.toString());
}
User createdUser = userRepository.save(user);
return createdUser;
}
Test
#SpringBootTest
class UserServiceTest {
#Mock
UserRepository userRepository;
#Autowired
Validator validator;
UserService userService = new UserService(validator, userRepository);
#Test
void createUserFailsBecauseNoFirstName() {
User testUser = new User("test#mail.de", "LastName", "FirstName");
when(userRepository.save(any(User.class))).thenReturn(testUser);
testUser.setFirstName(null);
Assertions.assertThrows(ConstraintViolationException.class,
() -> userService.create(testUser));
}
And since I always got a validator bean which didn't validate (so my tests didn't throw the expected error) and I didn't want to create a ValidatorFactory I also added a Configuration which holds a ValidatorBean.
Config
#Configuration
public class AppConfig {
#Bean
public Validator defaultValidator() {
return new LocalValidatorFactoryBean();
}
}

created repository method is returning wrong output like packagename.classname.table (com.blogconduitapi.entity.Users#6a3258a4)

I am new lerner of spring boot, i am creating a project after inserting user data into database when i am fetching data from table using method "User findByEmail(String email) it should return user object but it returning something like "com.blogconduitapi.entity.Users#5e2f219c".
All the codes are mentioned below
this is entity class
package com.blogconduitapi.entity;
import javax.persistence.*;
#Entity
#Table(name = "users")
public class Users {
#Id
#GeneratedValue
private int id;
private String name;
private String email;
private String password;
private boolean isEnabled;
public Users() {
}
public Users(String name, String email, String password, boolean isEnabled) {
this.name = name;
this.email = email;
this.password = password;
this.isEnabled = isEnabled;
}
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 getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public boolean isEnabled() {
return isEnabled;
}
public void setEnabled(boolean enabled) {
isEnabled = enabled;
}
}
this is controller
package com.blogconduitapi.controller;
import com.blogconduitapi.entity.Users;
import com.blogconduitapi.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class UserController {
#Autowired
UserService userService;
#PostMapping(value = "/register")
public String registerUser(#RequestBody Users users) {
Users existingUsers1 = userService.findUser(users.getEmail());
users.setEnabled(true);
userService.createUser(users);
return "user save successfully";
}
}
this is UserService
package com.blogconduitapi.service;
import com.blogconduitapi.entity.Users;
public interface UserService {
Users findUser(String email);
void createUser(Users users);
}
this is repository
package com.blogconduitapi.repository;
import com.blogconduitapi.entity.Users;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface UserRepository extends JpaRepository<Users, Integer> {
Users findByEmail(String email);
}
5.this is serviceImpl
package com.blogconduitapi.service.impl;
import com.blogconduitapi.entity.Users;
import com.blogconduitapi.exception.UserDefinedException;
import com.blogconduitapi.repository.UserRepository;
import com.blogconduitapi.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
#Service
public class UserServiceImpl implements UserService {
#Autowired
UserRepository userRepository;
#Override
public Users findUser(String email) {
Users users = userRepository.findByEmail(email);
System.out.println("{{{{{{{{{}}}}}}}}}}} " + users);
if (users != null) throw new UserDefinedException("mail already exist");
return users;
}
#Override
public void createUser(Users users) {
if (users.getName().isEmpty() || users.getEmail().isEmpty() || users.getPassword().isEmpty()) {
throw new UserDefinedException("There are some required fields are missing");
}
userRepository.save(users);
}
}
application.property
spring.datasource.url= jdbc:postgresql://localhost:5432/apidb
spring.datasource.username=postgres
spring.datasource.password=admin
spring.jpa.hibernate.ddl-auto=update
7.this is 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.3.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>blogconduitapi</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>blogconduitapi</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</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-data-rest</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-jdbc -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</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>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
The method is working it's just the issue with print. Override toString() method in your User class and try printing the user again. Java has no idea how to convert your User to string and print it in format you would like otherwise.

spring-boot-starter-data-jpa insert query does not save the data in database

I am using spring-boot-starter-data-jpa. While trying to insert the data in database, the utility executes without any error but the data is not persisted in the database.
I can also see the insert query on the console
I am not sure what exactly is going wrong here.
POM.XML
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- Spring data JPA -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.15</version>
</dependency>
</dependencies>
Main class
#SpringBootApplication
public class Application implements CommandLineRunner {
#Autowired
DataSource dataSource;
#Autowired
ElementDetailsRepository elementDetailsDAO;
#Autowired
ElementDetailsEntity elementDetailsEntity;
#Autowired
ElementDetailsPK elementDetailsPK;
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
#Transactional(propagation = Propagation.NESTED)
#Override
public void run(String... args) throws Exception {
for (ExcelPojo excelPojo : listOfExcelElements) {
if (excelPojo.getRecordType().equalsIgnoreCase("Item")) {
if (excelPojo.getMarket().equalsIgnoreCase("UK")) {
Integer elementID = elementDetailsDAO.findDNAElementId(excelPojo.getMarket(), 992,
excelPojo.getGenesisID(), "EN");
System.out.println("UK ITEM..." + elementID);
int flag = elementDetailsDAO.createPIMIDAttributeValue(excelPojo.getMarket(), 1914, excelPojo.getPimID(),elementID, "EN", getCurrentTime(), getUser());
}
}
Repository
#Repository
public interface ElementDetailsRepository extends JpaRepository<ElementDetailsEntity,Integer> {
#Query(value = QueryConstants.findElementId, nativeQuery = true)
public Integer findDNAElementId(#Param("country_code") String country_code, #Param("config_id") int config_id,
#Param("import_id") String import_id,#Param("language_code")String language_code);
#Modifying
#Query(value = QueryConstants.createPIMIDAttributeValue, nativeQuery = true)
public int createPIMIDAttributeValue(#Param("countrycode") String countrycode, #Param("configid") int configid,
#Param("pimid") String attribute_value, #Param("elementid") int elementId,#Param ("languageCode") String language_code,#Param("date") String date,#Param("user") String user);
}
Entity
#Service
#Entity
#Table(name = "element_details")
public class ElementDetailsEntity extends BaseDataObject {
private static final long serialVersionUID = -8033261173844397824L;
#EmbeddedId
private ElementDetailsPK elementDetailsPK;
#Column(name = "status_id")
private Integer statusId;
#Column(name = "attribute_value")
private String attributeValue;
#Column(name = "is_dirty")
private Boolean isDirty;
}
Application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/wxb_prod
spring.datasource.username=root
spring.datasource.password=admin
spring.datasource.driver-class-name= com.mysql.cj.jdbc.Driver
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto = none
spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
logging.level.org.hibernate.SQL=TRACE
spring.datasource.hikari.connectionTimeout=20000
spring.datasource.hikari.maximumPoolSize=5
Try using annotation #EnableJpaRepositories in your main class

Spring annotation gives null value in my Spring MVC when I create JAX-RS Web service

I added JAX-RS Web service for my project .I want to get XML file. It works fine when I hard cord something on return statement and it works fine. But I want to get data from my database. I use
#Autowired
private ProductServices productServices;
for call Spring Service class... For other normal controllers this #Autowired working fine. In JAX-RS it doesn't works.
JAX-RS gives null value like this
I want to call this service for get data to my method. How can I do that..
This is my Model.
#Entity
#Table(name = "products")
#XmlRootElement
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "product_id")
private long productId;
#NotNull
private String serialNo;
#NotNull
private int slsiUnit;
#NotNull
private String itemDesc;
#NotNull
private int slsNo;
#NotNull
private String hsCode;
#NotNull
private String userIDandTime;
#NotNull
private String recentUpdateBy;
public long getProductId() {
return productId;
}
public void setProductId(long productId) {
this.productId = productId;
}
public String getSerialNo() {
return serialNo;
}
public void setSerialNo(String serialNo) {
this.serialNo = serialNo;
}
public int getSlsiUnit() {
return slsiUnit;
}
public void setSlsiUnit(int slsiUnit) {
this.slsiUnit = slsiUnit;
}
public String getItemDesc() {
return itemDesc;
}
public void setItemDesc(String itemDesc) {
this.itemDesc = itemDesc;
}
public int getSlsNo() {
return slsNo;
}
public void setSlsNo(int slsNo) {
this.slsNo = slsNo;
}
public String getHsCode() {
return hsCode;
}
public void setHsCode(String hsCode) {
this.hsCode = hsCode;
}
public String getUserIDandTime() {
return userIDandTime;
}
public void setUserIDandTime(String userIDandTime) {
this.userIDandTime = userIDandTime;
}
public String getRecentUpdateBy() {
return recentUpdateBy;
}
public void setRecentUpdateBy(String recentUpdateBy) {
this.recentUpdateBy = recentUpdateBy;
}
}
This is my Repository.
public interface ProductRepository extends CrudRepository<Product, Long> {
#Override
Product save(Product product);
#Override
Product findOne(Long productId);
#Override
List<Product> findAll();
#Override
void delete(Long productId);
}
This is my Services class
#Service
public class ProductServices {
private static final Logger serviceLogger = LogManager.getLogger(ProductServices.class);
#Autowired
private ProductRepository productRepository;
public List<Product> getProductList() {
return productRepository.findAll();
}
public Product getProductById(long productId) {
return productRepository.findOne(productId);
}
}
This is my JAX-RS Web Service class
#Path("release")
public class GenericResource {
#Context
private UriInfo context;
#Autowired
private ProductServices productServices;
public GenericResource() {
}
#GET
#Produces(MediaType.APPLICATION_XML)
public List<Product> getXml() {
List<Product> a = productServices.getProductList();
return a;
}
}
This is the MessageBodyWriter
#Provider
#Produces(MediaType.APPLICATION_XML)
public class restConverter implements MessageBodyWriter<List<Product>> {
#Override
public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return Product.class.isAssignableFrom(type);
}
#Override
public long getSize(List<Product> t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return -1;
}
#Override
public void writeTo(List<Product> t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException {
out.write(t.toString().getBytes());
}
}
This is a extend class for JSX-RS
#ApplicationPath("TransferPermit/Slsi_Customs/restAPI")
public class restConfig extends Application{
}
This is my pom.xml
<dependencies>
<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>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
</dependency>
<!--handle servlet-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<!--<Email Dependency>-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
<version>1.4.3.RELEASE</version>
</dependency>
<!--Add mysql dependency-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>6.0.3</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<!--jasper-->
<dependency>
<groupId>net.sf.jasperreports</groupId>
<artifactId>jasperreports</artifactId>
<version>3.7.6</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.bundles</groupId>
<artifactId>jaxrs-ri</artifactId>
<version>2.13</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.mail</groupId>
<artifactId>javax.mail-api</artifactId>
<version>1.5.5</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0.1</version>
<type>jar</type>
</dependency>
</dependencies>
Special : This cord works fine. But in Web service class productServices auto-wired dependency not working. What is the error :
#RequestMapping(value = "/ViewProduct", produces = {MediaType.APPLICATION_JSON_VALUE}, method = RequestMethod.GET)
#JsonIgnore
public ResponseEntity<List<Product>> listAllProducts() {
List<Product> viewProducts = productServices.getProductList();
if (viewProducts.isEmpty()) {
return new ResponseEntity<List<Product>>(HttpStatus.NO_CONTENT);
}
System.out.println("entity " + new ResponseEntity<List<Product>>(HttpStatus.NO_CONTENT));
return new ResponseEntity<List<Product>>(viewProducts, HttpStatus.OK);
}
What is the error in my cord. How can I call data from database
Please help me someone for return XML...

Spring Boot + Spring Data JPA + Transactions not working properly

I have created a Spring Boot application using 1.2.0 version with spring-boot-starter-data-jpa and I am using MySQL.
I have configured my MySQL properties in application.properties file correctly.
I have a simple JPA Entity, Spring Data JPA Repository and a Service as follows:
#Entity
class Person
{
#Id #GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
private String name;
//setters & getters
}
#Repository
public interface PersonRepository extends JpaRepository<Person, Integer>{
}
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
#Service
#Transactional
class PersonService
{
#Autowired PersonRepository personRepository;
#Transactional
void save(List<Person> persons){
for (Person person : persons) {
if("xxx".equals(person.getName())){
throw new RuntimeException("boooom!!!");
}
personRepository.save(person);
}
}
}
I have the following JUnit test:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
public class ApplicationTests {
#Autowired
PersonService personService;
#Test
public void test_logging() {
List<Person> persons = new ArrayList<Person>();
persons.add(new Person(null,"abcd"));
persons.add(new Person(null,"xyz"));
persons.add(new Person(null,"xxx"));
persons.add(new Person(null,"pqr"));
personService.save(persons);
}
}
The expectation here is it should not insert any records into PERSON table as it will throw Exception while inserting 3rd person object.
But it is not getting rolled back, first 2 records are getting inserted and committed.
Then I thought of quickly try with JPA EntityManager.
#PersistenceContext
private EntityManager em;
em.save(person);
Then I am getting javax.persistence.TransactionRequiredException: No transactional EntityManager available Exception.
After googling for sometime I encounter this JIRA thread https://jira.spring.io/browse/SPR-11923 on the same topic.
Then I updated the Spring Boot version to 1.1.2 to get Spring version older than 4.0.6.
Then em.save(person) working as expected and Transaction is working fine (means it is rollbacking all the db inserts when RuntimeException occurred).
But even with Spring 4.0.5 + Spring Data JPA 1.6.0 versions transactions are not working when personRepository.save(person) is used instead of em.persist(person).
It seems Spring Data JPA repositories are committing the transactions.
What am I missing? How to make Service level #Transactional annotations work?
PS:
Maven 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.sivalabs</groupId>
<artifactId>springboot-data-jpa</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>springboot-data-jpa</name>
<description>Spring Boot Hello World</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.0.RELEASE</version>
<relativePath />
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<start-class>com.sivalabs.springboot.Application</start-class>
<java.version>1.7</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<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-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
</project>
Application.java
#EnableAutoConfiguration
#Configuration
#ComponentScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Change Transactional annotation to
#Transactional(rollbackFor=Exception.class)
From comment by #m-deinum:
Make your PersonService public as well as the method you are calling.
This seems to have done the trick for several users. The same thing is also covered in this answer, citing manual saying:
When using proxies, you should apply the #Transactional annotation
only to methods with public visibility. If you do annotate protected,
private or package-visible methods with the #Transactional annotation,
no error is raised, but the annotated method does not exhibit the
configured transactional settings. Consider the use of AspectJ (see
below) if you need to annotate non-public methods.
I tested this with SpringBoot v1.2.0 and v1.5.2 and all is working as expected, you don't need to use entity manager neither #Transactional(rollbackFor=Exception.class).
I could not see which part you misconfigured, all seems fine at first glance, so I am just posting all my config as reference with more updated annotations and H2 embedded memory DB:
application.properties
# Embedded memory database
spring.jpa.hibernate.ddl-auto=create
spring.datasource.url=jdbc:h2:~/test;AUTO_SERVER=TRUE
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>com.demo</groupId>
<artifactId>jpaDemo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>
</project>
Person.java
#Entity
public class Person
{
#Id
#GeneratedValue(strategy= GenerationType.AUTO)
private Integer id;
private String name;
public Person() {}
public Person(String name) {this.name = name;}
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;}
}
PersonRepository.java
#Repository
public interface PersonRepository extends JpaRepository<Person, Integer> {}
PersonService.java
#Service
public class PersonService
{
#Autowired
PersonRepository personRepository;
#Transactional
public void saveTransactional(List<Person> persons){
savePersons(persons);
}
public void saveNonTransactional(List<Person> persons){
savePersons(persons);
}
private void savePersons(List<Person> persons){
for (Person person : persons) {
if("xxx".equals(person.getName())){
throw new RuntimeException("boooom!!!");
}
personRepository.save(person);
}
}
}
Application.java
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
PersonServiceTest.java
#RunWith(SpringRunner.class)
#SpringBootTest
public class PersonServiceTest {
#Autowired
PersonService personService;
#Autowired
PersonRepository personRepository;
#Test
public void person_table_size_1() {
List<Person> persons = getPersons();
try {personService.saveNonTransactional(persons);}
catch (RuntimeException e) {}
List<Person> personsOnDB = personRepository.findAll();
assertEquals(1, personsOnDB.size());
}
#Test
public void person_table_size_0() {
List<Person> persons = getPersons();
try {personService.saveTransactional(persons);}
catch (RuntimeException e) {}
List<Person> personsOnDB = personRepository.findAll();
assertEquals(0, personsOnDB.size());
}
public List<Person> getPersons(){
List<Person> persons = new ArrayList() {{
add(new Person("aaa"));
add(new Person("xxx"));
add(new Person("sss"));
}};
return persons;
}
}
*The database is cleared and re-initialized for each test so that we always validate against a known state

Resources