Data is not getting inserted in Spring boot + Spring data JPA? - spring

I have made a spring boot application, in the application I am spring-data-jpa. The problem is there while inserting the data in database, it shows the data is been inserted but there is no data in database. Following is my code. Please let me know where I am doing mistake. Thanks in advance.
Main Class
package avs.controller;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
#SpringBootApplication
#EntityScan(basePackages = {"avs.pojo"})
#EnableJpaRepositories(basePackages = {"avs.repository"})
public class AVS {
public static void main(String[] args) {
SpringApplication.run(AVS.class, args);
}
}
Controller Class
package avs.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import avs.pojo.User;
import avs.repository.UserReposiroty;
#Controller
public class UserController {
#Autowired
private UserReposiroty userRepository;
#RequestMapping(value = "/saveuser", method = RequestMethod.POST)
#ResponseBody
#Bean
public String saveProduct(/*#RequestBody User user*/) {
User user = new User();
user.setUserId("ani");
user.setPassword("ani123");
user.setApplicatonId(123l);
userRepository.save(user);
return user.getUserId().toString();
}
}
Pojo Class
package avs.pojo;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import org.springframework.stereotype.Component;
#Entity
#Component
#Table(name="user")
public class User extends BasePOJO {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="id")
private Long id;
#Column(name="application_id")
private Long applicatonId;
#Column(name="user_id")
private String userId;
#Column(name="password")
private String password;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getApplicatonId() {
return applicatonId;
}
public void setApplicatonId(Long applicatonId) {
this.applicatonId = applicatonId;
}
#Override
public String toString(){
return String.format(
"Customer[id=%d, userId='%s', password='%s']",
id, userId, password);
}
}
Repository Class
package avs.repository;
import org.springframework.data.repository.CrudRepository;
import avs.pojo.User;
public interface UserReposiroty extends CrudRepository<User, Long> {
}
Application Properties
#port to run tomcat
server.port=8021
#database configuration
spring.datasource.url=jdbc:mysql://localhost/avs_db
spring.datasource.username=avsadmin
spring.datasource.password=avsadmin
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
# ===============================
# = JPA / HIBERNATE
# ===============================
# Use spring.jpa.properties.* for Hibernate native properties (the prefix is
# stripped before adding them to the entity manager).
# Show or not log for each sql query
spring.jpa.show-sql = true
# Hibernate ddl auto (create, create-drop, update): with "update" the database
# schema will be automatically updated accordingly to java entities found in
# the project
spring.jpa.hibernate.ddl-auto = update
# Naming strategy
spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy
# Allows Hibernate to generate SQL optimized for a particular DBMS
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
build gradle file
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.2.RELEASE")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'
jar {
baseName = 'avs-bookcab'
version = '0.1.0'
}
repositories {
mavenCentral()
}
dependencies {
//Spring boot and MVC
compile group: 'org.springframework.boot', name: 'spring-boot-starter-thymeleaf', version: '1.5.2.RELEASE'
compile("org.springframework.boot:spring-boot-devtools")
//Spring boot and hibernate
compile("org.springframework.boot:spring-boot-starter-data-jpa")
compile("com.h2database:h2")
compile group: 'mysql', name: 'mysql-connector-java', version: '6.0.6'
}

If the H2 database is found on your classpath, Spring Boot will automatically set up an in memory H2 database for your use. Just remove H2 dependency from your gradle!

Change compile("com.h2database:h2") to test("com.h2database:h2") and it will do the trick (you most likely would like to have H2 for your future tests).
Also, some suggestions for you:
annotation #Bean above the public String saveProduct(/*#RequestBody User user*/) method is not needed;
annotation #Component above the public class User extends BasePOJO class is not needed;
if you move class public class AVS to the base package of the project
(package avs;) you can get rid of both annotations:
#EntityScan(basePackages = {"avs.pojo"})
#EnableJpaRepositories(basePackages = {"avs.repository"})
The problem with current implementation is, that if you add a Service class to avs.service package, it won't be picked up by spring and you will be forced to configure #ComponentScan, which is kind of an option, but #SpringBootApplication does it automatically, if it's in a right place.

Related

Using transactional in spring boot with hibernate

