I am developing a standalone Spring 4 application, which uses javaFX. However, when I try to create a new ClassPathXmlApplicationContext, all autowired fields are null, leading to NPEs, even though I let Spring instantiate my classes.
This is my main class:
public class Main extends Application {
public static void main(String[] args) {
launch();
}
public void start(Stage stage) {
ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
Gui gui = context.getBean(Gui.class);
stage.setScene(new Scene(gui, 400, 400));
stage.show();
}
}
This is my spring-config.xml:
<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-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd">
<context:annotation-config />
<context:component-scan base-package="org.my.package" />
</beans>
Gui class:
#Controller
#Scope("singleton")
public class Gui extends GridPane {
#Autowired
private NetManager netManager;
#Autowired
private MessengerComponent messenger;
public Gui() {
netManager.init("Username");
...
}
}
NetManager.class:
#Service
#Scope("singleton")
public class NetManager {
...
}
The NPE occurs before I even retrieve the first bean, during the creation of the application context. Any idea why?
The order of the injection is the following:
Constructor args
Fields
Setters/methods
Under the hood, Spring (or any DI framework) create your class by calling the constructor, and THEN inject the dependencies. So you can't use injected fields in your constructor: they will be injected after.
You should inject the needed dependencies in your constructor:
#Autowired
public Gui(NetManager netManager) {
this.netManager = netManager;
netManager.init("Username");
...
}
Related
I want to test a class that simple shutdown the application:
#Component
public class ShutdownManager {
#Autowired
private ApplicationContext applicationcontext;
public int shutdown(int returnCode) {
return SpringApplication.exit(applicationcontext, () -> returnCode);
}
}
The test case I created is this:
public class ShutdownManagerTest {
#Test
public void should_shutdown_gracefully() {
SpringApplication app = new SpringApplication(TestClass.class);
ConfigurableApplicationContext context = app.run();
ShutdownManager shutdownManager = (ShutdownManager)context.getBean("shutdownManager");
int result = shutdownManager.shutdown(10);
assertThat(result).isEqualTo(10);
}
#SpringBootApplication
#ImportResource("classpath:/core/shutdownmanagertest.xml")
private static class TestClass {
public TestClass() {
}
public static void main(String[] args) {
}
}
}
My shutdownmanagertest.xml contains only one bean:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="shutdownManager" class="com.mycodebase.ShutdownManager" />
</beans>
However, when I run this, it complains that:
Field myOtherService in com.mycodebase.MyTask required a bean of type 'com.mycodebase.MyOtherService ' that could not be found.
The class MyTask is in the same package of the ShutdownManager which contains a field myOtherService which has an #Autowire annocation. But it is not defined in my test xml which contains just one bean.
Can someone help me understand why it tries to resolve a bean that is not in the context?
It's doing that because that's how #SpringBootApplication works.
#SpringBootApplication:
This is a convenience annotation that is equivalent to declaring #Configuration, #EnableAutoConfiguration and #ComponentScan.
#ComponentScan
If specific packages are not defined, scanning will occur from the package of the class that declares this annotation.
So everything in the same or a subpackage of ShutdownManagerTest is being picked up.
package com.mkyong.output;
IOutputGenerator.java
public interface IOutputGenerator
{
public void generateOutput();
}
package com.mkyong.output;
OutputHelper.java
#Component
public class OutputHelper {
#Autowired
IOutputGenerator outputGenerator;
public void generateOutput() {
outputGenerator.generateOutput();
}
/*//DI via setter method
public void setOutputGenerator(IOutputGenerator outputGenerator) {
this.outputGenerator = outputGenerator;
}*/
}
package com.mkyong.output.impl;
CsvOutputGenerator.java
#Component
public class CsvOutputGenerator implements IOutputGenerator {
public void generateOutput() {
System.out.println("This is Csv Output Generator");
}
}
SpringBeans.xml
<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-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:component-scan base-package="com.mkyong" />
</beans>
i am getting this exception Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'OutputHelper' is defined
even though i have marked OutputHelper as component.
I have changed
OutputHelper output = (OutputHelper) context.getBean("OutputHelper");
to
OutputHelper output = (OutputHelper) context.getBean("outputHelper");
and it worked.
Hi i think you haven't added following in your Spring XML configuration
xmlns:mvc="http://www.springframework.org/schema/mvc"
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
<mvc:annotation-driven/>
you need to see top exception and read the whole line.
i guess there have a exception is nested exception just like #Autowired xxxxxx,meas autowired fail.
i have notice this:
#Autowired
IOutputGenerator outputGenerator;
and
#Component
public class CsvOutputGenerator implements IOutputGenerator
so, in the default, class name is used to #Autowired,you can rewrite to
#Autowired
IOutputGenerator csvOutputGenerator;
notice:
"csvOutputGenerator" first letter is lowercase
the easier option would be to enable annotations in beans already registered in the application context, means that you can just use #Autowired instead of getting manually all beans with context.getBean()
just add this line to your SpringBeans.xml
<context:annotation-config>
if you really want to understand what you are doing reading this could help.
First of all, I know there are very similar questions (Camel producerTemplate is not injected in spring MVC and Initializing camel from Spring annotation config) but they don't help in my case.
I have a bean which sends messages with ProducerTemplate:
public class SimpleProducer {
#Produce(uri = "activemq:queue:simple")
private ProducerTemplate activeMqProducer;
public void send(String message) {
activeMqProducer.sendBody(message);
}
}
When I use annotation driven configuration like below, it trhows NPE from the send method (activeMqProducer is not injected):
#Configuration
public class AnnotationConfigApp {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AnnotationConfigApp.class);
SimpleProducer simpleProducer = context.getBean(SimpleProducer.class);
simpleProducer.send("Hello World!");
}
#Autowired
private ApplicationContext ctx;
#Bean
public SimpleProducer simpleProducer() {
return new SimpleProducer();
}
#Bean
public CamelContext camelContext() throws Exception {
CamelContext camelContext = new SpringCamelContext(ctx);
camelContext.start();
return camelContext;
}
}
while using equivalent (at least I believe so) XML configuration, it sucessfully sends a message to ActiveMQ:
<?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:spring="http://camel.apache.org/schema/spring"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
<bean id="simpleProducer" class="makasprzak.so.camel.producer.testing.SimpleProducer"/>
<spring:camelContext xmlns="http://camel.apache.org/schema/spring" id="simple.sender" />
</beans>
initialized like this:
public class XmlConfigApp {
public static void main(String[] args) {
ApplicationContext context = new GenericXmlApplicationContext("context.xml");
SimpleProducer simpleProducer = context.getBean(SimpleProducer.class);
simpleProducer.send("Hello World!");
}
}
I've been playing with CamelContext implementation a bit, tried DefaultCamelContext or some SpringCamelContextFactory - no luck.
The problematic code is available in GitHub
<properties>
<camel.version>2.15.2</camel.version>
<activemq.version>5.10.0</activemq.version>
<java.version>1.8</java.version>
</properties>
What did I miss in the annotation configuration?
You should extend org.apache.camel.spring.javaconfig.CamelConfiguration in AnnotationConfigApp class
This question already has answers here:
Using Spring 3 autowire in a standalone Java application
(5 answers)
Closed 9 years ago.
Is there a way to run Spring application configured by annotation, directly from main method?
I'm still getting NullPointerException runing code below. Note that I'm not using SpringMVC and when I'm using beans defined inside context.xml, injected inside main method by context.getBean method, all code works perfect (without error) - but I just wondering if it is a way to manage runing this only with annotations?
//IElem.java
package com.pack.elem;
public interface IElem {
public abstract String sayHello();
}
//Elem.java
package com.pack.elem;
import org.springframework.stereotype.Component;
#Component
public class Elem implements IElem{
#Override
public String sayHello() {
return ("Hello from Elem class object");
}
}
//RunElem.java
package com.pack.elem;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Component
public class RunElem {
#Autowired
private IElem elem;
public void runHello(){
System.out.println(elem.sayHello());
}
}
//Main.java
package com.pack.main;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.pack.elem.RunElem;
public class Main {
#Autowired
private RunElem runelem;
public static void main(String[] args) {
ApplicationContext context= new ClassPathXmlApplicationContext("/META-INF/application-context.xml");
new Main().runRun();
}
private void runRun(){
runelem.runHello();
}
}
<!--/META-INF/application-context.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-3.2.xsd">
<context:annotation-config/>
<context:component-scan base-package="com.pack"/>
</beans>
Put simply, Spring is autowiring if it is the one instantiating the bean. So you have to use getBean(). If you want to use annotations only, something like this should work:
#Component
public class Main {
#Autowired
private RunElem runelem;
public static void main(String[] args) {
ApplicationContext context= new ClassPathXmlApplicationContext("/META-INF/application-context.xml");
Main mainBean = context.getBean(Main.class);
mainBean.runRun();
}
private void runRun(){
runelem.runHello();
}
}
Alternatively you can autowire an existing bean as shown below, but this is not a recommended Spring usage:
public class Main {
#Autowired
private RunElem runelem;
public static void main(String[] args) {
ApplicationContext context= new ClassPathXmlApplicationContext("/META-INF/application-context.xml");
Main mainBean = new Main();
context.getAutowireCapableBeanFactory().autowireBean(mainBean);
mainBean.runRun();
}
private void runRun(){
runelem.runHello();
}
}
I am using Spring autoscan components in my testing framework.
Autowired works fine in all classes except in class which extends Junit Testwatcher.
The class where I extend Junit testwatcher is:
#Component
public class PrintTrace extends TestWatcher{//this class overrides pass and fail
//methods in Testwatcher
#Autowired
private HTMLLogger htmlLogger //this is null all the time. it works in
//other classes
}
My Base class looks like:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:beans.xml"})
#TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class })
public class YahooTestSetUp {
public static WebDriver driver;
#Rule
public PrintTrace printTrace = new PrintTrace();
#Autowired
private HTMLLogger htmlLogger;//here its working fine
}
And my xml file:
<?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-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config />
<context:component-scan base-package="com.pilz"/>
</beans>
Please advice this is very important for me. Otherwise I should go for
singleton objects,which is not a good solution for me.
Adding more info:
Lets say i have 2 test suites which access 2 common classes HTMLLogger.class and PrintTraece.class.
Each testsuite is independent of other suite. These suites have #BeforeClass and #AfterClass
see below:
#RunWith(Suite.class)
#Suite.SuiteClasses({ AutowireClass.class})
public class YahooTestSuite extends YahooTestSetUp{
private static HTMLLogger htmlLogger;
#BeforeClass
public static void allTests() throws Exception {**//Can I use #Autowired in
static methods(no)**
htmlLogger = new HTMlLogger()
htmlLogger.createHTMLLogFile();
}
#AfterClass
public static void afterAll() throws Exception{
htmlLogger.htmlLogEnd();
}
}
and another suite is doing same for other module.
As i said before my PrintTrace.class extends Testwatcher.class(Junit rule) its look like
This class is invoked with the the rule created in baseclass.
#Component
public class PrintTrace extends TestWatcher{
private HTMLLogger htmlLogger = null;
#Override
public void starting(final Description description) {
}
#Override
public void failed(final Throwable e, final Description description) {
htmlLogger.writeFailLog();**//This is common for all suites**
//This should be same object used in suite
}
#Override
public void succeeded(final Description description) {
htmlLogger.writePassLog();//This is common for all suites
//This should be same object used in suite
}
#Override
public void finished(Description description) {
}
thanks
Why do you want to use Spring DI for JUnit rules? Your test code is not your application.
In some of the java classes, like the test cases or web-listeners, #Autowired doesn't work. You have to define the applicationContext like an object and receive beans manually.
ApplicationContext context = AnnotationConfigApplicationContext("app_context_file_path")
HTMLLogger htmlLogger = context.getBean("loggerBeanName");
Also, have a look over here - http://static.springsource.org/spring/docs/3.0.x/reference/testing.html
And google about the #Resource spring annotation.
To get the exact object you need, you should have the following configuration:
If you create a bean in the application context file, just use the id of it in the getBean(name) method. If you have it as a separate class, provide it (class) with the #Component(value) annotation and scan the package in the application context. After that use the value name of that bean(component) to get the exact object you've configured.