jpa repositofy findall() returns empty list - spring-boot

I'm practicing making web pages using spring boot.
I created an h2 DB and connected it, and I want to show the name properties of the members table as a list on my web page.
I created the findall() method, but only an empty list is returned. What's wrong with my code?
my web page
MemberRepository
package com.example.testproject.store.h2.repository;
import com.example.testproject.store.h2.domain.Members;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface MemberRepository extends JpaRepository<Members, Integer> {
}
MemberService
package com.example.testproject.store.h2.service;
import com.example.testproject.store.h2.domain.Members;
import java.util.List;
public interface MemberService {
List<Members> getAll();
}
MemberServiceImpl
package com.example.testproject.store.h2.service;
import com.example.testproject.store.h2.domain.Members;
import com.example.testproject.store.h2.repository.MemberRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.lang.reflect.Member;
import java.util.List;
#Service(value = "memberServiceImpl")
public class MemberServiceImpl implements MemberService {
#Autowired
private MemberRepository memberRepository;
public List<Members> getAll(){
return memberRepository.findAll();
}
}
MemberController
package com.example.testproject.controller;
import com.example.testproject.store.h2.domain.Members;
import com.example.testproject.store.h2.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
#RestController
public class MemberController {
#Autowired
private MemberService memberService;
#GetMapping(value = "/members")
public List<Members> getAll() {
List<Members> users = memberService.getAll();
return users;
}
/*#GetMapping(value = "/members")
public List<Members> getAll() throws Exception {
return memberService.getAll();
}*/
}
Members(Entity)
package com.example.testproject.store.h2.domain;
import jakarta.persistence.*;
#Entity
#Table(name = "members")
public class Members {
#Id
private int id;
#Column
private String name;
}
I want to show the name properties of the members table as a list on my web page.

You have missed the getter setter method in entity class either you need to 1:-define getter setter method for each field or
2:-you need to add lombook dependency in pom.xml file and add #Data annootation on top of entity class so that when spring uses your entity can set and get the value from database and if you dontot want to give id explicitly then add #GeneratedValue(strategy=GenerationType.AUTO) so that spring automatically increase you id

I think you missed getters and setters in your Entity
Class just add them by using #Data annotation and try again.

You missed getters and setters for the fields in your Entity
You do not need any library, you can write it by yourself.
Otherwise, even if you use lombok, you should avoid to use #Data annotation on Entity, because it could lead to errors with default implementation of equals and hashCode. Instead you can use annotations #Getter and #Setter on the class.

Related

Spring batch item writer rest API

