Depedency inject request parameter with CDI and JSF2 - jsf-2

When using CDI and JSF2 How can a HTTP request parameter be injected into a bean?

HINT: before reading any further have a look at http://showcase.omnifaces.org/cdi/Param.
Do it yourself is probably obsolete seeing how omnifaces is a de facto standard today. I would probably not have written this if omnifaces had this at the time
CDI does not solve specialized problems like injecting a request parameter. That's supposed to be solved by extensions.
This is already provided by solder. http://docs.jboss.org/seam/3/solder/latest/reference/en-US/html/injectablerefs.html
It will probably be included in Deltaspike 0.4-incubating or similar as well.
That said the code required is rather simple to implement yourself. Example below:
Annotation to use for the injection point (For example private String myParam;)
import javax.enterprise.util.Nonbinding;
import javax.inject.Qualifier;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
#Qualifier
#Retention(RUNTIME)
#Target({METHOD, FIELD, PARAMETER })
public #interface RequestParam {
#Nonbinding
public String value() default "";
}
Now we have the annotation but we can't just ask the container to dependency inject a #RequestParam - we obviously need an implementation.
import javax.enterprise.inject.Produces;
import javax.enterprise.inject.spi.InjectionPoint;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
public class RequestParamProducer implements Serializable {
private static final long serialVersionUID = -4260202951977249652L;
#Inject
FacesContext facesContext;
// Producer for #RequestParam
#Produces
#RequestParam
String getRequestParameter(InjectionPoint ip) {
String name = ip.getAnnotated().getAnnotation(RequestParam.class)
.value();
if ("".equals(name))
name = ip.getMember().getName();
return facesContext.getExternalContext().getRequestParameterMap()
.get(name);
}
}
So how does it work? Well quite simply it first checks if you did specify what parameter you wanted as in #Requestparam("longAndTerribleFieldNameBestToSpecify");
If you didn't it will use the fieldName. So if you annoted a setter called setMyInstance it will look for a parameter called setMyInstance.
The normal use case would be to have a String variable that is named exactly like the parameter you want.
Note that we inject FacesContext, that must also be produced. A FacesContext producer could look like this:
class FacesContextProducer {
#Produces #RequestScoped FacesContext getFacesContext() {
return FacesContext.getCurrentInstance();
}
}
End usage:
#Inject
#RequestParam
private String session_secret;
Note that this will not work for Servlet or similar as it requires access to FacesContext. In those cases one need to wrap the injection with for example a bean that is #RequesScoped. You inject that bean instead.

Related

Context & Dependency Injection : How to inject implementation of an interface?

I am at beginner stage of CDI and trying to inject the implementation of interface using field injection as below:
AutoService.java
package com.interfaces;
public interface AutoService {
void getService();
}
BMWAutoService.java
package com.implementations;
import javax.inject.Named;
import com.interfaces.AutoService;
#Named("bmwAutoService")
public class BMWAutoService implements AutoService {
public BMWAutoService() {
// TODO Auto-generated constructor stub
}
#Override
public void getService() {
System.out.println("You chose BMW auto service");
}
}
AutoServiceCaller.java
package com.interfaces;
public interface AutoServiceCaller {
void callAutoService();
}
AutoServiceCallerImp.java
package com.implementations;
import javax.inject.Inject;
import javax.inject.Named;
import com.interfaces.AutoService;
import com.interfaces.AutoServiceCaller;
public class AutoServiceCallerImp implements AutoServiceCaller {
#Inject
#Named("bmwAutoService")
private AutoService bmwAutoService;
public AutoServiceCallerImp() {
}
#Override
public void callAutoService() {
bmwAutoService.getService();
}
}
TestDisplayMessage.java
package com.tests;
import com.implementations.AutoServiceCallerImp;
import com.interfaces.AutoServiceCaller;
public class TestDisplayMessage {
public TestDisplayMessage() {
// TODO Auto-generated constructor stub
}
public static void main(String[] args) {
AutoServiceCaller caller = new AutoServiceCallerImp();
caller.callAutoService();
}
}
When I run TestDisplayMessage.java , the expected result would be "You chose BMW auto service" but I get NullPointerException as below :
Exception in thread "main" java.lang.NullPointerException
at com.implementations.AutoServiceCallerImp.callAutoService(AutoServiceCallerImp.java:21)
at com.tests.TestDisplayMessage.main(TestDisplayMessage.java:16)
Couldn't figure out exactly what I am missing here. Please help.Thanks in advance.
Ok, it seems you misunderstood the concept of CDI a bit - the idea is that you leave the bean lifecycle to CDI container. That means CDI will create a dispose beans for you. In other words, you are not supposed to create beans by calling new. If you do that, CDI does not know about it and will not inject anything into it.
If you are in SE environment, which I think you are since you use main method to test, you want to use Weld (CDI implementation) SE artifact (I guess you do that).
There, you will need to start the CDI container. Note that if you were developing a classical EE application on a server, you don't do this, because the server will handle it for you. Now, the very basic way to boot Weld SE container is:
Weld weld = new Weld();
try (WeldContainer container = weld.initialize()) {
// inside this try-with-resources block you have CDI container booted
//now, ask it to give you an instance of AutoServiceCallerImpl
AutoServiceCallerImpl as = container.select(AutoService.class).get();
as.callAutoService();
}
Now, second issue with your code. The usage of #Named is intended for EL resolution. E.g. in JFS pages, so you can access the bean directly. What you probably want is to differentiate between several AutoService implementations and choose a given one. For that CDI has qualifiers. Check this documentation section for more information on how to use them.

