I read about org.eclipse.e4.core.contexts.IContextFunction but could not find online an actual example.
My understanding is that a component implements an IContextFunction and on calling compute another object is lazily created.
But how/when the compute method is called it is not clear to me.
For example with the following:
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0"
name="com.example.e4.rcp.todo.contextservice.translate">
<implementation class="com.example.e4.rcp.todo.contextservice.Test"/>
<service>
<provide interface="org.eclipse.e4.core.contexts.IContextFunction"/>
</service>
<property name="service.context.key" type="String"
value="com.example.e4.rcp.todo.contextservice.test"/>
</scr:component>
someone must call for the com.example.e4.rcp.todo.contextservice.test for compute to be called but it is unclear to me how this is used.
Does anyone have an example reference?
It is what gets injected into your pojos.
E.g.
public class YourPojo {
#Inject
#Named("com.example.e4.rcp.todo.contextservice.test")
private Object yourObject;
}
OR
public class YourPojo {
#Inject
public void test(IEclipseContext ctx) {
Object yourObject = ctx.get("com.example.e4.rcp.todo.contextservice.test");
}
}
OR
public class YourPojo {
#Inject
public void test(#Named("com.example.e4.rcp.todo.contextservice.test") Object yourObject) {
// consume yourObject
}
}
Related
I have a "MyInterface" Interface as follows:
public interface MyInterface {
void showStatus();
Map<String,String> getMembers();
}
My "MyClass" class implements this interface and is as follows:
public class MyClass implements MyInterface {
private Map<String,String> members;
public void setMembers(Map<String, String> members) {
this.members = members;
}
public Map<String, String> getMembers() {
return members;
}
}
In my beans file I have set the property tag as follows:
<property name="members">
<map>
<entry key="key1" value="value1"></entry>
</map>
</property>
How does Spring set the value of the members variable, even though the setter method is not defined in the interface?
As jordanpg said, field injection is now discouraged and not proposed in the spring framework reference. But the answer to your question:
How does the property tag in Spring Beans set the value for the private member?
Is :
by using reflection.
This is not stated in the documentation but you can see it by inspecting the source code of the spring framework. Such as in the inject method of the InjectedElement static inner class of InjectionMetadata:
protected void inject(Object target,
#Nullable String requestingBeanName,
#Nullable PropertyValues pvs)
throws Throwable {
if (this.isField) {
Field field = (Field) this.member;
ReflectionUtils.makeAccessible(field);
field.set(target, getResourceToInject(target, requestingBeanName));
}
Field injection: http://vojtechruzicka.com/field-dependency-injection-considered-harmful/
Still supported by Spring, but not even documented anymore. I assume it's on a long-term deprecation roadmap, but in my experience lots of people still use it in spite of the mountains of recommendations not to.
I have a problem with a batchlet where I want to use an EJB to populate a list.
When I start the project, glassfish flags an error:
Caught exception executing step:
com.ibm.jbatch.container.exception.BatchContainerRuntimeException:
java.lang.NullPointerException
Glassfish version is 4.1.1
The code of my batchlet is:
#Named
public class getPingStatusBatchlet extends AbstractBatchlet {
private static GetPingStatus gps = new GetPingStatus();
private List<Node> nodes = null;
#EJB
private NodeFacade nodeEJB;
#Override
public String process() throws NamingException {
nodes = nodeEJB.findAll();
for (Node item : nodes) {
gps.getPingStatus(item.getIpv4());
}
return "COMPLETED";
}
#Override
public void stop() throws Exception {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
}
I tried to run the application in debug and inspect the nodeEJB, it always keep the null value.
Have you an idea how I can use my EJB into my batchlet?
Thanks for your help
Ersch
EDIT:
the NodeFacade code:
#Stateless
public class NodeFacade extends AbstractFacade<Node> {
#PersistenceContext(unitName = "powwoPU")
private EntityManager em;
#Override
protected EntityManager getEntityManager() {
return em;
}
public NodeFacade() {
super(Node.class);
}
}
beans.xml:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd"/>
getNetworkStatusBatch.xml:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<job version="1.0" id="getNetworkStatusBatch" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://www.oracle.com/webfolder/technetwork/jsc/xml/ns/javaee/jobXML_1_0.xsd" xmlns="http://xmlns.jcp.org/xml/ns/javaee" >
<step id="getNetworkStatusBatchlet">
<batchlet ref="com.powwo.app.batchlet.getPingStatusBatchlet"/>
</step>
</job>
myBackgroundJobManager.java:
#Singleton
#Startup
public class BackgroundJobManager {
#Schedule(minute = "*", hour = "*", second = "*/10", persistent = false)
public void myBackgroundJobManager() {
BatchRuntime.getJobOperator().start("getNetworkStatusBatch", null);
}
}
You need to reference the artifact from JSL by bean name (not class name).
So you should have:
<batchlet ref="getPingStatusBatchlet"/>
which matches the #Named (default) value on your batchlet.
You need this in order to load your batch artifact in Glassfish as a managed bean, and have the CDI engine perform injection of other beans.
More info:
Just for completeness, I'll mention something you already had taken care of, but someone else looking later may not have.
You also need to make sure the batch artifact is discovered as a managed bean, which you've taken care of by using the 1.0-level beans.xml. In later levels of CDI, you could use bean discovery mode = all, which is the same thing as the 1.0 beans.xml you have, or add a "bean-defining annotation" to your batch artifact, like #Dependent).
I have a simple example program here:
package com.test;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.support.FileSystemXmlApplicationContext;
public class Main {
public static void main(String[] args) throws InterruptedException {
try {
FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("TestBeanFile.xml");
Object o = context.getBean("AInstance");
}
catch (Throwable e) {
e.printStackTrace();
}
Thread.sleep(Long.MAX_VALUE);
}
private static class A implements InitializingBean {
private B myB;
public A() {
System.out.println("A constructor");
}
public void setB(B aB) {
myB = aB;
}
#Override
public void afterPropertiesSet() throws Exception {
System.out.println("A aps");
}
}
private static class B implements Runnable, InitializingBean {
private C myC;
private volatile boolean exit = false;
public B() {
System.out.println("B constructor");
}
public void setC(C aC) {
myC = aC;
}
#Override
public void afterPropertiesSet() throws Exception {
System.out.println("B aps");
if (myC == null) throw new IllegalArgumentException("C cannot be null");
new Thread(this).start();
}
public void exit() {
exit = true;
}
#Override
public void run() {
while (!exit) {
System.out.println(myC.getValue());
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
private static class C implements InitializingBean {
private String value = "C's value";
public C() {
System.out.println("C constructor");
}
public String getValue() {
return value;
}
#Override
public void afterPropertiesSet() throws Exception {
System.out.println("C aps");
}
}
}
And here is a simple XML to bean load them which intentionally has an incorrect fully qualified name to the A class. This should mean that C B and A dont get constructed.
<?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:int="http://www.springframework.org/schema/integration"
xmlns:int-stream="http://www.springframework.org/schema/integration/stream"
xmlns:int-ip="http://www.springframework.org/schema/integration/ip"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-2.1.xsd
http://www.springframework.org/schema/integration/stream http://www.springframework.org/schema/integration/stream/spring-integration-stream-2.1.xsd
http://www.springframework.org/schema/integration/ip http://www.springframework.org/schema/integration/ip/spring-integration-ip-2.1.xsd">
<bean id="CInstance" class = "com.test.Main.C" />
<bean id="BInstance" class = "com.test.Main.B">
<property name="C" ref="CInstance" />
</bean>
<bean id="AInstance" class = "com.test.Main.A1">
<property name="B" ref="BInstance"/>
</bean>
</beans>
When you run this application using the above XML C and B DO get constructed but A doesnt. It will produce the following output (omitting the stack trace when the exception is thrown, but I assure you A does not get constructed):
C constructor
C aps
B constructor
B aps
C's value
C's value
C's value
....... // one a second
If you modify the XML to look 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" xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-stream="http://www.springframework.org/schema/integration/stream"
xmlns:int-ip="http://www.springframework.org/schema/integration/ip"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-2.1.xsd
http://www.springframework.org/schema/integration/stream http://www.springframework.org/schema/integration/stream/spring-integration-stream-2.1.xsd
http://www.springframework.org/schema/integration/ip http://www.springframework.org/schema/integration/ip/spring-integration-ip-2.1.xsd">
<bean id="AInstance" class = "com.test.Main.A1">
<property name="B" ref="BInstance"/>
</bean>
<bean id="BInstance" class = "com.test.Main.B">
<property name="C" ref="CInstance" />
</bean>
<bean id="CInstance" class = "com.test.Main.C" />
</beans>
The only output you get is the stack trace, and the B and C objects dont get constructed at all.
This seems like its a bug in spring. I dont understand why the marshaling of the objects, and the constructors / afterpropertiesSet methods which are run depend on the order of their appearance in the XML. What this means for me, is that when I have classes which construct threads in their constructors / after properties set methods, if I'm not careful about how I order the elements in the XML I can end up leaking resources if my only reference to them is, in this example, the A class. Because it fails construction in both cases.
So, is this a bug, or is this some feature that I dont understand? If this is a feature, what reason would they have to make the order of marshaling dependent on the XML file, instead of the object graph of the bean definitions?
Spring first reads the <bean> and other elements in the XML configuration and creates appropriate BeanDefinition objects defining them.
It then has to initialize them. To do this, it has to decide on an order. The order of initialization is undefined, unless a bean depends on another or there is a mix of #Order, implementations of Ordered and a few others (depends on the case).
In your first example, CInstance is initialized first. Then BInstance is initialized. Part of its initialization involves invoking its afterPropertiesSet() method which launches a non-daemon thread. Then Spring attempts to initialize AInstance and fails.
In your second example, Spring attempts to initialize AInstance first. It fails immediately, with no change to start a second thread.
Note that in a declaration like
<bean id="AInstance" class="com.example.Spring.A1">
<property name="B" ref="BInstance" />
</bean>
although AInstance depends on BInstance, the actual instance needs to be initialized before any property setters can be invoked to assign BInstance to B. So Spring begins the initialization of AInstance by instantiating the class. If it fails, the entirety of context refresh fails. If it passes, it will then initialize the BInstance bean and use it to set the B property.
OK, I haven't used Spring in a while, so I'm a little rusty. Not sure if I missed something in all of this or not. My appContext.xml for Spring states that 'no setter is found for property testBean in class com.ztp.spring.injection.TestBean.
Here is the appContext.xml file:
<bean id="myTestBean" class="com.ztp.spring.injection.TestBean" />
<bean id="myTestClass" class="com.ztp.spring.injection.TestClass">
<property name="testBean" ref="myTestBean" />
</bean>
and here is the TestClass.java file in its entirety:
public class TestClass {
TestBean testBean;
public void setTestClass(TestBean testBean) {
this.testBean = testBean;
}
public void fillBean() {
testBean.setId(5);
testBean.setTestAnimal("sheltie");
}
}
I have another program that I worked on months ago, and its the same logic-wise, and it works. So I'm not sure what I'm missing.
If its already been answer or you need more info, just say so, I'd like to figure this out.
Thank you in advance.
Typo in the method name. What you meant is this:
public void setTestBean(TestBean testBean) {
this.testBean = testBean;
}
You had setTestClass. This would violate the JavaBean conventions.
The method name should match the property name for the bean:
public void setTestBean(TestBean testBean) {
I faced this issue, while trying to autowire a runnable class and creating different instances of it in different call and keeping it in an array.
xml configuration is :
<bean name="threadName" Class="ABC" scope="prototype" />
In my code, I am trying something like this:
public class ThreadHandler{
#Autowired
private ABC threadName;
//getter
ABC getThreadName(){
return threadName;
}
public void someFunction(){
List<ABC> abc = new ArrayList(ABC>();
for (int i=0;i<SOME_CONST;i++){
ABC tName = getThreadName();
abc.add(tName);
tName.start();
}
}
}
Let ABC be a class which is Thread/Runnable/Callable.
In this way, it throws java.lang.IllegalThreadStateException.
But, it works fine, if I use ABC tName =appContext.getBean("threadName",ABC.class);
Why does it happen?
Don't we get a new instance while trying to get an object from getMethod?
There is much better practice when you need to create Runnable/Callable and inject it into applicationContext it's called look up method:
Let's consider that all Runnable/Callable classes are #Prototype and #Lazy
#Component(value="task")
#Scope(value="prototype")
#Lazy(value=true)
public class Task implements Runnable {
public void run(){
.....
}
}
Now you need to Create Look up method factory:
<bean id="taskFactory" class="x.y.z.TaskFactory">
<lookup-method name="createTask" bean="task"/>
</bean>
Now let's implement TaskFactory itself which is abstract class and have one abstract method :
#Component(value="taskFactory")
public abstract class TaskFactory {
public abstract Task createTask();
}
Here comes the magic:
public class ThreadHandler{
#Autowired
private TaskFactory taskFactory;
public void someFunction(){
Runnable task = taskFactory.createTask();
taskExecutor.execute(task);
}
}
Every time you are calling createTask() method of taskFactory singleton object. you will receive completely new instance of your prototype object.
P.S: don't forget to add
<context:annotation-config />
<context:component-scan base-package="x.y.z"></context:component-scan>
to enable Annotations correctly.
hope it Helps.
No, you don't get a new object, just by accessing a field that holds a reference to a bean scoped as Prototype. Spring doesn't have any way to replace your instance level reference with a new reference based just on field access. It's set once by the autowiring and then it's just a reference to that one object. If you want it to actually create a new one you need to use getBean as you observed.
You can tell Spring to override your get method and replace it with a 'getBean' using method injection, to get the Spring dependencies out of your bean:
<bean id="threadHandler" class="com.stackexchange.ThreadHandler">
<lookup-method name="getThreadName" bean="threadName"/>
</bean>