Quantcast
Channel: OmniFaces & JSF Fans
Viewing all articles
Browse latest Browse all 74

CDI-JSF: Injecting HTTP parameters via a producer method

$
0
0
Remeber from the Inject a Java logger via a CDI producer method post that the InjectionPoint can be used to access metadata of the class where the artifact is injected. Based on this statement, we can write a producer method capable to inject HTTP parameters.

Typically, as a JSF developer you write a form like below:

<h:form>
 Name: <h:inputText value="#{playerBean.name}"/>
 Surname: <h:inputText value="#{playerBean.surname}"/>
 <h:commandButton value="Register" action="#{playerBean.registerAction()}"/>
</h:form>

The two fields, nameand surname are declared in a bean privateand with some getters and setters:

@Named
@RequestScoped
public class PlayerBean {

 private static final Logger LOG = Logger.getLogger(PlayerBean.class.getName());

 private String name;
 private String surname;

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }

 public String getSurname() {
  return surname;
 }

 public void setSurname(String surname) {
  this.surname = surname;
 }

 public void registerAction() {
  LOG.info("Register: " + name + "" + surname);
 }
}

Well, nothing fancy here, and even a JSF novice can understand what this code do just by looking over it in a second. But, now let's replace the <h:inputText/>with simple HTML <input/>as below:

<h:form>
 Name: <input type="text" name="name" id="name"/>
 Surname: <input type="text" name="surname" id="surname"/>
 <h:commandButton value="Register" action="#{playerBean.registerAction()}"/>
</h:form>

This time our getters and setters become useless, but we can still obtain these two HTTP parameters like this:

FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
ServletRequest request = (ServletRequest) externalContext.getRequest();

request.getParameter("name");
request.getParameter("surname");

Now, let's generalize this  case in CDI style. Instead of writing request.getParameter("name"); we want to inject the HTTP parameter. For this, we start by defining a qualifier and instruct the container to ignore the value:

@Qualifier
@Retention(RUNTIME)
@Target({METHOD, FIELD, PARAMETER, TYPE})
public @interface HttpParam {
 @Nonbinding public String value();
}

Furthermore, we write the producer method as below - instead of explicitly nominated the HTTP parameter name, we use the InjectionPoint metadata features:

public class HttpParams {

 @Produces
 @HttpParam("")
 String getParamValue(InjectionPoint ip) {

  // obtain the current request
  FacesContext facesContext = FacesContext.getCurrentInstance();
  ExternalContext externalContext = facesContext.getExternalContext();
  ServletRequest request = (ServletRequest) externalContext.getRequest();

  // obtain the desired parameter
  Annotated annotated = ip.getAnnotated();
  HttpParam httpParam = annotated.getAnnotation(HttpParam.class);

  return request.getParameter(httpParam.value());
 }
}

Finally, we adjust the PlayerBeanto inject the desired HTTP parameters:

@Named
@RequestScoped
public class PlayerBean {

 private static final Logger LOG = Logger.getLogger(PlayerBean.class.getName());

 @HttpParam("name") @Inject String name;
 @HttpParam("surname") @Inject String surname;

 public void registerAction() {
  LOG.log(Level.INFO, "Register: {0} {1}", new Object[]{name, surname});
 }
}

Done! Following this example you can inject any other HTTP parameter. The complete example is available here.

Now, you can use this with <f:param/> or in place of <f:event type="preRenderView/> or <f:viewAction/>. In addition, you may be interested in converting and validating the HTTP parameters. Check out a great implementation from OmniFaces which is materialized in the CDI annotation @Param that allows us to inject, convert and validate a HTTP request parameter in a CDI managed bean. 

Viewing all articles
Browse latest Browse all 74

Trending Articles