I have a problem with Spring bean DefaultConfigurationService initialization that is extended from abstract class. I am totally stuck.
Class hiearchy is as follows:
public interface ConfigurationService {
TaxPayer getTaxPayer();
}
This class is mentioned to be useful for services that need to be initialized:
public abstract class BaseInitializationAwareService {
private boolean initialized = false;
public abstract void initialize();
protected void checkInitialization() {
if (!initialized) {
initialize();
}
}
protected void setInitialized() {
this.initialized = true;
}
}
This class acts as base class for Configuration service.
public abstract class BaseConfigurationService extends BaseInitializationAwareService implements ConfigurationService {
}
And with this bean, that acts as a configuration service, is a problem:
public class DefaultConfigurationService extends BaseConfigurationService {
private TaxPayerService taxPayerService;
#Autowired
public void setTaxPayerService(TaxPayerService taxPayerService) {
Assert.notNull(taxPayerService);
this.taxPayerService = taxPayerService;
}
public void initialize() {
Optional<TaxPayer> dbtaxPayer = taxPayerService.getActiveTaxPayer();
if (!dbtaxPayer.isPresent()) {
throw new IllegalStateException("Tax payer setting not found!");
}
this.taxPayer = dbtaxPayer.get();
setInitialized();
}
// the rest omitted...
}
when I'm creating DefaultConfigurationService bean:
#Bean
public BaseConfigurationService configurationService() {
DefaultConfigurationService configurationService = new DefaultConfigurationService();
configurationService.initialize();
return configurationService;
}
then taxPayerService in DefaultConfigurationService is null - it seems that is not autowired.
Can it be connected to the fact that DefaultConfigurationService is extended from abstract class?
TaxPayer service bean:
#Bean
public TaxPayerService taxPayerService() {
DatabaseTaxPayerService taxPayer = new DatabaseTaxPayerService();
return taxPayer;
}
This bean is probably never initialized...
Thats is a exception:
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'webSecurityConfig.ApiSecurity':
Unsatisfied dependency expressed through method
'setContentNegotationStrategy' parameter 0; nested exception is
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name
'org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration':
Unsatisfied dependency expressed through method 'setConfigurers'
parameter 0; nested exception is
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'passwordRecoverController': Unsatisfied
dependency expressed through method 'setUserService' parameter 0;
nested exception is
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'defaultUserService': Unsatisfied
dependency expressed through method 'setNotificationService' parameter
0; nested exception is
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'notificationService': Unsatisfied
dependency expressed through method 'setConfigurationService'
parameter 0; nested exception is
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'configurationService' defined in class path
resource [com.example.config/AppConfig.class]: Bean instantiation via
factory method failed; nested exception is
org.springframework.beans.BeanInstantiationException: Failed to
instantiate [com.example.services.BaseConfigurationService]: Factory
method 'configurationService' threw exception; nested exception is
java.lang.NullPointerException
For example, bean that needs BaseConfigurationService:
public class EmailNotificationService extends BaseService implements NotificationService {
private BaseConfigurationService configurationService;
#Autowired
public void setConfigurationService(BaseConfigurationService configurationService) {
Assert.notNull(configurationService);
this.configurationService = configurationService;
}
// the rest omitted...
}
#update 1
Bean initialization example with internal dependencies to another beans:
#Bean
public TransactionDataService transactionDataService() {
return new DefaultTransactionDataService();
}
and DefaultTransactionDataService:
public class DefaultTransactionDataService implements TransactionDataService {
private PrivateKeyService privateKeyService;
#Autowired
public void setPrivateKeyService(PrivateKeyService privateKeyService) {
Assert.notNull(privateKeyService);
this.privateKeyService = privateKeyService;
}
}
and bean dependency
#Bean
public PrivateKeyService privateKeyService() {
return new DefaultPrivateKeyAwareService();
}
and it works.
It is related to your instruction to Spring how to initialize your bean:
#Bean is used to explicitly declare a single bean, rather than letting Spring do it automatically as above. It decouples the declaration of the bean from the class definition, and lets you create and configure beans exactly how you choose.
So when you create instance of your class manually your have to set all class field manually as well.
It can be done like this:
#Bean
public BaseConfigurationService configurationService() {
DefaultConfigurationService configurationService = new DefaultConfigurationService();
configurationService.setTaxPayerService(taxPayerService());
configurationService.initialize();
return configurationService;
}
Or move dependency directly to constructor, so dependency of your DefaultConfigurationService will be more obvious:
#Bean
public BaseConfigurationService configurationService() {
DefaultConfigurationService configurationService = new DefaultConfigurationService(taxPayerService());
configurationService.initialize();
return configurationService;
}
Good description
Related
I'm having a trouble while configuring Spring AOP.
I created an aspect class which is below:
#Slf4j
#Aspect
#RequiredArgsConstructor
#Component
public class LoggingAspect {
private static final Logger logger = CommonLogger.getLogger(LoggingAspect.class);
private final ObjectMapper mapper;
private final JobExecutionService jobExecutionService;
}
Then I added a configuration file:
#Configuration
#EnableAspectJAutoProxy(proxyTargetClass = true)
#RequiredArgsConstructor
public class AspectConfiguration {
private final ObjectMapper objectMapper;
private final JobExecutionService jobExecutionService;
#Bean
public LoggingAspect loggingAspect() {
return new LoggingAspect(objectMapper, jobExecutionService);
}
}
But when I started the application, I am getting below errors:
Bean instantiation via constructor failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.context.support.ClassPathXmlApplicationContext]: Constructor threw exception; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'aspectConfiguration' defined in URL: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.fasterxml.jackson.databind.ObjectMapper' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
I have added aspectjrt and aspectjweaver dependencies to pom.xml.
Spring version is 4.3.6
I couldn't figure out where the problem is. Any help would be appreciated.
Add class:
#Configuration
public class BeanConfig {
#Bean
public ObjectMapper objectMapper() {
return new ObjectMapper();
}
}
I have a springboot app, in which I am connecting to cassandra DB.
My pom.xml:
parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-cassandra</artifactId>
</dependency>
The cassandraConfig definitition:
#Configuration
#PropertySource("file:///Users/s1b03vf/Work/carrierhub/cass.properties")
#ConfigurationProperties()
#EnableCassandraRepositories(basePackageClasses = {MCSEDistributorRepository.class})
public class MSCECassandraConfig {
protected String contactPoints;
protected int port;
protected String username;
protected String password;
protected String keyspace;
#Override
protected AuthProvider getAuthProvider() {
return new PlainTextAuthProvider(username, password);
}
#Override
protected String getKeyspaceName() {
return keyspace;
}
#Override
protected String getContactPoints() {
return contactPoints;
}
#Override
protected int getPort() {
return port;
}
#Override
public String[] getEntityBasePackages() {
return new String[]{"com.example.demo.entity.cassandra"};
}
}
Repository class:
#Repository
public interface MCSEDistributorRepository extends CassandraRepository<MCSEDistributor, String> {
}
Entity class:
#Table("mcse_offer")
public class MCSEDistributor {
#Column
#PrimaryKey
private int id;
#Column
private String name;
}
Now when I start my application I am running into the below error:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'documentationPluginsBootstrapper' defined in URL [jar:file:/Users/s1b03vf/.m2/repository/io/springfox/springfox-spring-web/2.9.2/springfox-spring-web-2.9.2.jar!/springfox/documentation/spring/web/plugins/DocumentationPluginsBootstrapper.class]: Unsatisfied dependency expressed through constructor parameter 1; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'webMvcRequestHandlerProvider' defined in URL [jar:file:/Users/s1b03vf/.m2/repository/io/springfox/springfox-spring-web/2.9.2/springfox-spring-web-2.9.2.jar!/springfox/documentation/spring/web/plugins/WebMvcRequestHandlerProvider.class]: Unsatisfied dependency expressed through constructor parameter 1; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'requestMappingHandlerMapping' defined in class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]: Unsatisfied dependency expressed through method 'requestMappingHandlerMapping' parameter 1; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mvcConversionService' defined in class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.format.support.FormattingConversionService]: Factory method 'mvcConversionService' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'MCSEDistributorRepository': Cannot resolve reference to bean 'cassandraTemplate' while setting bean property 'cassandraTemplate'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cassandraTemplate' defined in class path resource [com/example/demo/config/MSCECassandraConfig.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.data.cassandra.core.CassandraAdminTemplate]: Factory method 'cassandraTemplate' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in class path resource [com/example/demo/config/MSCECassandraConfig.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.data.cassandra.SessionFactory]: Factory method 'sessionFactory' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'session' defined in class path resource [com/example/demo/config/MSCECassandraConfig.class]: Invocation of init method failed; nested exception is com.datastax.driver.core.exceptions.DriverInternalError: Unexpected exception thrown
It says dependency and bean creation issue for cassandraTemplate and sessionFactory. I am new to using spring-data, so not sure what I am missing here.
From startup log, I can see that it is using the below driver version:
2020-06-08 22:44:57.782 INFO 42129 --- [ restartedMain] com.datastax.driver.core : DataStax Java driver 3.7.2 for Apache Cassandra
Try calling super and then set the required properties
#Bean
public CassandraClusterFactoryBean cluster() {
CassandraClusterFactoryBean cluster = super.cluster();
cluster.setContactPoints("127.0.0.1");
cluster.setPort(9142);
return cluster;
}
Figured out the issue. Issue was that the CassandraConfig class was missing this:
#Override
protected boolean getMetricsEnabled() {
return false;
}
Added this and it started running fine.
There is something wrong with your #configuration class. it doesn't have #bean annotations. look at this example cassandra #configuration class from: https://www.baeldung.com/spring-data-cassandra-tutorial
#Configuration
public class CassandraConfig extends AbstractCassandraConfiguration {
#Override
protected String getKeyspaceName() {
return "testKeySpace";
}
#Bean
public CassandraClusterFactoryBean cluster() {
CassandraClusterFactoryBean cluster =
new CassandraClusterFactoryBean();
cluster.setContactPoints("127.0.0.1");
cluster.setPort(9142);
return cluster;
}
#Bean
public CassandraMappingContext cassandraMapping()
throws ClassNotFoundException {
return new BasicCassandraMappingContext();
}
}
There is also explanation on how to configure the repository and table.
I create spring-boot-starter, which registers some bean:
#Configuration
#EnableConfigurationProperties(ClusterJProperties.class)
#ConditionalOnProperty(prefix = "clusterj", name = {"connectString", "dataBaseName"})
public class ClusterJAutoConfiguration {
private final ClusterJProperties clusterJConfigProperties;
#Autowired
public ClusterJAutoConfiguration(ClusterJProperties clusterJConfigProperties) {
this.clusterJConfigProperties = clusterJConfigProperties;
}
#Bean
#ConditionalOnMissingBean
public SessionFactory sessionFactory() {
Properties clusterJProperties = new Properties();
clusterJProperties.setProperty("com.mysql.clusterj.connectstring", clusterJConfigProperties.getConnectString());
clusterJProperties.setProperty("com.mysql.clusterj.database", clusterJConfigProperties.getDataBaseName());
clusterJProperties.putAll(clusterJConfigProperties.getProperties());
return ClusterJHelper.getSessionFactory(clusterJProperties);
}
}
I want using this starter in another module. For this, I created a component, and inject this bean there:
#Component
public class GetEntityHandler implements VoidTreeNodeHandler {
private final SessionFactory sessionFactory;
#Autowired
public GetEntityHandler(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
#Override
public void handle(TreeContext context, Map<String, Object> parameters) {
//do smth
}
}
But, when, properties clusterj.connectString and clusterj.connectString not present in application.yml, bean SessionFactory not create. It is ok, but GetEntityHandler want to create, and fall with error:
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'getEntityHandler' defined in file [GetEntityHandler.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.mysql.clusterj.SessionFactory' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
How to make my GetEnityNandler component not be created if the SessionFactory bean is not present in context?
I need use a bean inject with #Component #FeignClient(name = "xxx") when my spring boot application initializing, but it always throws exception like this:
20180706 10:18:40,043 WARN [main]
[org.springframework.context.annotation.AnnotationConfigApplicationContext]
Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'feignContract' defined in org.springframework.cloud.netflix.feign.FeignClientsConfiguration: Unsatisfied dependency expressed through method 'feignContract' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'feignConversionService' defined in org.springframework.cloud.netflix.feign.FeignClientsConfiguration: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.format.support.FormattingConversionService]: Factory method 'feignConversionService' threw exception; nested exception is java.lang.StackOverflowError
my feignClient code:
#Component
#FeignClient(name = "domain-account")
public interface IDomainService {
#RequestMapping(value = "/userInfos", method = RequestMethod.GET)
public String getUserInfos(#QueryMap Map<String, Object> condition);
}
ApplicationListenner code:
public class GlobalInit implements ApplicationListener<ContextRefreshedEvent> {
#Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
System.out.println("======== GlobalInit ========");
IDomainService domainService = contextRefreshedEvent.getApplicationContext().getBean(IDomainService.class);
System.out.println("*********************" + domainService);
GlobalInitManager.getInstance().doInit();
}
}
It's not entirely clear for me what you try to do with the GlobalInit but the 'standard' way of designing your Feign client in Spring Boot would the following:
#SpringBootApplication
#EnableFeignClients
#EnableHypermediaSupport(type = EnableHypermediaSupport.HypermediaType.HAL)
#EnableCaching
public class MyHelloWorldApplication {
public static void main(String[] args) {
SpringApplication.run(MyHelloWorldApplication.class, args);
}
}
#Component
public class HelloWorldServiceImpl implements HelloWorldService {
#Autowired
private IDomainService iDomainService ;
public void myMethod() {
String userinfo = iDomainService.getUserInfos(...);
}
}
Hopefully this helps.
All the best,
Wim
i am trying to inject a prototype object in the singleton class..
public class Triangle implements ApplicationContextAware{
private Point pointA;
private ApplicationContext context=null;
Point point=(Point)context.getBean("pointA",Point.class);
public void draw(){
System.out.println("The prototype point A is ("+point.getX()+","+point.getY()+")");
}
#Override
public void setApplicationContext(ApplicationContext context)
throws BeansException {
this.context=context;
}
}
i created a Point java file with the co-ordinates x and y..
when i tried to compile the above code i get the following errors
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'triangle' defined in class path resource [Spring.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.david.shape.Triangle]: Constructor threw exception; nested exception is java.lang.NullPointerException
private ApplicationContext context=null;
Point point=(Point)context.getBean("pointA",Point.class);
You're calling getBean() on context which is, obviously, null.
The context will only be initialized by Spring after the Triangle bean has been constructed, and after its setApplicationContext() method has been called by Spring. Only then, you can call getBean() on the context.
BTW, you're not doing dependency injection here. You're doing dependency lookup, which is exactly what dependency injection frameworks like Spring are used to avoid. To inject your point, just do
public class Triangle {
private Point pointA;
#Autowired
public Triangle(#Qualifier("pointA") Point pointA) {
this.pointA = pointA;
}
...
}