Spring does not find bean - spring

I get the following error:
Field delegate in package.rest.api.MyApiController required a bean of type 'package.rest.api.MyApiDelegate' that could not be found.
I've tried to add annotation #ComponentScan("package.rest") to the main class, but it didn't help.
package package;
#SpringBootApplication
#Import(SpecificationConf.class)
//#ComponentScan("package.rest")
public class MyApp extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
}
package package.rest.api;
#Controller
#RequestMapping(...)
public class MyApiController implements MyApi {
#Autowired
#Qualifier("myService")
private MyApiDelegate delegate;
}
package package.rest;
#Service("myService")
public class MyApiDelegateImpl implements MyApiDelegate {
...
}
package package.rest.api;
public interface MyApiDelegate {
...
}
Can that problem happen due to incorrect configuration of the Application context or an inappropriate maven profile? I've tried to move classes to the same package, but it also didn't help.

Given that you are building a JAR file and not a WAR file, please try dropping SpringBootServletInitializer from your main class as follows:
package package;
#SpringBootApplication
#Import(SpecificationConf.class)
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
}

Related

Spring interface injection from external jar

I have spring API based authentication classes in external library,
Below are some of the classes in external library,
package com.security;
import org.springframework.security.authentication.AuthenticationProvider;
#Component
public class ApiKeyAuthenticationProvider implements AuthenticationProvider {
private static final Logger LOGGER = LoggerFactory.getLogger(ApiKeyAuthenticationProvider.class);
private ApiAuthCredentialsConfig apiAuthCredentialsConfig;
public ApiKeyAuthenticationProvider(ApiAuthCredentialsConfig apiAuthCredentialsConfig) {
this.apiAuthCredentialsConfig = apiAuthCredentialsConfig;
}
}
ApiAuthCredentialsConfig:
package com.security;
public interface ApiAuthCredentialsConfig {
String getAuthToken();
String getAuthTokenHeaderName();
}
And in the repo I have added the above external library as a gradle dependency.
I have below changes in actual repo.
#Component
#Data
public class ApiAuthenticationConfig implements ApiAuthCredentialsConfig {
#Value("${auth-token}")
private String authToken;
#Value("${auth-token-header-name}")
private String authTokenHeaderName;
}
SecurityConfig:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private ApiKeyAuthenticationProvider apiKeyAuthenticationProvider;
#Override
public void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.
antMatcher("/**").
csrf().disable().
sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).
and().addFilterBefore(new ApiKeyAuthenticationFilter(authenticationManager(), apiKeyAuthenticationProvider.getHeaderName()), AnonymousAuthenticationFilter.class)
.authorizeRequests().anyRequest().authenticated();
}
#Bean
public AuthenticationManager authenticationManager() {
return new ProviderManager(Collections.singletonList(apiKeyAuthenticationProvider));
}
}
Application:
#SpringBootApplication(scanBasePackages = {"com.security"})
#EnableSwagger2
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
When I run the application its failing with below error
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in com.security.ApiKeyAuthenticationProvider required a bean of type 'com.security.ApiAuthCredentialsConfig' that could not be found.
How to resolve this issue?
After the above comment, I realized that ApiAuthenticationConfig is not in the same package as ApiAuthCredentialsConfig, after I moved ApiAuthenticationConfig to com.security package it started working.

Spring Boot #Component doesn't create Beans

