Archive for 'jsf 2.0'

How to wrap a ValueExpression in EL 1.0 and 2.2

Posted on Dezember 15, 2010, under java, jsf, jsf 2.0.

The problem

A new Class was introduced in the EL API 2.2: javax.el.ValueReference. In addition javax.el.ValueExpression now provides the following method:

public ValueReference getValueReference(ELContext context)
{
    return null;
}

This makes wrapping of a javax.el.ValueExpression (which is actually a very common thing in projects like MyFaces or OpenWebBeans) not really an easy task if you have to support both EL versions in one project, because there are a lot of unanswered questions:

  • Which EL version should I use to compile the code?
  • Should the ValueExpression wrapper implement getValueReference()?
  • Do I need one wrapper or two?
  • How can I even determine the EL version at runtime?

To find a solution for this problem we have to take a closer look at the Java classloading mechanism:

What does the ClassLoader do?

After a lot of experimenting with different classpath configurations, I found out some pretty interesting things. For the experiments I used the following custom ValueExpression implementation:

import javax.el.ELContext;
import javax.el.ValueExpression;
import javax.el.ValueReference;

/**
 * @author Jakob Korherr
 */
public class MyValueExpression extends ValueExpression
{

    @Override
    public ValueReference getValueReference(ELContext context)
    {
        return new ValueReference("base", "property");
    }

    @Override
    public String toString()
    {
        return "toString() of MyValueExpression";
    }

    @Override
    public Object getValue(ELContext context)
    {
        return null;
    }

    @Override
    public void setValue(ELContext context, Object value)
    {
    }

    // ... other methods cut for clarity ...

}

Of course, you must compile this class using EL 2.2, because otherwise javax.el.ValueReference will not be present and you will get a compile error.

Now if you use this custom ValueExpression in any scenario in an EL 2.2 environment, everything will work just fine. However, the interesting part is using this class in an EL 1.0 environment, because here javax.el.ValueReference is NOT available.

At first I thought I will get a NoClassDefFoundError as soon as I use a MyValueExpression instance with EL 1.0. Thus I created the following test:

public static void main(String... args)
{
    ValueExpression m = new MyValueExpression();
    System.out.println(m);
}

However, it went well and I got “toString() of MyValueExpression” although my class references javax.el.ValueReference, which was not on the classpath.

Then I added private ValueReference valueReference; to MyValueExpression and ran the test again. To my surprise, it worked well again!

After a lot of tests, I found out just 2 scenarios which did not work with EL 1.0:

1) Calling a method on MyValueExpression which creates a new ValueReference or tries to call methods of it. OK, this can obviously not work with EL 1.0. You will get a java.lang.NoClassDefFoundError: javax/el/ValueReference

2) Calling m.getValueReference(). Here you will get the following error, because obviously this method is not available in EL 1.0: java.lang.NoSuchMethodError: javax.el.ValueExpression.getValueReference(Ljavax/el/ELContext;)Ljavax/el/ValueReference;

Solution

Because of the above findings you can just use EL 2.2 as compile dependency in your project and everything will work just fine also with EL 1.0, as long as you:

1) do not call ValueExpression.getValueReference()
2) do not call any method on ValueReference
3) do not create an instance of ValueReference

…outside of the getValueReference() method of your javax.el.ValueExpression implementation. Inside this method, you can do all of the above, because you will only get into this method if you’re using EL 2.2 at runtime!

Thus you can use this wrapper without any problems on EL 1.0:

import javax.el.ELContext;
import javax.el.ValueExpression;
import javax.el.ValueReference;

/**
 * @author Jakob Korherr
 */
public class ValueExpressionWrapper extends ValueExpression
{

    private ValueExpression wrapped;

    public ValueExpressionWrapper(ValueExpression wrapped)
    {
        this.wrapped = wrapped;
    }

    @Override
    public ValueReference getValueReference(ELContext context)
    {
        // You will only get here if EL 2.2 is available at runtime.
        // Thus you can use ValueReference without any problems!
        return wrapped.getValueReference(context);
    }

    @Override
    public Object getValue(ELContext context)
    {
        return wrapped.getValue(context);
    }

    @Override
    public void setValue(ELContext context, Object value)
    {
        wrapped.setValue(context, value);
    }

    // ... other methods cut for clarity ...

}

Using this wrapper in a pure EL 2.2 environment will not cause any problems when calling getValueReference() on the wrapper, because javax.el.ValueReference is provided by EL 2.2 at runtime.

Using this wrapper in a pure EL 1.0 environment will have the effect that getValueReference() is not visible at runtime and thus it will never get called and not cause any problems.

Custom ELResolver ordering in MyFaces

Posted on August 16, 2010, under jsf, jsf 2.0.

As with MyFaces core 2.0.2 (or 1.2.10) it is possible to change the predefined order or ELResolvers.

To change this predefined order you can provide a java.util.Comparator<ELResolver> implementation which will be applied to the List of ELResolvers mentioned above.

To install the comparator you simply have to set a web.xml config parameter:

