I am writing a (composite) component that needs to interact with my DAO. Here is how the Java part is declared:
#FacesComponent(value="selectLocation")
public class SelectLocation extends UINamingContainer {
To get the DAO object, I tried the CDI annotation:
#Inject private LocationControl lc;
And that didn't work so I tried the Faces annotation:
#ManagedProperty (value = "#{locationControl}") private LocationControl lc;
Both cases nothing happens -- the property lc ends up as null after the constructor finishes.
I use CDI in all my backing beans and it all works. This would be using Weld inside GlassFish 3.1.1. Any suggestions on how to get the resource?
I have a work-around for now, which is to basically put in the boiler-plate code that CDI et. al. is supposed to do away with. I now have this method:
public LocationControl getLocationControl() {
if (lc != null) return lc;
FacesContext fc = getFacesContext();
Object obj = fc.getApplication().evaluateExpressionGet(fc, "#{locationControl}", LocationControl.class);
if (obj instanceof LocationControl) lc = (LocationControl) obj;
return lc;
}
I would like to know if anyone has a better solution.
I don't know if it also works for components, but with CDI + MyFaces CODI you have #Advanced to mark e.g. Phase-Listeners which should be able to use #Inject. If it doesn't work, you could create a feature request in their JIRA. They are pretty fast and there are frequent releases.
Or you use:
MyBean myBean = BeanManagerProvider.getInstance().getContextualReference(MyBean.class);
manually.
There is a way to do this work without workarounds?
Yes, just use a backing bean the usual way.
<x:someComponent value="#{someBean.someProperty}" />
Wrap if necessary in a reusable tagfile/composite to keep it DRY:
<my:someComponent />
Related
I use tomcat 7.0 and JSF 2.1 and I have problem when I call in my .xhtml page something like that: #{homePage.get("userName")}
I get javax.el.ELException: Caused by: java.lang.NullPointerException
at mainPacket.HomePageBean.get(HomePageBean.java:35)
I have ManagedBean like below:
#ManagedBean(name = "homePage")
#ViewScoped
public class HomePageBean {
private Map<String, Object> map;
public HomePageBean() {
map= FacesContext.getCurrentInstance().getExternalContext().getSessionMap();
//remove unnecessary values from sessionMap
FacesContext.getCurrentInstance().getExternalContext().getSessionMap().clear();
}
public String get(Object s){
return map.get(s).toString();
}
}
When I don't use clear, everything works ok. But I want to clear sessionMap. How to resolve it ?
Thanks
Java is an object oriented language. It doesn't give you a copy of the object everytime you request it. No, it gives you a reference to the object instance in memory. At the moment you invoke Map#clear() on the session map, then the map reference which you obtained just beforehand is basically also emptied, because it points to exactly the same map instance which you just emptied!
Your concrete functional requirement is nowhere mentioned in the question and the whole design in the code posted so far makes honestly no utter sense (I can't imagine any sensible real world use case for this), so it's hard to propose you the right solution. Best what you can get is the advice to add a nullcheck.
public String get(Object s){
Object value = map.get(s);
return (value != null) ? value.toString() : null;
}
You should by the way be very careful with abruptly emptying the session map this way. JSF stores view scoped and session scoped managed beans in there and it's also used by the flash scope.
From just a few searches, this seems like a problem that has been around for a while. I have written a FacesConverter that looks like the following. The object Category is a JPA entity and CategoryControl is the DAO that fetches it.
#FacesConverter(value = "categoryConverter")
public class CategoryConverter implements Converter {
#Inject private CategoryControl cc;
public CategoryConverter() { }
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (cc != null) return cc.getByName(value);
System.out.println("CategoryConverter().getAsObject(): no injection!");
return null;
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (!(value instanceof Category)) return null;
return ((Category) value).getName();
}
}
As you probably guessed by now, I never get the injection. I got this workaround from this page, which looks like this.:
Workaround for this problem: create this method in your localeController:
public Converter getConverter()
{
return FacesContext.getCurrentInstance().getApplication().createConverter("localeConverter");
}
and use converter="#{localeController.converter}" in your h:selectOneMenu.
However I can't make this work either. My backing bean creates and returns a converter all right, but it doesn't get the object injected into it.
I am using MyFaces CODI 1.0.1. With the current GlassFish/Weld container. Can anyone suggest a solution before I re-code to not use a Converter?
Replace
#FacesConverter(value = "categoryConverter")
by
#Named
and use
<h:inputSomething converter="#{categoryConverter}" />
or
<f:converter binding="#{categoryConverter}" />
instead of
<h:inputSomething converter="categoryConverter" />
or
<f:converter converterId="categoryConverter" />
By the way, similar problem exist for #EJB inside a #FacesConverter. It however offers a way to be grabbed by JNDI manually. See also Communication in JSF 2.0 - Getting an EJB in #FacesConverter and #FacesValidator. This way you can use a #FacesConverter(forClass=Category.class) without manually defining it everytime. Unfortunately I can't tell from top of head how to realize that for CDI beans.
Update: if you happen to use JSF utility library OmniFaces, since version 1.6 is adds transparent support for using #Inject and #EJB in a #FacesConverter class without any additional configuration or annotations. See also the CDI #FacesConverter showcase example.
The #Inject Annotation only works in CDI managed instances. If you want to use CDI features inside a non-CDI managed instance (Like a JSF Validator or a JSF Converter) you can just programm against the CDI API.
This works only in at least Java EE 7 + CDI 1.1 server.
#FacesValidator("userNameValidator")
public class UserNameValidator implements Validator {
private UserService userService;
public UserNameValidator(){
this.userService = CDI.current().select(UserService.class).get();
}
#Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
....
}
}
https://docs.oracle.com/javaee/7/api/javax/enterprise/inject/spi/CDI.html
With all the AnnotationHell in Java EE people forget how to code.
Just use #Advanced of CODI for your #FacesConverter see the Wiki.
As soon as a converter or a validator is annotated with #Advanced it's possible to use #Inject.
Per BalusC's answer here, I decided to add JSF (requestscoped) managed beans that only contained #FacesConverter and Converter to resolve this issue in my app, since I'm migrating from JSF managed beans to CDI managed beans.
I tried CODI #Advanced against #FacesConverter, but it does not inject the bean at all.
I'm currently experimenting a little with Apache MyFaces CODI. I managed to create a simple working Typesafe-Navigation using #Page and an action Method which returns a Class.
However, when I'm adding an #PageBean-Annotation with e.g. MyPageBean.class, the following exception is thrown when I try to navigate to the page:
exception
javax.servlet.ServletException: WELD-001324 Argument bean must not be null
root cause
org.jboss.weld.exceptions.IllegalArgumentException: WELD-001324 Argument bean must not be null
The code of my page is:
#Page
#PageBean(MyPageBean.class)
public final class MyPage implements ViewConfig, Serializable {
}
and my Page-Bean:
public class MyPageBean implements Serializable {
#InitView
protected void initView() { }
#PrePageAction
protected void prePageAction() { }
#PreRenderView
protected void preRenderView() { }
}
And the Action-Method called by the Facelets Page:
public Class<? extends ViewConfig> nextPage() {
return MyPage.class;
}
Does the pageBean-Class (MyPageBean) need to have a specific annotation or interface? I already tried using #Model but this didn't change anything.
My Configuration:
Jave EE6 with Weld (created using the weld-archetype)
Glassfish 3.1 Community Edition (The one shipped with Netbeans 7)
JSF2.0 (Mojarra 2.1)
EJB 3.1
MyFaces CODI 0.9.4
RichFaces 4.0.0.Final
Thanks for any advices!
Best regards,
Robert
If you don't use any specific scope, it will end up being #Dependent.
I suggest to at least use #RequestScoped (take care, don't use the javax.faces.bean.RequestScoped, but the annontation from CDI!)
Oki, talked with Gerhard now as he has more experience with CODI on Weld.
Apparently this seems to be an error in the Weld version you use. This should be working in weld-1.1.1.Final https://github.com/weld/core/tree/1.1.1.Final
Please try to replace the weld-osgi-bundle in your glassfish with the one from weld 1.1.1.Final
cp target/weld-osgi-bundle-1.1.1.jar /opt/sun/glassfish/glassfish/modules/weld-osgi-bundle.jar
if it works: credits go to os890 ;)
I am attempting to create an AttachedProperty for a DataGridColumn within Silverlight 3.0 and I am having some issues.
Here is the AttachedProperty:
public class DataGridColumnHelper
{
public static readonly DependencyProperty HeaderProperty =
DependencyProperty.RegisterAttached("Header", typeof(string), typeof(DataGridColumnHelper),
new PropertyMetadata(OnHeaderPropertyChanged));
private static void OnHeaderPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
string header = GetHeader(d);
var dataGridColumn = d as DataGridColumn;
if (dataGridColumn == null)
{
return;
}
dataGridColumn.Header = GetHeader(dataGridColumn);
}
public static string GetHeader(DependencyObject obj)
{
return (string)obj.GetValue(HeaderProperty);
}
public static void SetHeader(DependencyObject obj, string value)
{
obj.SetValue(HeaderProperty, value);
}
}
As you can see it is really simple, I am trying to overcome the limitation that the Header Property in the DataGridColumn class cannot be bound.
This XAML works as expected...
<Controls:DataGridTextColumn Binding="{Binding OwnerName}"
HeaderStyle="{StaticResource DataGridColumnHeaderStyle}"
Behaviors:DataGridColumnHelper.Header="User Name"/>
However this XAML throws an error...(Specifically: {System.Windows.Markup.XamlParseException: AG_E_PARSER_PROPERTY_NOT_FOUND [Line: 224 Position: 112]
at System.Windows.Application.LoadComponent(Object component, Uri resourceLocator)
....})
<Controls:DataGridTextColumn Binding="{Binding OwnerName}"
HeaderStyle="{StaticResource DataGridColumnHeaderStyle}"
Behaviors:DataGridColumnHelper.Header="{Binding Resources.UserNameListViewHeading, Source={StaticResource Labels}}"/>
Just for experimentation I attached this property (with the binding syntax above) to a DataGrid and checked the DataGridColumnHelper.Header property in the OnHeaderPropertyChanged method and the value was correct (and an exception wasn't thrown)
It is my understanding that the object that the AttachedProperty is attached to must be a DependencyProperty. Looking through Reflector, DataGridColumn (from which DataGridTextColumn derives) derives from DependencyProperty.
Can somebody please shed some light on this? I am trying to Localize our application, and I am having trouble with the DataGrid. I am sure I can do this in code-behind, but I am trying to avoid that.
Chris, the problem is very simple, this won't work because the DataGridTextColumn is "detached" from the Visual Tree. Your DataGridTextColumn object is rooted in the Columns collection of the DataGrid - see the indirection. So even attached properties will not work as you expect. Now there is a way to make all this work using something I'm calling Attached Bindings, see:
http://www.orktane.com/Blog/post/2009/09/29/Introducing-nRouteToolkit-for-Silverlight-(Part-I).aspx
Just remember to attach the binding properties using something that is in the VisualTree (so the Grid holding the column would do just fine.)
Hope this helps.
Try using this, im assuming UserName is a property in your viewmodel
<Controls:DataGridTextColumn Binding="{Binding OwnerName}"
HeaderStyle="{StaticResource DataGridColumnHeaderStyle}"
Behaviors:DataGridColumnHelper.Header="{Binding UserName}"/>
I cant test your scenario so my post is just an idea. Might work, might not.
How do you handle primitive types when using a IoC container?
I.e. given that you have:
class Pinger {
private int timeout;
private string targetMachine;
public Pinger(int timeout, string targetMachine) {
this.timeout = timeout;
this.targetMachine = targetMachine;
}
public void CheckPing() {
...
}
}
How would you obtain the int and string constructor arguments?
Make another interface for this.
Then you will get something like:
public Pinger(IExtraConfiguration extraConfig)
{
timeout = extraconfig.TimeOut;
targetmachine = extraconfig.TargetMachine;
}
I don't know about other IOC containers, but Castle Windsor resolves these extra constructor parameters automatically.
I'm not sure if your difficulty is the value types or the concrete type. Neither is a problem. You don't need to introduce a configuration interface (it's useful if you want to pass the same parameters to multiple objects, but not in the case you've given). Anyway, here's the Windsor fluent code, I'm sure someone will submit an XML version soon.
container.Register(
Component.For(typeof(Pinger))
.ImplementedBy(typeof(Pinger)) // This might not be necessary
.Parameters(Parameter.ForKey("timeout").Eq("5000"),
Parameter.ForKey("targetMachine").Eq("machine")
)
);
It depends. The IoC-Container StructureMap will allow you to declare those dependencies when you configure the instance at the beginning of your execution.
e.g. in a registry
ForRequestedType<Pinger>()
.TheDefault.Is.OfConcreteType<Pinger>()
.WithCtorArg("timeout").EqualTo(5000)
.WithCtorArg("targetMachine").EqualToAppSetting("machine");
In Spring, one can look up property values from a property file using ${propertyName} notation
<bean class="blah.Pinger">
<constructor-arg value="${blah.timeout}"/>
<constructor-arg value="${blah.targetMachine}"/>
</bean>
In Spring.net the same functionality is provided by the PropertyPlaceholderConfigurer, which has the same syntax, and uses name value sections in config files.