Since according to the docs #Component registers beans for the Spring container I'm trying to create a simple example of dependency injection using the following code:
package pl.playground;
//...
#SpringBootApplication
public class PlaygroundApplication {
#Autowired
private static Building building;
public static void main(String[] args) {
building.setBuildingSize(12L);
System.out.println(building.monthlyHeatingCost());
}
}
package pl.playground.facade;
//...
#Component
public class Building {
private HeatingService service;
private Long buildingSize;
#Autowired
public Building(HeatingService service) {
this.service = service;
}
public Double monthlyHeatingCost() {
return service.getMonthlyHeatingCost(buildingSize);
}
// getters & setters...
}
package pl.playground.service;
public interface HeatingService {
Double getMonthlyHeatingCost(Long size);
}
package pl.playground.service;
//...
#Component
public class HeatingServiceImpl implements HeatingService {
private final Double CUBIC_PRICE = 2.3;
public HeatingServiceImpl() {}
#Override
public Double getMonthlyHeatingCost(Long size) {
return size * CUBIC_PRICE;
}
}
It builds and runs, but there is a NullPointerException at building.setBuildingSize(12L);. However the one below works without any issues:
//PlaygroundApplication.java
package pl.playground;
//...
#SpringBootApplication
public class PlaygroundApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
Building building = context.getBean(Building.class);
building.setBuildingSize(12L);
System.out.println(building.monthlyHeatingCost());
}
}
package pl.playground.config;
//...
#Configuration
public class Config {
#Bean
public Building building(HeatingService service) {
return new Building(service);
}
#Bean
public HeatingServiceImpl heatingServiceImpl() {
return new HeatingServiceImpl();
}
}
The rest is the same as before.
Why is #Component not creating Beans?
It is working the way I think it should when used inside a #Controller of a web app, does that make a difference? How does exactly #Bean and #Component differ?
What am I failing to understand?
EDIT
Consider the following scenario:
package pl.playground;
//...
#SpringBootApplication
public class ExampleApplication {
public static void main(String[] args) {
SpringApplication.run(ExampleApplication.class, args);
}
}
package pl.playground.controller;
//...
#Controller
public class Controller {
private Facade facade;
#Autowired
public Controller(Facade facade) {
this.facade = facade;
}
#GetMapping("/")
public String getIndexPage(Model model) {
return "index";
}
}
package pl.playground.facade;
//...
#Component
public class Facade {
private PostsService postService;
private UserService userService;
private TagService tagService;
#Autowired
public Facade(PostsService retrieve, UserService user, TagService tag) {
this.postService = retrieve;
this.userService = user;
this.tagService = tag;
}
//...
}
I don't need #Configuration here for it to work. That's my concern.
The problem with your code is that you are trying to #Autowire on a static field. You simply cannot do that. Look here: Can you use #Autowired with static fields?
It fails to work because the PlaygroundApplication class is not being created and managed by spring. The injection works only inside instances managed by spring. You can treat class annotated with #SpringBootApplication as configuration classes. Spring creates instances of those classes and injection works inside them but only on instance fields.
The second example shows the correct way to access spring beans from main method of the application.
Well. I used your original question and is working without any issues. #cezary-butler pointed out in the comments you can autowire into PlaygroundApplication but you can get hold of it easily in the static main method using context.getBean(Building.class)
#SpringBootApplication
public class PlaygroundApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context =
SpringApplication.run(PlaygroundApplication.class);
Building building = context.getBean(Building.class);
building.setBuildingSize(12L);
System.out.println(building.monthlyHeatingCost());
}
}
Here is the sample repo https://github.com/kavi-kanap/stackoverflow-63072236
TLDR;
A Spring context needs to be created before any bean can be injected. In the first scenario, just the fact of having a #SpringBootApplication decorator does not ensure a context in the scope of the class it decorates.
SpringApplication.run(ExampleApplication.class, args); instantiates a context (and e.g. a web server among other things)
var context = new AnnotationConfigApplicationContext(Config.class); instantiates a scoped context
Thus the first example had null inside of Building as there was no context with the bean to inject.

Spring boot - autowire fails

