-
1. Re: Weld Proxies
philipp91 Sep 2, 2013 8:58 AM (in response to philipp91)Hi again,
I think I found a solution:
if (something instanceof TargetInstanceProxy) {
something = ((TargetInstanceProxy<?>) something).getTargetInstance();
}
Philipp
-
2. Re: Weld Proxies
mkouba Sep 2, 2013 9:10 AM (in response to philipp91)Hi Phillip,
keep in mind that TargetInstanceProxy is a Weld-specific internal interface - not even part of the Weld API. So your app will not be portable and may even stop working with future versions of Weld.
-
3. Re: Weld Proxies
jharting Sep 2, 2013 9:37 AM (in response to mkouba)The portable way of obtaining an unproxied instance of a Bean is to get the Context object from BeanManager (BeanManager.getContext) and then call Context.get(), passing the Bean object (and possibly CreationalContext) as a parameter.
-
4. Re: Weld Proxies
philipp91 Sep 2, 2013 1:05 PM (in response to jharting)Jozef, thank you for pointing out this way (which is most likely the correct answer to my original question). However, I don't know where to get the Bean object (and the CreationalContext?) from, because all I have is the proxy object (TargetInstanceProxy) that was returned by CDI.current().select(someClass).get()
-
5. Re: Weld Proxies
mkouba Sep 2, 2013 4:04 PM (in response to philipp91)Phillip, you can obtain a bean by type ("someClass" in your case) - see also 11.3.6. Obtaining a Bean by type. CreationalContext is not necessary to retrieve an existing instance. If you're not sure the instance already exists you'll have to provide a creational context as well - see 11.3.5. Obtaining a CreationalContext.
-
6. Re: Weld Proxies
stefan.grossmann Jan 8, 2014 8:12 AM (in response to philipp91)The following solution also works fine:
beanManager.getContext(MyScope.class).get((Contextual<T>) bean, ctx);
But the problem for me is that I get a MyJavaFXController$Proxy$_$$_WeldSubclass, if e. g. the Controller uses interceptors. In this case the JavaFX injection of a field annotated with @FXML does not work, if the field is private. If the field is package protected it works.
For beans where I get the bean instance, instead of a ...$Proxy$_$$_WeldSubclass, I have no problem in with @FXML and private field.
Any idea what I can do, to make the @FXML injection for private fields?
-
7. Re: Weld Proxies
jharting Jan 9, 2014 2:50 AM (in response to stefan.grossmann)What do you mean by "injection of private field does not work"? Are you getting an exception? Once you get to the target instance and are able to inject fields it should make no difference whether the field is private or not (assuming you set the accessible flag of the field).
-
8. Re: Weld Proxies
philipp91 Jan 9, 2014 3:46 AM (in response to jharting)@Josef: It looks like Stefan is not talking about CDI injection (which works as designed in this case) but about FXML injection. When loading an fxml file, JavaFX will inject the UI component objects to your controller bean if you annotated the corresponding fields with @FXML.
@Stefan: I just checked and I have a private field in a super-class that works with @FXML. Also from reading the code of FXMLLoader, I cannot see any reason why that wouldn't work. The only thing that is *not* possible is injection on a private field in a super-class when there exists an identically named field in the sub-class. So maybe that is the reason. You might just check with the debugger (or ask Jozef) whether the WeldSubclass defines the same private fields as the original class did.
// EDIT:
Sorry, I was wrong. You seem to be using a newer version of JavaFX and there is definitely some code that restricts injection on private field to the class itself and excludes super-classes:
And when looking at the placement of this code, it's very unlikely that you will be able to change that ...
-
9. Re: Weld Proxies
stefan.grossmann Jan 10, 2014 5:55 AM (in response to philipp91)Philipp Keck wrote:
@Josef: It looks like Stefan is not talking about CDI injection (which works as designed in this case) but about FXML injection. When loading an fxml file, JavaFX will inject the UI component objects to your controller bean if you annotated the corresponding fields with @FXML.
Exactly. FXML injection simply does nothing, the fields are null.
Sorry, I was wrong. You seem to be using a newer version of JavaFX and there is definitely some code that restricts injection on private field to the class itself and excludes super-classes:
And when looking at the placement of this code, it's very unlikely that you will be able to change that ...
philipp91: I think you are right!
Weld subclasses my controller to make the CDI-Interceptors working:
contollerInstance.getClass()
(java.lang.Class<T>) class examples.helloworld.HelloWorldController$Proxy$_$$_WeldSubclass
contollerInstance.getClass().getSuperclass()
(java.lang.Class<T>) class examples.helloworld.HelloWorldController
So for the FXMLLoader the HelloWorldController is a superclass of the controller an JavaFX ignores the private fields.
-
10. Re: Weld Proxies
philipp91 Jan 10, 2014 12:44 PM (in response to stefan.grossmann)A solution for you might be to make your fields protected.
// EDIT: Sorry, my previous answer was partly wrong. JavaFX 8 is just as good as JavaFX 2 with regard to this issue. In order to make it work, you need to make the fields protected or package-private, both of which are reasonable options, I think.
-
11. Re: Weld Proxies
stefan.grossmann Jan 13, 2014 3:45 AM (in response to philipp91)I now use the following implementation to retrieve the controller:
private <T> T getController(Class<T> clazz) {
final List<Bean<T>> types = IteratorUtils.toList(beanManager.getBeans(clazz).iterator());
if (types.size() > 1) {
LOG.warn(...);
} else if (types.size() == 0) {
throw new ...;
}
final Bean<T> bean = types.get(0);
final CreationalContext<T> ctx = beanManager.createCreationalContext(null);
T contollerInstance = beanManager.getContext(bean.getScope()).get((Contextual<T>) bean, ctx);
return contollerInstance;
}
Note: The getController method is executed in a callback which is passed to the FXMLLoader with the setControllerFactory method. (see: http://java.dzone.com/articles/fxml-javafx-powered-cdi-jboss).
The call of beanManager.getContext(bean.getScope()).get((Contextual<T>) bean, ctx) returns the bean-implementation or a sub-class of the bean. A subclass is e. g. returned if you want to use interceptors for your controller. With JavaFX 2.2 and Weld 1.1 you have to make the attributes of your controller package protected, to make the @FXML-Injection working in that situation. In Java8 FXML-Injection it will not work for sub-classed beans any-more. See https://javafx-jira.kenai.com/browse/RT-30131 and the other entries of this discussion for more details.
-
12. Re: Weld Proxies
philipp91 Jan 13, 2014 6:15 AM (in response to stefan.grossmann)In Java8 FXML-Injection it will not work for sub-classed beans any-more.
Actually, I think it does. Any field that is visible to the sub-class will be injected. And because in the case of Weld with interceptors, the sub-class is always in the same package, anything works except private fields. However, I didn't test it, because I don't need it.