I try to write some programme using Java, Hibernate and Spring. I see NullPointerException when I call the SQL query. I tried perhaps every samples of code on the internet, but I don't know how to do this. How can I solve it? This is my sample code. There is my full code of programme: https://github.com/lukasz-chojn/films_database/tree/master/src/main/java/Films
#Controller
public class DataFromUserController {
private FilmDaoImpl filmDaoImpl = new FilmDaoImpl();
private DirectorDaoImpl directorDaoImpl = new DirectorDaoImpl();
private Locale locale = Locale.getDefault();
private Scanner sc = new Scanner(System.in).useLocale(locale);
public FilmDs collectData() {
//....
filmDaoImpl.insert(film);
directorDaoImpl.insert(director);
return film;
}
private String collectTitle() {
System.out.print("Podaj tytuł filmu: ");
String tytul = sc.nextLine();
List<String> existingEntry = filmDaoImpl.existingTitle();
if (existingEntry.contains(tytul)) {
System.out.println("Tytuł jest już w bazie. Podaj inny");
return collectTitle();
}
if (tytul.isEmpty()) {
System.out.println("Tytuł nie może być pusty. Podaj go");
return collectTitle();
}
return tytul;
}//......
}
#Service
#Transactional
public class FilmDaoImpl implements FilmDAO {
#PersistenceContext
private EntityManager entityManager;
//......
#Override
#SuppressWarnings("unchecked")
public List<String> existingTitle() {
List<String> titleInTheDatabase;
// here is NPE
return titleInTheDatabase = entityManager.createQuery("SELECT film.tytul FROM FilmDs film").getResultList();
}
//....
}
You're creating instances on your own instead of letting spring inject it for you which is why you're losing all the dependencies like entitymanager, etc. change your DataFromUserController
#Controller
public class DataFromUserController {
#Autowired
private FilmDAO filmDao;
#Autowired
private DirectorDAO directorDao;
.....
}
Related
I try write service test, for example, I have this ExamServiceImpl:
#Service
public class ExamServiceImpl implements ExamService {
#Autowired
private final SubjectService subjectService;
private final ScoreDAO scoreDAO;
#Autowired
public ExamServiceImpl(ScoreDAO scoreDAO) {
this.scoreDAO = scoreDAO;
}
#Override
public ResponseModel insertScore(RequestModel request) throws IOException {
List<TeacherModel> teacher = teacherDAO.getNameList(request);
List<StudentModel> student = studentDAO.findStudentList(teacher.get(0).getName, request.getStudentScore);
String nameStudent = student.get(0).getFirstName() + student.get(0).getLastName();
SubjectModel subject = subjectService.getNameSubject(request, nameStudent);
ScoreModel score = new ScoreModel();
score.setStudentName(request.getStudentName);
score.setScore(request.getStudentScore);
score.setSubject(subject.getName);
int result = scoreDAO.insert(score);
return result;
}
}
Sample my test:
#SpringBootTest
public class ExamServiceImplTest {
#MockBean
private ScoreDAO scoreDAO;
#Autowired
private SubjectService subjectService;
#Autowired
private ExamService examService;
#Test
void insertScoreTest() {
SubjectModel resFromSubject = new SubjectModel();
resFromSubject.setSubject("Math");
TeacherModel resTeacher = new Teacher()
resTeacher.setName("test Teacher");
StudentModel studentData = new Student();
student.setFirstName("firstname");
studebt.setLastName("lastname");
Mockito.when(teacherDAO.getNameList(new RequestModel())).thenReturn(resTeacher);
Mockito.when(studentDAO.findStudentList(anyString(), anyString())).thenReturn(studentData);
Mockito.when(subjectService.getNameSubject(Mokito.any(RequestModel.class), anyString())).thenReturn(resFromSubject);
Mockito.when(scoreDAO.insert(Mokito.any(ScoreModel.class)).thenReturn(1);
int resultTest = examService.insertScore(new RequestModel());
assertSame(ex, 1);
}
But output resultTest is error. I try debugger, I found
Mock studentDAO.findStudentList() return null >> mock is not working.
When I close code + test teacherDAO and studentDAO for test mock subjectService >> mock subjectService is not working too. (I not sure mock service should be use #Autowired or #MorkBean)
Please, could you help write me test methods? I covered with tests more simple other services.
Thank you!
You can find demo application in this blog
[https://blog.joshsoftware.com/2020/05/27/introduction-to-mockito-unit-testing-framework/][1]
I have this method and it does return a list:
public List<ReportReconciliationEntry> getMissingReports(List<ReportReconciliationEntry> expectedReports,
List<GeneratedReportContent> generatedReports){
...
return missingReports;
}
but this method is never called:
#AfterReturning(value = "execution(* com.XXX.YYY.ZZZ.service.ReconciliationService.getMissingReports(..)) && args(expectedReports,generatedReports)", argNames = "expectedReports,generatedReports,missingReports", returning = "missingReports")
public void logReportReconciliationException(List<ReportReconciliationEntry> expectedReports, List<GeneratedReportContent> generatedReports, List<ReportReconciliationEntry> missingReports) {
final String notApplicable = properties.getNotApplicable();
ReportingAlertMarker marker = ReportingAlertMarker.builder()
.eventType(E90217)
.userIdentity(notApplicable)
.destinationIp(properties.getDestinationIp())
.destinationPort(properties.getDestinationPort())
.dataIdentity(notApplicable)
.resourceIdentity(notApplicable)
.responseCode(404)
.build();
MDC.put(SYSTEM_COMPONENT, properties.getBpsReportGenerationService());
System.out.println(missingReports);
logWrapper.logError(marker, "SDGFHDZFHDFR!!");
}
I check the return of the first method with a breakpoint. It does return a list, but the #AfterReturning is never called, although the IDE shows the "Navigate to AOP advices" icon. What am I missing?
This is what my class looks like:
#Component
#Aspect
#Slf4j
public class ReportingAlertAspect {
private final LogWrapper logWrapper;
private final ReportingAlertProperties properties;
public ReportingAlertAspect(final ReportingAlertProperties properties, final LogWrapper logWrapper) {
this.logWrapper = logWrapper;
this.properties = properties;
}
....
}
I have another class with a function in it and this one works fine:
#Component
#Aspect
#Slf4j
public class ReportingInfoAspect {
private final LogWrapper logWrapper;
private final ReportingAlertProperties properties;
#AfterReturning(value = "execution(* com.xxx.yyy.zzz.qqq.ReconciliationService.reconcile(..)) && args(windowId)", argNames = "windowId,check",
returning = "check")
public void logSuccessfulReportReconciliation(ReconciliationEvent windowId, boolean check){
String notApplicable = properties.getNotApplicable();
MDC.put(SYSTEM_COMPONENT, properties.getBpsReportGenerationService());
ReportingAlertMarker marker = ReportingAlertMarker.builder()
.eventType(E90293)
.userIdentity(notApplicable)
.destinationIp(properties.getDestinationIp())
.destinationPort(properties.getDestinationPort())
.dataIdentity(notApplicable)
.resourceIdentity(notApplicable)
.responseCode(200)
.build();
if (check){
logWrapper.logInfo(marker, "All reports for windowId {} were generated successfully", windowId.windowId);
}
}
}
I found the problem.
The getMissingReports method was called from another method inside the same class. This is a case of self-invocation and the method was never called through the proxy.
This is what the class looks like:
#Service
#RequiredArgsConstructor
public class ReconciliationService {
private final ReconciliationRepository reconciliationRepository;
private final ReportSafeStoreClientService reportSafeStoreClientService;
#Handler
public whatever whatever() {
...
getMissingReports()
}
}
You can find more info here
We have to test class, see below. Our question is how can we fill the dependencies, so that we can test the original class you see below.
public class FragenAntwortenDataprovider extends SortableDataProvider<FragenAntworten, String> {
#SpringBean
private IFragenAntwortenService service;
private IModel<FragenAntworten> filter;
public FragenAntwortenDataprovider(IModel<FragenAntworten> filter){
this.filter = filter;
Injector.get().inject(this);
setSort("id", SortOrder.DESCENDING); // absteigend sortieren
}
#Override
public Iterator<? extends FragenAntworten> iterator(long first, long count){
List<FragenAntworten> list = load();
List<FragenAntworten> sublist = list.subList((int) first, (int) (first+count));
return sublist.iterator();
}
#Override
public long size() {return getListSize();}
#Override
public IModel<FragenAntworten> model(FragenAntworten object) {
return Model.of(object);
}
private void sort(final List<FragenAntworten> list){
}
private long getListSize(){
List<FragenAntworten> list = service.ladeAlle(filter.getObject().getSystem());
return list.size();
}
private List<FragenAntworten> load(){
List<FragenAntworten> list = service.ladeAlle(filter.getObject().getSystem());
return list;
}
}
Since you use Spring you can use its ReflectionUtils helper class to inject the dependency:
IFragenAntwortenService service = mock(IFragenAntwortenService.class);
IModel<FragenAntworten> model = ...;
FragenAntwortenDataprovider provider = new FragenAntwortenDataprovider(model);
Field serviceField = ReflectionUtils.findField("service", provider);
ReflectionUtils.setField(serviceField, provider, service);
Another option is to introduce package-private setter for service field and avoid using reflection.
You should have your original class have the dependencies injected with #Autowired or #Inject. Actually you should not use field injection, but constructor injection. Then you should use the #ExtendWith(MockitoExtension.class) for the JUnit 5 test class. Every dependency you have to define as a #Mock and for the class you wish to test you use the #InjectMocks annotation.
This is the constructor injection to use:
public class FragenAntwortenDataprovider extends SortableDataProvider<FragenAntworten, String> {
private IFragenAntwortenService service;
private IModel<FragenAntworten> filter;
#Inject
public FragenAntwortenDataprovider(IFragenAntwortenService service, IModel<FragenAntworten> filter){
this.service = service;
this.filter = filter;
//I guess you don't need the injector anymore
//Injector.get().inject(this);
setSort("id", SortOrder.DESCENDING); // absteigend sortieren
}
//Rest of class
}
And this is then a test-class:
#ExtendWith(MockitoExtension.class)
public class testClass() {
#Mock
private IFragenAntwortenService service;
#Mock
private IModel<FragenAntworten> filter;
#InjectMocks
FragenAntwortenDataprovider sut; //System under Test
#Test
void test() {
//Testcode
// Control the mock with
when(service.anymethod()).thenReturn(result);
var result = sut.callMethodToTest();
// verify all calls
verify(service, times(1)).anymethod();
// and assert
assertNotNull(result);
}
}
I am trying to write unit tests for Repository layer classes with Junit and Mockito.
I have mocked the base class that supplies NamedParameterJdbcOperations and tried to inject into the repo class.
In the repo class, we are loading sql queries from files on classpath. This is done in a method that is annotated with #PostConstruct.
When trying to test a method of the repo, it is not able to find or load the query and thus throwing NullPointerException.
Need help / suggestion on how to deal with such scenario.
PS: I am not allowed to change the repo class implementation.
Attaching the code of repo and test class for reference.
RepositoryImpl.java
#Repository
public class RepositoryImpl extends AppJdbcImpl implements
Repository {
private static final StudentMapper STUDENT_ROW_MAPPER = new StudentMapper();
private static final CourseMapper COURSE_ROW_MAPPER = new CourseMapper();
#Value("classpath:sql/sql1.sql")
private Resource sql1;
private String query1;
#Value("classpath:sql/sql2.sql")
private Resource sql2;
private String query2;
public RepositoryImpl() { }
public RepositoryImpl(NamedParameterJdbcOperations jdbc) {
super(jdbc);
}
#PostConstruct
public void setUp() {
query1 = loadSql(sql1);
query2 = loadSql(sql2);
}
public Iterable<Course> findCoursesByStudentId(int studentId) throws
DataAccessException {
try {
return jdbc().queryForObject(query1,
ImmutableMap.of("studentId", studentId),
COURSE_ROW_MAPPER);
} catch (EmptyResultDataAccessException emptyResult) {
return null;
} catch (DataAccessException e) {
// Need to create exception classes and throw specific exceptions
throw e;
}
}
public Iterable<Student> findStudentsByCourseId(int courseId) throws DataAccessException {
try {
return jdbc().query(query2,
ImmutableMap.of("courseId", courseId),
STUDENT_ROW_MAPPER);
} catch (DataAccessException e) {
// Need to create exception classes and throw specific exceptions
throw e;
}
}
private String loadSql(Resource resource) {
try {
return CharStreams.toString(new InputStreamReader(resource.getInputStream()));
} catch (IOException e) {
return null;
}
}
}
RespositoryImplTest.java
#RunWith(MockitoJUnitRunner.class)
public class RepositoryImplTest {
#Mock
private NamedParameterJdbcOperations jdbc;
#Mock
private ResultSet resultSet;
#Mock
private StudentMapper studentMapper;
#Mock
private CourseMapper CourseMapper;
#InjectMocks
private RepositoryImpl repository;
private Student student1;
private Student student2;
private Course course1;
private Course course2;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
course1 = new Course(1, "Karate");
course2 = new Course(2, "Riding");
course8 = new Course(8, "Swimming");
List<Course> courseList = Arrays.asList(course1, course2, course8);
student1 = new Student(1, "Chuck", "Norris", 27, new Arrays.asList(course1, course2));
student2 = new Student(2, "Bruce", "Lee", 54, new Arrays.asList(course1, course8));
List<Student> studentList = Arrays.asList(student1, student2);
when(jdbc.queryForObject(Matchers.anyString(), anyMap(),
isA(StudentMapper.class)))
.thenAnswer(new Answer() {
#Override
public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
Object[] args = invocationOnMock.getArguments();
int queryParam = Integer.parseInt(args[0].toString());
Iterable<Credentials> result = studentList.stream()
.filter(d -> d.getId() == queryParam)
.collect(Collectors.toList());
return result;
}
});
}
#Test
public void findCoursesByStudentId() {
Iterable<Course> result = repository.findCoursesByStudentId(1);
assertNotNull(result);
}
}
In repo class, exception is thrown as query1 is null.
Need help to properly solving the issue.
Thanks, Baru
#RunWith(MockitoJUnitRunner.class)
you start test with mockito starter, not spring starter. It's mean that spring not provided you beans. Mockito starter nothing know about PostConstruct annotation.
You may call PostConstruct method youself in sturUp junit method or in test method.
I am not being able to make messageSource work in the Pojo classes,its throwing a nullpointerexception. However in all the other classes namely controller,service messageSource is working alright. Could someone please suggest what needs to be done ?
#Autowired
private MessageSource messageSource;
I have autowired the MessageSource using the above code snippet.
public class ProposalWiseSelectionForm implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Autowired
private MessageSource messageSource;
private String txtPageHierarchy="";
private String txtLineOfBusiness;
private String txtProduct;
private String btn;
private String clickedGo="N";
private List arrLineOfBusiness=new ArrayList();
private List arrProduct=new ArrayList();
#Valid
private ArrayList documentList=initiateDocumentList();
private String txtPageMode="I";
private String enableDiscardBtn="N";
private String enableInsertBtn="N";
private String isDivVisible="N";
private int numApplicationType=1;
public ProposalWiseSelectionForm() {
}
public String getTxtPageHierarchy() {
return txtPageHierarchy;
}
public void setTxtPageHierarchy(String txtPageHierarchy) {
this.txtPageHierarchy = txtPageHierarchy;
}
public String getTxtLineOfBusiness() {
return txtLineOfBusiness;
}
public void setTxtLineOfBusiness(String txtLineOfBusiness) {
this.txtLineOfBusiness = txtLineOfBusiness;
}
public String getTxtProduct() {
return txtProduct;
}
public void setTxtProduct(String txtProduct) {
this.txtProduct = txtProduct;
}
public String getBtn() {
return btn;
}
public void setBtn(String btn) {
this.btn = btn;
}
public String getClickedGo() {
return clickedGo;
}
public void setClickedGo(String clickedGo) {
this.clickedGo = clickedGo;
}
public List getArrLineOfBusiness() {
return arrLineOfBusiness;
}
public void setArrLineOfBusiness(List arrLineOfBusiness) {
this.arrLineOfBusiness = arrLineOfBusiness;
}
public List getArrProduct() {
return arrProduct;
}
public void setArrProduct(List arrProduct) {
this.arrProduct = arrProduct;
}
public void setArrProduct(ArrayList arrProduct) {
this.arrProduct = arrProduct;
}
public ArrayList getDocumentList() {
return documentList;
}
public void setDocumentList(ArrayList documentList) {
this.documentList = documentList;
}
public String getTxtPageMode() {
return txtPageMode;
}
public void setTxtPageMode(String txtPageMode) {
this.txtPageMode = txtPageMode;
}
public String getEnableDiscardBtn() {
return enableDiscardBtn;
}
public void setEnableDiscardBtn(String enableDiscardBtn) {
this.enableDiscardBtn = enableDiscardBtn;
}
public String getEnableInsertBtn() {
return enableInsertBtn;
}
public void setEnableInsertBtn(String enableInsertBtn) {
this.enableInsertBtn = enableInsertBtn;
}
public String getIsDivVisible() {
return isDivVisible;
}
public void setIsDivVisible(String isDivVisible) {
this.isDivVisible = isDivVisible;
}
public int getNumApplicationType() {
return numApplicationType;
}
public void setNumApplicationType(int numApplicationType) {
this.numApplicationType = numApplicationType;
}
}
In order to be able to use #Autowired in a class, that class has to be managed by Spring.
of
Your ProposalWiseSelectionForm class is obviously not managed by Spring and therefor messageSource is always null.
Using #Autowired MessageSource messageSource in your other classes works, because as you mention those classes are managed by Spring (as you have mentioned they are either controllers, services etc).
I am guessing that ProposalWiseSelectionForm is a DTO used to capture values from a form. The sort of class will not be a Spring bean and therefor you can't autowire stuff into it.
I suggest you either move the logic you need out of the DTO and into the controller (or some Spring managed utility) or in the extreme case that you absolutely need #Autowired in the DTO, take a look at #Configurable here and here
Try using #Component,you might be getting this issue because of the fact the Pojo class is not being recognized.
You have to make your class a Spring bean
Add #Component annotation to your class and add these 2 lines to your appContext.xml:
<context:component-scan base-package="com.<your-company-name>" />
<context:annotation-config />
Or just add the service in your beans section in the appContext.xml if you wish not to work with Spring component-scan feature.