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();
}
}
Related
I am trying to use the properties file and inject it to my fields of a class, but I am getting null .
I have created a properties file called fortune.properties:
fortune1=Have a good day
fortune2=Have a bad day
fortune3=Have a medioccure day
Then I am loading it in the applicationContext.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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- Enable Component Scanning -->
<context:component-scan base-package="com.luv2code.springdemo"></context:component-scan>
<context:property-placeholder location="classpath:fortune.properties" />
</beans>
In the RandomFortuneClass, I am using value injection using #Value() annotation:
package com.luv2code.springdemo;
import java.util.Random;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
#Component()
public class RandomFortuneService implements FortuneService {
#Value("${fortune1}")
private String fortune1;
#Value("${fortune2}")
private String fortune2;
#Value("${fortune3}")
private String fortune3;
String[] fortunes = new String[] {fortune1, fortune2, fortune3};
private Random random = new Random();
#Override
public String getFortune() {
int index = random.nextInt(fortunes.length);
return fortunes[index];
}
}
Then I am declaring fortuneService in SwimCoach class using constructor injection:
package com.luv2code.springdemo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
#Component()
public class SwimCoach implements Coach {
private FortuneService fortuneService;
#Autowired
SwimCoach(#Qualifier("randomFortuneService") FortuneService fs) {
fortuneService = fs;
}
#Override
public String getDailyWorkout() {
System.out.println();
return "Swim 5m everyday";
}
#Override
public String getDailyFortune() {
return fortuneService.getFortune();
}
}
Now when I try to call the method getDailyFortune in the AnnotationDemoApp class, I always get null as output.
package com.luv2code.springdemo;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AnnotationDemoApp {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Coach theCoach = context.getBean("swimCoach", Coach.class);
System.out.println(theCoach.getDailyFortune());
context.close();
}
}
What is the error here?
Kindly comment if more information is needed.
Here is my file hierarchy:
PS: I am following the spring & hibernate course for beginners by Chad Darby.
You simply need to move fortune.properties into /src/main/resources, but let me suggest a cleaner way...
First, drop the xml configuration, it's outdated by several years and everything you can do there can be done via java annotations.
Second, add your property files to src/main/resources.
Third, tell Spring where to resolve your properties from, you can do this by adding #PropertySources({#PropertySource("fortune.properties")}) to a configuration class like this (also note that I've added the #ComponentScan and #Configuration annotations here):
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.PropertySource;
#Configuration
#ComponentScan
#PropertySource("fortune.properties")
public class Config {
}
Fourth, in your main method, use the AnnotationConfigApplicationContext as opposed to the ClassPathXmlApplicationContext. I think you'll find it's much cleaner.
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
Coach theCoach = context.getBean("swimCoach", Coach.class);
System.out.println(theCoach.getDailyFortune());
}
I stuck converting my current test app in Spring from using XML configuration to using Java configuration...
I have the following files
App.java
package com.spring.ioc.DependencyInjection;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("app-config.xml");
Phone p = ctx.getBean("phone", Phone.class);
p.calling();
p.data();
}
}
Galaxy.java
package com.spring.ioc.DependencyInjection;
public class Galaxy implements Phone {
public void calling() {
System.out.println("Calling using Galaxy");
}
public void data() {
System.out.println("Browsing internet using Galaxy");
}
}
IPhone.java
package com.spring.ioc.DependencyInjection;
public class IPhone implements Phone {
public void calling() {
System.out.println("Calling using iPhone");
}
public void data() {
System.out.println("Browsing internet using iPhone");
}
}
Phone.java
package com.spring.ioc.DependencyInjection;
public interface Phone {
void calling();
void data();
}
app-config.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="phone" class="com.spring.ioc.DependencyInjection.IPhone"></bean>
</beans>
The code above allows me to demo how you can use XML & edit the text between 'IPhone' or 'Galaxy' by changing the bean name at the end of the fully qualified name
<bean id="phone" class="com.spring.ioc.DependencyInjection.IPhone"></bean>
or
<bean id="phone" class="com.spring.ioc.DependencyInjection.Galaxy"></bean>
How can do the same in using JavaConfig instead of XML config?
I know how to use Java configuration to just pull one bean but am lost how to set it up to alternate between two objects.
Can you please show me by modifying the code I provided or adding any other code needed?
I believe you can use
#Component("iphone")
public class IPhone {}
#Component("galaxy ")
public class Galaxy {}
and where you inject it,
#Autowired
#Qualifier(value = "iphone")
private Phone iPhone;
#Autowired
#Qualifier(value = "galaxy")
private Phone galaxy;
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.
Here is my code:
public class Main {
public static void main(String[] args) {
Main p = new Main();
p.start(args);
}
#Autowired
private MyBean myBean;
private void start(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("META-INF/config.xml");
System.out.println("my beans method: " + myBean.getStr());
}
}
#Service
public class MyBean {
public String getStr() {
return "string";
}
}
<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="mypackage"/>
</beans>
Why doesn't this work? I get NullPointerException. Is it possible to use autowiring in a standalone application?
Spring works in standalone application. You are using the wrong way to create a spring bean. The correct way to do it like this:
#Component
public class Main {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("META-INF/config.xml");
Main p = context.getBean(Main.class);
p.start(args);
}
#Autowired
private MyBean myBean;
private void start(String[] args) {
System.out.println("my beans method: " + myBean.getStr());
}
}
#Service
public class MyBean {
public String getStr() {
return "string";
}
}
In the first case (the one in the question), you are creating the object by yourself, rather than getting it from the Spring context. So Spring does not get a chance to Autowire the dependencies (which causes the NullPointerException).
In the second case (the one in this answer), you get the bean from the Spring context and hence it is Spring managed and Spring takes care of autowiring.
Spring is moving away from XML files and uses annotations heavily. The following example is a simple standalone Spring application which uses annotation instead of XML files.
package com.zetcode.bean;
import org.springframework.stereotype.Component;
#Component
public class Message {
private String message = "Hello there!";
public void setMessage(String message){
this.message = message;
}
public String getMessage(){
return message;
}
}
This is a simple bean. It is decorated with the #Component annotation for auto-detection by Spring container.
package com.zetcode.main;
import com.zetcode.bean.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
#ComponentScan(basePackages = "com.zetcode")
public class Application {
public static void main(String[] args) {
ApplicationContext context
= new AnnotationConfigApplicationContext(Application.class);
Application p = context.getBean(Application.class);
p.start();
}
#Autowired
private Message message;
private void start() {
System.out.println("Message: " + message.getMessage());
}
}
This is the main Application class. The #ComponentScan annotation searches for components. The #Autowired annotation injects the bean into the message variable. The AnnotationConfigApplicationContext is used to create the Spring application context.
My Standalone Spring tutorial shows how to create a standalone Spring application with both XML and annotations.
For Spring 4, using Spring Boot we can have the following example without using the anti-pattern of getting the Bean from the ApplicationContext directly:
package com.yourproject;
#SpringBootApplication
public class TestBed implements CommandLineRunner {
private MyService myService;
#Autowired
public TestBed(MyService myService){
this.myService = myService;
}
public static void main(String... args) {
SpringApplication.run(TestBed.class, args);
}
#Override
public void run(String... strings) throws Exception {
System.out.println("myService: " + MyService );
}
}
#Service
public class MyService{
public String getSomething() {
return "something";
}
}
Make sure that all your injected services are under com.yourproject or its subpackages.
I case you are running SpringBoot:
I just had the same problem, that I could not Autowire one of my services from the static main method.
See below an approach in case you are relying on SpringApplication.run:
#SpringBootApplication
public class PricingOnlineApplication {
#Autowired
OrchestratorService orchestratorService;
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(PricingOnlineApplication.class, args);
PricingOnlineApplication application = context.getBean(PricingOnlineApplication.class);
application.start();
}
private void start() {
orchestratorService.performPricingRequest(null);
}
}
I noticed that SpringApplication.run returns a context which can be used similar to the above described approaches. From there, it is exactly the same as above ;-)
A nice solution would be to do following,
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
#Component
public class SpringContext implements ApplicationContextAware {
private static ApplicationContext context;
/**
* Returns the Spring managed bean instance of the given class type if it exists.
* Returns null otherwise.
* #param beanClass
* #return
*/
public static <T extends Object> T getBean(Class<T> beanClass) {
return context.getBean(beanClass);
}
#Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
// store ApplicationContext reference to access required beans later on
SpringContext.context = context;
}
}
Then you can use it like:
YourClass yourClass = SpringContext.getBean(YourClass.class);
I found this very nice solution in the following website: https://confluence.jaytaala.com/pages/viewpage.action?pageId=18579463
I am trying create an project with and without spring xml configurations.
First at all, I create my xml configuration like that:
<?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-4.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.1.xsd">
<bean id="memoryManagerProduct" class="br.com.caelum.stock.ProductManager">
<constructor-arg ref="memoryProductDAO"/>
</bean>
<bean id="memoryProductDAO" class="br.com.caelum.stock.dao.MemoryProductDAO"/>
</beans>
That I created my non XML configuration (I do not know if is right base in the fact that I do not know how invoke that)
package br.com.caelum.spring.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import br.com.caelum.stock.ProductManager;
import br.com.caelum.stock.dao.MemoryProductDAO;
import br.com.caelum.stock.dao.Persistable;
import br.com.caelum.stock.model.Product;
#Configuration
public class AppConfig {
#Bean
public Persistable<Product> memoryProductDAO(){
return new MemoryProductDAO();
}
#Bean
public ProductManager memoryProductManager(){
return new ProductManager(memoryProductDAO());
}
}
Than I created an JUnit test:
package br.com.caelum.stock;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import br.com.caelum.stock.model.Product;
public class ProductManagerTest {
private ProductManager manager;
#Test
public void testSpringXMLConfiguration() {
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring.xml");
manager = (ProductManager) context.getBean("memoryManagerProduct");
Product product = new Product();
product.setDescription("[Book] Spring in Action");
product.setQuantity(10);
manager.add(product);
assertThat(manager.getProducts().get(0).getDescription(), is("[Book] Spring in Action"));
}
#Test
public void testSpringWithoutXMLConfiguration() {
ApplicationContext context = ?
}
}
How can I inject the configurations that are in my AppConfig to do a similar test as in my testSpringXMLConfiguration?
There are good examples in the Spring reference guide here: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#beans-java-instantiating-container
In short, you would do this:
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
manager = (ProductManager) context.getBean("memoryManagerProduct");
However a better way of testing with Spring would be to use the spring-test support, details are here - http://docs.spring.io/spring/docs/current/spring-framework-reference/html/testing.html#integration-testing-annotations
You can do something like this with spring-test support:
#ContextConfiguration(classes = AppConfig.class)
#RunWith(SpringJUnit4ClassRunner.class)
public class ProductManagerTest {
#Autowired
private ProductManager manager;
#Test
public void testSpringXMLConfiguration() {
//use the productmanager in a test..
}
}