I am looking at some old example I have in the workspace. I can't see how is the
autowiring done as there is no #Autowired. Spring boot + facebook default configurations.
#Controller
#RequestMapping("/")
public class HelloController {
private Facebook facebook;
private ConnectionRepository connectionRepository;
public HelloController(Facebook facebook, ConnectionRepository connectionRepository) {
this.facebook = facebook;
this.connectionRepository = connectionRepository;
}
#GetMapping
public String helloFacebook(Model model) {
System.out.println("we are here!!!");
if (connectionRepository.findPrimaryConnection(Facebook.class) == null) {
return "redirect:/connect/facebook";
}
PagedList<Post> feed = facebook.feedOperations().getFeed();
model.addAttribute("feed", feed);
return "hello";
}
}
It works perfect but how these beans autowire themselves without the #Autowired? Are they autowired as a field or in the constructor?
With spring boot 1.4+ constructors are automatically autowired
https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-spring-beans-and-dependency-injection.html
In this controller you have not given any annotation #Autowired and may be you have the interface in the controller so you dont need to give the annotation and further also check in the service layer #Service annotation is there or not if you have not given #Service you are not able to use #Autowired also.
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 am new at spring MVC framework and i am currently working in a web application that uses a session scoped bean to control some data flow.
I can access these beans in my application context using #Autowired annotation without any problem in the controllers. The problem comes when I use a class in service layer that does not have any request mapping (#RequestMapping, #GetMapping nor #PostMapping) annotation.
When I try to access the application context directly or using #Autowired or even the #Resource annotation the bean has a null value.
I have a configuration class as follow:
#Configuration
#EnableAspectJAutoProxy
#EnableJpaRepositories(repositoryFactoryBeanClass = EnversRevisionRepositoryFactoryBean.class, basePackages = "com.quantumx.nitididea.NITIDideaweb.repository")
public class AppConfig implements WebMvcConfigurer {
#Bean (name = "lastTemplate")
#SessionScope
public LastTemplate getlastTemplate() {
return new LastTemplate();
}
//Some extra code
}
The POJO class is defined as :
public class LastTemplate {
private Integer lastId;
public LastTemplate(){
}
public Integer getLastId() {
return lastId;
}
public void setLastId(Integer lastId) {
this.lastId = lastId;
}
}
The I have a Test class that is annotated as service and does not have any request mapping annotated method:
//#Controller
#Service
public class Test {
// #Autowired
// private ApplicationContext context;
// #Autowired
#Resource(name = "lastTemplate")
public LastTemplate lastTemplate;
// #Autowired
// public void setLastTemplate(LastTemplate lastTemplate) {
// this.lastTemplate = lastTemplate;
// }
public Test() {
}
// #RequestMapping("/test")
public String testing() {
// TemplateForma last = (TemplateForma) context.getBean("lastInsertedTemplate");
// System.out.println(last);
System.out.println(lastTemplate);
// System.out.println(context.containsBean("lastTemplate"));
// System.out.println(context.getBean("lastTemplate"));
System.out.println("Testing complete");
return "Exit from testing method";
// return "/Messages/Success";
}
}
As you can see, there is a lot of commented code to show all the ways i have been trying to access my application context, using an Application context dependency, autowiring, declaring a resource and trying with a request mapping. The bean is null if no controller annotation and request mapping method is used and throws a java null pointer exception when I use the context getBean() methods.
Finally I just test my class in a controller that i have in my app:
#RequestMapping("/all")
public String showAll(Model model) {
Test test = new Test();
test.testing();
return "/Administrator/test";
}
Worth to mention that I also tried to change the scope of the bean to a Application scope and singleton, but it not worked. How can access my application context in a service class without mapping a request via controller?
Worth to mention that I also tried to change the scope of the bean to a Application scope and singleton, but it not worked
It should have worked in this case.
How can access my application context in a service class without mapping a request via controller?
Try one of these :-
#Autowired private ApplicationContext appContext;
OR
Implement ApplicationContextAware interface in the class where you want to access it.
Edit:
If you still want to access ApplicationContext from non spring managed class. Here is the link to article which shows how it can be achieved.
This page gives an example to get spring application context object with in non spring managed classes as well
What worked for me is that session scoped bean had to be removed in the application configuration declaration and moved to the POJO definition as follows:
#Component
#SessionScope
public class LastTemplate {
private Integer lastId;
public LastTemplate(){
}
public Integer getLastId() {
return lastId;
}
public void setLastId(Integer lastId) {
this.lastId = lastId;
}
}
The I just call the bean using #Autowired annotation.
I'm working on a Spring Boot 2.3 based application. I have a controller that currently has one autowired dependency:
public class ValidationController {
private ValidationService validationService;
#Autowired
public ValidationController(ValidationService validationService) {
this.validationService = validationService;
}
}
I have tests that run on this service and pass. I am attempting to add a second service to this controller:
public class ValidationController {
private ValidationService validationService;
private TokenService tokenService;
#Autowired
public ValidationController(ValidationService validationService, TokenService tokenService) {
this.validationService = validationService;
this.tokenService = tokenService;
}
}
When I do this, all of my ValidationControllerTest cases start failing. I found this message in the stack trace:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.example.auth.service.service.TokenService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
My TokenService interface is as follows:
public interface TokenService {
JsonWebToken getToken(User user, Account account);
}
The implementation is annotated with the #Service annotation:
#Service
public class TokenServiceImpl implements TokenService {
private final String url;
private final String username;
private final String password;
public TokenServiceImpl(
#Value("${service.url}") String url,
#Value("${service.username}") String username,
#Value("${service.password}") String password
) {
this.url = url;
this.username = username;
this.password = password;
}
#Override
public JsonWebToken getToken(User user, Account account) {
...
return jsonWebToken;
}
}
My ValidationService looks very similar to my TokenService as far as annotations, but for whatever reason, Spring Boot can find my ValidationService just fine but my TokenService, which lives in the same place, is nowhere to be found.
How do I make sure that Spring Boot can find my TokenService?
Thanks very much for the comments!
Can you double check that you bring up a spring application context in your tests?
It is my understanding that the #WebMvcTest annotation will load my application context, is that accurate? I have the following annotations on my ValidationControllerTest class:
#ExtendWith(SpringExtension.class)
#WebMvcTest(controllers = ValidationController.class)
Is this sufficient to load the application context in my tests?
Can you double check that this context does a component scan to the package where the TokenServiceImpl resides?
I am new to Spring Boot and still trying to grok component scanning. I have a #SpringBootApplication annotation on my main AuthServiceApplication class, which is in the com.example.auth.service package. I read about component scanning here:
If your other packages hierarchies are below your main app with the #SpringBootApplication annotation, you’re covered by implicit components scan.
My TokenServiceImpl class resides at com.example.auth.service.service.impl, which I think means that it is within the hierarchy of the main app, so it should be covered by the implicit component scan. Is that accurate?
Can you double check that ValidationService is not mocked (via #Mock annotation or something) somewhere in your test suite?
I do have the following in my ValidationServiceImplTest:
#MockBean
private TokenService tokenService;
It looks like I am not using it at the moment. I will remove this #MockBean and see if that does the trick.
I want to initialize a collection and fill it with data at the startup of my application. Then I would like to access it everywhere in my application. I want for example that my REST API can access the shared collection that is already populated with data.
I first tried to do it with an startup class annotated with #Startup and #Singleton. When I injected my userService in there I had some problems and because of the advice in this post: #Inject and #PostConstruct not working in singleton pattern I tried to do it with an #ApplicationScoped annotation:
#Named
#ApplicationScoped
public class KwetterApp {
#Inject
private UserService service;
#PostConstruct
public void init() {
try {
User harry = new User("Harry", "harry#outlook.com", "New York", "http://harry.com", "Hi, I'm Harry!", UserType.REGULAR);
User nick = new User("Nick", "nick#outlook.com", "California", "http://nick.com", "Hi, I'm Nick!", UserType.REGULAR);
User jane = new User("Jane", "jane#outlook.com", "Texas", "http://jane.com", "Hi, I'm Jane!", UserType.REGULAR);
Tweet tweet = new Tweet("eating...", harry);
Tweet tweet1 = new Tweet("swimming...", harry);
Tweet tweet2 = new Tweet("jogging...", jane);
harry.addTweet(tweet);
harry.addTweet(tweet1);
jane.addTweet(tweet2);
service.create(harry);
service.create(nick);
service.create(jane);
}
catch (Exception e){
e.printStackTrace();
}
}
public UserService getService() {
return service;
}
}
I inject this class in my rest service:
#RequestScoped
#Path("/user")
public class UserRest {
// #Inject
// private UserService userService;
#Inject
private KwetterApp kwetterApp;
// private KwetterApp kwetterApp = KwetterApp.getInstance();
private UserService userService = kwetterApp.getService();
#GET
#Produces({"application/json"})
public List<User> get() throws UserException {
return userService.getAll();
}
}
When injecting this KwetterApp it leads to the following exception:
StandardWrapperValve[rest.RestApplication]: Servlet.service() for servlet rest.RestApplication threw exception
java.lang.NullPointerException
at rest.UserRest.<init>(UserRest.java:27)
at rest.UserRest$Proxy$_$$_WeldClientProxy.<init>(Unknown Source)
I have an empty beans.xml file with bean-discovery-mode set to 'all'. The CDI framework should recognize my KwetterApp class for injection, right? Why is it null?
Thanks in advance,
Mike
Here
#Inject
private KwetterApp kwetterApp;
private UserService userService = kwetterApp.getService();
I do not think the kwetterApp field is going to be set before userService.
CDI will set that field after the object has been constructed.
An alternative, which should be used anyway, is constructor injection
#RequestScoped
#Path("/user")
public class UserRest {
private KwetterApp kwetterApp;
private UserService userService;
protected UserRest() {}
#Inject
public UserRest(final KwetterApp kwetterApp) {
this.kwetterApp = kwetterApp;
this.userService = kwetterApp.getService();
}
#GET
#Produces({"application/json"})
#Override
public List<User> get() throws UserException {
return userService.getAll();
}
}
A protected constructor is needed because #RequestScoped is a normal-scoped bean, and it must be proxiable, as described in the specification.
The only annotation that doesn't require an empty constructor is #Singleton (from javax.inject).
If you want to initialize an object by using an injected bean, then you have to use a #PostConstruct annotated method, because injected CDI beans are only available in CDI in a #PostContruct annotated method and afterwards and not during field initialization or the constructor invocation.
Therefore that the UserService is a CDI bean already, you can just inject it into your rest service bean, because it will be the same bean used within the current active scope. KwetterApp is available within the current active scope, so UserService will be as well. Only #Dependend scoped beans behave different, whereby each bean gets its own instance provided.
i'm using Spring MVC for my project. Is it possible to use the same autowired object on another class?
I have two controllers, one for navigation and one for the operations.
this is my sample navigation controller:
#Controller
public class NavigationController {
#Autowired
private DepartmentDAO deptDao;
#RequestMapping("/")
public ModelAndView panel() {
ModelAndView mv = new ModelAndView("panel");
Department dept = deptDao.getDept();
mv.addObject("department",dept);
return mv;
}
}
then my operations controller:
#Controller
public class OperationController {
#RequestMapping(value = "/save.do", method = RequestMethod.POST)
public ModelAndView saveEvent(){
ModelAndView mv = new ModelAndView("next");
Event event = new EventCreator().createEvent();
//some logic here
return mv;
}
}
And this is my business delegate class :
public class EventCreator {
public Event createEvent(){
//logic here
//I need to use the deptDao here.
}
}
Thank You So Much!
You can simply Autowire DepartmentDAO in the EventCreator class, like how your autowired it in NavigationController class. Make sure that you annotate the EventCreator class with #Component and include it in the package where component scanning is done so that spring will autowire the DepartmentDao in your EventCreator class.
#Component
public class EventCreator {
#Autowired
private DepartmentDAO deptDao;
public Event createEvent(){
//logic here
//I need to use the deptDao here.
//deptDao.getAllDepartments();
}
}
You can #Autowired a spring bean object in another spring bean object
Assumption
I assume that you have declared DepartmentDAO with #Repository
annotation as you haven't include code of DepartmentDAO in your
question
There are two ways to solve your problem ,
one is very well explain by #TimeTravel annotate EventCreator with
#Component with create spring bean and you can easy autowire
DepartmentDAO in the EventCreator class
As You have two controller class which makes it spring beans as they are annotated with #Controller, what you can do you can Autowire
departmentDAO in OperationController class and pass instance of
DepartmentDAO as argument in EventCreator class constructor
#Controller
public class OperationController {
#Autowired
private DepartmentDAO deptDao;
#RequestMapping(value = "/save.do", method = RequestMethod.POST)
public ModelAndView saveEvent(){
ModelAndView mv = new ModelAndView("next");
Event event = new EventCreator(deptDao).createEvent();
//some logic here
return mv;
}
}
public class EventCreator {
private DepartmentDAO deptDao=null;
public EventCreator(DepartmentDAO deptDaoAsArg){
deptDao=deptDaoAsArg;
}
public Event createEvent(){
//logic here
//I need to use the deptDao here.
}
}