#Required causes exceptions even when bean is initialized - java

I would like for Spring Boot to throw an exception if any of my beans are not fully configured during initialization. I thought that the correct way to do that would be to annotate the relevance bean methods with #Required, but it does not behave as I expect.
application.yml:
my_field: 100
Simple bean class:
package com.example.demo;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.stereotype.Component;
#Component
public class MyProperties {
private int myField;
public MyProperties(){}
#Required
public void setMyField(int myField) {
this.myField = myField;
}
#Override
public String toString() {
return "{myField=" + myField + '}';
}
}
My application class:
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import javax.annotation.PostConstruct;
#SpringBootApplication
public class DemoApplication {
#Bean
#ConfigurationProperties
public MyProperties getMyProperties() {
return new MyProperties();
}
#PostConstruct
public void init() {
MyProperties myProperties = getMyProperties();
System.out.println(myProperties);
}
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
In the init method of DemoApplication I am printing the resulting bean object. Without the #Required annotation it is loaded correctly and prints {myField=100}. However, when I add the annotation it throws this exception:
org.springframework.beans.factory.BeanInitializationException: Property 'myField' is required for bean 'myProperties'
This is despite the fact that the config file contains the required value.
What is the correct to tell Spring that a field is required?

From the docs
Spring Boot will attempt to validate #ConfigurationProperties classes whenever they are annotated with Spring’s #Validated annotation. You can use JSR-303 javax.validation constraint annotations directly on your configuration class. Simply ensure that a compliant JSR-303 implementation is on your classpath, then add constraint annotations to your fields
You should declare myField as follows:
#NonNull
private int myField;

Related

How to keep duplicate spring bean in container. [ConflictingBeanDefinitionException]

I am working on an application which uses some third java libraries which are build on top of core spring framework.
Now when my application uses these libraries I am getting ConflictingBeanDefinitionException because two libraries have the same bean name.
Now as these libraries are external I cannot change the bean name. Is there a way by which in my application I can use both the beans in same container?
#Component
class ApplicationLogic {
#Autowire FetcherAndResolver fetchFromLibraryA;
#Autowire FetcherAndResolver fetchFromLibraryB; //Because both bean names are same here comes the exception.
}
I think this would require a bit of a hack.
First of all, structure your packages in a way so that external beans are not added automatically.
So, if external class is located in package a.b. Then you have to move your own classes in either a.c or a.b.c. THis will ensure that you are in control of how beans are initialized.
Once this is done, you can add a #Configuration class where you can create Beans of both type:
#Configuration
public class ExternalBeanConfiguration {
#Bean("internal-resolver" )
public FetcherAndResolver internalResolver() {
return new FetcherAndResolver();
}
#Bean("external-resolver" )
public a.b.c.FetcherAndResolver externalResolver() {
return new a.b.c.FetcherAndResolver();
}
}
I am assuming that FetcherAndResolver is a class rather than an interface. If it is an interface, it is easier to do it as you won't have to use fully-qualified name for classes.
Then you can simply autowire with qualifiers.
#Component
public class SomeComponent {
#Qualifier( "internal-resolver" )
FetcherAndResolver internalResolver;
#Qualifier( "external-resolver" )
FetcherAndResolver externalResolver;
}
First component from third java libraries:
package com.example.component1;
import org.springframework.stereotype.Component;
#Component
public class MyComponent {
public String makeSomeWork() {
return "Component 1";
}
}
Second component from third java libraries:
package com.example.component2;
import org.springframework.stereotype.Component;
#Component
public class MyComponent {
public String makeSomeWork() {
return "Component 2";
}
}
Controller:
package com.example.controller;
import com.example.component1.MyComponent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class MyController {
#Autowired
private MyComponent myComponent;
#Autowired
private com.example.component2.MyComponent myComponent2;
#RequestMapping("/components")
public String getComponents() {
return myComponent.makeSomeWork() + "_" + myComponent2.makeSomeWork();
}
}

Spring Boot can't find my autowired class (Autowired members must be defined in valid Spring bean)

I'm trying to use Spring's autowire annotation in my test class in order to inject an instance of a class.
package com.mycom.mycust.processing.tasks.references;
public class ReferenceIdentifierTest {
#Autowired
private FormsDB formsDB;
#PostConstruct
#Test
public void testCreateTopLevelReferencesFrom() throws Exception {
ReferenceIdentifier referenceIdentifier = new ReferenceIdentifier(formsDB);
}
}
This is the FormsDB class:
package com.mycom.mycust.mysql;
import org.springframework.stereotype.Component;
import java.sql.SQLException;
#Component
public class FormsDB extends KeyedDBTable<Form> {
public FormsDB(ConnectionFactory factory) throws SQLException {
super(factory.from("former", new FormsObjectMapper()));
}
}
And here is the SpringBootApplication class:
package com.mycom.mycust.processing;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
#SpringBootApplication
#ComponentScan("com.mycom.mycust")
public class Processing implements CommandLineRunner {
// Code
}
When I run my test, formsDB is null. Since I've used the PostConstruct annotation on the test function I think that FormsDB could not be autowired due to the class not being found. There is also an IntelliJ warning on the Autowired annotation in test class: Autowired members must be defined in valid Spring bean (#Component|#Service...). But I have put the Component annotation above the FormsDB class and I've also put the path com.mycom.mycust in the ComponentScan annotation of the SpringBootApplication. So I can't see why it can't find the class.
What is wrong here?
Your test calls is missing some important annotations to make autowiring work:
#SpringBootTest
#RunWith(SpringRunner.class)
public class ReferenceIdentifierTest {
#Autowired
private FormsDB formsDB;
#Test
public void testCreateTopLevelReferencesFrom() throws Exception {
ReferenceIdentifier referenceIdentifier = new ReferenceIdentifier(formsDB);
}
}
also you can remove #PostConstruct that does not make sense in a test.

Field in required a bean of type that could not be found consider defining a bean of type in your configuration

I'm getting the following error when trying to run my app:
Field edao in com.alon.service.EmployeeServiceImpl required a bean of
type 'com.alon.repository.EmployeeRepository' 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.alon.repository.EmployeeRepository' in your configuration.
Project structure:
EmployeeRepository:
package com.alon.repository;
import com.alon.model.Employee;
import org.springframework.stereotype.Repository;
import java.util.List;
#Repository
public interface EmployeeRepository {
List<Employee> findByDesignation(String designation);
void saveAll(List<Employee> employees);
Iterable<Employee> findAll();
}
EmployeeServiceImpl:
package com.alon.service;
import com.alon.model.Employee;
import com.alon.repository.EmployeeRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
#Service
public class EmployeeServiceImpl implements EmployeeService {
#Autowired
private EmployeeRepository edao;
#Override
public void saveEmployee(List<Employee> employees) {
edao.saveAll(employees);
}
#Override
public Iterable<Employee> findAllEmployees() {
return edao.findAll();
}
#Override
public List<Employee> findByDesignation(String designation) {
return edao.findByDesignation(designation);
}
}
MyApplication:
package com.alon;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class MyApplicataion {
public static void main(String[] args) {
SpringApplication.run(MyApplicataion.class, args);
}
}
As you have added spring-boot tag I guess you are using sprig data jpa. Your repository interfaces should extend org.springframework.data.repository.Repository (a marker interface) or one of its sub interfaces (usually org.springframework.data.repository.CrudRepository) for instructing spring to provide a runtime implementation of your repository, if any of those interfaces are not extened you'll get
bean of type 'com.alon.repository.EmployeeRepository' that could not
be found.
I assume you try to use spring data JPA. What you can check / debug is:
Is JpaRepositoriesAutoConfiguration executed? You can see this in the start up log in the debug log level
Does something change if you addionally add #EnableJpaRepositories with the corresponding basepackages.
Add #ComponentScan with the corresponding packages, normally #SpringBootApplication should do it, but just in case.
you can also check the autconfig documentation: https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-auto-configuration.html
EDIT: see comment from #ali4j: I did not see that it is the generic spring Repository interface and not the spring data interface
regards,WiPu

No bean named '' is defined [duplicate]

This question already has an answer here:
Is it possible to set a bean name using annotations in Spring Framework?
(1 answer)
Closed 4 years ago.
I am testing out simple AOP use case in Spring but am getting the below error,
Exception in thread "main"
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
bean named 'bean1' is defined
Below are my source files,
DemoConfig.java
package com.luv2code.aopdemo;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import com.luv2code.aopdemo.aspect.MyDemoLoggingAspect;
import com.luv2code.aopdemo.dao.AccountDAO;
#Configuration
#EnableAspectJAutoProxy
#ComponentScan("com.luv2code.aopdemo")
public class DemoConfig {
#Bean
#Qualifier("bean1")
public AccountDAO accDao() {
return new AccountDAO();
}
#Bean
#Qualifier("bean2")
public MyDemoLoggingAspect myAscpect() {
return new MyDemoLoggingAspect();
}
}
MyDemoLoggingAspect.java
package com.luv2code.aopdemo.aspect;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
#Aspect
public class MyDemoLoggingAspect {
// this is where we add all of our related advices for logging
// let's start with an #Before advice
#Before("execution(** com.luv2code.aopdemo.dao.AccountDAO.addAccount(..))")
public void beforeAddAccountAdvice() {
System.out.println("\n=====>>> Executing #Before advice on addAccount()");
}
}
MainDemoApp.java
package com.luv2code.aopdemo;
import com.luv2code.aopdemo.dao.AccountDAO;
public class MainDemoApp {
public static void main(String[] args) {
// read spring config java class
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(DemoConfig.class);
// get the bean from spring container
AccountDAO theAccountDAO = context.getBean("bean1", AccountDAO.class);
// call the business method
theAccountDAO.addAccount();
// do it again!
System.out.println("\nlet's call it again!\n");
// call the business method again
theAccountDAO.addAccount();
// close the context
context.close();
}
}
I have given my bean ID "bean1", even after that Spring is not able to find my bean in the context. Why am I getting this error and how to resolve this?
The #Qualifier tag is used with the #Autowired annotation.
What you need is
#Bean(name="bean1")
public AccountDAO accDao() {
return new AccountDAO();
}

Using Java configuration and constructor injection

I have a spring bean class with a constructor with multiple parameters and #Inject annotation.
Is there a way to use spring Java configuration class to create a bean for the class without actually writing code for creating the object? Something like using #Bean on a field?
#Bean(MyClassName.class) private MyInterfaceName myBean;
Or maybe by making the configuration class abstract and the bean method abstract, like:
#Bean(MyClassName.class) abstract MyInterfaceName myBean();
It's quite annoying (and pointless) to write each time the whole method that only creates a new object if you know that you only have 1 implementation of the class and you want to use auto wiring and constructor injection.
You can use #Component annotation. According to Spring documentation:
#Component indicates that an annotated class is a "component". Such classes are
considered as candidates for auto-detection when using
annotation-based configuration and classpath scanning.
Use the #Component annotation.
Indicates that an annotated class is a "component". Such classes are
considered as candidates for auto-detection when using
annotation-based configuration and classpath scanning. Other
class-level annotations may be considered as identifying a component
as well, typically a special kind of component: e.g. the #Repository
annotation or AspectJ's #Aspect annotation.
Here is an example:
import org.springframework.stereotype.Component;
#Component
public class CustomerDAO
{
#Override
public String toString() {
return "Hello , This is CustomerDAO";
}
}
A DAO class:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Component
public class CustomerService
{
#Autowired
CustomerDAO customerDAO;
#Override
public String toString() {
return "CustomerService [customerDAO=" + customerDAO + "]";
}
}
And a runner class:
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App
{
public static void main( String[] args )
{
ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] {"Spring-AutoScan.xml"});
CustomerService cust = (CustomerService)context.getBean("customerService");
System.out.println(cust);
}
}
And your output:
CustomerService [customerDAO=Hello , This is CustomerDAO]

Categories

Resources