CDI will not work with implicit #Dependent scope, unsatisfied injection point compile time error

The container is Glassfish 4.1
I am having a very weird issue with CDI right now. If I don't annotate my NumberGenerator services #Dependent, then I keep getting unsatisfied injection point error when I run the app. But if I explicitly annotate my NumberGenerator implementations, then everything will work. In one word, if I want dependency injection with the #Dependent which is the default scope, I must specify it explicitly.
public interface NumberGenerator {
String generateNumber();
}
The first implementation of NumberGenerator
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.enterprise.context.Dependent;
import javax.inject.Inject;
#ThirteenDigits
#Dependent
public class IsbnGenerator implements NumberGenerator {
#Inject
private Logger logger;
#Override
public String generateNumber() {
String isbn = "13-84356-" + Math.abs(new Random().nextInt());
logger.log(Level.INFO, "Generated ISBN : {0}", isbn);
return isbn;
}
}
The second implementation of NumberGenerator
import java.util.Random;
import java.util.logging.Logger;
import javax.enterprise.context.Dependent;
import javax.inject.Inject;
#EightDigits
#Dependent
public class IssnGenerator implements NumberGenerator {
#Inject
private Logger logger;
#Override
public String generateNumber() {
String issn = "8-" + Math.abs(new Random().nextInt());
logger.info("Generated ISSN : " + issn);
return issn;
}
}
This is where the NumberGenerator will be injected
import javax.enterprise.context.Dependent;
import javax.inject.Inject;
import javax.interceptor.Interceptors;
#Dependent
public class BookService {
#Inject
#EightDigits
private NumberGenerator numberGenerator;
public Book createBook(String title, float price, String description) {
Book book = new Book(title, price, description);
book.setNumber(numberGenerator.generateNumber());
return book;
}
}
Finally, the BookService is injected into this JSF managed bean to create a Book instance.
import javax.enterprise.context.Dependent;
import javax.inject.Inject;
import javax.inject.Named;
#Named
#Dependent /* if I leave this out, then this bean will not display
the book instance properties on the JSF page, I just see
a blank screen, but when I add this #Dependent annotation
the JSF page displays the dummy content below.
*/
public class MyBean {
#Inject
private BookService bookService;
public Book getBook() {
return bookService.createBook("Dummy Title", 21.05f, "Dummy Description");
}
}
As you can see, I have to use #Dependent for the default scope every time I want DI. Right now, I am injecting the IssnGenerator with the qualifier #EightDigits into the BookService class, and if I remove the #Dependent from the IssnGenerator, I receive this compile error.
Unsatisfied dependencies for type NumberGenerator with qualifiers #EightDigits at injection point [BackedAnnotatedField] #Inject #EightDigits private BookService.numberGenerator
Thank you for any suggestion.
If you do not specify a META-INF/beans.xml file, which seems to be your case, you got an implicit bean archive (see CDI-1.1 §12.1).
In an implicit bean archive, only beans with a bean defining annotation will be discovered by the CDI engine.
Any scope is a bean defining annotation (see CDI-1.1 §2.5). That's why if you add a scope, like #Dependent, you bean gets discovered by CDI and you don't have the unsatisfied dependency error.
The fact that #Dependent is the default scope is not relevant here because without the any scope your beans is simply not discovered.
If you add a META-INF/beans.xml file with the bean-discovery-mode set to all, then you got an explicit bean archive, this means that all beans in your archive will be discovered and will have the #Dependent scope by default.

Grails & AspectJ: advice for private methods is not working

