No qualifying bean, annotated with #ConfigurationProperties - spring

I use #ConfigurationProperties for configurating properties:
#Getter
#Setter
#ConfigurationProperties("kafka")
public class KafkaConnectionSettings {
private String bootstrapAddress = "dataflow-kafka:9092";
{
And trying to autowire it in other configuration-class. For example:
#Configuration
#AllArgsConstructor
public class KafkaProducerConfig {
private KafkaConnectionSettings kafkaSettings;
#Bean
public ProducerFactory<String, String> producerFactory() {
Map<String, Object> configProps = new HashMap<>();
configProps.put(
ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,kafkaSettings.getBootstrapAddress());
}
}
But I receive the following exeption:
No qualifying bean of type 'com.app.config.kafka.KafkaConnectionSettings' available: expected single matching bean but found 2: kafkaConnectionSettings,kafka-com.app.config.kafka.KafkaConnectionSettings
Its a "little" strange, considering that in "com.app.config"-package I have a similar config:
#Getter
#Setter
#ConfigurationProperties("app")
public class FileSettings {
}
and this last authowired successfully in classes, annotated with #Service
What am I doing wrong?

The problem is solved. I forgot to add KafkaConnectionSettings.class in #EnableConfigurationProperties at my testclass
#ActiveProfiles("test")
#EnableConfigurationProperties({FileSettings.class, KafkaConnectionSettings.class})
#RunWith(SpringRunner.class)
#SpringBootTest
public class AppTest {
Sorry for not quite clear question.

Related

#ConfigurationProperties, #Value not Working YET Passing the Tests

I have a strange problem reading configuration, none of solutions I've seen seem to work. Here is my code:
#SpringBootApplication
#EnableConfigurationProperties
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Here is my properties class
#Component
#ConfigurationProperties(prefix = "my")
#Data
#ToString
#NoArgsConstructor
#AllArgsConstructor
public class MyProperties {
private String host;
private int port;
}
I then use MyProperties class in my class using #Autowired:
#Autowired
private MyProperties props;
However, I'm getting null for my props object.
Strangely, this is passing the tests just perfectly:
#SpringBootTest
class ApplicationTests {
#Autowired
private MyProperties props;
#Test
void test_configuration() {
Assertions.assertEquals(props.getHost(), "xx.xx.xx.xx");//pass!
Assertions.assertEquals(props.getPort(), xxxxxx);//pass!
}
}
It has totally refused to work, and so has #Value injection. What could I be missing?
EDIT
Here's complete code of how I'm using #Autowired on MyProperties (I've included #Value which is also not working)
#Slf4j
#Component //also tried #Configurable, #Service
public class MyService {
#Autowired
private MyProperties props;
#Value("localhost")
public String host;
public void post() {
log.info(host + props);// =null and null
}
}
EDIT2
However, I've noticed that on the controller, it works perfectly okay:
#Slf4j
#RestController
#Service
public class Main {
#Autowired
private MyProperties props;
#Value("localhost")
private String host;
#GetMapping("/post")
public void post() {
log.info(host + props);//=it's perfect!
new MyService().post();// calling MyService - where #Autowired or #Value is failing
}
}
The reason this isn't working is because the MyService you're using isn't a Spring bean, but an instance you created by yourself (using new MyService()).
To make this work, you should autowire MyService, in stead of creating your own instance:
#Slf4j
#RestController
public class Main {
#Autowired // Autowire MyService
private MyService myService;
#GetMapping("/post")
public void post() {
myService.post(); // Use the myService field
}
}
For more information, look at this Q&A: Why is my Spring #Autowired field null.
UPDATE:
new MyService() is not a "spring bean", thus can't be auto-wired with anything!;)
1. Lombok
Some people use Project Lombok to add getters and setters automatically. Make sure that Lombok does not generate any particular constructor for such a type, as it is used automatically by the container to instantiate the object.
With "such a type" ConfigurationProperties is referred in Externalized Configuration (one of my favorite chapters;) More Exact: 2.8.1. JavaBean properties binding, at the bottom of second "Note!" ;)
So this could be a reason (for strange behavior).

How to #Autwired MessageSource in spring into Entity class correctly?

I have the following entity in spring boot application:
#Entity
#Data
#AllArgsConstructor
#NoArgsConstructor
#Audited
#XmlRootElement
#XmlAccessorType(XmlAccessType.NONE)
#Table(name = "currency", catalog = "currency_db")
public class Currency implements java.io.Serializable {
#Autowired
Messages messages;
As for message, it just a container of spring MessageSource here it is:
#ApplicationScope
#Component
#Slf4j
public class Messages {
#Autowired
private MessageSource messageSource;
private MessageSourceAccessor accessor;
#PostConstruct
private void init() {
accessor = new MessageSourceAccessor(messageSource, Locale.ENGLISH);
log.info("Messages initialized");
}
public String get(String code) {
return accessor.getMessage(code);
}
}
I'm getting the following error when run mvn clean install. Any idea what I'm missing here?
org.hibernate.MappingException: Could not determine type for: com.company.currencyservice.Messages, at table: currency, for columns: [org.hibernate.mapping.Column(messages)]
It's looks like hibernate think it's a column. Thanks.
Entities are not Spring beans and therefor you cannot use dependency injection in entities.
If you want to access a Spring bean from within an entity you can use a helper class like this:
#Service
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext context;
public static <T> T bean(Class<T> beanType) {
return context.getBean(beanType);
}
public static Object bean(String name) {
return context.getBean(name);
}
#Override
public void setApplicationContext(#SuppressWarnings("NullableProblems") ApplicationContext ac) {
context = ac;
}
}
Then you can use ApplicationContextProvider.getBean(Messages.class) to get access to the Messages.

springboot yml map property how to ref bean

I want to inject a map in yml file like that ;
abc-identify:
test:
51L: anhuiAbcIdentifyRule
my config class like that
#ConfigurationProperties(prefix = "abc-identify")
#Component
#Data
public class AbcIdentifyConfig {
private Map<Long, IdentifyRule> test;
anhuiAbcIdentifyRule is a existing bean in container
#Component
public class AnhuiAbcIdentifyRule implements IdentifyRule
I tried above setting which not work,how can I resolve this?
Spring does not support this type of string to bean conversion yet. Your code need to be changed to
private Map<Long, String> test;
If you want to get bean by rule from properties, there is a workaround.
#Data
#Component
#ConfigurationProperties(prefix = "abc-identify")
public class AbcProperties {
private Map<Long, String> test;
#Autowired
private Map<String, IdentifyRule> identifyRuleMap;
public IdentifyRule getRule(Long rule){
String beanName = test.get(rule);
if(beanName != null){
return identifyRuleMap.get(beanName);
}
return null;
}
}
Here Map<String, IdentifyRule> identifyRuleMap will contain all beans of IdentityRule with keys as beanName and values as bean.

#Qualifier & #Autowired object coming as null

I am having following code below.
#Builder(toBuilder = true)
#AllArgsConstructor(access = AccessLevel.PRIVATE)
#NoArgsConstructor(access = AccessLevel.PRIVATE)
#ToString
#EqualsAndHashCode
#Configurable
public class Employee {
#Autowired
#Qualifier("findEmpByDepartment")
private Function<Long, Long> empByDepartment;
private void save() {
this.empByDepartment.getList();
}
}
and FindEmpByDepartment class below.
#Component("findEmpByDepartment")
public class FindEmpByDepartment implements Function<Long, Long> {
public void getList() {
}
....
}
My problem is I am always getting null when invoke
this.empByDepartment.getList();
line. Here this.empByDepartment is coming as null. Any idea why it is like this?
Thanks
May be you would have missed annotating any class in the flow hierarchy .
#Service, #Repository and #Controller are all specializations of #Component, so any class you want to auto-wire needs to be annotated with one of them.
IoC is like the cool kid on the block and if you are using Spring then you need to be using it all the time .
So make sure you do not have any object created with new operator in the entire flow .
#Controller
public class Controller {
#GetMapping("/example")
public String example() {
MyService my = new MyService();
my.doStuff();
}
}
#Service
public class MyService() {
#Autowired
MyRepository repo;
public void doStuff() {
repo.findByName( "steve" );
}
}
#Repository
public interface MyRepository extends CrudRepository<My, Long> {
List<My> findByName( String name );
}
This will throw a NullPointerException in the service class when it tries to access the MyRepository auto-wired Repository, not because there is anything wrong with the wiring of the Repository but because you instantiated MyService() manually with MyService my = new MyService().
For more details , you can check
https://www.moreofless.co.uk/spring-mvc-java-autowired-component-null-repository-service/

Spring Boot not autowiring #Repository

I'm trying to configure a datasource with Spring Boot but I'm getting org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'authenticationServiceImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.mycompany.myapp.repository.UserRepository com.mycompany.myapp.service.AuthenticationServiceImpl.userRepository; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.mycompany.myapp.repository.UserRepository] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
These is my project structure:
Main Class:
package com.mycompany.myapp;
#ComponentScan(basePackageClasses = {com.mycompany.myapp.domain.user.User.class,
com.mycompany.myapp.repository.UserRepository.class,
com.mycompany.myapp.service.AuthenticationServiceImpl.class})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Domain Class:
package com.mycompany.myapp.domain.user
#Entity
public class User {
#Id
#GeneratedValue
private long id;
#Column(nullable = false)
private String name;
#Column(nullable = false)
private String lastName;
#Column(nullable = false)
private String password;
#Column(nullable = false)
private String email;
public User() {}
public User(String email, String password){
this.email = email;
this.password = password;
}
}
Repository:
package com.mycompany.myapp.repository;
public interface UserRepository extends CrudRepository<User, Long> {
List<User> findByLastName(String lastName);
}
Controller
package com.mycompany.myapp.service;
#RestController
public class AuthenticationServiceImpl implements AuthenticationService {
#Autowired
private UserRepository userRepository;
#RequestMapping("/add")
public User add(){
User user = new User();
user.setName("Juan");
user.setLastName("Sarpe");
user.setEmail("email#gmail.com");
userRepository.save(user);
return user;
}
}
application.properties
spring.datasource.url:jdbc:mysql://localhost:3306/mydb
spring.datasource.username=user
spring.datasource.password=pass
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update
I guess my app is not detecting my #Repository annotation on UserRepository. As far as I know, Spring Boot will automatically set my class as #Repository because it is extending CrudRepository. What am I doing wrong? (Notice that my Application class is on top of packages hierarchy).
In main class of spring boot you have to use this below annotation :
#SpringBootApplication
#ComponentScan(basePackages = "basepackage")
#EntityScan(basePackages ="basepackage")
#EnableAutoConfiguration
#EnableJpaRepositories(basePackages = "basepackage")
In Repository layer use below annotation :
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
#Transactional
#Repositor
If you have any service layer then use below annotation in the implementation class:
import org.springframework.stereotype.Service;
#Service
Have you tried #EnableJpaRepositories in your configuration ?
The standard way to configure is to create a base marker repository interface and provide that in the component scan.
public interface RepositoryPackage {
}
Keep the interface RepositoryPackage in the same package as UserRepository.
#ComponentScan(basePackageClasses= "RepositoryPackage.class")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

Resources