Spring: Nested application contexts - java

I have a hierarchy of application contexts. The bean that is defined in the parent context depends on a bean that is defined in the child. Here's how it looks like:
public class X {
public static class A {
public B b;
public void setB(B b) { this.b = b; }
}
public static class B { }
public static void main(String[] args) {
ClassPathXmlApplicationContext parent = new ClassPathXmlApplicationContext(
"/a.xml");
go1(parent);
}
public static void go1(ClassPathXmlApplicationContext parent) {
GenericApplicationContext child = new GenericApplicationContext(parent);
child.getBeanFactory().registerSingleton("b", new B());
A a = (A) child.getBean("a");
Assert.assertNotNull(a.b);
}
}
The xml file defining the "a" bean looks like this:
<?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-2.5.xsd">
<bean id="a" class="X$A" autowire="byName" lazy-init="true"/>
</beans>
The problem is that B is not injected into A. Injection will occur only if I register the "b" singleton with the parent - which is not an option in my program.
Any ideas?

You can't do that. Parent contexts cannot refer to bean definitions in the child contexts. It only works the other way around.

Related

Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'car' is defined

Can anyone tell me what is the error in this program and how to correct the error? I have given proper annotation and still getting errors.
I need help fixing this error I get when trying to deploy . Why isn't the Car bean being defined? Am I missing something in my web.xml or do I have to map the customerService somehow? I am using annotations for mapping. any help would be much appreciated. Here is the error log entry from the localhost log:
App.java
package om.venkatesh.omshakthi;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App
{
public static void main( String[] args )
{
ApplicationContext context=new ClassPathXmlApplicationContext("Spring.xml");
Car obj=(Car)context.getBean("car");
obj.drive();
}
}
Car.java
package om.venkatesh.omshakthi;
import org.springframework.stereotype.Component;
#Component
public class Car implements Vehicle{
public void drive()
{
System.out.println("Car");
}
}
Vehicle.java
package om.venkatesh.omshakthi;
public interface Vehicle {
void drive();
}
Spring.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-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<bean id="tyre" class="om.venkatesh.omshakthi.Tyre">
</bean>
</beans>
Without xml you can do it like this:
Create config class:
#Configuration
public class AppConfig {
#Bean
public Car car() {
return new Car();
}
}
Main class:
public class App {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(AppConfig.class);
ctx.refresh();
Car car = (Car) ctx.getBean("car");
car.drive();
}
}
Spring.xml has no bean with id "car" (although there is one for "tyre")
You need to define your bean in XML
<bean id="car" class="om.venkatesh.omshakthi.Car">
You don`t need #Component annotation when you use ClassPathXmlApplicationContext.
Just define a Car bean in your xml:
<bean id="car" class="om.venkatesh.omshakthi.Car">

Spring Boot trying to resolve bean not in my xml

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.

Spring 4: NullPointerException during instantiation of ClassPathXmlApplicationContext

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");
...
}

Spring lookup-method and abstract class

Would like to understand how Spring creates a bean from an abstract class, as if it is instantiating an Abstract class, as it is known that is not possible. Would like to know, what is getting instantiated for the "abstractLookupBean" bean.
Thank you.
public abstract class AbstractLookupDemoBean implements DemoBean {
public abstract MyHelper getMyHelper();
public void someOperation() {
getMyHelper().doSomethingHelpful();
}
}
DemoBean class
public interface DemoBean {
public MyHelper getMyHelper();
public void someOperation();
}
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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
<bean id="helper" class="com.rami.methodlookup.helper.MyHelper" scope="prototype"/>
<bean id="abstractLookupBean" class="com.rami.methodlookup.helper.AbstractLookupDemoBean">
<lookup-method name="getMyHelper" bean="helper"/>
</bean>
<bean id="standardLookupBean" class="com.rami.methodlookup.helper.StandardLookupDemoBean">
<property name="myHelper">
<ref local="helper"/>
</property>
</bean>
</beans>
main class
public static void main(String[] args) {
GenericXmlApplicationContext ctx = null;
try{
ctx = new GenericXmlApplicationContext();
ctx.load("applicationContext.xml");
ctx.refresh();
DemoBean abstractBean = (DemoBean) ctx.getBean("abstractLookupBean"); //What is getting instantiated?
}finally{
ctx.close();
}
Please see spring documentation here
...If the method is abstract, the dynamically-generated subclass will implement the method. Otherwise, the dynamically-generated subclass will override the concrete method defined in the original class...

Autowiring in spring (property name and bean name must be same)

public class B {
public B(){
System.out.println("B is created");
}
public void print(){
System.out.println("hello b");
}
}
class B.java
public class A {
B c;
public A(){
System.out.println("a is created");
}
public B getB(){
return c;
}
public void setB(B c){
this.c =c;
}
void print(){
System.out.println("hello a");
}
void display(){
print();
c.print();
}
}
class A.java
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="b" class="B"></bean>
<bean id="a" class="A" autowire="byName"></bean>
</beans>
applicationcontext.xml
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationcontext.xml");
A a1 = context.getBean("a",A.class);
a1.display();
}
}
Test .java
i was going through the tutorials on autowiring in spring by using "byName" mode. and it says- The byName mode injects the object dependency according to name of the bean. In such case, property name and bean name must be same. It internally calls setter method.
but in this application the property name and the bean name both are different but it still works fine,so how this autowiring is working even though the both names are different?
It says property name, not field name.
Property name in this case is inferred from the setter method name as defined by the JavaBeans naming convention (setB -> b), thus property name and bean name are the same.

Categories