0

I am developing simple Hibernate project with Spring IoC and faced stupid NPE during injection. Both xml and Java style Spring configurations turned out to be inefficient and I stuck. Any help will be appreciated.

Exception I meet:

Exception in thread "main" java.lang.NullPointerException
at com.phoneBook.DAO.ContactDAOImpl.getSession(ContactDAOImpl.java:22)
at com.phoneBook.DAO.ContactDAOImpl.save(ContactDAOImpl.java:28)
at com.phoneBook.DAO.ContactDAOImpl.main(ContactDAOImpl.java:61)

My application-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
                            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
                            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
                            http://www.springframework.org/schema/tx  http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">

    <context:component-scan base-package="com.phoneBook" />

    <tx:annotation-driven transaction-manager="transactionManager" />

    <bean id="propertyConfigurer"
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location" value="classpath:properties/database.properties" />
    </bean>

    <bean id="dataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${jdbc.driverClassName}" />
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
    </bean>

    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="packagesToScan" value="com.phoneBook.entities" />
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                <prop key="hibernate.flushMode">${hibernate.flushMode}</prop>
                <prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
            </props>
        </property>
    </bean>

    <bean id="transactionManager"
        class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

    <bean id="persistenceExceptionTranslationPostProcessor"
        class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
</beans>

application-context.xml

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">

    <context:component-scan base-package="com.phoneBook" />

</beans>

Contact.class

package com.phoneBook.entities;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="contacts")
public class Contact {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="contact_id")
private int id;

@Column(name="contact_surname", nullable = false, length = 20)
private String surname;

@Column(name="contact_name", nullable = false, length = 20)
private String name;

@Column(name="contact_patname", nullable = false, length = 20)
private String patName;

@Column(name="contact_mobtel", unique = true, nullable = false, length = 12)
private String telNumberMob;

@Column(name="contact_hometel", length = 12)
private String telNumberHome;

@Column(name="contact_address", length = 30)
private String address;

@Column(name="contact_email", length = 20)
private String email;

    public Contact(){}

    public Contact(String surname, String name, String patName, String mobTel, String homeTel, String address, String email){
        this.surname = surname;
        this.name = name;
        this.patName = patName;
        this.telNumberMob = mobTel;
        this.telNumberHome = homeTel;
        this.address = address;
        this.email = email;
    }
    //getters and setters

}

and ContactDAOimpl.java

    package com.phoneBook.DAO;

import java.util.List;

import javax.transaction.Transactional;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.phoneBook.entities.Contact;

@Repository
@Transactional
public class ContactDAOImpl implements ContactDAO {
    @Autowired
    private SessionFactory sessionFactory;   

    protected Session getSession(){
         return sessionFactory.getCurrentSession();
    }

    @Override
    public void save(Contact cont) {
        if(cont.getId()==0)
            getSession().persist(cont);
        else
            getSession().update(cont);
    }

    @Override
    public Contact getById(int id) {
        Contact contact = (Contact)getSession().createCriteria(Contact.class).add(Restrictions.eq("id",id)).uniqueResult();
          return contact;
    }

    @Override
    public List<Contact> getAll() {
        @SuppressWarnings("unchecked")
        List<Contact> allContacts = sessionFactory.getCurrentSession().createCriteria(Contact.class).list();
        return allContacts;
    }

    @Override
    public int remove(Contact cont) {
        getSession().delete(cont);
        return cont.getId();
    }

    public static void main(String args[]){
        ContactDAOImpl dao = new ContactDAOImpl();
        Contact testContact = new Contact("name", "surname", "patname", "380442322233", "380442322233", 
                "address", "name@gmail.com");
        dao.save(testContact);
    }

}

My dependencies:

Dependencies

ryzhman
  • 674
  • 10
  • 22

3 Answers3

0

Your sessionFactory is null - is the sessionFactory bean being created or is the autowire simply failing to find it?

Lee
  • 738
  • 3
  • 13
  • Thanks for a response. How can I check it? – ryzhman May 05 '16 at 11:51
  • Download the sources for `org.springframework.orm.hibernate4.LocalSessionFactoryBean` and put a break point in the constructor. – Lee May 05 '16 at 11:52
  • Thanks for a hint, but Sessionfactory is initialised correctly. The problem is in beans wiring and context invocation. – ryzhman May 05 '16 at 13:24
0

You did not initialize your application context

ApplicationContext context = new ClasspathApplicationContext("application-config.xml")

or using annotations:

@Configuration
@ImportXml("classpath:application-config.xml")
hasnae
  • 2,137
  • 17
  • 21
0

You can't do it

ContactDAOImpl dao = new ContactDAOImpl();

  1. You should add contactDao to the application-config.xml.
  2. Create a spring context, as @hasnae suggested

    ApplicationContext context = new ClasspathApplicationContext("application-config.xml");

  3. Get contactDao form the context

    ContactDAO contactDao = (ContactDAO) context.getBean("contactDao");

As a quick fix, you can get sessionFactory form the context and set it to the contactDao (It is just for an illustration, as you you will not have a transactions and save() will not work)

ContactDAOImpl contactDao = new ContactDAOImpl();
contactDao.setSessionFactory((SessionFactory)context.getBean("sessionFactory"));

You need to add a setter for it.

v.ladynev
  • 19,275
  • 8
  • 46
  • 67
  • But I considered and appropriate annotations to be enough to invoke context without an explicit call. Another issue is transaction: even though I marked class as @Transactional, I still face the "No Session found for current thread". What is the way out? – ryzhman May 05 '16 at 13:44
  • `` works for all nested beans except the first root bean. Spring knows nothing about your code and can't auto ware a session factory with `ContactDAOImpl dao = new ContactDAOImpl()`. You need to get `dao` from a spring context to let Spring add a transaction support for it. – v.ladynev May 05 '16 at 13:49
  • But if I create new ContactDAOImpl() and it has an injected Session, why shouldn't Spring do what it is supposed to? And could you please elaborate your idea about "first root bean": if I inject DAO instance (includes Injected Session property) from Service layer, I don't have to do any extra job, ain't I? – ryzhman May 05 '16 at 14:11
  • @ryzhman In your example `ContactDAOImpl` is a root bean. If you don't get it from a Spring context and create with `new ContactDAOImpl()`, and set `sessionFactory` manually — a root bean is `sessionFactory`. If you get a service from a Spring context, DAO and a session factory will be injected by Spring. – v.ladynev May 05 '16 at 14:50
  • Thanks for explanations! Small offtopic: if an application is based on an application web server, is it the server that is responsible for the creation of Spring context and root bean? – ryzhman May 05 '16 at 18:36
  • @ryzhman The server is not responsible. Spring MVC can be responsible for it, if you use it. Or you can use a context listener http://stackoverflow.com/a/6451410/3405171, but you need to get the root bean yourself. Such root bean can be java based configuration: http://www.tutorialspoint.com/spring/spring_java_based_configuration.htm. I speak about _the root bean_ for the sake of simplicity. In a real application every service can be such root bean. – v.ladynev May 06 '16 at 06:25