NullPointerException of JDBC Template in DAO Constructor - spring

I am new to Spring Boot and was trying to implement the below code for Spring Boot JDBC. I am getting a NullPointerException in the this.jdbcTemplate in the UserDao constructor while running the application. I think the error is because the UserDao constructor is being called before the instantiation of JdbcTemplate. Is that correct?
I haven't come across this error until now where the #Autowired cannot resolve the dependencies. Can someone please elaborate upon the reason for the error?
SpringBootDatabaseApplication.java
package com.mrityu.springbootdatabase;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class SpringBootDatabaseApplication {
#Autowired
private UserDao userDao;
public static void main(String[] args) {
SpringApplication.run(SpringBootDatabaseApplication.class, args);
}
}
UserDao.java
package com.mrityu.springbootdatabase;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
#Repository
public class UserDao {
#Autowired
private JdbcTemplate jdbcTemplate;
public UserDao() {
String query = "create table if not exists User(id int primary key, name varchar(200))";
int update = this.jdbcTemplate.update(query);
System.out.println("Constructor Called: " + update);
}
}

I didn't try to run the code, but you're trying to use the uninitialized jdbcTemplate field in your constructor.
Constructor base injection should do the trick
public UserDao(JdbcTemplate jdbcTemplate) {...}
Otherwise, you can still use field injection and move your logic into a method.
public void yourMethod() {
String query = "create table if not exists User(id int primary key, name varchar(200))";
int update = this.jdbcTemplate.update(query);
System.out.println("Method Called: " + update);
}
In your case, it's about how java initializes classes, not spring boot auto wiring.
You can check this answer for the dependency injection precedence.

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);
}
}

#Autowired is Null in Spring Boot but same is accessible through Application Context

