In my Spring Boot application I'm trying to implement a fuzzy search via Elasticsearch.
This is my ES config:
#Profile("test")
#Configuration
#EnableElasticsearchRepositories(basePackages = "com.example.domain.repository.elasticsearch")
public class ElasticsearchTestConfig {
}
I have a repository:
#Repository
public interface ESDecisionRepository extends ElasticsearchRepository<ESDecision, String>, ESDecisionRepositoryCustom {
}
In order to be able to do a fuzzy search I have created a custom repository:
public interface ESDecisionRepositoryCustom {
public List<ESDecision> findFuzzyBySearchTerm(String searchTerm);
}
and provided a custom implementation:
#Repository
public class ESDecisionRepositoryCustomImpl implements ESDecisionRepositoryCustom {
#Autowired
protected ElasticsearchTemplate elasticsearchTemplate;
#Override
public List<ESDecision> findFuzzyBySearchTerm(String searchTerm) {
Criteria c = new Criteria("name").fuzzy(searchTerm);
return elasticsearchTemplate.queryForList(new CriteriaQuery(c), ESDecision.class);
}
}
Right now during startup my application fails with a following exception:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'ESDecisionRepository': Invocation of init method failed; nested exception is org.springframework.data.mapping.PropertyReferenceException: No property searchTerm found for type ESDecision!
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1628)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:208)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1138)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585)
... 43 common frames omitted
Caused by: org.springframework.data.mapping.PropertyReferenceException: No property searchTerm found for type ESDecision!
at org.springframework.data.mapping.PropertyPath.<init>(PropertyPath.java:77)
at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:329)
at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:309)
at org.springframework.data.mapping.PropertyPath.from(PropertyPath.java:272)
at org.springframework.data.mapping.PropertyPath.from(PropertyPath.java:243)
at org.springframework.data.repository.query.parser.Part.<init>(Part.java:76)
at org.springframework.data.repository.query.parser.PartTree$OrPart.<init>(PartTree.java:247)
at org.springframework.data.repository.query.parser.PartTree$Predicate.buildTree(PartTree.java:398)
at org.springframework.data.repository.query.parser.PartTree$Predicate.<init>(PartTree.java:378)
at org.springframework.data.repository.query.parser.PartTree.<init>(PartTree.java:89)
at org.springframework.data.elasticsearch.repository.query.ElasticsearchPartQuery.<init>(ElasticsearchPartQuery.java:44)
at org.springframework.data.elasticsearch.repository.support.ElasticsearchRepositoryFactory$ElasticsearchQueryLookupStrategy.resolveQuery(ElasticsearchRepositoryFactory.java:119)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.<init>(RepositoryFactorySupport.java:436)
at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:221)
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.initAndReturn(RepositoryFactoryBeanSupport.java:277)
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertiesSet(RepositoryFactoryBeanSupport.java:263)
at org.springframework.data.elasticsearch.repository.support.ElasticsearchRepositoryFactoryBean.afterPropertiesSet(ElasticsearchRepositoryFactoryBean.java:67)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1687)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1624)
... 53 common frames omitted
What am I doing wrong and how to fix it ?
Change your custom repository implementation class name from ESDecisionRepositoryCustomImpl to ESDecisionRepositoryImpl.
From the docs
The most important bit for the class to be found is the Impl postfix of the name on it compared to the core repository interface (see below).
There is a naming convention that has to be followed to make the custom repository implementation work. Check out the docs
Try this:
#Repository
public class ESDecisionRepositoryCustomImpl implements ESDecisionRepositoryCustom {
#Autowired
protected ElasticsearchTemplate elasticsearchTemplate;
#Override
public List<ESDecision> findFuzzyBySearchTerm(String searchTerm) {
Criteria c = new Criteria("name").fuzzy(searchTerm);
return elasticsearchTemplate.queryForList(new CriteriaQuery(c), ESDecision.class);
}
}
Hope this helps.
Related
I am getting the following error :
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'factoryBO': Unsatisfied dependency expressed through field 'cleanupProvider': No qualifying bean of type [com.spring.factory.interfaces.impl.CleanupProvider] found for dependency [com.spring.factory.interfaces.impl.CleanupProvider]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.spring.factory.interfaces.impl.CleanupProvider] found for dependency [com.spring.factory.interfaces.impl.CleanupProvider]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:573)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:350)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:775)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:861)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:541)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
at com.spring.factory.runner.FactoryRunner.main(FactoryRunner.java:10)
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.spring.factory.interfaces.impl.CleanupProvider] found for dependency [com.spring.factory.interfaces.impl.CleanupProvider]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1398)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1051)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1018)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:570)
... 15 more
Source code :
FactoryBo.java
I added #Autowired on top od CleanupProvider class; I did it for corresponding interface as well; But it didn't work for me;
package com.spring.factory.bo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.spring.factory.interfaces.ICleanupProvider;
import com.spring.factory.interfaces.impl.CleanupProvider;
#Component
public class FactoryBO {
#Autowired
CleanupProvider cleanupProvider;
public void getFactoryProviderLogic() {
cleanupProvider.performCleanup("Algo");
}
}
CleanupProvider.java
package com.spring.factory.interfaces.impl;
import com.spring.factory.interfaces.ICleanupProvider;
import com.spring.factory.interfaces.ICleanupStrategy;
public class CleanupProvider implements ICleanupProvider {
#Override
public String performCleanup(String strate) {
System.out.println("Received Text:::"+ strate);
return strate+":"+"Received";
}
#Override
public void registerStrategy(ICleanupStrategy normalizeStrategy) {
System.out.println("NormalizationProvider:::registerStrategy::");
}
}
CleanupProviderFactory .java
So, here I want to make the existing method createInstance as a factory method;
package com.spring.factory.interfaces.impl;
import com.spring.factory.interfaces.ICleanupProvider;
import com.spring.factory.interfaces.ICleanupProviderFactory;
public class CleanupProviderFactory implements ICleanupProviderFactory {
public ICleanupProvider createInstance() {
ICleanupProvider normalizeProvider = new CleanupProvider();
normalizeProvider.registerStrategy(new CleanupStrategy());
return normalizeProvider;
}
public static ICleanupProviderFactory createFactoryInstance() {
return new CleanupProviderFactory();
}
}
ICleanupProvider.java
package com.spring.factory.interfaces;
public interface ICleanupProvider {
public String performCleanup(String algo);
public void registerStrategy(ICleanupStrategy strategy);
}
ICleanupProviderFactory.java
package com.spring.factory.interfaces;
public interface ICleanupProviderFactory {
}
package com.spring.factory.runner;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.spring.factory.bo.FactoryBO;
public class FactoryRunner {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
FactoryBO bo = context.getBean(FactoryBO.class);
bo.getFactoryProviderLogic();
context.close();
}
}
spring.xml
<context:annotation-config/>
<context:component-scan base-package="com.spring.factory.bo"></context:component-scan>
<bean id="cleanupProviderFactory"
class="com.spring.factory.interfaces.impl.CleanupProviderFactory"
factory-method="createFactoryInstance"></bean>
<bean id="cleanupProvider"
class="com.spring.factory.interfaces.ICleanupProvider"
factory-bean="cleanupProviderFactory" lazy-init="default" factory-method="createInstance"></bean>
Is there anything I missed?
You can add #Component to your CleanupProvider class:
#Component
public class CleanupProvider { ...}
Or define a method to create your been like so:
#Bean
public CleanupProvider getCleanupProvider() {
return new CleanupProvider();
}
An explanation of which annotation to use is best described here: Understanding Spring #Autowired usage
I believe you just missed providing your CleanupProvider class a #Bean annotation (like #Component, #Service, #Repository, #Controller) so that bean factory recognizes it and is able to Autowire, like this Spring documentation tells you to do so.
EDIT
Ok, so have seen your spring.xml, I assume the mistake was you were declaring the bean as ICleanupProvider class, which is the interface, whereas FactoryBO autowires the implementation (CleanupProvider).
I am trying to inject a Map into a UtilityClass. I have created a Map Bean and I am injecting it using #Resource annotation.
#Configuration
class MyConfiguration {
#Bean
Map<String, String> testMap(){
def map = [:] // Using groovy
// Putting things into map
map
}
}
#Component
class MyUtilityClass {
#Resource(name="testMap")
Map<String, String> testMap
}
I am getting following error:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'testMap' defined in com.my.company.config.MyConfiguration: Initialization of bean failed; nested exception is java.lang.NullPointerException
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:547) ~[spring-beans-4.1.5.RELEASE.jar:4.1.5.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476) ~[spring-beans-4.1.5.RELEASE.jar:4.1.5.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303) ~[spring-beans-4.1.5.RELEASE.jar:4.1.5.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.1.5.RELEASE.jar:4.1.5.RELEASE]
.....
Caused by: java.lang.NullPointerException
at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:571) ~[spring-core-4.1.5.RELEASE.jar:4.1.5.RELEASE]
at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:490) ~[spring-core-4.1.5.RELEASE.jar:4.1.5.RELEASE]
at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:474) ~[spring-core-4.1.5.RELEASE.jar:4.1.5.RELEASE]
Am I doing something wrong here while injecting the Map. Not sure why the NPE is caused?
UPDATE -
So created a class and added the Map as an attribute of that class. And injected that class as a Bean. It worked correctly and it could inject the Class with the Map in it.
#Configuration
class MyConfiguration {
#Bean
Testclass testClass(){
def map = [:] // Using groovy
// Putting things into map
new TestClass(testMap: map)
}
}
class TestClass {
Map<String, String> testMap
}
So seems like the issue is in the Map being injected.
I have setup 2 Spring Boot applications. I am trying to #Autowire the repository from Application 1 in Application 2.
Both of these applications will be using REST to communicate back and forth. When I ran application 2 alone without the #Autowire of the repository for Application 1 I could correctly communicate with http://localhost:8082/runTestExecution via the #RestController HomeController class without an issue.
When I setup the #Autowire and #ComponentScan({"com.miw.mcb.server.repositories"}) so that I have access to the repositories of Application 1, Application 2 no longer functions correctly.
I am unable to reach the #RestController at http://localhost:8082/runTestExecution.
I also had a class which implemented CommandLineRunner which would run when I started up Spring Boot and this no longer runs either.
#Component
public class InitialRunner implements CommandLineRunner
Is this a issue because Application 1 also has a main class which loads #SpringBootApplication?
Can anyone suggest what is going wrong?
Below I have outlined my steps I took to add the jar of Application 1 and #Autowired class to Application 2
Here are the steps I took:
Setup maven to have the new library dependency and add it to the maven library mvn:install
Add Autowired bean to the HomeController class:
#RestController
public class HomeController {
#Autowired
TestSuiteRepository repo;
#RequestMapping(value = "/")
public String index() {
return "index";
}
#RequestMapping("runTestExecution")
public String runTestExecution(#RequestParam(value = "testExecutionID", required = true) String testExecutionID) {
return "Good";
}
}
Main class
#SpringBootApplication
public class AdbService {
public static void main(String[] args) {
SpringApplication.run(AdbService.class, args);
}
TestResultRepository class
package com.miw.mcb.server.repositories;
#Component
public interface TestResultRepository extends PagingAndSortingRepository<TestResult, Long> {
}
Add #Configuration and #ComponentScan, only supply the comment scan for the repositories package of the JAR file
Application 2 main class
#Configuration
#ComponentScan({"com.miw.mcb.server.repositories"})
#SpringBootApplication
public class AdbService {
public static void main(String[] args) {
SpringApplication.run(AdbService.class, args);
}
}
Application 1 Config Class
#Configuration
#ComponentScan({"com.miw.mcb.server.repositories"})
public class AppConfig {
}
Application 1 Main class
#SpringBootApplication
public class ReactAndSpringDataRestApplication {
public static void main(String[] args) {
SpringApplication.run(ReactAndSpringDataRestApplication.class, args);
}
}
Prior to adding the #ComponentScan I got the following stack trace:
2016-04-14 13:29:56 - Application startup failed
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'homeController': Injection of autowired
dependencies failed; nested exception is
org.springframework.beans.factory.BeanCreationException: Could not
autowire field: com.miw.mcb.server.repositories.TestSuiteRepository
com.miw.mcb.adbservice.HomeController.repo; nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type
[com.miw.mcb.server.repositories.TestSuiteRepository] 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)}
at
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334)
at
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214)
at
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543)
at
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
at
org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
at
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at
org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at
org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at
org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772)
at
org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:839)
at
org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:538)
at
org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118)
at
org.springframework.boot.SpringApplication.refresh(SpringApplication.java:766)
at
org.springframework.boot.SpringApplication.createAndRefreshContext(SpringApplication.java:361)
at
org.springframework.boot.SpringApplication.run(SpringApplication.java:307)
at
org.springframework.boot.SpringApplication.run(SpringApplication.java:1191)
at
org.springframework.boot.SpringApplication.run(SpringApplication.java:1180)
at com.miw.mcb.adbservice.AdbService.main(AdbService.java:38) at
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497) at
org.springframework.boot.maven.AbstractRunMojo$LaunchRunner.run(AbstractRunMojo.java:478)
at java.lang.Thread.run(Thread.java:745)
Try to use #EnableJpaRepositories instead of #ComponentScan for JpaRepositories:
#Configuration
//#ComponentScan({"com.miw.mcb.server.repositories"})
#EnableJpaRepositories("com.miw.mcb.server.repositories")
#SpringBootApplication
public class AdbService {
public static void main(String[] args) {
SpringApplication.run(AdbService.class, args);
}
}
I am trying to figure out a issue for some days but no luck. I came across this issue but not able figure out what is the problem since i am not doing any test here. java.lang.IllegalArgumentException: A ServletContext is required to configure default servlet handling
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'defaultServletHandlerMapping' defined in class path resource [org/springframework/boot/autoconfigure/web/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.web.servlet.HandlerMapping]: Factory method 'defaultServletHandlerMapping' threw exception; nested exception is java.lang.IllegalArgumentException: A ServletContext is required to configure default servlet handling
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:599) ~[spring-beans-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1119) ~[spring-beans-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1014) ~[spring-beans-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:504) ~[spring-beans-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476) ~[spring-beans-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303) ~[spring-beans-4.1.6.RELEASE.jar:4.1.6.RELEASE]
I am using spring boot
#ComponentScan
#EnableAutoConfiguration
public class Application {
.....
}
public class ApplicationWebXml extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
#Configuration
#AutoConfigureAfter
public class WebConfigurer implements ServletContextInitializer, EmbeddedServletContainerCustomizer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
EnumSet<DispatcherType> disps = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.ASYNC);
initCachingHttpHeadersFilter(servletContext, disps);
initStaticResourcesProductionFilter(servletContext, disps);
initGzipFilter(servletContext, disps);
}
Now the problem is coming in TypeToJsonMetadataConverter bean definition in the following #Configuration classes.
#Configuration
public class EntityRestMvcConfiguration extends RepositoryRestMvcConfiguration {
#Bean
public TypeToJsonMetadataConverter typeToJsonMetadataConverter() {
return new TypeToJsonMetadataConverter(typeConfiguration(),
entityLinks());
}
#Bean
public TypeConfiguration typeConfiguration() {
return new TypeConfiguration();
}
}
I am trying to take under control the context loading process. As I can read in Spring reference documentation I determined to use Phased interface provided by Spring.
When starting, the objects with the lowest phase start first, and when
stopping, the reverse order is followed. Therefore, an object that
implements SmartLifecycle and whose getPhase() method returns
Integer.MIN_VALUE would be among the first to start and the last to
stop. At the other end of the spectrum, a phase value of
Integer.MAX_VALUE would indicate that the object should be started
last and stopped first (likely because it depends on other processes
to be running). When considering the phase value, it’s also important
to know that the default phase for any "normal" Lifecycle object that
does not implement SmartLifecycle would be 0. Therefore, any negative
phase value would indicate that an object should start before those
standard components (and stop after them), and vice versa for any
positive phase value.
public interface Phased {
int getPhase();
}
public interface SmartLifecycle extends Lifecycle, Phased {
boolean isAutoStartup();
void stop(Runnable callback);
}
Only I want load two controllers in phased after all others have been initialized.
To achieve this behaviour I have implemented the Phased Interface in both Spring Components.
#Service to be initialized at firstly.
#Service
public class BatchTaskController implements Phased{
#Autowired
private ActorService actorService;
#Autowired
private SessionFactory sessionFactory;
public BatchTaskController(){
this.batch();
}
public void batch(){
//TO DO...
}
#Override
public int getPhase() {
return 1;
}
}
#Controller to be initialized after batch task #Service.
#Controller
public class MainController implements Phased{
#Autowired
private ActorService actorService;
#Autowired
private SessionFactory sessionFactory;
#RequestMapping(value = {"/", "/index"})
public String showHome(HttpServletRequest request) {
//TO DO
return "index";
}
#Override
public int getPhase() {
return 2;
}
}
ActorService #Service not implement Phased Interface. Therefore I guess as I could read in the Spring Reference article exposed above that ActorService #Service is starting before than previous #Controllers because ActorService #Service phase valor was 0 by default.
But, when I deploy my app i get the next NullPointerException error.
04-04-2014 08:34:10,286 AM ERROR ContextLoader:331 - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'batchTaskController' defined in file [E:\Desarrollo\Spring\pjcomspringehcache\target\pjcomspringehcache-1.0-SNAPSHOT\WEB-INF\classes\com\pjcom\pjcomspringehcache\BatchTaskController.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.pjcom.pjcomspringehcache.BatchTaskController]: Constructor threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1076)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1021)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:504)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:703)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:403)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:306)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:106)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4738)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5158)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:726)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:702)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:697)
at org.apache.catalina.startup.HostConfig.deployDescriptor(HostConfig.java:579)
at org.apache.catalina.startup.HostConfig$DeployDescriptor.run(HostConfig.java:1744)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.uti
l.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:744)
Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.pjcom.pjcomspringehcache.BatchTaskController]: Constructor threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:164)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:89)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1069)
... 26 more
Caused by: java.lang.NullPointerException
at com.pjcom.pjcomspringehcache.BatchTaskController.batch(BatchTaskController.java:32)
at com.pjcom.pjcomspringehcache.BatchTaskController.<init>(BatchTaskController.java:23)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:408)
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:148)
... 28 more
Why?
SOLUTION
#Service to be initialized at firstly.
#Service
public class BatchTaskController implements Phased{
#Autowired
private ActorService actorService;
#Autowired
private SessionFactory sessionFactory;
#PostConstruct
public void batch(){
//TO DO...
}
#Override
public int getPhase() {
return 1;
}
}