Rest Controller works just for Application class - java

I'm trying to do a getmapping method using rest-api which will return as a JSON on localhost: 8080. When I do this from the default Application class it works great but when I move this functionality to another class nothing happens. Could someone help me with this, please?

The issue is that your package structure prevents BookController from being component scanned.
When you have your #SpringBootApplication defined in package com.xenon.myspringbootapp, anything in that package and in nested packages is eligible for component scanning, which will register a bean out of #(Rest)Controller and other stereotypes.
Because BookController is defined in book, it is outside of the component scanned packages and will therefore not be component scanned by your #SpringBootApplication annotation.
See the reference docs for more best practices on package structure with Spring Boot applications.
To resolve this, there are two choices to get your class component scanned.
The first (and the way I would recommend) is just to restructure your packages so that the #SpringBootApplication class is at the "base" of your application packages. For example, you could move book.BookController to be at com.xenon.myspringbootapp.book.BookController.
The second is to change the component scanning configuration to include your book package. You can do this either on the #SpringBootApplication annotation itself:
#SpringBootApplication(scanBasePackages = {
"com.xenon.myspringbootapp",
"book"
})
Or, define a different #ComponentScan. Note that the configuration class annotated with #ComponentScan must still be component scanned itself.
#SpringBootApplication
public class MySpringBootAppApplication {
#Configuration
#ComponentScan("book")
public static class MyBookComponentScanConfiguration {}
public static void main(String[] args) {
SpringApplication.run(MySpringBootAppApplication.class);
}
}

Reason 1: Default Spring's component scanning can't fount your #RestController component, so you can try to do #ComponentScan directly.
Reason 2: You need to specify an endpoint for your #GetMapping by using #RequestMapping/#GetMapping("url") or both of them.

Related

Failing to import external jar containing bean