Through #Autowired i am not able to access the #Component/#Service/#Respository/#Controller class objects in other java files which has #Component annotation (Step 1: Approach) with the Step 1 approach getting Null pointer Exception, but same i could achieve using (Step 2: Approach).
Can anyone please tell me why i am not able to achieve using Step 1 approach:
FYI- I've searched in my entire project i have not used/called/initialized the #Component classes using new method for the autowired class still i getting the issue as "Null Pointer Exception"
Step 1: Using #Autowired Annotation
#Component
public class Processor {
#Autowired
PropertyConfigurator propconfigrator; --> Getting here as null pointer Exception
public void getDetails(){
System.out.println ("Application URL +propconfigrator.getProperties().getProperty("appURL"));
}
}
Step 2: Using ApplicationContext Interface with/without #AutoWired annotation . I am able to get the property value from PropertyConfigurator java file
#Component
public class Processor {
#Autowired
PropertyConfigurator propconfigrator = ApplicationContextHolder.getContext().getBean(PropertyConfigurator.class);
public void getDetails(){
System.out.println ("Application URL +propconfigrator.getProperties().getProperty("appURL"));
}
}
ApplicationContextHolder.java
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
#Component
public class ApplicationContextHolder implements ApplicationContextAware {
private static ApplicationContext context;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
public static ApplicationContext getContext() {
return context;
}
}
PropertyConfigurator.java file
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
#Service
#Configurable
public class PropertyConfigurator {
private final Properties properties;
public Properties getProperties () {
return properties;
}
public PropertyConfigurator(){
properties = new Properties();
try {
properties.load(getClass().getClassLoader().getResourceAsStream("dbconfig.properties"));
} catch (IOException e) {
Logger.getLogger(getClass().getName()).log(Level.SEVERE, e.getMessage(), e);
}
}
}
Why did you use #Configurable annotation? In the code you postet, it doesn't make sense. #Configurable is only needed in cases when instances of this class are not createt by spring.
I have changed into Constructor Injection Autowiring as below with the step 1 approach of above (Not using Step 2. It resolved my issue finally.
Not sure why Spring is not able to inject the bean without using the Constructor Autowiring.
Step 1: Using #Autowired Annotation with Constructor
#Component
public class Processor {
#Autowired
public Processor (PropertyConfigurator propconfigrator) {
this.propconfigrator = propconfigrator;
}
public void getDetails(){
System.out.println ("Application URL +propconfigrator.getProperties().getProperty("appURL"));
}
}

Cannot inject property value to class parameter (#Value annotatnion)

I'm learing Spring Boot and I have probably very simple question, but it's not clear enough for me. I'm facing some problem with #Value annotation - I would like to know why apprication property cannot be injected to class parameter.
I prepared some very basic project using Spring Initializr and I added one property to my "application.properties" resource. Moreover, I created two additional classes: "YellowCar" (which works fine) and "RedCar" (which does not work - the parameter cannot be properly injected).
"application.properties" file:
car.age=15
The main class of my application:
package com.example.helper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.core.env.Environment;
#SpringBootApplication
public class HelperApplication implements CommandLineRunner {
#Autowired
private Environment env;
public static void main(String[] args) {
SpringApplication.run(HelperApplication.class, args);
}
#Override
public void run(String... args) throws Exception {
System.out.println (new RedCar(env));
System.out.println (new YellowCar());
}
}
RedCar is build by passing the Environment variable to constructor:
package com.example.helper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
#Component
public class RedCar {
private int age;
#Autowired
public RedCar (Environment env) {
this.age = new Integer(env.getRequiredProperty("car.age")).intValue();
}
#Override
public String toString() {
return "Car [age=" + age + "]";
}
}
YellowCar is build without passing the Environment variable to the constructor, but using the #Value annotation:
package com.example.helper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
#Component
public class YellowCar {
#Value("${car.age}")
private int age;
#Override
public String toString() {
return "YellowCar [age=" + age + "]";
}
}
This is the program output:
Car [age=15]
YellowCar [age=0]
As you can see, age of YellowCar was not properly injected (it equals 0).
My goal: I'd like not to pass everywhere Environment object to the constructor of other classes... I'd like to use #Value annotatnio instead. Could somebody explain me:
1) why my code is not working?
2) how this code should be updated in order to get the following output?
Car [age=15]
YellowCar [age=15]
Thanks!
This happens, because you instantiate YellowCar directly. In order to make thing work, #Autowire YellowCar inside HelperApplication and use this injected instance like this(not tested):
#Autowired
private YellowCar yellowCar;
public static void main(String[] args) {
SpringApplication.run(HelperApplication.class, args);
}
#Override
public void run(String... args) throws Exception {
System.out.println (new RedCar(env));
System.out.println (yellowCar);
}
Explanation:
When you creating class using new, Spring knows nothing about this new instance, hence, it cannot inject anything. But when instance is created through Spring infrastructure (I'm trying not use a lot of slang words here), it will have all fields injected: when you mark class with #Component annotation or create method with #Bean annotation, you tell Spring, that you want it to be a Bean. On application startup, spring creates instances of this beans - by default only one instance per context - and inject this instance into all other beans, where requested. In this case, this instance is being processed by spring infrastructure (exact class which do it - AutowiredAnnotationBeanPostProcessor), and instances of other beans will be injected into our bean.
UPD: You can do the same thing with RedCar:
#Autowired
private YellowCar yellowCar;
#Autowired
private RedCar redCar;
public static void main(String[] args) {
SpringApplication.run(HelperApplication.class, args);
}
#Override
public void run(String... args) throws Exception {
System.out.println (redCar);
System.out.println (yellowCar);
}

Why is #Autowired working differently in application and test?

I made a sample program revealing my question:
package test;
public interface InterfaceA {
}
package test;
public class ClassA implements InterfaceA {
}
package test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class Application {
#Bean
public InterfaceA beanA() {
return new ClassA();
}
#Autowired
private ClassA beanA;
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext
= new AnnotationConfigApplicationContext(Application.class);
}
}
#Autowired doesn't work with the concrete class in this application code.
package test;
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 = Application.class)
public class ApplicationTest {
#Autowired
ClassA beanA;
#Test
public void di() {
System.out.println(beanA);
}
}
But #Autowired works with the concrete class in this test code.
Why is #Autowired working differently in application and test?
I shared the above code at:
https://github.com/izeye/SpringTest
You're using your application context in the main entry point of the application. Make an additional 'Main' class and wire in your context like so:
#Autowired
Application context;
In your test, you're taking the time to start up the application context when you use the annotation: #ContextConfiguration(classes = Application.class).
In your concrete example you're referencing the context in the same class that you're trying to use it in. When you initialize the context in the main, the instance of Application that is running the code has already been instantiated, and did not get autowired, because at the time of its instantiation there wasn't any context for it to use.
It is a bit tricky:
Solution would be to make beanA static method and annotate Application with #Lazy or #DependsOn(value="beanA") annotations. I.e. something like this:
#Configuration
#Lazy
public class Application {
#Bean
public static InterfaceA beanA() {
return new ClassA();
}
#Autowired
private ClassA beanA;
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext
= new AnnotationConfigApplicationContext(Application.class);
}
}
Reason: for actual beanA bean creation spring need to instantiate Application class first. And while trying to resolve reference to a beanA the only information container has about this future bean is its type (InterfaceA) since there is no actual implementation exists.
However in a case of test class context was already initialized and bean can be resolved by actual implementation class which physically was already created. Same would be if you will try to reference beanA by class from any other spring component.

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