I am getting the error while using hibernate in spring boot application No qualifying bean of type TransactionManager' available
I am using the following config class:
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
#org.springframework.context.annotation.Configuration
#EnableTransactionManagement
public class Config {
#Bean
public SessionFactory sessionFactory() {
Configuration configuration = new Configuration();
configuration.configure();
configuration.addAnnotatedClass(Ct.class);
configuration.addAnnotatedClass(St.class);
SessionFactory sessionFactory = configuration.buildSessionFactory();
return sessionFactory;
}
}
#RestController
public class RestAPIController {
#Autowired
private SessionFactory sessionFactory;
#PutMapping("/addS")
#Transactional
public void addSt(#RequestParam("cc") String cc,#RequestParam("st") String st) {
CC cc1= new CC();
CC.setCode(cc);
State state = new State(cc,st);
sessionFactory.getCurrentSession().save(state);
}
}
}
The main reason I added the #Transactional in the addSt method is due to error: The transaction was still an active when an exception occurred during Database.
So I turned to use spring boot for managing transactions. I am not sure what to do here.
--------------------UPDATED CODE--------------------
#Repository
public interface StateRepository extends CrudRepository<State, String> {}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.ArrayList;
import java.util.List;
#Service
#Transactional
public class StateService {
#Autowired
private StateRepository stateRepository;
public void save(State state) {
stateRepository.save(state);
}
public List<State> findAll() {
List<State> states = new ArrayList<>();
stateRepository.findAll().forEach(states::add);
return states;
}
}
For starters use proper layers and write a service and use JPA instead of plain Hibernate. If you want a Session you can always use EntityManager.unwrap to obtain the underlying Session.
#Service
#Transactional
public StateService {
#PersistenceContext
private EntityManager em;
public void save(State state) {
em.persist(state);
}
Use this service in your controller instead of the SessionFactory.
#RestController
public class RestAPIController {
private final StateService stateService;
RestAPIController(StateService stateService) {
this.stateService=stateService;
}
#PutMapping("/addS")
public void addSt(#RequestParam("cc") String cc, #RequestParam("st") String st) {
CC cc1= new CC();
CC.setCode(cc);
State state = new State(cc,st);
stateService.save(state);
}
}
Now ditch your Config class and restart the application.
NOTE
When using Spring Data JPA it is even easier, define a repository extending CrudRepository and inject that into the service instead of an EntityManager. (I'm assuming that Long is the type of primary key you defined).
public interface StateRepository extends CrudRepository<State, Long> {}
#Service
#Transactional
public StateService {
private final StateRepository states;
public StateService(StateRepository states) {
this.states=states;
}
public void save(State state) {
states.save(state);
}
}

Spring batch item writer rest API

Is it possible to read data from DB, process it and in ItemWriter send to another system using RestAPI (REST TEMPLATE) in Spring batch project? All I can see is fetch data and write it in a csv file.
It is possible to create your own custom ItemWriter.
In your case, please add the spring-boot-starter-web dependency to either your pom.xml or build.gradle
Example:
package com.example.batch;
import lombok.extern.log4j.Log4j2;
import org.springframework.batch.item.ItemWriter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
import java.util.List;
#Log4j2
public class RestItemWriter implements ItemWriter<String> {
#Autowired
RestTemplate restTemplate;
public RestItemWriter(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
#Override
public void write(List<? extends String> items) throws Exception {
ResponseEntity<Users> users = restTemplate.getForEntity("https://jsonplaceholder.typicode.com/users/1", Users.class);
log.info("Status code is: " + users.getStatusCode());
}
}
package com.example.batch;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Getter;
import lombok.Setter;
#Getter
#Setter
#JsonInclude(JsonInclude.Include.NON_NULL)
public class Users {
public String id;
public String name;
public String username;
public String email;
public String phone;
}
More information about custom item writers here

How to us a constructor with parameters in a method used by Spring Boot's #RestController annotation to create a request handler

I bought this new book to try to learn Spring Boot quickly. It started out well, and I easily created a REST API. But then we added CrudRepository, and I'm seeing issues with the code as described in the book. Also, there is no code available to download because the author took it down from Oreily's git repo in order to fix some things...
The issue is that if I try to build the code as the book describes (without a default constructor) I get a Java error complaining that there is no default constructor. If I add a default constructor, it builds, but Spring uses it instead of the new constructor, that requires a parameter to be passed. So when I actually call the API, like if I call the /coffees endpoint, I get a java.lang.NullPointerException: null
So how is Spring supposed to know which constructor to use, and how could it pass in values for this parameter?
Here is the controller:
package com.bw.restdemo;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
#RestController
#RequestMapping("/coffees")
class RestAPIDemoController {
private final CoffeeRepository coffeeRepository;
public RestAPIDemoController(CoffeeRepository coffeeRepository) {
this.coffeeRepository = coffeeRepository;
this.coffeeRepository.saveAll(List.of(
new Coffee("Cafe Cereza"),
new Coffee("Freedom Fuel"),
new Coffee("Cold Brew"),
new Coffee("Sumatra")
));
}
public RestAPIDemoController() {
this.coffeeRepository = null;
};
//#RequestMapping(value = "/coffees", method = RequestMethod.GET)
#GetMapping
Iterable<Coffee> getCoffees() {
return coffeeRepository.findAll();
}
#GetMapping("/{id}")
Optional<Coffee> getCoffeeById(#PathVariable String id) {
return coffeeRepository.findById(id);
}
#PostMapping
Coffee postCoffee(#RequestBody Coffee coffee) {
return coffeeRepository.save(coffee);
}
#PutMapping("/{id}")
ResponseEntity<Coffee> putCoffee(#PathVariable String id, #RequestBody Coffee coffee) {
return (!coffeeRepository.existsById(id))
? new ResponseEntity<>(coffeeRepository.save(coffee), HttpStatus.CREATED)
: new ResponseEntity<>(coffeeRepository.save(coffee), HttpStatus.OK);
}
#DeleteMapping("/{id}")
void deleteCoffee(#PathVariable String id) {
coffeeRepository.deleteById(id);
}
}
Here is where I'm defining the interface:
package com.bw.restdemo;
import org.springframework.data.repository.CrudRepository;
interface CoffeeRepository extends CrudRepository<Coffee, String> {
}
And here's the main class -- apologies for the class stuffed at the bottom.
package com.bw.restdemo;
import java.util.UUID;
import javax.persistence.Entity;
import javax.persistence.Id;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class RestDemoApplication {
public static void main(String[] args) {
SpringApplication.run(RestDemoApplication.class, args);
}
}
#Entity
class Coffee {
#Id
private String id;
private String name;
public Coffee(String id, String name) {
this.id = id;
this.name = name;
}
public void setId(String id) {
this.id = id;
}
public Coffee(String name) {
this(UUID.randomUUID().toString(), name);
}
public String getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
CoffeeRepository interface is missing #Repository Annotation.
Update:
Add #Repository Annotation at CoffeeRepository
Remove the default constructor from RestAPIDemoController.
package com.bw.restdemo;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
#Repository
interface CoffeeRepository extends CrudRepository<Coffee, String> {
}
Explanation
In spring framework, #Component annotation marks a java class as a bean so the component-scanning mechanism can pick it up and pull it into the application context. As #Repository serves as a specialization of #Component , it also enable annotated classes to be discovered and registered with application context.
More at HowToDoInJava - #Repository annotation in Spring Boot

How to Autowire LdapRepository in Spring?

I am attempting to use Spring's auto-configuration to spin up an embedded LDAP server and access it using spring-data-ldap. However, the autowired fields, repository (an instance of LdapRepository) and the ldapTemplate (an instance of the LdapTemplate) are null.
For example,
spring.ldap.model.UserTest > testSaveUser FAILED
java.lang.NullPointerException at UserTest.java:32
What am I missing?
build.gradle
plugins {
id 'org.springframework.boot' version '2.0.6.RELEASE' apply false
}
apply plugin: 'io.spring.dependency-management'
apply plugin: 'java'
repositories {
jcenter()
}
dependencyManagement {
imports {
mavenBom org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES
}
}
dependencies {
compile 'org.springframework.data:spring-data-ldap'
compile 'com.unboundid:unboundid-ldapsdk'
testCompile 'org.springframework.boot:spring-boot-starter-data-ldap'
testCompile 'org.springframework.boot:spring-boot-starter-test'
}
sourceCompatibility = '1.8'
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
Under src/main/java/spring/ldap/model:
Config.java
package spring.ldap.model;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.ldap.repository.config.EnableLdapRepositories;
#Configuration
#EnableLdapRepositories
public class Config { }
User.java
package spring.ldap.model;
import javax.naming.Name;
import org.springframework.ldap.odm.annotations.Attribute;
import org.springframework.ldap.odm.annotations.DnAttribute;
import org.springframework.ldap.odm.annotations.Entry;
import org.springframework.ldap.odm.annotations.Id;
#Entry(objectClasses = { "person", "top" }, base="dc=spring,dc=ldap,dc=model" )
public class User {
#Id private Name dn;
#Attribute(name = "cn") #DnAttribute(value = "cn", index = 0) private String userName;
#Attribute(name = "sn") private String fullName;
public Name getDn() { return dn; }
public void setDn(Name dn) { this.dn = dn; }
public String getUsername() { return userName; }
public void setUsername(String userName) { this.userName = userName; }
public String getFullName() { return fullName; }
public void setFullName(String fullName) { this.fullName = fullName; }
}
UserRepository.java
package spring.ldap.model;
import org.springframework.data.ldap.repository.LdapRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface UserRepository extends LdapRepository<User> { }
Under src/test/java/spring/ldap/model:
UserTest.java
package spring.ldap.model;
import static org.junit.Assert.assertNotNull;
import javax.naming.Name;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.ldap.DataLdapTest;
import org.springframework.ldap.core.DirContextAdapter;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.support.LdapNameBuilder;
import org.springframework.test.context.ContextConfiguration;
#DataLdapTest()
#ContextConfiguration(classes = Config.class)
public class UserTest {
#Autowired UserRepository repository;
#Autowired LdapTemplate ldapTemplate;
#Before
public void SetUp() {
LdapNameBuilder builder = LdapNameBuilder.newInstance();
builder.add("dc", "model");
builder.add("dc", "ldap");
builder.add("dc", "spring");
Name dn = builder.build();
DirContextAdapter context = new DirContextAdapter(dn);
context.setAttributeValues("objectclass", new String[] { "top", "domain", "extensibleObject" });
context.setAttributeValue("dc", "spring");
ldapTemplate.bind(context);
}
#Test public void testSaveUser() {
User user = new User();
user.setUsername("ncornish");
user.setFullName("Nicholas Cornish");
repository.save(user);
assertNotNull("Id was not generated!", user.getDn());
}
}
Under src/test/resources:
application.properties
spring.ldap.embedded.base-dn=dc=spring,dc=ldap,dc=model
spring.ldap.embedded.credential.username=uid=admin
spring.ldap.embedded.credential.password=secret
Must put these annotations on test class context:
#RunWith(SpringRunner.class)
#SpringBootTest(classes = { UserRepository.class, LdapTemplate.class })
#ContextConfiguration(classes = Config.class)
#EnableConfigurationProperties
Kind regards.
Thanks JB Nezit, your comment
Your test doesn't run into a Spring context, since it's not annotated
with #RunWith(SpringRunner.class). So nothing will ever autowire
anything inside it.
resolves the issue. ie. add the following to the test class
#RunWith(SpringRunner.class)

Managing transactions of dynamically created objects in spring

I have a web service which receives a data object(Let's call the class Student). At the web service, I wrap it using a StudentWrapper object as follows
new StudentWrapper(student)
and I want the StudentWrapper class to have methods such as save which would save the data to the database. I want to use the spring framework to annotate the save method so that it will run within a transaction. But then the StudendWrapper object would have to be a spring bean(defined in XML). If it is a spring bean, then I won't be instantiating it as I have shown above.
My question is how can I make the StudentWrapper a Spring bean (so that I can use Spring annotations to manage the transactions) but pass the Student object (that I receive over the web service) in to the StudentWrapper?
If there are any other suggestions that would help me in solving this problem, please share them as well.
If you really want to create the object using a constructor, make the StudentWrapper #Configurable and read up about using AspectJ to create prototype bean definitions for domain objects (section 9.8 of the reference manual.)
A simpler alternative, if you don't want to go with AspectJ but don't want a direct dependency on Spring is to encapsulate the prototype bean creation in a factory. I'll show you using JavaConfig, though you can do something similar in XML.
First the student object...
package internal;
public class Student {
private String name;
public Student(String name) {
this.name = name;
}
public String getName() {
return name;
}
#Override
public String toString() {
return "Student{name='" + name + "'}";
}
}
And now the wrapper object...
package internal;
public class StudentWrapper {
private Student student;
public StudentWrapper(Student student) {
this.student = student;
}
public Student getStudent() {
return student;
}
#Override
public String toString() {
return "StudentWrapper{student='" + student + "'} " + super.toString();
}
}
And now the factory,
package internal;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
#Component
public class StudentWrapperFactory {
#Autowired
private ApplicationContext applicationContext;
public StudentWrapper newStudentWrapper(Student student) {
return (StudentWrapper) this.applicationContext.getBean("studentWrapper", student);
}
}
And now the JavaConfig, equivalent to an XML configuration
package internal;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
#Configuration
#ComponentScan(basePackages = "internal")
public class FooConfig {
#Bean
#Scope("prototype")
public StudentWrapper studentWrapper(Student student) {
return new StudentWrapper(student);
}
}
Finally the unit test...
package internal;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {FooConfig.class})
public class FooIntegrationTest {
#Autowired
private StudentWrapperFactory studentWrapperFactory;
#Test
public void foo() {
Student student1 = new Student("student 1");
Student student2 = new Student("student 2");
StudentWrapper bean1 = this.studentWrapperFactory.newStudentWrapper(student1);
StudentWrapper bean2 = this.studentWrapperFactory.newStudentWrapper(student2);
System.out.println(bean1);
System.out.println(bean2);
}
}
produces
StudentWrapper{student='Student{name='student 1'}'} internal.StudentWrapper#1b0fa7ff
StudentWrapper{student='Student{name='student 2'}'} internal.StudentWrapper#20de643a
As you can see from the object references of StudentWrapper, they're different prototype beans. #Transactional methods should work as expected in StudentWrapper.

Resources