I want to create two spring-boot projects which communicate via rest calls. The first one contains the UI part with loginForm. The second project should communicate with the DB and should fetch the information about the user and then send it back to the UI.
The service project contains two modules: data module and impl module. The data project should contain the common data shared between the UI and the service project. It should be only a jar which I will add as a dependency in the UI project and the impl module in the service project.
The impl module should contain entities, repositories, restcontrollers and a service layer containing the real back-end logic of the application. I have already created the UI project but I have problems with the service. In the data module I have created the classes with the user information in a package org.tu.userdata. In the service impl I have an userController like this:
package org.tu.userserviceimpl.controller;
#RestController
#RequestMapping("/user")
public class UserController {
private final UserAuthenticationService userService;
#Autowired
public UserController(UserAuthenticationService userService) {
this.userService = userService;
}
#PostMapping(value = { "/logUser" })
public UserDto logUser(#RequestBody AuthenticateUserDto authenticateUserDto) throws Exception {
return userService.logUser(authenticateUserDto);
}
#PostMapping(value = { "/register" })
public UserDto register(#RequestBody RegisterUserDto registerUserDto) throws Exception {
return userService.registerUser(registerUserDto);
}
}
It injects the UserAuthenticationService which is an interface implemented like this:
package org.tu.userserviceimpl.service.impl;
#Service
public class UserAuthenticationServiceImpl implements UserAuthenticationService {
private final UserRepository userRepository;
#Autowired
public UserAuthenticationServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}
#Override
public UserDto registerUser(RegisterUserDto registerUserDto) throws AuthenticationException {
return new UserDto();
}
#Override
public UserDto logUser(AuthenticateUserDto authenticateUserDto)
throws UserPrincipalNotFoundException, AuthenticationException {
return new UserDto();
}
}
the UserRepository:
package org.tu.userserviceimpl.repository;
#Repository
public interface UserRepository extends JpaRepository<UserEntity, Long> {
UserEntity findByUsername(String username);
boolean existsByUsername(String username);
boolean existsByEmail(String email);
}
and an application class:
package org.tu.userserviceimpl;
#SpringBootApplication
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}
When I run it I get:
*************************** APPLICATION FAILED TO START
Description:
Parameter 0 of constructor in
org.tu.userserviceimpl.service.impl.UserAuthenticationServiceImpl
required a bean of type
'org.tu.userserviceimpl.repository.UserRepository' that could not be
found.
I thought that's strange because the UserRepository should be visible there since its a directory below the application class. To solve this I added a ComponentScan annotation on the application class:
#ComponentScan("org.tu.userserviceimpl.repository")
After that the project builds and deploys fine but I cannot access it. I got an 404 error. I even added an method like this one in the UserController just to troubleshoot it:
#GetMapping("/hello")
public String hello() {
return "hello";
}
But still cannot access it. The application is deployed on port 8082 but when I try to access "http://localhost:8082/user/hello" I cannot. After that I tried to remove the code in the UserAuthenticationServiceImpl which injects the UserRepository and I removed the componentScan annotation as well. After this code removal I was able to reach "http://localhost:8082/user/hello" and I got the message "hello" there. This means that the problem is somewhere in the Repository. Then I tried to add:
#EnableJpaRepositories("org.tu.userserviceimpl.repository")
#EntityScan("org.tu.userserviceimpl.entity")
on top of the application class and I added the code which injects the repository in the UserAuthenticationServiceImpl again. This time the outcome was a different error:
Parameter 0 of constructor in org.tu.userserviceimpl.service.impl.UserAuthenticationServiceImpl required a bean named 'entityManagerFactory' that could not be found.
I deleted the EntityScan annotation but the result was the same. Any ideas? What I am doing wrong?
I uploaded almost the same project in github: https://github.com/lei-gustavson/user-service.git
You have already created an argument based constructor in UserAuthenticationServiceImpl .
as below:
public UserAuthenticationServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}
So NO argument constructor can't be created by JVM automatically.
and the below line has also not autowired
private final UserRepository userRepository;
Please add no argument constructor or remove the existing to resolve this issue.
Can you try putting below statement ?
#EntityScan("org")
I also have faced same issue but when i have used above statement for my directory structure it works.
Note :
You are confused between #ComponentScan and #EntityScan.
Just do one thing both above annotation annote like,
#ComponentScan("org"),
#EntityScan("org") and
#EnableJPARepository("org")
Mostly it will work for you
Thank you all for trying to help me! I find a solution. The problem was that i didnt have JPAConfig file. This solved the problem:
#Configuration
#EnableJpaRepositories("org.tu.userserviceimpl.repository")
public class JPAConfig {
}
After that i deleted the ComponentScan annotation from the SpringBootApplication class and everything was up and running
Related
As part of my university project I was asked to implement a simple spring-boot app(backend only) which can communicate with Postman through HTTP requests.
The project built in controller-service-repository architecture and conatins only 1 Entity(Post object with string content) and 2 end-points(create new post, get all posts).
I know there is a few ways to configure beans in spring-boot:
with an external XML file.
With #Configuration annotation & #Bean annotation
With #Component annotation(#RestController,#Service, #JpaRepository)
The 3rd way working great but i was asked to implement the 2nd way and I'm really struggling to get this working.
Im getting:
ServletException: Circular view path [post]: would dispatch back to the current handler URL [/post] again. Check your ViewResolver setup!
Tried to explore about this exception and i did manage to "solve" it by adding this maven dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>2.5.2</version>
</dependency>
which led to:
"org.thymeleaf.exceptions.TemplateInputException: Error resolving template [post], template might not exist or might not be accessible by any of the configured Template Resolvers"
what am i doing wrong ?
Configuration class:
#Configuration
#EnableJpaRepositories(basePackages = {
"com.example.microblog.post.domain.repository"
})
public class ApplicationBeans {
#Bean
public PostController postController(PostService postService){
return new PostController(postService);
}
#Bean
public PostService postService(){
return new PostService();
}
}
Controller class:
#AllArgsConstructor
#RequestMapping(path = "post")
public class PostController {
#Autowired
private PostService service;
#CrossOrigin(origins = "http://localhost:4200")
#PostMapping("")
public PostEntity create(#RequestBody PostDto dto) {
return service.create(dto);
}
#GetMapping("/all")
#CrossOrigin(origins = "http://localhost:4200")
public List<PostEntity> getAll() {
return service.getAll();
}
}
Service Class:
#Transactional
public class PostService {
#Autowired
private PostRepository PostRepository;
public PostEntity create(PostDto dto){
PostEntity newPost = new PostEntity(dto.getContent());
return PostRepository.save(newPost);
}
public List<PostEntity> getAll(){
return PostRepository.findAll();
}
Repository class:
public interface PostRepository extends JpaRepository<PostEntity,Long> {}
For second approach, when you create a Bean, try not to have #Component/#Controller ... on the class for which you create the bean
#Configuration
public class AppConfig {
#Bean
public TransferService transferService() {
return new TransferServiceImpl();
}
}
You can continue to autowire them like in third approach, try not to keep beans of same name
Your error points in the direction, that your Controller has difficulties to resolve the answer of your Service to a valid JSON response.
Note that #RestController is just a convenient way to add #Controller and #ResponseBody annotation. When you just add a #Bean annotation you are not adding either #Controller or #ResponseBody.
If you want to use the Controller class without using these Annotations you need to implement the functionality that these classes provide.
However I really see no way, why option 2 would be used for a Controller class. If you want to use it for a #Service class (which is doing the same as #Component) you can use the approach that Ravi suggested.
I have a spring boot application where, suddenly, the autowired services returning null at specific methods.
Here is a code snippet for the controller:
#RestController
#RequestMapping("/user")
#CrossOrigin
public class UserManagementController {
#Autowired
private UserService userService;
...
#PostMapping("/register")
private GameInfo register(#RequestBody UserInfo userInfo) {
User user = new User();
...
user.setUsername("user-" + userService.count());
...
return gameController.getGameInfo(user);
}
...
#PostMapping("/statistics")
public StatisticsInfo statistics(
#RequestParam(name = "username", required = true) String username,
Authentication authentication) {
User user = userService.findByUsername(username);
...
}
}
The userService is null in the first method, and works fine in the second one.
UPDATE:
Here is the code snippet for the UserService which is null in "register" method.
#Service
public class UserService implements UserDetailsService {
#Autowired
private UserRepository repository;
public long count() {
return repository.count();
}
...
}
The userService has normal CRUD methods.
Kindly note that the userService is null, so a NullPointerException is thrown when I invoke any of its methods.
UPDATE 2:
I have created a clone of the faulty method register and named it dontRegister, this magically solved the issue of register but introduced the same issue in the new method.
I don't understand the logic behind this, as it seems that I always need to add one extra unused method.
I'll keep the question open until maybe someone comes up with an explanation.
Your register method is private, make it public. Logically it should be public anyway as it is called from outside the package.
I have an application based on Spring 4.3.28 (i.e. not Spring Boot!) and I want to migrate my integration tests to Cucumber.
I’ve followed this tutorial and adapted it to plain Spring.
The tests I’ve written so far are working fine (Spring context is initialized etc.), but as soon as there are request-scoped beans involved, they stop working:
Caused by: java.lang.IllegalStateException: No thread-bound request found: Are you
referring to request attributes outside of an actual web request, or processing a
request outside of the originally receiving thread? If you are actually operating
within a web request and still receive this message, your code is probably running
outside of DispatcherServlet/DispatcherPortlet: In this case, use
RequestContextListener or RequestContextFilter to expose the current request.
I’ve created a small sample project
that tries to reproduce the problem.
There is one context configuration class called AppConfig:
#Configuration
public class AppConfig {
#Bean
#Scope("request“) // when this line is removed, the test succeeds
public ExampleService exampleService() {
return new ExampleService();
}
#Bean("dependency")
#Scope("request") // when this line is removed, the test succeeds
public String dependencyBean() {
return "dependency bean";
}
}
The ExampleService is request-scoped, and gets one request-scoped bean injected by #Autowired:
public class ExampleService {
#Autowired
#Qualifier("dependency")
String dependencyBean;
public String process() { return "I have a "+dependencyBean; }
}
For the tests, I have one Spring-annotated superclass:
#ContextConfiguration(classes = AppConfig.class)
#CucumberContextConfiguration
#WebAppConfiguration
public class TestBase {
#Autowired
public ExampleService underTest;
}
There’s also a plain Spring test that runs just fine:
#RunWith(SpringRunner.class)
public class ExampleServicePlainSpringTest extends TestBase {
#Test
public void whenProcessingDataThenResultShouldBeReturned() {
assertThat(this.underTest.process()).isEqualTo("I have a dependency bean");
}
}
The Cucumber test is executed by this test class stub:
#RunWith(Cucumber.class)
public class ExampleServiceCucumberTest extends TestBase {}
The actual cucumber step definitions are here:
public class CucumberStepDefinitions extends TestBase {
private String result;
#When("I process data")
public void iProcessData() {
result = this.underTest.process();
}
#Then("the result should be returned")
public void checkResult() {
assertThat(result).isEqualTo("I have a dependency bean");
}
}
The .feature file for Cucumber is in the src/test/resources directory under the same package name as the step definitions class:
Feature: Example
Scenario: Example service bean returns dependency
When I process data
Then the result should be returned
Usually when I encountered the „no thread-bound request found“ error, it was because the #WebAppConfiguration annotation was missing, or when I tried to inject a request-scoped bean into a non-request scoped bean. But that’s not the case here.
What am I doing wrong?
I was able to figure out how to resolve it; the updated code is in the github repository linked in the question.
When using the SpringRunner, the request context is initialized in a ServletTestExecutionListener that is implicitly added to the list of TestExecutionListeners for the test.
The initialization happens in the beforeTestMethod() method of that listener.
However, as #M.P.Korsanje correctly remarked in the comments (thanks!), Cucumber doesn't have test methods, so beforeTestMethod() is never executed.
My solution was to add a custom subclass of ServletTestExecutionListener as a TestExecutionListener that delegates the beforeTestClass() call to the beforeTestMethod():
public class ClassLevelServletTestExecutionListener extends ServletTestExecutionListener {
#Override
public void beforeTestClass(TestContext testContext) throws Exception {
super.beforeTestMethod(testContext);
}
#Override
public void afterTestClass(TestContext testContext) throws Exception {
super.afterTestMethod(testContext);
}
}
And in ExampleServiceCucumberTest:
#ContextConfiguration(classes = {AppConfig.class})
#CucumberContextConfiguration
#WebAppConfiguration
#TestExecutionListeners(ClassLevelServletTestExecutionListener.class)
// extend the Spring class to get the default TestExecutionListeners
public class TestBase extends AbstractJUnit4SpringContextTests {
#Autowired
public ExampleService underTest;
}
I am creating a REST service in Spring boot. I am creating a bean in config class and trying to use in service class by auto wiring, but I am always getting null, I have tried in constructor injection as well but not working. Below is the code,
Main app
#SpringBootApplication
public class Main {
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}
}
REST controller
#RestController
#RequestMapping("/v1")
public class RestController {
#Autowired
private Service service;
Service
#Service
public class ServiceImpl implements Service {
//This is the bean
#Autowired
private Record record;
public ServiceImpl() { //-----------------> tried injecting in constructor as well
System.out.println(record); //-------------------> null
}
Config class
#Configuration
public class AppConfig {
#Bean
public Record record() {
return new Record("test");
}
}
I noted whenever I remove the record() from config class I get below error
required a bean of type 'com.ns.service.Record' that could not be found
And after adding the method the error is not reported but null is returned, which indirectly means record() is considered as returning the required bean.
I can't find what I am doing wrong please advise.
Project folder structure
I think you're doing everything right conceptually
Spring creates an object first and only after that injects the values (technically done in bean post processors):
So try this:
#Service
public class ServiceImpl implements Service {
//This is the bean
#Autowired
private Record record;
public ServiceImpl() {
// here the record is null - not injected yet
System.out.println(record);
}
#PostConstruct
public void checkThisOut() {
// here print the record
}
You say you've tried constructor injection as well - it should work because spring has to inject something into the constructor of a bean (ServiceImpl) or fail. Please show the code snippet
One this that might be wrong in some level (although it doesn't sound like this from your description) is that you have to put all the #Configuration/#Service annotated classes in the package that is the same or underneath the package where you've created the main class annotated with #SpringBootApplication annotation. It instructs spring boot where to look for the beans.
So make sure your classes obey this rule...
My Controller class is below.
#Controller
public class app {
#GetMapping(path = "/")
public #ResponseBody
String hello() {
return "Hello app";
}
}
It works fine when I navigate through url. But when this below code is added it says "Could not autowire. No beans of 'NoteRepository' type found".
#Autowired
NoteRepository noteRepository;
// Create a new Note
#PostMapping("/notes")
public Note createNote(#Valid #RequestBody Note note) {
return noteRepository.save(note);
}
App controller class is in the same package where main class(which run the application) is. but when we add above code to a controller in different package it doesn't show error. but it doesn't work when we navigate through url even a simple get method.
My main class is below.
#SpringBootApplication
#EnableJpaAuditing
public class CrudApplication {
public static void main(String[] args) {
SpringApplication.run(CrudApplication.class, args);
}
}
My Repository class is
#Repository
public interface NoteRepository extends JpaRepository<Note, Long> {
}
My project structure
I want to find solution to:
Inject an instance of NoteRepository. I always get the message "Could not autowire. No beans of type found" error. Spring cannot inject it, doesn't matter if the interface is in the same or a different package.
I am not able to run methods in a controller(MyController) that are located in a different package than application entry point.
The main symptom is this:
App controller class is in the same package where main class(which run the application) is. but when we add above code to a controller in different package it doesn't show error. but it doesn't work when we navigate through url even a simple get method.
By default, Spring Boot application will only auto discover beans declared in the same package than the main class. For beans that are in a different package, you need to specify to include them. You can use #ComponentScan for this.
package foo.bar.main;
//import statements....
//this annotation will tell Spring to search for bean definitions
//in "foo.bar" package and subpackages.
#ComponentScan(basePackages = {"foo.bar"})
#SpringBootApplication
#EnableJpaAuditing
public class CrudApplication {
public static void main(String[] args) {
SpringApplication.run(CrudApplication.class, args);
}
}
package foo.bar.controller;
//import statements....
//since #ComponentScan, now this bean will be discovered
#Controller
public class app {
#GetMapping(path = "/")
public #ResponseBody
String hello() {
return "Hello app";
}
}
For Spring Data to recognize which repositories should create, you should add #EnableJpaRepositories annotation to your main class. Also, in order for Spring Data and the JPA implementation to scan the entities, add #EntityScan:
#ComponentScan(basePackages = {"foo.bar"})
#SpringBootApplication
#EnableJpaAuditing
#EnableJpaRepositories("your.repository.packagename")
#EntityScan("your.domain.packagename")
public class CrudApplication {
//code...
}
you should add packages for spring to scan them
#SpringBootApplication(scanBasePackages={"package1", "package2"})