• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Spring, @Autowired NullPointerException przy tworzeniu instancji serwisu

Object Storage Arubacloud
0 głosów
253 wizyt
pytanie zadane 4 sierpnia 2018 w Java przez Przemyslaw Użytkownik (610 p.)

Cześć! Tworzę aplikację webową za pomocą Springa 5, ale niestety mam problem, bo gdy tworzę obiekt za pomocą IoC, zwraca mi w miejsce tego obiektu null.

AccountDAOImpl

package main.com.java.dao.implementation;

import java.util.List;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.query.Query;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import main.com.java.dao.interfaces.AccountDAO;
import main.com.java.entity.Account;;import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;

@Repository
public class AccountDAOImpl implements AccountDAO{

    @Autowired
    private SessionFactory sessionFactory;

    public Session createCurrentSession(SessionFactory sessionFactory){
        Session session = sessionFactory.getCurrentSession();
        return session;

    }

    @Override
    @Transactional
    public List<Account> getAccountList() {     
        Query<Account> theQuery = createCurrentSession(sessionFactory).createQuery("from Account", Account.class);      
        List<Account> accountsList = theQuery.getResultList();

        return accountsList;
    }

    @Override
    public Account getAccountById(int id) {
        try {           
            return createCurrentSession(sessionFactory).get(Account.class, id);     
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }

    }

