Dear StackOverflow experts.
We are solving interesting issue in current sprint and our understanding of Spring workflow doesn't allow us to find a solution.
So we ask you to share your thought on next problem:
We need to import class from a library which we can not modify right now.
The thing is that the class we need to import has an Autowired dependency of a class which implements "ApplicationListener".
We won't use this dependency in our code (it is used in methods we won't call).
We trying to set all unused dependencies to null.
But when we set this class to null we get an exception:
Caused by: java.lang.IllegalArgumentException: Delegate listener must not be null
Obviously, we don't want to instantiate ApplicationListener class in our application.
To reproduce our situation we create a simple unit tests:
Application configuration:
#Configuration
public class TestApplicationConfiguration {
#Bean
public ApplicationListener<ContextRefreshedEvent> applicationListener() {
return null;
}
}
Test class:
#ContextConfiguration(classes = TestApplicationConfiguration.class)
public class ConfigurationManagerTests extends AbstractTestNGSpringContextTests {
#Autowired
private ApplicationListener<ContextRefreshedEvent> applicationListener;
#Test
public void dummyTest() {
Assert.assertNull(applicationListener);
}
}
Full stacktrace of the exception listed below.
java.lang.IllegalStateException: Failed to load ApplicationContext
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124)
at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:83)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:117)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:230)
at org.springframework.test.context.testng.AbstractTestNGSpringContextTests.springTestContextPrepareTestInstance(AbstractTestNGSpringContextTests.java:149)
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:483)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:86)
at org.testng.internal.Invoker.invokeConfigurationMethod(Invoker.java:514)
at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:215)
at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:142)
at org.testng.internal.TestMethodWorker.invokeBeforeClassMethods(TestMethodWorker.java:178)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:108)
at org.testng.TestRunner.privateRun(TestRunner.java:782)
at org.testng.TestRunner.run(TestRunner.java:632)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:366)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:361)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:319)
at org.testng.SuiteRunner.run(SuiteRunner.java:268)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1244)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1169)
at org.testng.TestNG.run(TestNG.java:1064)
at org.testng.IDEARemoteTestNG.run(IDEARemoteTestNG.java:72)
at org.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:124)
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:483)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
Caused by: java.lang.IllegalArgumentException: Delegate listener must not be null
at org.springframework.util.Assert.notNull(Assert.java:115)
at org.springframework.context.event.GenericApplicationListenerAdapter.<init>(GenericApplicationListenerAdapter.java:48)
at org.springframework.context.event.AbstractApplicationEventMulticaster.supportsEvent(AbstractApplicationEventMulticaster.java:280)
at org.springframework.context.event.AbstractApplicationEventMulticaster.retrieveApplicationListeners(AbstractApplicationEventMulticaster.java:229)
at org.springframework.context.event.AbstractApplicationEventMulticaster.getApplicationListeners(AbstractApplicationEventMulticaster.java:185)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:127)
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:382)
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:336)
at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:877)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:544)
at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:128)
at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:60)
at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.delegateLoading(AbstractDelegatingSmartContextLoader.java:108)
at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.loadContext(AbstractDelegatingSmartContextLoader.java:251)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:98)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:116)
... 33 more
Thanks.
Looks like Spring itself doesn't allow that bean to be null, so why not just create a dummy one which doesn't do anything?
#Bean
public ApplicationListener<ContextRefreshedEvent> applicationListener() {
return new ApplicationListener<ContextRefreshedEvent>() {
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
// Do nothing
}
};
}
Related
I am using SpringBoot and I have a DataJpaTest, but when I run the Test class, I get this StackTrace:
java.lang.IllegalStateException: Failed to load ApplicationContext
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124)
at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:83)
at org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener.prepareTestInstance(SpringBootDependencyInjectionTestExecutionListener.java:47)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:230)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:228)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:287)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:289)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:247)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:51)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:237)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
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:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'restTemplate' defined in br.com.mobtrack.api.MobTrackApplication: Unsatisfied dependency expressed through method 'restTemplate' parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.boot.web.client.RestTemplateBuilder' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:749)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:467)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1134)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1028)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:513)
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:197)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:759)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:866)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:542)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:761)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:371)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)
at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:111)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:98)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:116)
... 28 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.boot.web.client.RestTemplateBuilder' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1474)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1102)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1064)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:835)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:741)
I think this happens because I have a RestTemplate bean inside my Application class like this:
#SpringBootApplication
public class TestApplication {
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}
#Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.build();
}
}
This is my Test Class:
#RunWith(SpringRunner.class)
#DataJpaTest
public class CityRepositoryTest {
#Autowired
private TestEntityManager entityManager;
#Autowired
private CityRepository cityRepository;
private City city;
#Before
public void init() {
city = new City();
city.setName("New York");
city.setImage("http://www.mockimage.com");
}
#Test
public void findByNameShouldReturnCity() throws Exception {
this.entityManager.persist(city);
Optional<City> hasCity = this.cityRepository.findByNameIgnoreCase("New York");
city = hasCity.get();
assertThat(city.getId()).isNotNull();
assertThat(city.getName()).isEqualTo("New York");
assertThat(city.getImage()).isEqualTo("http://www.mockimage.com");
}
#Test
public void findByNameStartingWithShouldReturnCity() throws Exception {
this.entityManager.persist(city);
Optional<City> hasCity = this.cityRepository.findByNameStartingWithIgnoreCase("New");
city = hasCity.get();
assertThat(city.getId()).isNotNull();
assertThat(city.getName()).isEqualTo("New York");
assertThat(city.getImage()).isEqualTo("http://www.mockimage.com");
}
#Test
public void findByNameWhenNoCityShouldReturnFalse() throws Exception {
this.entityManager.persist(city);
Optional<City> hasCity = this.cityRepository.findByNameStartingWithIgnoreCase("Ohaio");
assertThat(hasCity.isPresent()).isFalse();
}
}
Any help is welcome,Thanks a lot!
I didn't like the other solution as I did want my application to use the spring provided RestTemplateBuilder since it provides some default message converters and other functionality I needed when running my app.
However I found 2 ways to alter my test to get my DataJpaTest's to run, not sure which is best:
Method One - provide a mock RestTemplate in your test.
#RunWith(SpringRunner.class)
#DataJpaTest
public class SomeTest {
#MockBean
private RestTemplate restTemplate;
Method Two - add AutoConfigureWebClient annotation so spring will wire the RestTemplateBuilder
#RunWith(SpringRunner.class)
#DataJpaTest
#AutoConfigureWebClient
public class SomeTest {
With both ways I could keep my existing configured rest template in my application class:
#Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.build();
}
As the error is clearly saying - there is no qualifying bean of type RestTemplateBuilder being available for use of RestTemplate bean building.
The bean for RestTempalteBuilder is injected into context by the spring boot starter for web. There is generally no need to declare a RestTemplateBuilder bean into the context as it is already provided by the spring-boot auto-configuration. If the project is a spring-boot application this will work out of box as intended.
If required, one can customise it by creating a new one in the application configuration.Something like below:
#Bean
public RestTemplateBuilder restTemplateBuilder() {
return new RestTemplateBuilder()
.basicAuthorization("abc", "password");
}
#Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.build();
}
And if no real reason to customise it, you could rather have a simpler bean definition for RestTemplate as below:
#Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
I am new to Spring unit Testing. Writing test cases for the Spring rest Controller. When I am writing the test cases in this way
#WebAppConfiguration
#ContextConfiguration(locations = {"file:src/test/resources/applicationContext.xml"})
public class TaskControllerIntegrationTest extends AbstractTransactionalTestNGSpringContextTests {
private MockMvc mockMvc;
#Autowired
private WebApplicationContext wac;
#BeforeClass
public void setUp() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}
#Test
public void testGetAllTasks() throws Exception {
mockMvc.perform(get("/v1/testSessions/{testSessionId}/tasks", 1l))
.andExpect(status().isOk());
}
}
I am getting the testcase failed don't know why :( while If i initialize the MockMvc using the standalone controller it works perfect and my allTest cases are passes.The setup for the MockMvc using standalone controller is in this way. It's for unit testing:
#Mock
private TaskService taskServiceMock;
#InjectMocks
private TaskController taskController;
private MockMvc mockMvc;
#Spy
List<Task> allTasks = new ArrayList<Task>();
/* #Spy
List<TaskSessionModel> taskSessionModelList = new ArrayList<TaskSessionModel>();*/
#BeforeClass
public void setUp() {
// Mockito.reset(taskServiceMock);
MockitoAnnotations.initMocks(this);
// taskSessionModelList = getAllTaskSessionModels();
allTasks = getAllTasks();
this.mockMvc = MockMvcBuilders.standaloneSetup(taskController).build();
}
#Test
public void testGetAllTasks() throws Exception {
// when(taskSessionDao.findAllByTestSession(1l)).thenReturn(taskSessionModelList);
when(taskServiceMock.getAllTasks(1l)).thenReturn(allTasks);
mockMvc.perform(get("/v1/testSessions/{testSessionId}/tasks", 1l)
.accept(MediaType.APPLICATION_JSON_VALUE))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
.andExpect(jsonPath("$", hasSize(2)))
.andExpect(jsonPath("$[0].name", is("Average")));
List<Task> expTaskList = taskController.getAllTasks(1l);
verify(taskServiceMock, times(2)).getAllTasks(1l);
verifyNoMoreInteractions(taskServiceMock);
assertEquals(allTasks, expTaskList);
}
But if i write the same unit test by using the WebApplicationContext .. I will get error and test cases will failed :
java.lang.AssertionError: Status
Expected :200
Actual :500
<Click to see difference>
at org.springframework.test.util.AssertionErrors.fail(AssertionErrors.java:60)
at org.springframework.test.util.AssertionErrors.assertEquals(AssertionErrors.java:89)
at org.springframework.test.web.servlet.result.StatusResultMatchers$10.match(StatusResultMatchers.java:654)
at org.springframework.test.web.servlet.MockMvc$1.andExpect(MockMvc.java:152)
at com.blueoptima.dt.controller.TaskControllerIntegrationTest.testGetAllTasks(TaskControllerIntegrationTest.java:46)
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:498)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:84)
at org.testng.internal.MethodInvocationHelper$1.runTestMethod(MethodInvocationHelper.java:200)
at org.springframework.test.context.testng.AbstractTestNGSpringContextTests.run(AbstractTestNGSpringContextTests.java:171)
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:498)
at org.testng.internal.MethodInvocationHelper.invokeHookable(MethodInvocationHelper.java:212)
at org.testng.internal.Invoker.invokeMethod(Invoker.java:707)
at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:901)
at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1231)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:127)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:111)
at org.testng.TestRunner.privateRun(TestRunner.java:767)
at org.testng.TestRunner.run(TestRunner.java:617)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:334)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:329)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:291)
at org.testng.SuiteRunner.run(SuiteRunner.java:240)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1224)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1149)
at org.testng.TestNG.run(TestNG.java:1057)
at org.testng.IDEARemoteTestNG.run(IDEARemoteTestNG.java:74)
at org.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:124)
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:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
I don't know what's the wrong? I tried almost all the solution for the WebApplicationContext setup(see the first code) it's in the same way as I see .. on this website and mostly configuration in spring official website and other after googling it but still error remains same?
Have a look into this ! Cheers !!
Go back one step, forget about all Spring and technology stuff and ask yourself what you want to achieve with the tests?
If you want to do a real integration tests, don't mock controllers or services, so the following code makes no sense:
#Mock
private TaskService taskServiceMock;
That should be the problem in your setup. Remove all mocks instead of MockMvc and try again. Take a cup of coffee and read the official documentation, it will teach you all the details including setting up a in-memory-database and setting up the Spring TestContext Framework.
To access your controllers, you have two choices, depending on how deep the tests shall go.
I am integrating Spring into Vaadin and thanks to the Vaadin Spring addon and to this wiki: https://vaadin.com/wiki?p_p_id=36&p_p_lifecycle=0&p_p_state=normal&p_p_mode=view&p_p_col_id=row-1&p_p_col_pos=2&p_p_col_count=4&_36_struts_action=%2Fwiki%2Fview&p_r_p_185834411_nodeName=vaadin.com+wiki&p_r_p_185834411_title=I+-+Getting+started+with+Vaadin+Spring I was actually able to do it.
However when I restart Tomcat and the Vaadin application is restarted I get the following NotSerializableException complaining about Spring's XmlWebApplicationContext:
SEVERE: Exception loading sessions from persistent storage
java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: org.springframework.web.context.support.XmlWebApplicationContext
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1355)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1993)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1918)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1801)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)
at java.util.LinkedList.readObject(LinkedList.java:1149)
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:483)
at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1017)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1896)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1801)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1993)
at java.io.ObjectInputStream.defaultReadObject(ObjectInputStream.java:501)
at com.vaadin.server.VaadinSession.readObject(VaadinSession.java:1443)
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:483)
at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1017)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1896)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1801)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)
at org.apache.catalina.session.StandardSession.doReadObject(StandardSession.java:1634)
at org.apache.catalina.session.StandardSession.readObjectData(StandardSession.java:1099)
at org.apache.catalina.session.StandardManager.doLoad(StandardManager.java:261)
at org.apache.catalina.session.StandardManager.load(StandardManager.java:180)
at org.apache.catalina.session.StandardManager.startInternal(StandardManager.java:460)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5213)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1409)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1399)
at java.util.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:745)
Caused by: java.io.NotSerializableException: org.springframework.web.context.support.XmlWebApplicationContext
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
at java.util.LinkedList.writeObject(LinkedList.java:1131)
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:483)
at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:988)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1496)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
at org.apache.catalina.session.StandardSession.doWriteObject(StandardSession.java:1710)
at org.apache.catalina.session.StandardSession.writeObjectData(StandardSession.java:1116)
at org.apache.catalina.session.StandardManager.doUnload(StandardManager.java:401)
at org.apache.catalina.session.StandardManager.unload(StandardManager.java:320)
at org.apache.catalina.session.StandardManager.stopInternal(StandardManager.java:487)
at org.apache.catalina.util.LifecycleBase.stop(LifecycleBase.java:232)
at org.apache.catalina.core.StandardContext.stopInternal(StandardContext.java:5409)
at org.apache.catalina.util.LifecycleBase.stop(LifecycleBase.java:232)
at org.apache.catalina.core.ContainerBase$StopChild.call(ContainerBase.java:1425)
at org.apache.catalina.core.ContainerBase$StopChild.call(ContainerBase.java:1414)
... 4 more
Actually the code is really simple (based on the tutorial and some other Spring features):
Here is the UI class:
package com.example.vaadinwithspring;
//...
#SpringUI("")
#Theme("valo")
#SuppressWarnings("serial")
public class MyUI extends UI {
private transient ApplicationContext appContext;
#Override
protected void init(VaadinRequest vaadinRequest) {
final VerticalLayout layout = new VerticalLayout();
layout.setMargin(true);
setContent(layout);
UserService service = getUserService(vaadinRequest);
User user = service.getUser();
String userName = user.getName();
Label userHelloLabel = new Label("Hello " + userName + "!");
layout.addComponent(userHelloLabel);
}
#WebListener
public static class MyContextLoaderListener extends ContextLoaderListener {
}
#Configuration
#EnableVaadin
public static class MyConfiguration {
#Bean(name="userService")
public UserService helloWorld() {
return new UserServiceImpl();
}
}
#WebServlet(urlPatterns = "/*", name = "MyUIServlet", asyncSupported = true)
#VaadinServletConfiguration(ui = MyUI.class, productionMode = false)
public static class MyUIServlet extends SpringAwareVaadinServlet {
}
private UserService getUserService(VaadinRequest request) {
WrappedSession session = request.getWrappedSession();
HttpSession httpSession = ((WrappedHttpSession) session).getHttpSession();
ServletContext servletContext = httpSession.getServletContext();
appContext = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
return (UserService) appContext.getBean("userService");
}
}
Although quite messy (I followed the wiki), the only important things here are the Vaadin Spring annotations (#SpringUI(""), #EnableVaadin, as for the linked tutorial) and some Spring's annotations (beyond the #Configuration one I also define a Spring bean named "userService" via the #Bean annotation inside the MyConfiguration class). Please also note that I have a member transient field which references Spring's ApplicationContext (which I use inside the UI's getUserService(VaadinRequest) method in order to get the "userService" bean).
Here is the code either for the UserService interface and for the class UserServiceImpl:
package com.example.vaadinwithspring;
public class UserService {
public User getUser();
}
-------------------------------------------------------------------
package com.example.vaadinwithspring;
public class UserServiceImpl implements UserService {
#Override
public User getUser() {
User user = new User();
user.setName("UserName");
return user;
}
}
And then, the User class:
package com.example.vaadinwithspring;
public class User {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
All components are dummy implementations, just to see that Vaadin cooperates fine with Spring and that everything works.
Finally, the Vaadin Spring tutorial advises to use an applicationContext.xml and put it inside src/main/webapp/WEB-INF/ when not using Spring Boot or JavaConfig.
I have created the following applicationContext.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.1.xsd">
<bean class="com.example.vaadinwithspring.MyUI.MyConfiguration" />
<context:component-scan base-package="com.example.vaadinwithspring" />
</beans>
Now, as I said, if I launch the application, everything works great. The only issue I am facing is that NotSerializableException related to XmlWebApplicationContext when I restart the application.
Why the exception is thrown at all if I have a transient ApplicationContext member which shouldn't be serialized? I suppose that Spring uses another instance of XmlWebApplicationContext and uses it internally, is it so? Then:
Is there a way to fix it? How?
Thanks for the attention!
By default, Tomcat tries to load sessions from previous run on restart. If it fails loading those sessions (your case), it prints the error to log then it initializes your application normally. Effectively, there is no problem here but you don't get session persistence. Unless you're using a production app, you don't need this functionality.
Some approaches you may take other than simply ignoring it:
Disable session persistence
Use another container like Jetty, which does not persist sessions by default
I believe the problem comes from SpringAwareVaadinServlet. It injects your applicationContext into the SpringAwareUIProvider and it effectively gets stored in persistent session store.
If you really want session persistence with this setup, you need to extend VaadinServlet and implement a custom UIProvider that does not store applicationContext itself but it gets it from another place, possibly a static field in your servlet.
I am migrating away from XML config for Spring context configuration. Instead when I try to use the functionally equivalent #EnableTransactionManagement on a Spring 4.0.3.RELEASE Java Configuration, my Spring context fails to instantiate with the following exception:
java.lang.IllegalStateException: Failed to load ApplicationContext
at org.springframework.test.context.CacheAwareContextLoaderDelegate.loadContext(CacheAwareContextLoaderDelegate.java:99)
at org.springframework.test.context.DefaultTestContext.getApplicationContext(DefaultTestContext.java:101)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:109)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:75)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:319)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:212)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:289)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:291)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:232)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:89)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:175)
at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:236)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:134)
at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:113)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:103)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:74)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'baseMySQLTest.TestConfig': Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.transaction.config.internalTransactionAdvisor' defined in class path resource [org/springframework/transaction/annotation/ProxyTransactionManagementConfiguration.class]: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public org.springframework.transaction.intercep...skipping...
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1558)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
... 45 more
Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration.transactionAdvisor()] threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionInterceptor' defined in class path resource [org/springframework/transaction/annotation/ProxyTransactionManagementConfiguration.class]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Property 'transactionManager' is required
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:188)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:586)
... 62 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionInterceptor' defined in class path resource [org/springframework/transaction/annotation/ProxyTransactionManagementConfiguration.class]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Property 'transactionManager' is required
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1553)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
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.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:324)
at org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration$$EnhancerBySpringCGLIB$$83a12634.transactionInterceptor()
at org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration.transactionAdvisor(ProxyTransactionManagementConfiguration.java:45)
at org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration$$EnhancerBySpringCGLIB$$83a12634.CGLIB$transactionAdvisor$0()
at org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration$$EnhancerBySpringCGLIB$$83a12634$$FastClassBySpringCGLIB$$cc829ae.invoke()
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:312)
at org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration$$EnhancerBySpringCGLIB$$83a12634.transactionAdvisor()
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:166)
... 63 more
Caused by: java.lang.IllegalArgumentException: Property 'transactionManager' is required
at org.springframework.transaction.interceptor.TransactionAspectSupport.afterPropertiesSet(TransactionAspectSupport.java:195)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1612)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1549)
... 82 more
This happens to obtain in a unit test, but when it works here, I can use it in production code.
Here is my unit test base class where the Spring wiring occurs:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {PropertyPlaceholderConfigurer.class, BaseMySQLTest.TestConfig.class})
public class BaseMySQLTest extends AbstractTransactionalJUnit4SpringContextTests {
#Configuration
#Import(DaoConfig.class)
#PropertySource("classpath:/jdbc.properties")
#EnableTransactionManagement
public static class TestConfig {
#Bean
public PlatformTransactionManager providesTransactionManager(ListableBeanFactory beanFactory) {
return new DataSourceTransactionManager(beanFactory.getBean(DataSource.class));
}
}
}
and here is a subclass that uses this base class and config:
public class UserDaoImplTest extends BaseMySQLTest {
#Autowired
private UserDao userDao;
#Test
public void testById() throws Exception {
jdbcTemplate.execute("insert into users (email) values ('bob#example.com')");
...
}
}
As one can see, my Spring TestConfig has a transaction manager bean defined, which according to the Javadoc
http://docs.spring.io/spring/docs/3.1.x/javadoc-api/org/springframework/transaction/annotation/EnableTransactionManagement.html
means I do not have to name the bean (though I have named it in an attempt to get this to work). In fact, the Spring context is behaving as if configured with XML config in the face of no bean explicitly named "transactionManager".
What is my Java Config missing such that the Spring context cannot use this transaction manager bean to satisfy its requirements at instantiation time?
Thank you for any helpful observations.
EDIT:
(I'm not sure where this edit should go, so I try here. ae6rt)
Here is the new test class, which results in the same error as the original work:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {BaseMySQLTest.TestConfig.class})
public class BaseMySQLTest extends AbstractTransactionalJUnit4SpringContextTests {
protected int lastInsertId() {
return jdbcTemplate.queryForInt("select LAST_INSERT_ID()");
}
#Autowired
private UserDao userDao;
#Test
public void testById() throws Exception {
jdbcTemplate.execute("insert into mgdb.users (email) values ('bob#example.com')");
int userId = lastInsertId();
Optional xoomUserOptional = userDao.byId(userId);
assertThat(xoomUserOptional.isPresent(), equalTo(true));
XoomUser user = xoomUserOptional.get();
assertThat(user.getEmailAddress(), equalTo("bob#example.com"));
}
#Configuration
#Import(DaoConfig.class)
#PropertySource("classpath:/jdbc.properties")
#EnableTransactionManagement
public static class TestConfig {
#Bean
public PlatformTransactionManager providesTransactionManager(ListableBeanFactory beanFactory) {
return new DataSourceTransactionManager(beanFactory.getBean(DataSource.class));
}
}
}
I didn't actualy need the property config here
#ContextConfiguration(classes = {BaseMySQLTest.TestConfig.class})
so I removed it. Hope this meets the spirit of this round.
Looks like the only change should be to name your transaction manager bean name to "transactionManager":
public static class TestConfig {
#Autowired
private DataSource datasource;
#Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(datasource);
}
}
EDIT :
Can you try these additional things:
.1. Remove PropertyPlaceHolderConfigurer from here.. #ContextConfiguration(classes = {PropertyPlaceholderConfigurer.class, BaseMySQLTest.TestConfig.class}), that is not how PropertyPlaceholderConfigurer is used, you have to do it this way:
#Bean
public static PropertySourcesPlaceholderConfigurer placeholderConfigurer() {
PropertySourcesPlaceholderConfigurer placeholderConfigurer = new PropertySourcesPlaceholderConfigurer();
ClassPathResource resource = new ClassPathResource("/META-INF/spring/database.properties");
placeholderConfigurer.setLocation(resource);
return placeholderConfigurer;
}
Also, just for test, can you move your actual test to the base class also and see if one of these configuration works out for you. I tested in my own machine and it seems to work nicely with Spring 4.0.2+.
I have spent numerous hours of setting this up. I am trying to setup a JUnit to test a simple NodeEntity class and a Repository. I am also using Gradle (not Maven -- to be Gradle seems cleaner then the Maven pom.xml). Also, I am using the Java Configuration class.
build.gradle:
apply plugin:'java'
apply plugin:'idea'
project.ext {
springVersion = "4.0.3.RELEASE"
neo4jVersion = "2.0.1.RELEASE"
springDataGraphVersion = "3.0.1.RELEASE"
sourceCompatibility = 1.7
version = '1.0'
}
configurations {
runtime
testCompile
}
repositories {
mavenCentral()
mavenLocal()
maven {
url "http://m2.neo4j.org/content/repositories/releases/"
}
}
dependencies {
compile 'org.slf4j:slf4j-api:1.7.5'
compile "org.springframework:spring-context:${springVersion}"
compile "org.neo4j:neo4j:${neo4jVersion}"
// Provides Repository based Object <-> Graph Mapping
compile "org.springframework.data:spring-data-neo4j:${springDataGraphVersion}"
compile "javax.validation:validation-api:1.0.0.GA"
testCompile 'junit:junit-dep:4.11'
testCompile "org.springframework:spring-test:${springVersion}"
testCompile 'org.hamcrest:hamcrest-all:1.3'
// Access to Neo4j testing facilities: TestGraphDatabaseFactory
testCompile "org.neo4j:neo4j-kernel:${neo4jVersion}:tests#jar"
testRuntime 'org.slf4j:slf4j-simple:1.7.5'
}
// Generate wrapper for Gradle
task wrapper(type: Wrapper) {
gradleVersion = '1.11'
}
Test Class
import domains.BaseClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Transaction;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
import repos.BaseClassRepository;
import static org.junit.Assert.assertEquals;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes={AppConfigTest.class})
public class TestBaseClass {
#Autowired
private BaseClassRepository baseClassRepository;
#Autowired
private GraphDatabaseService graphDb;
#Transactional
#Test
public void shouldCreateNode () {
BaseClass testClass = null;
try (Transaction tx = graphDb.beginTx()) {
testClass = new BaseClass();
testClass.setName("Archer");
baseClassRepository.save(testClass);
tx.success();
} catch (Exception e) {
System.err.println(e.getMessage());
}
BaseClass testClass1 = baseClassRepository.findByName("Archer");
assertEquals(testClass1.getName(), "Archer");
System.out.println(testClass.getName());
}
}
Stack Trace:
java.lang.IllegalStateException: Failed to load ApplicationContext
at org.springframework.test.context.CacheAwareContextLoaderDelegate.loadContext(CacheAwareContextLoaderDelegate.java:99)
at org.springframework.test.context.DefaultTestContext.getApplicationContext(DefaultTestContext.java:101)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:109)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:75)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:319)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:212)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:289)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:291)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:232)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:89)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:175)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.runTestClass(JUnitTestClassExecuter.java:80)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.execute(JUnitTestClassExecuter.java:47)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassProcessor.processTestClass(JUnitTestClassProcessor.java:69)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:49)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.messaging.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
at org.gradle.messaging.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:103)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.messaging.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:355)
at org.gradle.internal.concurrent.DefaultExecutorFactory$StoppableExecutorImpl$1.run(DefaultExecutorFactory.java:66)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'baseClassRepository': Cannot resolve reference to bean 'neo4jTemplate' while setting bean property 'neo4jTemplate'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'neo4jTemplate' is defined
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:336)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:108)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1456)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1197)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537)
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:684)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:121)
at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:60)
at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.delegateLoading(AbstractDelegatingSmartContextLoader.java:100)
at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.loadContext(AbstractDelegatingSmartContextLoader.java:250)
at org.springframework.test.context.CacheAwareContextLoaderDelegate.loadContextInternal(CacheAwareContextLoaderDelegate.java:64)
at org.springframework.test.context.CacheAwareContextLoaderDelegate.loadContext(CacheAwareContextLoaderDelegate.java:91)
... 44 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'neo4jTemplate' is defined
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:641)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1159)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:282)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:328)
... 62 more
Also, for some reason the shouldCreateNode() function runs twice for the test. Not sure why either. =(
AppConfigTest Configuration
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.test.TestGraphDatabaseFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.neo4j.config.EnableNeo4jRepositories;
import org.springframework.data.neo4j.config.Neo4jConfiguration;
#Configuration
#ComponentScan(basePackages = "domains")
#EnableNeo4jRepositories(basePackages = "repos")
public class AppConfigTest extends Neo4jConfiguration {
public AppConfigTest () {
setBasePackage("domains");
}
#Bean
public GraphDatabaseService graphDatabaseService() {
return new TestGraphDatabaseFactory().newImpermanentDatabase();
}
}
I finally got a working solution.
For my AppConfigTest class. I needed to extend it from Neo4jConfiguration for it to #Autowire the Neo4jTemplate. I thought this was only for the real application.
Secondly, after I fixed I was getting a error similar to spring-data-neo4j#161 on github. That error points you to the Neo4j Blog's post: Spring-Data-Neo4j Progress Update SDN 3 which I was missing the setBasePackages() function in my constructor (see updated code in question).
Third, seems #NodeEntity objects can't contain vars in the constructor either. So removed that from my test when creating my base class.
The compiler complains about
No bean named 'neo4jTemplate' is defined
which is in your test class TestBaseClass. So in order to inject the dependency of this class, you need to add the Neo4jTemplate bean in the configuration class:
public class AppConfigTest {
#Bean
public GraphDatabaseService graphDatabaseService() {
return new TestGraphDatabaseFactory().newImpermanentDatabase();
}
#Bean
public Neo4jTemplate neo4jBean() {
return new Neo4jTemplate(graphDatabaseService());
}
}
Note that Neo4jTemplate class in latest Spring version has the constructor argument dependency on GraphDatabaseService class. So you can do the above to do bean injection via constructor argument.