I'm a little new t working with Spring so any help provided would be great.
I have a SpringApplication class (annotated with #SpringBootApplication. In another class (within the same project), it contains a ServiceClass class. When the class is in the same project, it runs as expected.
When the ServiceClass is moved to an external jar, I get the following error.
Description:
Field service in
package-to-class.Comp required a
bean of type 'package-to-class.ServiceClass'
that could not be found.
The injection point has the following annotations:
#org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type
'package-to-class.ServiceClass' in your
configuration.
I am trying to find what I need to do to inject (#AutoWired) into my project with the above error.
By default, Spring Boot's component scanning only looks in the same package as the #SpringBootApplication and its descendants.
The approach I would suggest is using #Import to import specific beans from outside the project, or use #ComponentScan to import all beans from a package in another project.
#SpringBootApplication
#Import(ServiceClass.class)
public class SpringApplication {
// ...
}
or
#SpringBootApplication
#ComponentScan(basePackages = "com.example.mylibrary")
public class SpringApplication {
// ...
}
Okey some basic things, you have mixed up your packages a bit.
#SpringBootApplication will scan all classes in packages below the class this is annotated on. This annotation is an alias for #EnableAutoConfiguration, #Configuration and #ComponentScan means that #ComponentScan(basePackages = {"com.springdi.example"}, basePackageClasses = DependencyBasePackageClass.class) is not needed.
com.springdi.example // class with #SpringBootApplication annotation
|
|
|
com.springdi.example.* // Will find all #Service, #Component, #Configuration
// in subpackages below the #SpringBootApplication
// annotation
You can read more about the annotation here SpringBootApplication
Since your other annotated classes are NOT in the same package structure as the #SpringBootApplication you need to define all the places you want to scan for annotations.
#SpringBootApplication(scanBasePackages = {"com.springdi.example", "com.dependency.example"})
will probably include all the packages that you want to scan through.

Spring boot #ComponentScan vs #Import

I and my friend were discussed about #ComponentScan and #Import. Which one is better?
We have 2 different ideas.
#ComponentScan: Easy to use, import all beans from the component
scan.
#Import: You need to know what component you want to use, no need to scan all.
How about your idea? Which one is better for you to use?
Thanks!
#Import is used to import Java configuration classes marked with #Configuration/#Component typically. So if you have a bean inside this component, Spring will load it into Application Context. You can just put the name of the component or class and Spring will pull it up for you.
However, by using #ComponentScan, you tell the application which packages to scan for java classes are annotated with #Configuration/#Component (or any of #Component's sub-annotations like #Service or #Repository etc) and load all of them up in Application Context so they can be autowired when required. If there are inner instances that need to be populated, Spring will take care of it.
You can read more about #Import and #ComponentScan on their respective doc pages.
This page explains pretty well the difference.
#ComponentScan scans and searches for any beans inside packages/classes specified under basePackageClasses or basePackages options, whichever is configured.
This option also allows you to filter some classes that you do not want to be included in search.
#Import is like clubbing one java configuration into another.
eg:
#Configuration
#ComponentScan(basePackages="com.stackoverflow")
public class Dbconfig {
#Bean
public Datasource dSource(){
return new Datasource()
}
}
#Configuration
#Import(Dbconfig.class)
#ComponentScan(basePackages="org.hellospring")
public class AppConfig {
...// beans
}
So here, if we check AppConfig class,
it will include all beans registered in Dbconfig configuration class including inside of package com.stackoverflow
+
It will include all beans inside AppConfig class and beans under package org.hellospring

SpringBootApplication scanBasePackages is not reading subpackages

I have a common library published on nexus that has package id
x.xx.common
it contains sub packages of common feign clients proxy interfaces
The project that uses this library has package id.
x.xx.account
x.xx.device
each of these projects has its application class in the root
x.xx.account.AppClass
x.xx.device.AppClass
each of these class has
#SpringBootApplication(scanBasePackages = {"x.xx"})
for some reason both projects don't see any of the proxy interfaces under subpackages
x.xx.common.proxy
x.xx.common.configuration
I tried moved the proxy interfaces directly under main package
x.xx.common
but it also failed
Parameter 0 of constructor in x.xx.common.service.impl.AuditServiceImpl required a bean of type 'x.xx.common.LogProxy' that could not be found.
that error is given for every interface proxy
Add annotation to your sub packages class which you want to be scanned. Add the annotations like #Component, #Service or #Repository respectively to the class respectively.
For the annotation:
#SpringBootApplication(scanBasePackages = {"x.xx"})
Suppose there is a class named Abc in the subpackage x.xx, so add the annotation #Component to the class.
#Component
class Abc{}
This will help to read the sub packages class.
To know more about the difference between the above mention annotations: What's the difference between #Component, #Repository & #Service annotations in Spring?
I have figured it out, apparently the AppClass #EnableFeignClients need to have the base class added to it as well.
So for anyone that has the same problem my AppClass now has the following annotation
#SpringBootApplication(scanBasePackages = {"x.xx"})
#EnableFeignClients(basePackages= {"x.xx"})
public class AppClass {
}

How to #Autowire services in SpringBoot

Good day, guys. I have a question about autowiring services into my classes when using Springboot. All of the examples I have seen on the Internet as well as in the Springboot specification do something of the like (taking an excerpt from the Springboot version 1.5.7 specification):
package com.example.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
#Service
public class DatabaseAccountService implements AccountService {
private final RiskAssessor riskAssessor;
#Autowired
public DatabaseAccountService(RiskAssessor riskAssessor) {
this.riskAssessor = riskAssessor;
}
// ...
}
This is a class that injects a property through its constructor, by means of #Autowiring the constructor. Another form is to #Autowire the property like this:
#Autowired
private final RiskAssessor riskAssessor
But, where I work, for these two methods to work, I have been told that I need to use this method:
applicationContext.getAutowireCapableBeanFactory().autowireBean(Object.class)
They have told me that I need this in order for the #Autowired annotation to work.
Now my question to you is: why is there no simple annotation that allows the #Autowire to function correctly? (Something like #AutowiredClass). The above method is too verbose and hard to remember, so surely there must be a better way to make #Autowired work on classes in order to inject services, just like we do in Grails where we just say def someService and it is automatically injected.
If you want properly use #Autowired in your spring-boot application, you must do next steps:
Add #SpringBootApplicationto your main class
Add #Service or #Component annotation to class you want inject
Use one of two ways that you describe in question, to autowire
If you don't have any wiered package structure and the main class package includes all other classes you want spring to instantiate (directly or in the subpackages) a simple annotation #ComponentScan on your main class will help you save all those boiler plate code. Then spring will do the magic, it will go and scan the package(and subpackages) and look for classes annotated with #Service, #Component etc and instantiate it.
Even better, use #SpringBootApplication in your main class, this will cover #Configuration as well. If it is a green field project , I would encourage to start from start.spring.io - a template generation/scaffolding tool for spring
Now my question to you is: why is there no simple annotation that allows the #Autowire to function correctly?
There is: #SpringBootApplication
If you put this at the root of your application (file that contains the main class) and as long as your services are at the same package or a sub-package, Spring will auto-discover, instantiate, and inject the proper classes.
There's an example in this walk-through: REST Service with Spring Boot
As described in that page:
#SpringBootApplication is a convenience annotation that adds all of the following:
#Configuration tags the class as a source of bean definitions for the application context.
#EnableAutoConfiguration tells Spring Boot to start adding beans based on classpath settings, other beans, and various property settings.
#ComponentScan tells Spring to look for other components, configurations, and services in the hello package, allowing it to find the controllers.
You need to annotate the implementation of RestService as a #Service or #Component so Spring would pick it up.
#Service
public class MyRiskAssessorImpl implements RiskAssessor {
///
}
#Autowired almost works out of the box. Just do your component scanning of the class you want to autowire and you are done. Just make sure your main class (or main configuration class) uses #ComponentScan("{com.example.app}") or #SpringBootApplication (main class). The docs explain this stuff pretty good

Consider defining a bean of type 'package' in your configuration [Spring-Boot]

I am getting the following error:
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of method setApplicant in webService.controller.RequestController required a bean of type 'com.service.applicant.Applicant' that could not be found.
Action:
Consider defining a bean of type 'com.service.applicant.Applicant' in your configuration.
I have never seen this error before but it's odd that the #Autowire is not working. Here is the project structure:
Applicant Interface
public interface Applicant {
TApplicant findBySSN(String ssn) throws ServletException;
void deleteByssn(String ssn) throws ServletException;
void createApplicant(TApplicant tApplicant) throws ServletException;
void updateApplicant(TApplicant tApplicant) throws ServletException;
List<TApplicant> getAllApplicants() throws ServletException;
}
ApplicantImpl
#Service
#Transactional
public class ApplicantImpl implements Applicant {
private static Log log = LogFactory.getLog(ApplicantImpl.class);
private TApplicantRepository applicantRepo;
#Override
public List<TApplicant> getAllApplicants() throws ServletException {
List<TApplicant> applicantList = applicantRepo.findAll();
return applicantList;
}
}
Now I should be able to just Autowire Applicant and be able to access, however in this case it is not working when I call it in my #RestController:
#RestController
public class RequestController extends LoggingAware {
private Applicant applicant;
#Autowired
public void setApplicant(Applicant applicant){
this.applicant = applicant;
}
#RequestMapping(value="/", method = RequestMethod.GET)
public String helloWorld() {
try {
List<TApplicant> applicantList = applicant.getAllApplicants();
for (TApplicant tApplicant : applicantList){
System.out.println("Name: "+tApplicant.getIndivName()+" SSN "+tApplicant.getIndSsn());
}
return "home";
}
catch (ServletException e) {
e.printStackTrace();
}
return "error";
}
}
------------------------UPDATE 1-----------------------
I added
#SpringBootApplication
#ComponentScan("module-service")
public class WebServiceApplication extends SpringBootServletInitializer {
#Override protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(WebServiceApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(WebServiceApplication.class, args);
}
}
and the error went away but nothing happened. However when I commented out everything dealing with Applicant in the RestController prior to adding #ComponentScan() I was able to return a string the UI, thus meaning my RestController was working, now it is being skipped. I ugly Whitelabel Error Page now.
---------------------UPDATE 2------------------------------
I added the base package of the bean it was complaining about. Error reads:
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of method setApplicantRepo in com.service.applicant.ApplicantImpl required a bean of type 'com.delivery.service.request.repository.TApplicantRepository' that could not be found.
Action:
Consider defining a bean of type 'com.delivery.request.request.repository.TApplicantRepository' in your configuration.
I added #ComponentScan
#SpringBootApplication
#ComponentScan({"com.delivery.service","com.delivery.request"})
public class WebServiceApplication extends SpringBootServletInitializer {
#Override protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(WebServiceApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(WebServiceApplication.class, args);
}
}
----------------------------Update 3----------------------
adding:
#SpringBootApplication
#ComponentScan("com")
public class WebServiceApplication extends SpringBootServletInitializer {
still is complaining about my ApplicantImpl class which #Autowires my repo TApplicantRepository into it.
It might be because the project has been broken down into different modules.
#SpringBootApplication
#ComponentScan({"com.delivery.request"})
#EntityScan("com.delivery.domain")
#EnableJpaRepositories("com.delivery.repository")
public class WebServiceApplication extends SpringBootServletInitializer {
There is a chance...
You might be missing #Service, #Repository or #Component annotation on your respective implementation classes.
Your Applicant class is not scanned it seems. By default all packages starting with the root as the class where you have put #SpringBootApplication will be scanned.
suppose your main class "WebServiceApplication" is in "com.service.something", then all components that fall under "com.service.something" is scanned, and "com.service.applicant" will not be scanned.
You can either restructure your packages such that "WebServiceApplication" falls under a root package and all other components becomes part of that root package. Or you can include #SpringBootApplication(scanBasePackages={"com.service.something","com.service.application"}) etc such that "ALL" components are scanned and initialized in the spring container.
Update based on comment
If you have multiple modules that are being managed by maven/gradle, all spring needs is the package to scan. You tell spring to scan "com.module1" and you have another module which has its root package name as "com.module2", those components wont be scanned. You can even tell spring to scan "com" which will then scan all components in "com.module1." and "com.module2."
Basically this happens when you have your Class Application in "another package". For example:
com.server
- Applicacion.class (<--this class have #ComponentScan)
com.server.config
- MongoConfig.class
com.server.repository
- UserRepository
I solve the problem with this in the Application.class
#SpringBootApplication
#ComponentScan ({"com.server", "com.server.config"})
#EnableMongoRepositories ("com.server.repository") // this fix the problem
Another less elegant way is to: put all the configuration classes in the same package.
In my case I had a terrible mistake. I put #Service up to the service interface.
To fix it, I put #Service on the implementation of service file and it worked for me.
If a bean is in the same package in which it is #Autowired, then it will never cause such an issue. However, beans are not accessible from different packages by default.
To fix this issue follow these steps :
Import following in your main class:
import org.springframework.context.annotation.ComponentScan;
add annotation over your main class :
#ComponentScan(basePackages = {"your.company.domain.package"})
public class SpringExampleApplication {
public static void main(String[] args) {
SpringApplication.run(SpringExampleApplication.class, args);
}
}
Important:
For anybody who was brought here by googling the generic bean error message, but who is actually trying to add a feign client to their Spring Boot application via the #FeignClient annotation on your client interface, none of the above solutions will work for you.
To fix the problem, you need to add the #EnableFeignClients annotation to your Application class, like so:
#SpringBootApplication
// ... (other pre-existing annotations) ...
#EnableFeignClients // <------- THE IMPORTANT ONE
public class Application {
Side note: adding a #ComponentScan(...) beneath #SpringBootApplication is redundant, and your IDE should flag it as such (IntelliJ IDEA does, at least).
This can also happen if you are using Lombok and you add the #RequiredArgsConstructor and #NonNull for fields but some of your fields are not to be injected in the constructor. This is only one of the possibilities to get the the same error.
parameter 0 required a bean of type MissingBeanName that could not be found
In my case the error told me what Controller the problem was in, after removing #NonNull the application started fine
In my case these two options worked.
in //#ComponentScan ({"myapp", "myapp.resources","myapp.services"})
include also the package which holds the Application.class in the list, or
Simply add #EnableAutoConfiguration; it automatically recognizes all the spring beans.
I faced with familiar problem in my Maven multi-module project with Spring Boot 2. The problem was related to naming of my packages in sub Maven modules.
#SpringBootApplication incapsulate a lots of component like - #ComponentScan, #EnableAutoConfiguration, jpa-repositories, json-serialization and so on. And he places #ComponentScan in com.*******.space package. This part of packages com.*******.space must be common for all modules.
For fixing it:
You should rename all module packages. Other words you had to have in all packages in all Maven modules - the same parent part. For example - com.*******.space
Also you have to move your entry point to this package - com.*******.space
I think you can make it simplified by annotating your repository with #Repository, then it will be enabled automatically by Spring Framework.
It worked for me after adding below annotation in application:
#ComponentScan({"com.seic.deliveryautomation.mapper"})
I was getting the below error:
"parameter 1 of constructor in required a bean of type mapper that could not be found:
Moving the Springbootapplication(application.java) file to another package resolved the issue for me. Keep it separate from the controllers and repositories.
In my case this error appear because my import was wrong, for example, using spring, the import automatically appear:
import org.jvnet.hk2.annotations.Service;
but i needed:
import org.springframework.stereotype.Service;
I faced the same issue. Mongo DB repository was identified by Spring boot, but it was not creating Bean for a repository interface that extended the mongo repository.
The issue in my case was incorrect version specification in maven pom for "spring + mango". I have changed the artifact's group id and it all worked like magic. no annotations needed as spring boot took care of everything.
During my problem resolution, I was all over web searching for solutions and realized that this problem is actually project configuration related, anyone facing this issue should first check their project setup and enable debug from spring to get more details on failure and pay close attention to where exactly in the process, the creation has failed.
I sought online for an answer but it seems there is no one proper solution to my case:
At the very beginning, everything works well as follows:
#Slf4j
#Service
#AllArgsConstructor(onConstructor = #__(#Autowired))
public class GroupService {
private Repository repository;
private Service service;
}
Then I am trying to add a map to cache something and it becomes this:
#Slf4j
#Service
#AllArgsConstructor(onConstructor = #__(#Autowired))
public class GroupService {
private Repository repository;
private Service service;
Map<String, String> testMap;
}
Boom!
Description:
Parameter 4 of constructor in *.GroupService required a bean of type 'java.lang.String' that could not be found.
Action:
Consider defining a bean of type 'java.lang.String' in your configuration.
I removed the #AllArgsConstructor(onConstructor = #__(#Autowired)) and add #Autowired for each repository and service except the Map<String, String>. It just works as before.
#Slf4j
#Service
public class SecurityGroupService {
#Autowired
private Repository repository;
#Autowired
private Service service;
Map<String, String> testMap;
}
Hope this might be helpful.
This can happen if the #Service class is marked abstract.
#Configuration annotation will just solve the error
You'll also get this error if you accidentally define the same bean in two different classes. That happened to me. The error message was misleading. When I removed the extra bean, the issue was resolved.
My error was that I had included:
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
instead of:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
It might help somebody. I had the same problem, same error message, same everything. I tried solutions from other answers, didn't help until I realised that the bean I am using has the same name as the one that is actually been autowired. It happened in the midst of refactor, thus I had to rename the class, which resulted positively. Cheers
Try configuring the project structure as given below:
Put all the repo, service, packages in the child package of the main package:
package com.leisure.moviemax; //Parent package
#SpringBootApplication
#PropertySource(value={"classpath:conf.properties"})
public class MoviemaxApplication implements CommandLineRunner {
package com.leisure.moviemax.repo; //child package
#Repository
public interface UsrRepository extends JpaRepository<UserEntity,String> {
This error message also pops up when you fail to annotate the Entity classes associated with your bean with the #Entity Annotation.
My ComponentScan worked fine but this popped up for the #repository interface:
#Repository
public interface ExpenseReportAuditRepository extends
PagingAndSortingRepository<ExpenseReportAudit, Integer> {
because I failed to add the #Entity annotation to ExpenseReportAudit
#Entity // <--- Adding this fixed the issue.
public class ExpenseReportAudit {
.....
#SpringBootApplication
#MapperScan("com.developer.project.mapper")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
I had a case where i need to inject RestTemplate into a service class. However, the RestTemplate cannot be picked up by the service class. What I did is to create a wrapper class under the same package as main application and mark the wrapper as Component and autowire this component in the service class. Problem solved. hope it also works for you
If your class dependency is managing by Spring then this issue may occur if we forgot to add default/empty arg constructor inside our POJO class.
There is a chance that you are trying to #autowired an interface before implement the interface.
example solution:
**HomeController.java**
class HomeController{
#Autowired
UserService userService;
.....
}
----------------------------------------------------------------------
**UserService.java**
public interface UserService {
User findByUsername(String username);
.....
}
-----------------------------------------------------------------------
**UserServiceImpl.java**
#Service
public class UserServiceImpl implements UserService{
public User findByUsername(String username) {
return userDao.findByUsername(username);
}
....
}
<i>This is not italic</i>, and [this is not a link](https://example.com)
In my case, our project has a Configuration class, so I just added mine like this
#Configuration
public class DependencyConfiguration {
#Bean
public ActivityService activityService(
#Value("${send.money.ms.activity.url}") final String activityHistoryUrl,
final HttpRestService httpRestService
) {
return new ActivityServiceImpl(activityHistoryUrl, httpRestService);
}
.......................
Then the microservice started alright.
PS: I encountered this issue even though the library I need is imported properly and could be seen on External Libraries imported.
Had the same error, transpired it was an issue with the application properties with incorrect username, password and driver and completely unrelated to Bean.
I also received a similar error:
Consider defining a bean of type 'A_REPOSITORY_INTERFACE' in your configuration.
Then, according to Akashe's solution, I added #EnableJpaRepositories to my main class. After that, I received the following error instead:
Consider defining a bean of type 'entityManagerFactory' in your configuration.
Next, I went through all the responses here, googled a lot and read a lot of other resources, which didn't worked out.
Finally, I was lucky to have found the solution on a blog/website (javatute.com). I just followed its examples.
Like suggested by many here, I added #ComponentScan("YOUR_BASE_PACKAGE.*") and #EntityScan("YOUR_BASE_PACKAGE.*") to my main app class, followed by adding a config package and creating a JpaConfig class like:
package YOUR_BASE_PACKAGE.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
#Configuration
#EnableJpaRepositories(basePackages = "YOUR_BASE_PACKAGE")
public class JpaConfig {
}
The blog I followed:
Consider defining a bean of type in your configuration
which lead me to:
Error creating bean with name entityManagerFactory defined in class path resource : Invocation of init method failed
and finally to:
Many To Many Mapping In Hibernate/JPA Using Spring Boot And Oracle

Categories