Is it possible to read data from DB, process it and in ItemWriter send to another system using RestAPI (REST TEMPLATE) in Spring batch project? All I can see is fetch data and write it in a csv file.
It is possible to create your own custom ItemWriter.
In your case, please add the spring-boot-starter-web dependency to either your pom.xml or build.gradle
Example:
package com.example.batch;
import lombok.extern.log4j.Log4j2;
import org.springframework.batch.item.ItemWriter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
import java.util.List;
#Log4j2
public class RestItemWriter implements ItemWriter<String> {
#Autowired
RestTemplate restTemplate;
public RestItemWriter(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
#Override
public void write(List<? extends String> items) throws Exception {
ResponseEntity<Users> users = restTemplate.getForEntity("https://jsonplaceholder.typicode.com/users/1", Users.class);
log.info("Status code is: " + users.getStatusCode());
}
}
package com.example.batch;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Getter;
import lombok.Setter;
#Getter
#Setter
#JsonInclude(JsonInclude.Include.NON_NULL)
public class Users {
public String id;
public String name;
public String username;
public String email;
public String phone;
}
More information about custom item writers here

How to us a constructor with parameters in a method used by Spring Boot's #RestController annotation to create a request handler

I bought this new book to try to learn Spring Boot quickly. It started out well, and I easily created a REST API. But then we added CrudRepository, and I'm seeing issues with the code as described in the book. Also, there is no code available to download because the author took it down from Oreily's git repo in order to fix some things...
The issue is that if I try to build the code as the book describes (without a default constructor) I get a Java error complaining that there is no default constructor. If I add a default constructor, it builds, but Spring uses it instead of the new constructor, that requires a parameter to be passed. So when I actually call the API, like if I call the /coffees endpoint, I get a java.lang.NullPointerException: null
So how is Spring supposed to know which constructor to use, and how could it pass in values for this parameter?
Here is the controller:
package com.bw.restdemo;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
#RestController
#RequestMapping("/coffees")
class RestAPIDemoController {
private final CoffeeRepository coffeeRepository;
public RestAPIDemoController(CoffeeRepository coffeeRepository) {
this.coffeeRepository = coffeeRepository;
this.coffeeRepository.saveAll(List.of(
new Coffee("Cafe Cereza"),
new Coffee("Freedom Fuel"),
new Coffee("Cold Brew"),
new Coffee("Sumatra")
));
}
public RestAPIDemoController() {
this.coffeeRepository = null;
};
//#RequestMapping(value = "/coffees", method = RequestMethod.GET)
#GetMapping
Iterable<Coffee> getCoffees() {
return coffeeRepository.findAll();
}
#GetMapping("/{id}")
Optional<Coffee> getCoffeeById(#PathVariable String id) {
return coffeeRepository.findById(id);
}
#PostMapping
Coffee postCoffee(#RequestBody Coffee coffee) {
return coffeeRepository.save(coffee);
}
#PutMapping("/{id}")
ResponseEntity<Coffee> putCoffee(#PathVariable String id, #RequestBody Coffee coffee) {
return (!coffeeRepository.existsById(id))
? new ResponseEntity<>(coffeeRepository.save(coffee), HttpStatus.CREATED)
: new ResponseEntity<>(coffeeRepository.save(coffee), HttpStatus.OK);
}
#DeleteMapping("/{id}")
void deleteCoffee(#PathVariable String id) {
coffeeRepository.deleteById(id);
}
}
Here is where I'm defining the interface:
package com.bw.restdemo;
import org.springframework.data.repository.CrudRepository;
interface CoffeeRepository extends CrudRepository<Coffee, String> {
}
And here's the main class -- apologies for the class stuffed at the bottom.
package com.bw.restdemo;
import java.util.UUID;
import javax.persistence.Entity;
import javax.persistence.Id;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class RestDemoApplication {
public static void main(String[] args) {
SpringApplication.run(RestDemoApplication.class, args);
}
}
#Entity
class Coffee {
#Id
private String id;
private String name;
public Coffee(String id, String name) {
this.id = id;
this.name = name;
}
public void setId(String id) {
this.id = id;
}
public Coffee(String name) {
this(UUID.randomUUID().toString(), name);
}
public String getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
CoffeeRepository interface is missing #Repository Annotation.
Update:
Add #Repository Annotation at CoffeeRepository
Remove the default constructor from RestAPIDemoController.
package com.bw.restdemo;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
#Repository
interface CoffeeRepository extends CrudRepository<Coffee, String> {
}
Explanation
In spring framework, #Component annotation marks a java class as a bean so the component-scanning mechanism can pick it up and pull it into the application context. As #Repository serves as a specialization of #Component , it also enable annotated classes to be discovered and registered with application context.
More at HowToDoInJava - #Repository annotation in Spring Boot

Setters for session scoped bean not working in RestController

I'm trying to get the username from the session scoped bean once the user has logged in using /users/login
I've Autowired a session scoped bean into a RestController and in one of the endpoints in the rest controller, I'm invoking a setter on the session scoped bean. But the effect of setters is not visible for requests from the same session.
The following is my session scoped bean:
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
#Getter
#Setter
public class SessionSpecificUserDetails implements Serializable {
private String userName;
}
import lombok.Getter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.annotation.SessionScope;
#Getter
#Configuration
public class UserSessionDetailsConfiguration {
#Bean
#SessionScope
public SessionSpecificUserDetails sessionSpecificUserDetails() {
return new SessionSpecificUserDetails();
}
}
The following is the RestController
import com.course.backend.coursebackend.config.SessionSpecificUserDetails;
import com.course.backend.coursebackend.dao.User;
import com.course.backend.coursebackend.repository.UserRepository;
import com.course.backend.coursebackend.utils.ResponseUtils;
import com.course.backend.coursebackend.utils.UserUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
#RestController
#RequestMapping("/users")
public class UserController {
#Autowired
UserRepository userRepository;
#Autowired
SessionSpecificUserDetails sessionSpecificUserDetails;
#GetMapping("/getLoggedInUser")
public String getLoggedInUser() {
return sessionSpecificUserDetails.getUserName();
}
#PostMapping("/login")
public ResponseUtils.CustomResponse login(#RequestBody User user) {
List<User> users = getAllUsers();
Optional<User> optionalUser = users.stream()
.filter(currentUser -> currentUser.getUserName().equals(user.getUserName()))
.findAny();
if (optionalUser.isEmpty()) {
return ResponseUtils.getErrorResponse(List.of("Username not found!"));
}
if (optionalUser.get().getPassword().equals(user.getPassword())) {
sessionSpecificUserDetails.setUserName(user.getUserName());
return ResponseUtils.getSuccessResponse("Login Successful!");
}
return ResponseUtils.getErrorResponse(List.of("Login failed due to wrong password!"));
}
}
I see that spring is creating proxy for the session scoped bean. (And may be because of that my setters are not having any effect even for the same session?)
My question is what's the correct way to use the session scoped beans in the RestController? And what's the good way to get the username for the same session across requests?
I tried marking UserController also as #SessionScope but that's also not working.

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.

Using Mock class with dependency injection in a JUnit test

I have a basic Interface which another class is implementing.
package info;
import org.springframework.stereotype.Service;
public interface Student
{
public String getStudentID();
}
`
package info;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
#Service
public class StudentImpl implements Student
{
#Override
public String getStudentID()
{
return "Unimplemented";
}
}
I then have a service to inject that class into
package info;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
#Service
public class InfoService {
#Autowired
Student student;
public String runProg()
{
return student.getStudentID();
}
}
What I want to know is, how do I set up a JUnit test so that a Mock class of the Student interface steps in with a stubbed method instead of the method in StudentImpl. The injection does work but I want to use amock class to simulate the results instead for the sake of testing. Any help would be greatly appreciated.
In my opinion, autowiring in unit tests is a sign that's it's an integration test rather than unit test, so I prefer to do my own "wiring", as you describe. It might require you to do some refactoring of your code, but it shouldn't be a problem. In your case, I would add a constructor to InfoService that get's a Student implementation. If you wish, you can also make this constructor #Autowired, and remove the #Autowired from the student field. Spring would then still be able to autowire it, and it's also more testable.
#Service
public class InfoService {
Student student;
#Autowired
public InfoService(Student student) {
this.student = student;
}
}
Then it will be trivial to pass mocks between your services in your tests:
#Test
public void myTest() {
Student mockStudent = mock(Student.class);
InfoService service = new InfoService(mockStudent);
}

Resources