I need to intercept calls to private methods in Grails services. The following aspect IS working for any annotated public methods, however nothing happens when the annotation is at PRIVATE methods.
import exceptions.DwcpExeption
import org.aspectj.lang.ProceedingJoinPoint
import org.aspectj.lang.annotation.Around
import org.aspectj.lang.annotation.Aspect
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Component
#Aspect
#Component
public class LoggerInterceptor {
private static Logger log = LoggerFactory.getLogger(LoggerInterceptor.class);
#Around("#annotation(newAnnotation)")
public Object aroundEvents(ProceedingJoinPoint proceedingJoinPoint, NewAnnotation newAnnotation) {
log.info newAnnotation.value()
String logMessage = String.format("%s.%s(%s)",
proceedingJoinPoint.getTarget().getClass().getName(),
proceedingJoinPoint.getSignature().getName(),
Arrays.toString(proceedingJoinPoint.getArgs()));
log.info "*Entering $logMessage"
def result
try {
result = proceedingJoinPoint.proceed()
catch (ex) {
log.error '', ex
}
log.info "*Exiting $logMessage. Result: $result"
return result
}
}
Maybe the problem is in config? I've tried in applicationContext.xml
<aop:aspectj-autoproxy proxy-target-class="true"/>
and in resources.groovy
aop.config("proxy-target-class": true)
Nevertheless, only public methods are intercepted.
Spring AOP is a proxy-based "AOP lite" approach in comparison to AspectJ. It only works for Spring components and only for public, non-static methods. This is also explained in the Spring AOP documentation as follows:
Due to the proxy-based nature of Spring’s AOP framework, protected methods are by definition not intercepted, neither for JDK proxies (where this isn’t applicable) nor for CGLIB proxies (where this is technically possible but not recommendable for AOP purposes). As a consequence, any given pointcut will be matched against public methods only!
If your interception needs include protected/private methods or even constructors, consider the use of Spring-driven native AspectJ weaving instead of Spring’s proxy-based AOP framework. This constitutes a different mode of AOP usage with different characteristics, so be sure to make yourself familiar with weaving first before making a decision.
Bottom line: Please switch to AspectJ which can be easily integrated into Spring applications via LTW (load-time weaving) as described in Section 9.8, “Using AspectJ with Spring applications”.
If you don't specify the scope it defaults to public. Add a pointcut for private methods:
#Around("#annotation(newAnnotation) && execution(private * *(..))")

Java EE Qualifier annotation not picked up

I am following a simple Java EE 6 annotations video on youtube. I have created a repo on github. There is a servlet to start with that creates a greeting string using annotation.
#WebServlet(urlPatterns = {"/HelloServlet"})
public class HelloServlet extends HttpServlet {
#Inject #Formal
String greetingMessage;
...
}
The formal qualifier is defined as follows:
#Qualifier
#Retention(RUNTIME)
#Target({TYPE, METHOD, FIELD, PARAMETER})
public #interface Formal {}
And the producer is:
public class ProduceFormalGreeting {
#Produces
#Formal
public String GetFormalGreeting(){
return "Good morning !";
}
}
At compile time I get the following message from NetBeans:
Unsatisfied Dependency: No bean matches the inject point
At runtime, the string is null in the servlet.
You have to add beans.xml file to WEB-INF. Now You have bean.xml file.
In ProduceFormalGreeting u have to use javax.enterprise.inject.Produces (not javax.ws.rs.Produces)

How can I check if an object stored with #WindowScoped is stored correctly?

Two days ago I wrote this question:
How can I retrieve an object on #WindowScoped?
and BalusC answered with some suggestions, now I have some problem to understand if my problem is that the object in WindowScoped is stored properly or my code to retrieve it is wrong!
Well, as I said, I have an object that I stored in #WindowScoped annotation but I can retrive this object only the first time! Why?
I just have a doubt: the CODI extension of MyFaces could be configured in some manner? Or I can use it simple adding the jar files to my project?
However, these are parts of my code because I don't know where is the problem:
LogicBean.java (the object that I should retrive):
#ManagedBean (name="logicBean" )
#WindowScoped
public class LogicBean implements Serializable
{
String pageIncluded;
// getter and setter methods
public String action(String value)
{
setPageIncluded(value);
return "include";
}
}
include.xhtml:
<ui:include src="#{logicBean.pageIncluded}"/>
ProgettiController.java
#ManagedBean(name = "progettiController")
#SessionScoped
public class ProgettiController implements Serializable {
private FacesContext context = FacesContext.getCurrentInstance();
private LogicBean logicBean = context.getApplication().evaluateExpressionGet(context, "#{logicBean}", LogicBean.class);
//getter and setter methods
public void testMethod()
{
logicBean.action("WEB-INF/jsf/page1.xhtml");
}
}
I tried also using #ManagedProperty("#{logicBean}") and setting the scope as WindowScoped but nothing change...
EDIT: after some new trials I found a strange problem, on my include.xhtml I added #{progettiController.logicBean.getPageIncluded()} and #{logicBean.getPageIncluded()} for check these two fields o?
Well, when I load the application for the first time the variables are correctly set and I see what I want, the second time the first variable is setted with the new value but the second is empty and I don't see anything, but now is coming the strange thing... if I should try again the app I should open index.xhtml where I had some forms like this:
<h:form>
<h:commandLink action="#{logicBean.action('/WEB-INF/jsf/progetti/List.xhtml')}" value="Show All Progetti Items"/>
</h:form>
and which is the result?
The first variable remains set with the old value (wrong) but the second is setted correctly so I can review the page like I would!
If someone can help me I will thank him/her forever!
CODI is an extension to CDI, so you should manage your beans by CDI #Named annotation instead of the JSF #ManagedBean annotation. Then you can inject the other bean by CDI #Inject annotation. The following example should work:
import javax.inject.Named;
import org.apache.myfaces.extensions.cdi.core.api.scope.conversation.WindowScoped;
#Named
#WindowScoped
public class LogicBean implements Serializable {
// ...
}
and
import javax.enterprise.context.SessionScoped;
import javax.inject.Inject;
import javax.inject.Named;
#Named
#SessionScoped
public class ProgettiController implements Serializable {
#Inject
private LogicBean logicBean;
// ...
}

Resources