#SpringBootApplication not detecting another #Configuration component in the same package - java

This is my project package structure.
org.myApp
MainApplication.java
org.myApp.controller
org.myApp.repositories
org.myApp.utils
I have a #SpringBootApplication placed in my org.myApp.MainApplication class and I'm expecting that it will scan all my subpackages for components as they are placed in the same package as this main class.
However, I have created this new class in org.myApp.utils called Utils which is not being picked up by the application context.
package org.myApp.utils;
import java.util.Properties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.io.IOException;
#Configuration
public class Utils {
Utils() throws IOException{
getAllProps();
}
#Bean
public static Properties getAllProps() throws IOException{
return new Properties();
}
}
The class is only scanned when I explicitly use a #ComponentScan("org.myApp.Utils") in my MainApplication.java class however this breaks the rest of my application for some reason.
How do I ensure that my Utils class is scanned and placed in the application context?

Related

I keep getting this #bean error when trying to run my spring boot app with dynamodb and graphql

This is the error which i am getting:
Description:
Field andiRepository in com.service.datafetcher.AllAndisDataFetcher required a bean of type 'com.repositories.AndiRepository' 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 'com.repositories.AndiRepository' in your configuration.
This is the data fetcher file which is requiring a bean:
import com.models.Andi;
import com.repositories.AndiRepository;
import graphql.schema.DataFetcher;
import graphql.schema.DataFetchingEnvironment;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
#Component
public class AllAndisDataFetcher implements DataFetcher<List<Andi>> {
#Autowired
AndiRepository andiRepository;
#Override
public List<Andi> get(DataFetchingEnvironment dataFetchingEnvironment) throws Exception {
return andiRepository.findAll();
}
}
this is the main method which resides in "com".
package com;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
#SpringBootApplication
#ComponentScan("com.repositories")//to scan repository files
#EntityScan("com.models")
#EnableJpaRepositories("com.repositories.AndiRepository")
public class DynamoDBApplication {
public static void main(String[] args) {
SpringApplication.run(DynamoDBApplication.class, args);
}
}
The models, repositories, service, packages are inside the main com package.
This is the repository file:
package com.repositories;
import com.andiskillsmaxmodels.Andi;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface AndiRepository extends CrudRepository<Andi, Integer> {
}
Thank you
Correct your package names. They're all over the place. You have imported classes from different packages it seems. Make sure that AndiRepository is in the com.repositories package. And Andi class in your com.models package. After correcting these mistakes do the following.
Remove #ComponentScan("com.repositories"). You don't need this, since #SpringBootApplicationautomatically does it for you.
And replace #SpringBootApplication with #SpringBootApplication(scanBasePackages = "com")

NoSuchBeanDefinitionException being thrown

So I am trying to use a bean generated in another class to be used in the main application
package com.simon.spring.basics.properties;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
#Component
public class SomeExternalService {
#Value("${external.service.url}")
private String url;
public String returnServiceURL(){
return url;
}
}
And the main application is here:
package com.simon.spring.basics.springin5steps;
import com.simon.spring.basics.properties.SomeExternalService;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
#Configuration
#SpringBootApplication
//#PropertySource("classpath:application.properties")
#ComponentScan()
public class SpringIn5StepsPropertiesApplication {
public static void main(String[] args) {
ApplicationContext applicationContext =
SpringApplication.run(SpringIn5StepsPropertiesApplication.class, args);
SomeExternalService service = applicationContext.getBean(SomeExternalService.class);
System.out.println(service);
}
}
So basically a Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.simon.spring.basics.properties.SomeExternalService' available is being thrown.
What Can I do to fix this error and to avoid the same problems later on
Put SpringIn5StepsPropertiesApplication in your package root;
package com.simon.spring.basics
also remove unnecessary #ComponentScan()
#SpringBootApplication will automatically trigger a component scan under all packages from the location of main class, namely com.simon.spring.basics, so your component in com.simon.spring.basics.properties can be picked up.
Otherwise it will try to find beans under com.simon.spring.basics.springin5steps and fail to find SomeExternalService
If moving the main class is not an option, then you can add the other package like;
#SpringBootApplication(scanBasePackageClasses = {com.simon.spring.basics.properties.SomeExternalService.class})

Spring Annotations Import Config not called

