Reputation: 1889
I keep looking at my codes all day along, I can't find the cause. The repository (@Repository) is working just fine, it's the @Service field that I keep failing get it autowired, I keep struggling since everything looks fine
The dispatched servlet:
<mvc:annotation-driven />
<context:component-scan base-package="com" />
com.repository
Repo.java
package com.repository;
import com.domain.Student;
import java.util.List;
public interface Repo { public List<Student> getAllSiswa(); }
RepoImplement.java
import com.domain.Student;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Repository;
@Repository
public class RepoImplement implements Repo {
List<Student> ls = new ArrayList<>();
public RepoImplement(){
Student s1 = new Student();
s1.setNama("paul");
Student s2 = new Student();
s2.setNama("robert");
ls.add(s1);
ls.add(s2);
}
@Override
public List<Student> getAllSiswa() {
return this.ls;
}
}
package com.service;
Serve.java
import com.domain.Student;
import java.util.List;
public interface Serve {
void changeName(String namaBaru);
public List<Student> newList();
}
I'm suspecting there's something wrong over here
ServeImplement.java
import com.domain.Student;
import com.repository.Repo;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class ServeImplement implements Serve {
@Autowired
public Repo repo;
List<Student> s = repo.getAllSiswa(); // THIS IS SUSPECTING ME.
@Override
public void changeName(String namaBaru) {
s.get(0).setNama(namaBaru); // get first Student, then update its name.
}
@Override
public List<Student> newList() {
return this.s;
}
}
controller2.java (it's the mapping request for serving student)
package com.controlller;
import com.domain.Student;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import com.service.Serve;
@Controller
public class controller2 {
@Autowired
public Serve serv;
@RequestMapping("/changename")
public ModelAndView sdaf() {
serv.changeName("New name");
List<Student> list = serv.newList();
return new ModelAndView("page2", "out", list);
}
}
The error:
Error creating bean with name 'controller2': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: public com.service.Serve com.controlller.controller2.serv; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'serveImplement' defined in file [C:\Users\hans\Documents\NetBeansProjects\WebApplication2\build\web\WEB-INF\classes\com\service\ServeImplement.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.service.ServeImplement]: Constructor threw exception; nested exception is java.lang.NullPointerException
Upvotes: 1
Views: 163
Reputation: 909
Because Autowired
on field happens right after construction, you need to change your code in order to get it to work.
This should works:
@Service
public class ServeImplement implements Serve {
public Repo repo;
List<Student> s;
@Autowired
public ServeImplement(Repo repo) {
this.repo = repo;
s = repo.getAllSiswa();
}
@Override
public void changeName(String namaBaru) {
s.get(0).setNama(namaBaru); // get first Student, then update its name.
}
@Override
public List<Student> newList() {
return this.s;
}
}
Moreover, using Autorwired
annotation on constructor allow you to mark your field as final
if the instance shouldn't have to change.
Upvotes: 1
Reputation: 691635
You need to understand how autowiring, or in fact Java in general, works.
Spring must create an instance of your ServImpl class, and populate the field repo
with the repository bean. It does that using reflection, but what it does is basically equivalent to the following code:
ServImpl s = new ServImpl();
s.repo = theRepoBean;
So, you see that s.repo
becomes non-null after the constructor has been executed. And, while executing the constructor, the following line of code is executed:
List<Student> s = repo.getAllSiswa();
At that moment, repo
hasn't been initialized yet. So it's null. So you get a NullPointerException.
Use constructor injection instead of field injection, or use a @PostConstruct
annotated method.
And please, make your fields private instead of public.
That said, the goal of a repository is normally to get data from a database. And the students can be modified,deleted or created in the database. So initializing a field of your service and returning always the same list defeats the whole point of having a repo. You should call repo.getAllSiswa()
from newList(), every time it's called, to get the latest, up-to-date, list of students.
Upvotes: 4