Java Spring REST and Hibernate JPA - http 400 while PUT entity twice - java

I am writing my own app using spring mvc (restful webservice) and hibernate.
The problem is, that I have my method in controller that is mapped to url: PUT /report/
and now, in the request body I send the JSON representation of Report entity. When I run the server, add some entities and then try to edit one, the first attempt succeed but the second and every next fails and returns http 400 code.
So it acts like it could be edited just once? strange
Here is my code:
REPOSITORY:
#Repository
public class ReportHibernateRepository implements ReportRepository {
#PersistenceContext
private EntityManager entityManager;
//.......other methods............
#Override
public Report update(Report report) {
Report report1 = entityManager.find(Report.class, report.getId());
report1.setDate(report.getDate());
report1.setReporter(report.getReporter());
report1.setReportText(report.getReportText());
report1.setTitle(report.getTitle());
return report1;
}
}
SERVICE:
#Service
#Transactional
public class ReportService {
#Autowired
private ReportRepository reportRepository;
//..........other methods...........
public Report update(Report report){
return reportRepository.update(report);
}
}
CONTROLLER:
#Controller
#RequestMapping(value = "/report")
public class ReportController {
#Autowired
private ReportService reportService;
//.........other methods...........
#RequestMapping(value = "/", method = RequestMethod.PUT)
#ResponseBody
#ResponseStatus(HttpStatus.NO_CONTENT)
public void update(#RequestBody Report report){
reportService.update(report);
}
}
Does anybody know what's the problem?

Related

Annotation on interface in Spring Boot

My interface:
package com.demo.dependency;
#RestController
#RequestMapping(value = "#{'${api.baseUrl}'}")
public interface BaseController<Response> {
#PostMapping(value = "#{'${api.interface}'}")
#ResponseBody
public Response process(#RequestBody #Valid Request request) throws Exception;
}
Implementation:
package com.demo.application;
public class BarController implements BaseController<BarResponse> {
#Override
public BarResponse process(Request request) throws Exception {
// do something
}
}
I'm new to Spring Boot. I wonder whether these annotations can work properly in implementation class:
#RestController and #RequestMapping on interface class
#PostMapping and #ResponseBody on interface method
#RequestBody and #Valid on method parameters
#{'${api.baseUrl}'} and #{'${api.interface}'} to read configure from application.properties
My spring boot version is 2.2.6.
It seems that my SpringApplication from package com.demo.application failed to auto scan BarController. However, this answer says that "the annotation should apply to all subclasses", including #Service. Is anything wrong with my code?
Thanks in advance.

Spring Boot does not recognize MongoDB RestController class

I am new to MongoDB and I am trying to use it with my SpringBoot application. I have followed my tutorials online and have downloaded their code and got it execute.
However for whatever reason my project fails to be able to print out
RequestMappingHandlerMapping : Mapped “{[/findAllBooks/{id}],methods=[GET]}”
I was wondering if anyone would be able to advise me if it is due to the nature of my project structure .
I wasn’t sure if my SpringBootMain could see my Controller class.
My project structure is best viewed here
https://github.com/emuldrew855/backend/tree/A/B-Testing/src/main/java/com/ebay/queens/demo
My Controller class
package com.ebay.queens.demo.resource;
#RestController
#RequestMapping("/v2")
public class UserController {
#Autowired
private UserRepository userRepository;
#PostMapping("/AddUser")
public String saveUser(#RequestBody User user) {
userRepository.save(user);
return "Added user with id: " + user.getId();
}
#GetMapping("/all")
public List<User> getAll(){
List<User> users = this.userRepository.findAll();
return users;
}
}
My main class
package com.ebay.queens.demo;
#SpringBootConfiguration
#SpringBootApplication
public class SpringBootMain implements CommandLineRunner {
#Autowired
private TokenUtilityClass tokenUtilityClass;
#Bean ResourceConfig resourceConfig() {
return new ResourceConfig().registerClasses(Version1Api.class, Login.class, SignUp.class, Paypal.class); }
#Override
public void run(String... args) throws Exception {
// test.authenticationToken();
}
public static void main(String[] args) {
SpringApplication.run(SpringBootMain.class, args);
}
}
I've figured out why is not working... You are using 2 different WebService API which are incompatible...
Spring-Boot has native API to work with API Rest with #RestController annotation. You don't need to use Glassfish server.
Solution #1
From SpringBootMain remove #Bean ResourceConfig resourceConfig() {...}. Now, you API /v2 will work as expected.
Your API /v1 won't work because it uses other library. You need to change #Path to #GetMapping or #PostMapping and add #RestController into your Version1Api class.
Solution #2
You ignore Spring-Boot native Rest API and implement Glassfish Server.
Add UserController.class reference
#Bean ResourceConfig resourceConfig() {
return new ResourceConfig().registerClasses(Version1Api.class, Login.class, SignUp.class, Paypal.class, UserController.class); }
For UserController change #RestController to #Path("/v2")
#Path("/v2")
public class UserController {
#Autowired
private UserRepository userRepository;
#POST
#Path("/AddUser")
#Produces(MediaType.TEXT_PLAIN)
public String saveUser(#RequestBody User user) {
userRepository.save(user);
return "Added user with id: " + user.getId();
}
#GET
#Path("/all")
#Produces(MediaType.APPLICATION_JSON)
public List<User> getAll(){
List<User> users = this.userRepository.findAll();
return users;
}
}
Now both API will work as expected

Using an ArrayList as a datasource in an ephemeral Spring Boot project