<context-param>
    <param-name>
        org.apache.myfaces.EL_RESOLVER_COMPARATOR
    </param-name>
    <param-value>
        com.acme.el.MyELResolverComparator
    </param-value>
</context-param>

Apache OpenWebBeans optimization

To optimize the marriage of MyFaces and OpenWebBeans, you simply have to set the following config parameter:

<context-param>
    <param-name>
        org.apache.myfaces.EL_RESOLVER_COMPARATOR
    </param-name>
    <param-value>
        org.apache.myfaces.el.unified.OpenWebBeansELResolverComparator
    </param-value>
</context-param>

This moves the WebBeansELResolver almost to the last place in the ELResolver chain, thus improving the overall performance of ELExpression evaluations.

Links

You can find more info in the MyFaces cwiki at https://cwiki.apache.org/confluence/display/MYFACES/ELResolver+ordering

Apache MyFaces Core 2.0.0 released

Posted on April 23, 2010, under jsf 2.0.

After the final release of the JSF 2.0 specification (JSR-314) in July 2009, the first alpha release in November 2009 and some beta releases in February and March 2010, Apache MyFaces Core 2.0.0 was released today. The release is 100% complaint with the JSR-314 specification and has passed Sun’s JSR-314 TCK.

You can download MyFaces Core 2.0.0 here or you can find it in the central Maven repository under Group ID “org.apache.myfaces.core”.

So now there is no reason anymore not to try it out yourself. You can check out all new features of JSF 2.0 with MyFaces Core 2.0.0 like e.g. composite components, the integrated Facelets view declaration language or the very easy AJAX support via f:ajax, just to mention a few here.

And please do not hesitate to file any issues you might run into in our bug tracker or to ask any questions you might have on our mailing list(s). We are very happy with every feedback we get!

You can also check out the related article on heise Developer (in German): JSF-Implementierung Apache MyFaces 2.0 erschienen

JSF 2.0: View parameters

Posted on April 10, 2010, under jsf 2.0.

One very cool new feature of JSF 2.0 are view parameters. If you are now wondering what I mean with a view parameter (or request parameter) – here’s the answer: Do you know those things at the end of an URL that often look like ?id=3&page=2, then you know what I mean. If not, take a look at this. The great advantage of these view parameters is that JSF’s URLs are now bookmarkable, because all values that are needed to display a certain page can be provided via the URL.

JSF 2.0 introduces a new UIInput component especially for view parameters called UIViewParameter. This component extends UIInput and thus has the same functionality as e.g. <h:inputText />. This means it can have converters and validators, its value is bound to a model (managed bean) and it goes through the JSF-lifecycle just as every other EditableValueHolder.

To define an UIViewParameter in your view you just have to add a <f:viewParam /> element inside your view metadata facet. Sounds complicated, but actually it is not, as you can see in the following Facelet page:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
 xmlns:h="http://java.sun.com/jsf/html"
 xmlns:f="http://java.sun.com/jsf/core"
 xmlns:ui="http://java.sun.com/jsf/facelets">

<f:metadata>
    <f:viewParam name="input" value="#{myBean.input}" />
</f:metadata>

<h:head>
    <title>UIViewParameter example by jakobk</title>
</h:head>
<h:body>
    The view parameter's value is:
    <h:outputText value="#{myBean.input}" />
</h:body>
</html>

If you now access this page with http://localhost:8080/pathToWebapp/view.xhtml?input=abc, #{myBean.input} will be set to “abc”.

Very important for this feature to work is to use the JSF 2.0 built-in Facelets-2 view declaration language and not JSP or Facelets-1.x. Although the <f:viewParam /> tag is defined for JSP in the specification javadoc, the <f:metadata /> tag is missing and also I could not make it work. However I will dig into this and write another blog post about the JSP support soon. If you are currently using Facelets-1.x with JSF 2.0, just get rid of <view-handler>com.sun.facelets.FaceletViewHandler</view-handler> in your faces-config to upgrade to the JSF 2.0 built-in Facelets-2.

If you want your view parameter(s) to be required to render the view (which will be most likely, I guess), you just have to add required=”true” to <f:viewParam /> and your view will not accept any inputs or actions unless the view parameter is provided. In addition and as mentioned before, you can attach any kind of converters or validators (with the help of any <f:converter /> and/or <f:validator /> tags) to your <f:viewParam /> to verify the value. The following snippet shows a view parameter which only accepts non null Strings that are at least 3 characters long:

<f:viewParam required="true" name="input" value="#{myBean.input}">
    <f:validateLength minimum="3" />
</f:viewParam>

The UIViewParameter component also stores its value in the state, so that the value will also be available on the next postback request (most likely a clicked button or link). So you only need to provide your view parameter(s) once and not on every request.

On my opinion, view parameters are a really cool new feature of JSF. Of course, you were able to do the same thing with JSF 1.x and the request parameter map from ExternalContext, but this just was not very elegant and in case of conversion and validation also far more complicated.

More detailed information about view parameters can be found on the specification javadoc of <f:viewParam />.