    @Override
    public void addAccount(Account theAccount) {
        try {
            Session currentSession = sessionFactory.getCurrentSession();
            currentSession.saveOrUpdate(theAccount);
            currentSession.clear();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    @Override
    public void updateAccount(Account theAccount) {
        try {
            createCurrentSession(sessionFactory).saveOrUpdate(theAccount);
        } catch (Exception e) {
            e.printStackTrace();
        } 
    }

    @Override
    public void removeAccount(Account theAccount) {
        try {
            createCurrentSession(sessionFactory).remove(theAccount);
        } catch (Exception e) {
            e.printStackTrace();
        } 

    }

    @Override
    public void saveAccount(Account theAccount) {
        // get hibernate session
        Session currentSession = sessionFactory.getCurrentSession();

        //save the account 
        currentSession.saveOrUpdate(theAccount);
        currentSession.clear();
    }

    @Override
    public List<String> getAccountNumberList(){

        CriteriaBuilder builder = sessionFactory.getCurrentSession().getCriteriaBuilder();
        CriteriaQuery<String> query = builder.createQuery(String.class);
        System.out.print("query = " + query);
        Root<Account> root = query.from(Account.class);
        query.select(root.get("accountNumber"));
        Query<String> theQuery = createCurrentSession(sessionFactory).createQuery(query);

        return theQuery.getResultList();
    }

}

AccountServiceImpl

package main.com.java.service.domain.implementation;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import main.com.java.dao.interfaces.AccountDAO;
import main.com.java.entity.Account;
import main.com.java.service.domain.interfaces.AccountService;

import java.util.List;

@Service
public class AccountServiceImpl implements AccountService {

    @Autowired
    AccountDAO accountDAO;

    @Override
    @Transactional
    public void addAccount(Account theAccount) {
        accountDAO.addAccount(theAccount);
    }

    @Override
    @Transactional
    public List<String> getAccountNumberList(){
        System.out.print("AccountServiceImpl");
        return accountDAO.getAccountNumberList();
    }

}

AccountNumberGenerator

package main.com.java.service.business.generators;

import main.com.java.service.domain.interfaces.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Random;

@Service
public class AccountNumberGenerator {

    @Autowired
    AccountService accountService;

    @Transactional
    public String generateAccountNumber(){
        String potentialAccountNumber = generatePotentialAccountNumber();
        if(checkIsAccountNumberIsFree(potentialAccountNumber)){
           return potentialAccountNumber;
        }else{
            while(checkIsAccountNumberIsFree(potentialAccountNumber)){
                potentialAccountNumber = generatePotentialAccountNumber();
            }
            return generatePotentialAccountNumber();
        }
    }

    private String generatePotentialAccountNumber(){
        String checksum = generateChecksum();
        String bankNumber = "12853321";
        String clientNumber = generateClientNumber();
        String accountNumber = "";

        StringBuilder stringBuilder = new StringBuilder(accountNumber);
        stringBuilder.append(checksum).append(bankNumber).append(clientNumber);

        return stringBuilder.toString();
    };

    private  boolean checkIsAccountNumberIsFree(String potentialAccountNumber){
        List<String> occupiedAccountNumberList = accountService.getAccountNumberList();
        for (String occupiedAccountNumber : occupiedAccountNumberList) {
            if(potentialAccountNumber.equals(occupiedAccountNumber)){
                return Boolean.FALSE;
            }
        }
        return Boolean.TRUE;

    };

    private static String generateChecksum(){
        Random random = new Random();
        String checksum = "";
        StringBuilder stringBuilder = new StringBuilder(checksum);

        for (int i =0; i<2; i++){
            stringBuilder.append(random.nextInt(10));
        }
        checksum = stringBuilder.toString();
        return checksum;
    };

    private String generateClientNumber(){
        Random random = new Random();
        String clientNumber = "";
        StringBuilder stringBuilder = new StringBuilder(clientNumber);

        for (int i =0; i<16; i++){
            stringBuilder.append(random.nextInt(10));
        }
        clientNumber = stringBuilder.toString();
        return clientNumber;
    }

}

NullPointerException wyrzuca w metodzie checkIsAccountNumberIsFree() w klasie AccountNumberGenerator w linijce:

List<String> occupiedAccountNumberList = accountService.getAccountNumberList();

Wykorzystując debuggera, zauważyłem że accountService zwraca null.

Czy mógłby ktoś pomóc?

Config

<?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:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context
		http://www.springframework.org/schema/context/spring-context.xsd
		http://www.springframework.org/schema/mvc
		http://www.springframework.org/schema/mvc/spring-mvc.xsd
		http://www.springframework.org/schema/tx 
		http://www.springframework.org/schema/tx/spring-tx.xsd">

	<!-- Add support for component scanning -->
	<context:component-scan base-package="main.com.java" />

	<!-- Add support for conversion, formatting and validation support -->
	<mvc:annotation-driven/>

	<!-- Define Spring MVC view resolver -->
	<bean
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/view/" />
		<property name="suffix" value=".jsp" />
	</bean>

    <!-- Step 1: Define Database DataSource / connection pool -->
	<bean id="myDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
          destroy-method="close">
        <property name="driverClass" value="com.mysql.jdbc.Driver" />
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/bank_application?useSSL=false" />
        <property name="user" value="admin" />
        <property name="password" value="admin" /> 

        <!-- these are connection pool properties for C3P0 -->
		<property name="initialPoolSize" value="5"/>
        <property name="minPoolSize" value="5" />
        <property name="maxPoolSize" value="20" />
        <property name="maxIdleTime" value="30000" />
	</bean>  
	
    <!-- Step 2: Setup Hibernate session factory -->
	<bean id="sessionFactory"
		class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
		<property name="dataSource" ref="myDataSource" />
		<property name="packagesToScan" value="main.com.java.entity" />
		<property name="hibernateProperties">
		   <props>
		      <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
		      <prop key="hibernate.show_sql">true</prop>
		   </props>
		</property>
   </bean>	  

    <!-- Step 3: Setup Hibernate transaction manager -->
	<bean id="myTransactionManager"
            class="org.springframework.orm.hibernate5.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>
    
    <!-- Step 4: Enable configuration of transactional behavior based on annotations -->
	<tx:annotation-driven transaction-manager="myTransactionManager" />

	<!-- Add support for reading web resources: css, images, js, etc ... -->
	<mvc:resources location="/resources/" mapping="/resources/**"></mvc:resources>
	
	
	
</beans>

 

1 odpowiedź

+1 głos
odpowiedź 4 sierpnia 2018 przez Aisekai Nałogowiec (42,190 p.)
wybrane 4 sierpnia 2018 przez Przemyslaw
 
Najlepsza
Pierwsze co bym zrobił, to usunął wiązanie przez pole. NAJGORSZE z możliwych wiązań, bo maksymalnie uzależniasz swoją aplikację od Springa i próba zrezygnowania z niego (na rzecz innego Frameworka, hipotetyczna sytuacja) będzie się wiązała z zmianą kodu w wielu miejscach.

Używaj powiązania przez settery albo, najlepiej przez konstruktor, najbardziej naturalny sposób wiązania dla programowania obiektowego.

Jak już to zmienisz, to daj znać czy coś pomogło.

PS: Plus dla Ciebie, że poszukałeś miejsca gdzie znajduje się błąd. Minus taki, że źle wskazałeś gdzie jest błąd (zamiast pisać w jakiej funkcji jest błąd, gdy wrzucasz 77 linijek kodu, a pomyśl co by było gdyby było ich 500, to podałeś nazwę funkcji - szanujmy swój czas) oraz wrzuciłeś bardzo dużo niepotrzebnego kodu (skoro zlokalizowałeś, że błąd jest prawdopodobnie w 43 linii oraz wiesz, że jest on spowodowany nullem to prawdopodobnie coś się niepowiązało tak jak powinno, więc po kiego grzyba wrzucasz niepotrzebny kod który np generuje jakąś sumę?)

PS2: Czy to na pewno jest Spring 5? Mi to wygląda na, co najwyżej, Spring 3 i archaicznego xmla.
komentarz 4 sierpnia 2018 przez Wiciorny Ekspert (270,150 p.)

Używaj powiązania przez settery 

to jest najgorsze rozwiązanie...  Przy atuomatyzacji lepiej już przez Pole- ale najlepiej zgadzam się jedynie przez Konstruktor.

Druga sprawa wiązanie przez settera może powodować błędy np przy korzystaniu z Hibernate,  jeśli nie uwzględnimy DDD  wspólnego dla wszystkiego, to np robiąc  raz setery raz pola, to Tryb dostępu do całej klasy się zmienia przez hibernate np... i się wysypie 

2
komentarz 4 sierpnia 2018 przez Aisekai Nałogowiec (42,190 p.)
Z tego co słyszałem, to najgorsze jest właśnie przez pole bo całkowicie uzależnia się aplikację od Springa. Ale i tak najlepiej przez konstruktor.

Mówiąc, żeby używał przez settery mówiłem to w ramach ciekawostki że przez setter też się da. Ale tak jak już wczesniej wspomniałem, najlepiej przez konstruktor.

Ale dzięki, będę pamietal minusy wiazania przez settery :)
1
komentarz 4 sierpnia 2018 przez Przemyslaw Użytkownik (610 p.)
Bus is solved!

Problemem nie było wiązanie przez pole.

Aczkolwiek zmieniłem na wiązanie za pomocą konstruktora, IDE dopiero wtedy pokazało mi, że w controllerze, próbuję stworzyć obiekt za pomocą "new" a nie Spring'a.

Obiecuję zagłębić się w lekturze, odnośnie którego wiązania używać.

Ad. PS1: Przepraszam za zbyt dużą ilość niepotrzebnego kodu, jednak nie chciałem tutaj żadnych niedomówień(de facto i tak nie wrzuciłem kodu controllera, który powodował błędy). Podejrzewam, że wyczucie odnośnie ilości wrzucanego kodu, przyjdzie z czasem.

Ad. PS2: Tak, są to biblioteki Spring'a 5. Używam póki co konfiguracji za pomocą XMLa, gdyż tak zaczęła osoba, która prowadziła kurs na udemy. W planach jest zmiana typu konfiguracji na kod javy, tak już mam konfigurowane komponenty security.

Podobne pytania

0 głosów
1 odpowiedź 140 wizyt
pytanie zadane 8 lutego 2018 w Java przez Mrmatiii Początkujący (300 p.)
0 głosów
1 odpowiedź 515 wizyt
pytanie zadane 14 października 2021 w Java przez Tajniakkk Użytkownik (600 p.)
+1 głos
1 odpowiedź 440 wizyt
pytanie zadane 14 sierpnia 2021 w Java przez DziQu Początkujący (420 p.)

92,572 zapytań

141,423 odpowiedzi

319,645 komentarzy

61,959 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...