I am building a REST provider with Spring Boot. It is ephemeral by design i.e. the data can be lost when the application is killed. So, I decided to use an ArrayList to make CRUD operations on: it should be like a singleton -created with the app and used along the way.
I have this rest controller, with the service layer autowired:
#RestController
public class MyController {
#Autowired
private MyServiceInterface myService;
#GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
public List<MyEntity> retrieveAll() {
return myService.getAll();
}
#PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public MyEntity create(#RequestBody MyEntity entity) {
return myService.insert(entity);
}
}
and the MyService implementing MyServiceInterface is as follows:
#Service
public class MyService implements MyServiceInterface {
// This is my ArrayList to live while the Spring Boot app runs
private List<MyEntity> myList = new ArrayList<MyEntity>();
#Override
public MyEntity insert(MyEntity entity) {
this.myList.add(entity);
return entity;
}
#Override
public List<MyEntity> getAll() {
return this.myList;
}
}
So, is it fine to use a humble private myList object in the serive class as shown above, or should I take a different approach (inject that myList after assigning it as a #Bean, add #Configuration or whatsoever Spring stuff)?
EDIT: Not to sail away from my concern, my primary point is not discussing databases instead of lists, but how to declare a variable used by multiple methods of a Spring Bean.

Spring boot app to accept user input and saving without any database

I do have a requirement to create a spring boot and angular application without the use of any database, not even in memory db.The application should accept user input and be displayed in Angular.
// The controller class looks like bellow
#CrossOrigin(origins = "http://localhost:4200", maxAge = 3600)
#RestController
#RequestMapping({ "/api" })
public class UserController {
#Autowired
userService userService;
#PostMapping
public Computer create(#RequestBody Computer computer) {
return computerService.save(computer);
}
#GetMapping
public List<Computer> findAll() {
return computerService.findAll();
}
}
#Service
public class UserServiceImpl implements UserService{
private static List<User> users = new ArrayList<>();
private static int Count = 3;
static {
user.add(new User(34, 2000.22,new Date()));
user.add(new User(60, 3000.44,new Date()));
user.add(new User(45, 2000.22,new Date()));
}
And of course there is a userService class with the methods in the implementation class.Is it possible to use hashMap to accept data and then display in Angular without first storing the data in a file or database?. Any ideas would be highly appreciated.
}

Why do I get 404 for rest with spring-boot

I am implementing rest services with Spring Boot. The entity classes are defined in a separate package. So I added that with Component annotation in Application.java.
#Configuration
#EnableAutoConfiguration
#ComponentScan("org.mdacc.rists.cghub.model")
#EnableJpaRepositories(basePackages = "org.mdacc.rists.cghub.model")
public class Application
{
public static void main( String[] args )
{
SpringApplication.run(Application.class, args);
}
}
Here is my controller class:
// SeqController.java
#RestController
public class SeqController {
#Autowired
private SeqService seqService;
#RequestMapping(
value = "/api/seqs",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<List<SeqTb>> getSeqs() {
List<SeqTb> seqs = seqService.findAll();
return new ResponseEntity<List<SeqTb>>(seqs, HttpStatus.OK);
}
}
I also created a JPA data repository that extends JPARepository in which I added custom query code.
// SeqRepository.java
#Repository
public interface SeqRepository extends JpaRepository<SeqTb, Integer> {
#Override
public List<SeqTb> findAll();
#Query("SELECT s FROM SeqTb s where s.analysisId = :analysisId")
public SeqTb findByAnalysisId(String analysisId);
}
Below is the servicebean class that implements a service interface
// SeqServiceBean.java
#Service
public class SeqServiceBean implements SeqService {
#Autowired
private SeqRepository seqRepository;
#Override
public List<SeqTb> findAll() {
List<SeqTb> seqs = seqRepository.findAll();
return seqs;
}
public SeqTb findByAnalysisId(String analysisId) {
SeqTb seq = seqRepository.findByAnalysisId(analysisId);
return seq;
}
}
When I started the application and type the following url in the browser "http://localhost:8080/api/seqs" , I got 404 error. What did I miss?
Edit #1:
I decided to take out the JPA repository stuff and change the controller class to the following:
#RestController
//#RequestMapping("/")
public class SeqController {
private static BigInteger nextId;
private static Map<BigInteger, Greeting> greetingMap;
private static Greeting save(Greeting greeting) {
if(greetingMap == null) {
greetingMap = new HashMap<BigInteger, Greeting>();
nextId = BigInteger.ONE;
}
greeting.setId(nextId);
nextId = nextId.add(BigInteger.ONE);
greetingMap.put(greeting.getId(), greeting);
return greeting;
}
static {
Greeting g1 = new Greeting();
g1.setText("Hello World!");
save(g1);
Greeting g2 = new Greeting();
g1.setText("Hola Mundo!");
save(g2);
}
#RequestMapping(
value = "/api/greetings",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Collection<Greeting>> getGreetings() {
Collection<Greeting> greetings = greetingMap.values();
return new ResponseEntity<Collection<Greeting>>(greetings, HttpStatus.OK);
}
}
When I started the application and put "localhost:8080/api/greetings" in my browser I still got 404.
==>Did you make sure that your Spring Boot application class and your Rest Controller are in the same base package? For Example if your package for Spring Boot application class is com.example.demo, then your Rest Controller should be in same base package as com.example.demo.controller.
==>I think that is the reason boot is unable to map to the uri of your rest controller. Because #SpringBootApplication has #ComponentScan and #Configuration embedded in it already. Try doing this. I hope it works.
If spring boot starter web is not there in your pom.xml then add the same as the reason could be the code not being able to map the endpoints.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
The first thing I would try is to put #RequestMapping("/") on the class definition of the controller. Keep the same value on the method.
Another thing, unrelated to your problem, is that you do not need to define that custom query. JPA is actually smart enough to do the query you defined just by using that method name. Check out the findByLastName example here: https://spring.io/guides/gs/accessing-data-jpa/.

Categories