Apache MyFaces CODI PageBean: "Argument bean must not be null" - jsf-2

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 ;)

Related

Spring Boot 1.3 WebSocket JSON converter Produces Invalid JSON

After upgrading to Spring Boot 1.3 (via Grails 3.1), the JSON output is rendered incorrectly. I believe it is because of the new auto-configured WebSocket JSON converter.
For example, with previous versions of Spring Boot (via Grails 3.0), using the following code:
#MessageMapping("/chat")
#SendTo("/sub/chat")
protected String chatMessage() {
def builder = new groovy.json.JsonBuilder()
builder {
type("message")
text("foobar")
}
builder.toString()
}
This would produce:
{"type": "message", "text": "foobar"}
With Spring Boot 1.3 (via Grails 3.1), that web socket produces the following:
"{\"type\":\"message\",\"text\":\"foobar\"}"
This is not valid JSON. How can I get rid of this new behavior and have it render the JSON as it was before? Please let me know if you have any suggestions.
I tried overriding the new configureMessageConverters method, but it did not have any effect.
looks like you are right. referenced commit shows questionable autoconfiguration imho.
especially b/c in the past, the converter ordering was intentionally changed to that StringMessageConverter takes precedence before MappingJackson2MessageConverter: https://github.com/spring-projects/spring-framework/commit/670c216d3838807fef46cd28cc82165f9abaeb45
for now, you can either disable that autoconfiguration:
#EnableAutoConfiguration(exclude = [WebSocketMessagingAutoConfiguration])
class Application extends GrailsAutoConfiguration { ... }
or, you add yet another StringMessageConverter to the top of the configured converters (maybe because you do want the boot autoconfiguration behavior because it is using the jackson ObjectMapper bean instead of creating a new one):
#Configuration
#EnableWebSocketMessageBroker
class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
boolean configureMessageConverters(List<MessageConverter> messageConverters) {
messageConverters.add 0, new StringMessageConverter()
return true
}
...
}
hope that helps.
I don't know how to do it in Grails but in Java you have to now pass the object instead of an object in the String class. I believe the old behavior was actually incorrect as it was returning a string as an object so there was no way to return a String that had JSON inside it as a String. So create an object with the structure you want and return it and you should be fine. I went through the same issue when upgrading from 1.2.X to 1.3.X. I am not exactly sure what change caused this but I think in the long run it is the correct thing to do.

CDI/WELD can a custom qualifier work in combination with the #Named annotation?

While having a custom qualifier for CDI support as followed:
#Qualifier
#Retention(RUNTIME)
#Target({METHOD, FIELD, PARAMETER, TYPE})
public #interface QualifiedFooBean {
}
#QualifiedFooBean
public class FooBean implements ImplFooBean {
}
public interface ImplFooBean {
}
I would like to bind FooBean #{fooBean} directly without requiring a wrapper or processor (seen from this example). The annotation "Named" (in class FooBean) seems not to work for my class layout.
My solution (without wrapper) which I'm wondering why it's not working and invoking: Target Unreachable, identifier 'fooBean' resolved to null
#Named
#QualifiedFooBean
public class FooBean implements ImplFooBean {
}
Has anyone any idea?
A wrapper is not needed. My solution is perfectly valid. It's also allowed to add Named in combination of a custom qualifier (in my case QualifiedFooBean). I had to just create an empty beans.xml file in WEB-INF folder in order to get CDI to work. Anyhow The question itself explains how custom qualifiers can work. You can also prefill beans.xml with following content:
<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">
</beans>
It will serve as a skeleton for future use, if you need to configure more fancy stuff with CDI.
Adding #Named to your bean should work : it works for me.
In Fact #Named is a qualifier, when JSF resolve the Bean for displaying it does a lokup based on #Named qualifier. In CDI a bean is found if the lookup side (i.e. Injection point) ask for a subset of its Qualifier.
For instance a bean qualified like that :
#QualifiedFooBean
#SecondQualifier
public class FooBean {}
Will be found (if there is no ambiguous resolution) by
#Inject
#SecondQualifier
FooBean bean;
or even :
#Inject
FooBean bean;
But not by
#Inject
#SecondQualifier
#ThirdQualifier
FooBean bean;
So you can add the #Named qualifier and let CDI resolution engine do its job.

ICE Faces and error in creation of a bean in WindowScoped

After some questions about WindowScoped and after an answer of BalusC I understand that I would use MyFaces CODI I should before rewrite all my previous code because I can't use Mojarra, so I would use ICEFaces because it have also the "window scope" and some other things that help me later and it is based on mojarra!
Ok, now I have a big problem, and I wrote also in ICE forum at this link:
http://www.icefaces.org/JForum/posts/list/0/20426.page#72064
, and it is that when I launch the application I have many of this link:
<h:form>
<h:commandLink action="#{logicBean.action('/WEB-INF/jsfpage1.xhtml')}" value="Open page1.xhtml"/>
</h:form>
the LogicBean.java (simplyfied because I would understand if the problem was locate into the others methods) is this:
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package it.cyborg.logic;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.CustomScoped;
/**
*
* #author FilTen
*/
#ManagedBean(name="logicBean")
#CustomScoped(value = "#{window}")
public class LogicBean implements Serializable
{
String pageIncluded;
String pageIncludedPrev;
static String crypt="MD5";
/** Creates a new instance of LogicBean */
public LogicBean() {
}
public String getPageIncluded()
{
return this.pageIncluded;
}
public void setPageIncluded(String pageIncluded)
{
this.pageIncluded=pageIncluded;
}
public String getPageIncludedPrev()
{
return this.pageIncludedPrev;
}
public void setPageIncludedPrev(String pageIncludedPrev)
{
this.pageIncludedPrev=pageIncludedPrev;
}
public String action(String value)
{
setPageIncludedPrev(pageIncluded);
setPageIncluded(value);
return "include";
}
public String getCrypt()
{
return crypt;
}
}
when I click on one of the links a javascript open a frame that contains this error:
class com.sun.faces.mgbean.ManagedBeanCreationException
The previous version had two differnce and it worked well, the first was that it was not the implementation of ice faces core, the second was that the scope was SessionScoped!
whic could the problem be?
Thank you for all your help!
[EDIT:]
I have a news:
I tried to add only the Icefaces core jar into the original project and the error change:
class java.lang.NullPointerException
what could it be?
Someone can tell me how set more verbosity on this message?
Hoi Filippo!
The information you received is NOT correct. MyFaces CODI is compatible with JSF 1.2 and 2.x --> you can use it with Mojarra as well as MyFaces Core.
BalusC:
Which problems have you seen? I'm using MyFaces CODI with Mojarra since the first version without problems.

CDI Injection into a FacesConverter

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.

Injecting Resources Into UIComponent (aka does CDI work here?)

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 />

Resources