I am trying to make an application that uses Spring annotations to import the configurations. For this question i narrowed it down to two files. The Startup class:
package core;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
#Slf4j
#Configuration
#Import(ConfigSettings.class)
public class Startup {
public static void main (String args[]) {
log.info("main class");
}
}
and the ConfigSettings
package core;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
#Slf4j
#Configuration
#ComponentScan({"connections", "filter"})
#PropertySource({"classpath:config/${env.config:dev}.application.properties"})
public class ConfigSettings {
public ConfigSettings() {
log.info("Constructor ConfigSettings");
}
}
I expected the outcome to be:
[INFO]Constructor ConfigSettings
[INFO]main class
But it only shows mainclass. It looks like the constructor of the config settings is not called at all. I expect it to call it because of the import annotation.
Can anyone explain what is going wrong? Thank you in advance!
Your best bet is to make the config class return config object that contains your values. Generally I don't tend to add an all-encompassing config object, but have a config file for each component (database, controllers, etc...).
You can then return the configured object as a bean and let spring inject it. If I were to make a config file for a RestTemplate (as a simple example):
#Service
public class RestClientConfig {
#Value("${your.config.value}")
private String yourValue;
private final RestTemplate restTemplate = new RestTemplate();
#Bean
public RestTemplate restTemplate() {
// Configure it, using your imported values
// ...
return restTemplate;
}
}
However, the main method is outside of the spring container and you won't be able to bootstrap it that way, but with the above method you can call the configured component directly where you need to use it.

Why is #PostConstruct recognised in my case?

Could you tell me why does a method annotated with #PostContruct runs in my case? As far as I know, a method with #PostContruct is processed by Bean Post Processors. If you want to activate the default CommonAnnotationBeanPostProcessor you need to add <context:annotation-config/> in the XML configuration but I want to use only annotation config. In my case, #ComponentScan in configuration is pointed to the service. It means that only classes from this package candidates to be instantiated.
Configuration class:
package config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
#Configuration
#ComponentScan(basePackages = "service")
public class AppConfig {
}
Simple class:
package service;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
#Component
public class Simple {
#PostConstruct
private void sout(){
System.out.println("SOUT");
}
}
And the launcher:
import config.AppConfig;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import service.Simple;
public class Launcher {
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
Simple simple = ctx.getBean("simple", Simple.class);
}
}
The output of the app is "SOUT". Could you explain be who invokes the #PostContruct method and how?
AnnotationConfigApplicationContext is an alternative to XML based configurations. When you use it to create objects, it first creates the object and the #Autowired properties, and then calls the #PostConstruct method. It is a handy alternative to writing a setup() or init() method which you would have to call yourself.

No qualifying bean of type is defined when running a main method

I've seen a lot of questions about this error before, but no resolution that works for me.
I'm new to Spring, but trying to use the Spring Data for Neo4J library for a project. I decided to start with a quick spike to make sure I know how everything is working, and so I set up a simple App class with a main method like so:
package org.example.neo4jSpike;
import org.example.neo4jSpike.domain.Actor;
import org.example.neo4jSpike.repositories.ActorRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.stereotype.Component;
/**
* Hello world!
*
*/
#Component
public class App
{
#Autowired
private ActorRepository actors;
#SuppressWarnings("resource")
public static void main( String[] args )
{
ApplicationContext context = new AnnotationConfigApplicationContext(SpikeConfiguration.class);
App a = context.getBean(App.class);
a.init();
}
private void init(){
Actor michaelDouglas = actors.save(new Actor("Michael Douglas"));
System.out.println( "Hello World!" );
System.out.println(michaelDouglas.getId());
System.out.println("Total people: " + actors.count());
}
}
I have the configuration class setup as well:
package org.example.neo4jSpike;
import org.neo4j.ogm.session.Session;
import org.neo4j.ogm.session.SessionFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.data.neo4j.config.Neo4jConfiguration;
import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;
import org.springframework.transaction.annotation.EnableTransactionManagement;
#Configuration
#EnableNeo4jRepositories(basePackages = "org.example.neo4jSpike.repositories")
#EnableTransactionManagement
public class SpikeConfiguration extends Neo4jConfiguration{
#Bean
public SessionFactory getSessionFactory() {
// with domain entity base package(s)
return new SessionFactory("org.example.neo4jSpike.domain");
}
// needed for session in view in web-applications
#Bean
#Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public Session getSession() throws Exception {
return super.getSession();
}
}
I'll add the code for my repositories and domain classes if needed, but they're all set up in a similar manner, and are all pretty simple.
When I try and run the main, however, I get
No qualifying bean of type [org.example.neo4jSpike.App] is defined
I don't see how it's not defined, it's right there, defined as an #Component. What am I misunderstanding?
Doesn't matter if you put the #Component annotation if Spring is not scanning your class package. You can add a #ComponentScan annotation in you configuration class and configure it to scan the package where your App class is located. Alternatively you can remove the #Component annotation and declare a Bean of type App in the configuration class.
Hope this can help.

Categories

Resources