I'm trying to fetch some properties from application.properties file ad my code is the following:
Main Application class:
package it.mysite;
#SpringBootApplication
#EnableTransactionManagement
public class MailSenderApplication {
public static void main(String[] args){
ConfigurableApplicationContext context = SpringApplication.run(MailSenderApplication.class, args);
System.out.println("*****");
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
System.out.println("*****");
new MySendService().sendReport();
}
}
My service class:
package it.mysite.service;
#Service
public class MySendService {
#Value("${mail.fc.to}")
private String[] to;
#Value("${mail.fc.subject}")
private String subject;
#Autowired ReportService reportEmailService;
#Autowired MailProperties mailProperties;
public void sendReport(){
if(mailProperties.getTo().length > 0) {
}
}
Class where I fetch the properties:
package it.mysite.properties;
#Component
#ConfigurationProperties("mail.fc")
public class MailProperties {
private String[] to;
public String[] getTo(){
return to;
}
}
Config file:
# Email config
mail.fc.to=my#mail.com
mail.fc.subject=My subject
All of the #Autowired properties are null, and also the #Value properties (I tried to get them in that way also). When I print my context I can see these classes in the bean list, and for what I know my packages hierarchy is correct, so what can be the problem?
EDIT
Ok, I got the suggestion from the duplicate question and I changed my main class code as follows:
Main Application class:
package it.mysite;
#SpringBootApplication
#EnableTransactionManagement
public class MailSenderApplication {
#Autowired MySendService mySendService;
public static void main(String[] args){
ConfigurableApplicationContext context = SpringApplication.run(MailSenderApplication.class, args);
System.out.println("*****");
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
System.out.println("*****");
new MailSenderApplication().boot();
}
private void boot(){
mySendService.sendReport();
}
}
But I got the same error. Wasn't that the suggestion?

#SpringbootApplication does not scan components in default package

Hi I have my main class of spring boot app in package com
and two other beans defined in com.bbh.fx.pack1.
As per my understanding SpringBootApplication will autoscan all the components in its pakacge and childern package. But it is not scanning. Not sure what i am missing
**package com.bbh.fx.pack1;**
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
#Component
public class BeanA {
#PostConstruct
public void init() {
System.out.println("in BEANA");
}
}
**package com;**
#SpringBootApplication
public class MainApp{
public static void main(String[] args) {
SpringApplication.run(MainApp.class, args);
}
}
You do not have a main in your MainApp your code should look like:
#SpringBootApplication
public class MainApp{
public static void main(String[] args) {
SpringApplication.run(MainApp.class, args);
}
}
I usually like to start all new applications from https://start.spring.io/ you can choose your project name, build type (maven or gradle) and select any spring dependencies you'd like included in the application.
Use #ComponentScan to scan components.
#SpringBootApplication
#ComponentScan("com")
public class MainApp{
public static void main(String[] args) {
SpringApplication.run(MainApp.class, args);
}
}

Create Spring boot standalone app

I'm trying to figure out how to build a Spring Boot standalone app. Of course to have things autowired requires some initial context starting point. If I just try to Autowire a class to run a job it is null even if I make it static.
Is there a way to use Spring #Services in a standalone non-web app?
#SpringBootApplication
public class MyApplication {
#Autowired
private static JobRunnerService job;
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
job.send(); //job is null !
}
}
So first wired in a static JobRunnerService to the main running MyApplication the JobRunner(Service) Class has a non-static SshSessionService wired into it.
the SshSession(Service) finally just has a no-arg constructor.
#Service("jobRunnerService")
public final class JobRunner implements JobRunnerService{
#Autowired
private SshSessionService ssh;
#Autowired
public JobRunner(SshSessionService ssh){
this.ssh = ssh;
}
public void sendToAgent() { ....
}
#Service("sshSessionService")
public class SshSession implements SshSessionService {
public SshSession() {
}
}
It starts off being null at the JobRunnerService job reference.
Several different solutions comes to mind:
If you take a look at the SpringApplication.run() method you will notice that it returns a ApplicationContext. From that, you can fetch the JobRunnerService, e.g.
#SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(MyApplication.class, args);
JobRunnerService job = ctx.getBean(JobRunnerService.class);
job.send();
}
}
Another solution is to use #PostConstruct annotation for the send() method:
#Service("jobRunnerService")
public class JobRunner implements JobRunnerService {
#PostConstruct
public void send() { ... }
}
However in your case, I would implement the ApplicationRunner interface, either as a separate bean which autowires the JobRunnerService and then calls its send() method
#Component
public class SendRunner implements ApplicationRunner {
#Autowired
private JobRunnerService job;
#Override
public void run(ApplicationArguments args) {
job.send();
}
}
or let the JobRunner implement the ApplicationRunner interface directly:
#Service("jobRunnerService")
public class JobRunner implements JobRunnerService, ApplicationRunner {
#Override
public void send() { ... }
#Override
public void run(ApplicationArguments args) {
send();
}
}
You haven't provided the code for JobRunnerService but I am assuming it has a default constructor and that it is annotated by #Component for Spring to figure it out as a bean before you can actually autowire it. your job is null probably because it's not able to find an autowired bean for JobRunnerService and that's probably because you don't have an identifier for Spring to scan and create bean of type JobRunnerService
You can use #Servicesor #Component to the JobRunnerService class then add annotation #ComponentScan("package of JobRunnerService") below #SpringBootApplication, see this link:
How to scan multiple paths using the #ComponentScan annotation?
You need a few steps to get your standalone app working:
A class with main() method.
A #SpringBootApplication annotation to your main class.
And a call to the SpringApplication.run() method.
package com.example.myproject;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication // same as #Configuration #EnableAutoConfiguration #ComponentScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
As noted, the #SpringBootApplication is a composite annotation which consist of #Configuration #EnableAutoConfiguration and #ComponentScan. In other words, it can be replaced by the three latter annotations. Alternatively, you can use the alias scanBasePackage or scanBasePackageClasses to customize which directories that should be used for component scanning.
The example is copied from the #SpringBootApplication paragraph in the Spring Boot reference docs (see link above). If you would like to quick start your project, complete with build scripts (Maven or Gradle), dependencies, etc, you can generate a project skeleton using the Spring Initializr
I'm trying to run as Thread/runnable now as mentioned in the Spring document 3. Task Execution and Scheduling..
import org.springframework.core.task.TaskExecutor;
public class TaskExecutorExample {
private class MessagePrinterTask implements Runnable {
private String message;
public MessagePrinterTask(String message) {
this.message = message;
}
public void run() {
System.out.println(message);
}
}
private TaskExecutor taskExecutor;
public TaskExecutorExample(TaskExecutor taskExecutor) {
this.taskExecutor = taskExecutor;
}
public void printMessages() {
for(int i = 0; i < 25; i++) {
taskExecutor.execute(new MessagePrinterTask("Message" + i));
}
}
}
So in my case I'm trying...
#Service("jobRunnerService")
#Component
public class JobRunner implements JobRunnerService, ApplicationRunner{
#Autowired
public TaskExecutor taskExecutor;
#Autowired
private SshSessionService ssh;
private class JobTask implements Runnable{
public void run(){
Boolean success = connectToAgent();
if(success){
log.debug("CONNECTED!!!");
}
}
}
/**
* Construct JobRunner with TaskExecutor
* #param taskExecutor
*/
#Autowired
public JobRunner(TaskExecutor taskExecutor, SshSessionService ssh) {
this.taskExecutor = taskExecutor;
this.ssh = ssh;
}
private Map<String, String> sessionParams;
private final Logger log = LoggerFactory.getLogger(this.getClass());
#Override
public void run(ApplicationArguments args) {
/**
* Starting point of application
*
*/
taskExecutor.execute(new JobTask());
}
just getting org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.core.task.TaskExecutor] found for dependency
How can i get the imported lib to be accepted as a TaskExecutor Bean ??

Resources