Introduction
For those who creates many small web applications, like proof of concepts, know how much time you can loose by setting up the project structure. Creating the pom file, web application file, faces configuration etc. And although there exists maven archetypes, they doesn't allows suite your needs. For a lot of tests, you need slightly different options and required dependencies.
And this is where JBoss Forge can help you. It is a command line driven tool that helps you in those repetitive tasks. And, a very important aspect for me, is the fact that it doesn't place any marker in your files or project. In fact, it can be used on a project which isn't created with JBoss Forge by interpreting the files it find.
My goal
I came to this tool in my search for something that could help me in creating a project setup according to our company standards for JEE6 projects. By default, JBoss Forge has the capability of creating a project that uses the JEE6 technology stack. But it doesn't go far enough, or we have requirements that goes much further. We want to be able to setup multiple projects for quality control (PMD, Findbugs, etc), model and services project, view project, functional testing project and so on.
The basic building blocks, but sometimes quit sophisticated, are already available. And creating plugins is very easy. So, everyone has to start with some easy things and thus I started by creating a plugin that is able to add the PrimeFaces component library.
Not from scratch
You can learn a lot by looking at some example code. And in my case, there was already someone that started with such a plugin (see https://github.com/kukel/forge-plugin-primefaces.git, by Ronald van Kuijk) Trying his code, there where some compilation problems, due to the fact that JBoss Forge is still in beta and his code was coded against a previous version, and things like scaffolding that I never use. With scaffolding, you can create default screens that are able to view, insert and update from a database table. They can be very handy in prototyping but in real world applications, they are never needed.
So I took his code, removed the scaffolding, made it compatible with the latest API (beta 3), added support for the latest PrimeFaces 3 release (with the new namespace declaration) and detection of CDI capabilities in the project.
Status
By just typing 'primefaces' at the JBoss Forge command prompt, you get information about the status of the project. When PrimeFaces is installed, it specifies which version (2 or 3) and otherwise you get information about how it can be added to the project.
Setup
Adding some kind of functionality is mostly done in JBoss Forge by specifying the setup command. With the PrimeFaces plugin you can achieve it by issuing the command 'primefaces setup'. This will convert your project to a war artifact, installs the other required dependencies like servlet (the web.xml) and JSF (the faces-config.xml), and adds the maven dependencies after you have selected the version of PrimeFaces you want.
Before you execute this command, you should always verify if you are in the correct project. The standard JSF setup adds also some files related to the error handling and they can overwrite some files which already exists in your project. But with a good version control system, you don't have to worry about this.
Example
The last command I describe here, is to add an example to the project, by issuing the command 'primefaces install-example-facelet'. It replaces the current index.xhtml file, so your are warned again, with an XHTML JSF file that uses a template and shows a value from a property from a managed bean. When the plugin detects CDI artifacts in the project, the managed bean is defined with the javax.inject and javax.enterprise annotations. Otherwise plain JSF2 annotations are used.
To discover
There are other command which are supported by the plugin. They are created by Ronald and kept in the code base. But they aren't very well tested so you can use them if you want to try them out.
And in fact, the plugin is also in some kind of beta phase. It should work but there are probably situations where it will fail. In that case you can contact me and I'll have a look at your problem and try to solve it or you can follow the git philosophy and fork it and implement the solution yourselve.
May the forge be with you ;-)
Oh, before I forget it, here you can find the code https://github.com/rdebusscher/forge-plugin-primefaces.
Thursday, 1 December 2011
Wednesday, 9 November 2011
Custom reference resolver tutorial : creating a grammar
Introduction
In my
previous blog entry, I presented an example on the new reference resolver
add-on of ExtVal. It was able to read from a property from a MBean and use that
value for validation.
As it was
designed as a Reference Resolver, you had to specify a parameter at the cross
field validation annotation of ExtVal where you needed the resolver. This is
not friendly if you have designed some kind of resolver that you would use on a
lot of locations. Therefore the add-on
has foreseen the option to create a new Reference Grammar. In this text I'll
explain you how you can convert a reference resolver to a reference grammar.
Coding it
Basically,
there are 2 small differences between a Reference Resolver and a Reference Grammar
and you can use almost the same code in both situations. You only need to
structure it a bit different. Besides
the registration of your grammar with the ExtVal add-on, see further, you
should extend from the AbstractReferenceGrammar class. This class has a type
parameter that needs to be specified. In
our case, it is just a simple object that holds the bean and property name. If
you remember from my previous text, we invented a new grammar 'mbean@property'
and the object just holds the 2 parts of the grammar (before and after the
@-sign).
Your
grammar has to implement 4 methods, so the empty grammar looks like this
@InvocationOrder(100)public class MBeanGrammar extends AbstractReferenceGrammar{@Overridepublic void initGrammar(){}@Overrideprotected boolean targetNotCompatibleWithGrammar(String targetValue){}@Overrideprotected MBeanGrammarData determineReference(String targetValue, MetaDataEntry metadataEntry){}@Overridepublic ReferencedValue resolveReference(MBeanGrammarData targetValue, MetaDataEntry metadataEntry){}}
where the
(MBeanGrammarData object holds the bean and property name the user specified.
The
initGrammar method is called when you register the grammar with the
add-on. You can use this interception
point to do any initialization required to have a proper function of the
grammar. In our case we grab a reference
to the MBean server we will be using for the resolving of the value. Important thing to remember is that this
method is just executed once.
When the
ExtVal add-on encounters an annotation related to the cross field validation
feature, it will ask to all the grammars if it can handle the specified
reference. Our implementation should
return false for the targetNotCompatibleWithGrammar method when it contains the
@-sign (our grammar can handle the reference) and true when we don't know it
(like some EL-reference). The first
grammar that says that it can handle, will be used by the add-on. How is the order determined? Grammars can be
annotated with @InvocationOrder and the value you specify determines the
order. The default grammars (JavaBean
and EL) have values of 950 and 1000. So
when we specify a value of 100, our new grammar is the first to be contacted to
resolve the reference.
If we have
a reference that we should handle, the add-on calls the determineReference
method next. There we have the opportunity to parse the reference according to
the grammar. In our case it is just
splitting the reference around the @-sign and put it into the MBeanGrammarData
instance.
As a last
step, the resolveReference method is called where we get the MBeanGrammarData
instance we prepared in the previous step and we need to resolve the
reference. In our case we contact the
MBean server, ask for the correct bean and extract the value of the
property. That value is wrapped nicely
into the ReferencedValue and returned.
So the main
difference is that the reference resolver contained all the logic in the
resolveReference method and in the grammar version, we have the functionality
split into 4 methods. You can find the code here.
Configuration
This is an
additional step we need to do to integrate our grammar in the ExtVal
add-on. With the following 2 lines,
placed in a startupListener, the Reference Grammar is registered and ready to
use.
ExtValContext extValContext = ExtValContext.getContext();extValContext.getModuleConfiguration(AdvancedCrossValidationAddonConfiguration.class).addReferenceGrammar(new MBeanGrammar());
Testing it
This
version behaves exactly the same as our previous example, so I refer to the
other text on how you can test it.
Conclusion
As easy it
was to create a Reference Resolver, as easy it is to create a reference
Grammar. The grammar has the advantage
that you don’t have to specify a parameter at the cross field validation
annotation. But on the other side, if you only using it on a few locations, the
add-on will ask your code for every reference, if you understand it. So based on the concrete situation you have
to decide what you need, a resolver or a reference.
Thursday, 20 October 2011
Custom reference resolver tutorial
Introduction
In the previous blog text, I described the cross field validation feature of ExtVal. In the meantime, the reference resolver add-on is released and this text shows how you can write your custom reference resolver.
And since the usage of the add-on API is easy, we are aiming a little bit higher with our example as a simple hello world. I'll explain you how you can write a resolver that checks a value stored in an MBean object.
Coding it
The reference resolver api is described here in the project documentation. There is just one method that you need to implement, resolveReference. The first parameter contains the string defined in the value attribute of the annotation (or method is repeatedly called for each string defined in the case of multiple values)
Our implementation of the method needs to do 3 things
Before we can use this new resolver, we have to define a validationParameter so that we are able to use it in the cross field annotations of ExtVal. It is described in the add-on documentation on the referenceResolver page.
In our case, it results in:
Testing it
Now we are ready to run the example. If we press the 'Submit' button, a comparison will be made between the entered value and the value which is by default set in the MBean, which is 'ExtVal'. If they don't match, you see the message that the input is different.
This default value is set by the class org.os890.extval.addon.demo.startup.MBeanResolverStartupListener which is defined as JSF PhaseListener in the faces config file.
The following steps makes this example interesting. You can start up the default JMX console of your environment (look for the JConsole program) or any other JMX console that is able to connect to your (application) server. You will find between all the other MBeans, the one created by the demo application in the org.os890.extval.reference.addon node. It is called demo. The property TargetValue can be changed to another value, let's say 'Test'. If you now go back to your browser you will see that the comparison now only succeed with the new value 'Test' that you have entered in the JMX bean.
Conclusion
This example shows how easy it is to create a new reference resolver and integrate it in ExtVal. With the add-on you can create any reference you like that needs to be used by the cross field validation feature of ExtVal.
In the previous blog text, I described the cross field validation feature of ExtVal. In the meantime, the reference resolver add-on is released and this text shows how you can write your custom reference resolver.
And since the usage of the add-on API is easy, we are aiming a little bit higher with our example as a simple hello world. I'll explain you how you can write a resolver that checks a value stored in an MBean object.
Coding it
The reference resolver api is described here in the project documentation. There is just one method that you need to implement, resolveReference. The first parameter contains the string defined in the value attribute of the annotation (or method is repeatedly called for each string defined in the case of multiple values)
ReferencedValue resolveReference(final String targetValue, final MetaDataEntry metadataEntry);So, first we have to 'invent' our indication how we will describe the property of the MBean where the value is stored. A possibility is using mbean@property where mbean is just the name in a certain node of our MBean server.
Our implementation of the method needs to do 3 things
- Get a reference to the MBean server of our environment
- Split the parameter in 2 parts (around the @ sign)
- Lookup the MBean and retrieve the value of the specified property.
Before we can use this new resolver, we have to define a validationParameter so that we are able to use it in the cross field annotations of ExtVal. It is described in the add-on documentation on the referenceResolver page.
In our case, it results in:
public class MBeanReferenceResolver implements ReferenceResolverNow we can use this resolver in all cross field annotations like @Equals. In the example you can find a usage in the class org.os890.extval.addon.demo.view.BackingBean.
{
public interface MBeanReferenceResolverParameter extends ValidationParameter
{
@ParameterKey
public Class KEY = ReferenceResolver.class;
@ParameterValue
public Class referenceResolverClass = MBeanReferenceResolver.class;
}
@Override
public ReferencedValue resolveReference(String targetValue, MetaDataEntry metadataEntry)
{
// Implementation details omitted
}
}
@Equals(value = "demo@TargetValue", parameters = MBeanReferenceResolver.MBeanReferenceResolverParameter.class)This property is linked to an inputField on a screen in the example.
private String source;
Testing it
Now we are ready to run the example. If we press the 'Submit' button, a comparison will be made between the entered value and the value which is by default set in the MBean, which is 'ExtVal'. If they don't match, you see the message that the input is different.
This default value is set by the class org.os890.extval.addon.demo.startup.MBeanResolverStartupListener which is defined as JSF PhaseListener in the faces config file.
The following steps makes this example interesting. You can start up the default JMX console of your environment (look for the JConsole program) or any other JMX console that is able to connect to your (application) server. You will find between all the other MBeans, the one created by the demo application in the org.os890.extval.reference.addon node. It is called demo. The property TargetValue can be changed to another value, let's say 'Test'. If you now go back to your browser you will see that the comparison now only succeed with the new value 'Test' that you have entered in the JMX bean.
Conclusion
This example shows how easy it is to create a new reference resolver and integrate it in ExtVal. With the add-on you can create any reference you like that needs to be used by the cross field validation feature of ExtVal.
Sunday, 9 October 2011
Announce: Reference Resolver add-on for ExtVal
The Reference Resolver add-on for MyFaces Extensions Validator project adds the possibility to define your own reference resolver for the cross field validation option. See my previous text for some intro about cross field validation.
By default, the Apache commons JEXL engine is used to resolve the references which are defined. This allows the definition of very powerful references and in the same time keep backwards compatibility with the standard resolving of ExtVal.
The egine allowed me to create a feature which I called dynamic references. These nested expressions allows to have EL expressions that are defined at runtime.
The documentation of the add-on can be found here.
The source code is put on bitbucket with the rest of the ExtVal add-ons.
The add-on is available as maven dependency in the os890-m2-repository project of google code.
<repository>You can find examples in the integration test project in the source code and soon I'll post here an example of using MBeans as validation target.
<id>os890.googlecode.com</id>
<url>svn:http://os890-m2-repository.googlecode.com/svn/trunk/os890</url>
</repository>
Have fun with it.
Thursday, 15 September 2011
Cross field validation with JSF and ExtVal
Introduction
JSF has support for validation built in, but it is limited to a single field. Is it required, is it in the correct range, has it the correct format and so on.
With the MyFaces Extensions Validator framework (ExtVal in short), there is support for cross field validation. You can verify if two fields have the same or different content. Check the relative order of two dates and so on. For the feature we need 2 fields we can compare and this is done by specifying a reference in the annotation on one field to the other field.
And although the current possibilities to specify the other field are sufficient in 99% of your cases, I was already thinking about a mechanism for two years that allows greater flexibility and easier custom implementations.
ReferenceResolver
And since I now have almost completed the Reference Resolver add-on for ExtVal, the time has come to start blogging about the possibilities.
The add-on introduces an interface, the ReferenceResolver, when it comes to resolving the references to the other field in ExtVal. This allows the developer to implement any kind of reference he like. But since the default ExtVal functionality is enough in 99% of the cases, the requirement of the add-on was that it should recognize and correctly evaluates the current system. Backwards compatibility was in this case a requirement.
The Apache Commons JEXL project proved to be the ideal candidate. With some extensions, it correctly handles the default references of ExtVal and allowed some advanced references out of the box.
Cross field validation overview
But the details of the add-on will be explained in the next blog entry/entries I'll make. First I need to explain some concepts of the cross field validation of ExtVal before I can continue with the explanation of the add-on.
So the rest of this blog entry will only explain the default functionality and concepts of ExtVal. You don't need the add-on for this.
An example makes it more clear.
-- Managed Bean
@ManagedBean(name="bean")
@RequestScoped
public class ClassicGrammarBean {
@Equals(value = "target")
private String source;
private String target;
// setters and getters omitted
}
-- screen
<h:inputText id="source" value="#{bean.source}" label="source"/>
<h:inputText id="target" value="#{bean.target}" label="target"/>
If you use the above code, posting the screen will result in an error except when the contents in the 2 fields are the same.
How does it work? ExtVal installs a proxy for each renderer defined in the JSF system. That way, it can perform some action anytime there is a decode or encode request. One of the actions is that after the standard decode method is called, the value is 'verified' against the annotations that are present on the property in the managed bean to which the field is linked.
How is cross field validation then implemented? Another action which is performed after the decode, is that the value is stored by the ProcessedInformationRecorder for later usage. After the JSF validation lifecycle phase, there is a check for any cross field annotations on the properties used in the screen. If so, the required checks are performed based on the values stored by the ProcessedInformationRecorder. Later on I'll make some comments on this principle.
Reference methods
There are 2 options to refer to the other field that is needed in the cross field validation. One is based on EL expression, but first I'll explain the other one.
local reference (javaBean reference)
The example which is presented earlier in this text, is an example of the local reference type. In the value attribute of the annotation, we specify the property name of the other property we like to use in our comparison. Besides the referring to other simple properties (like target in the example) we can reference properties in another class as long as the object is a local property in the bean.
As always, the example makes it very clear what I mean.
public class SubBean {
private String targetInSub;
// setter and getter omitted
}
@ManagedBean(name="bean")
@RequestScoped
public class ClassicGrammarBean {
@Equals(value = "subBean.targetInSub")
private String source;
private SubBean subBean;
// setters and getters ommitted
}
But not all kind of java references are supported. Besides the above 2 example, the map notation is also supported. But only with a fixed key value, a literal and not a reference to another property. The contents in the value attribute of the annotation then looks like mapProperty.key where key is the string literal of the map key.
EL reference
The El references are more common because we all use them in the JSF pages. But the disadvantage is that the bean name is placed in a string attribute of the annotation. Changing the bean name will break your validation rules, which isn't the case if you can use the local reference method. But there you have the problems when you rename the properties of the bean.
Validation mode
Knowing the possible reference methods isn't enough to understand how the cross field validation works. You basically point to 2 properties of objects but the values aren't yet pushed into them. This is done in the update model phase of the JSF lifecycle which comes after the validation phase.
A very important piece of the cross field functionality is the matching of the EL references used in the JSF pages to link a component to a managed bean property and the reference specified in the attribute of the annotations.
In the case the reference of the annotation couldn't be matched to a value found in the current request, the reference is evaluated and the value stored in the model, the managed bean property in this case, is taken. This is called the model validation mode.
Conclusion
The new Reference Resolver add-on for ExtVal makes it possible to reference any kind of other value for the cross field validation functionality of ExtVal. If you have exotic requirement regarding the other party in the validation rule, you can implement them yourself using the ReferenceResolver interface.
And by default, by using the fine JEXL engine, the backward compatibility is guaranteed and opens the gate for very complex references.
In the next blog entry I'll explain how you can use the value of an MBean in the cross field validation with the new add-on.
JSF has support for validation built in, but it is limited to a single field. Is it required, is it in the correct range, has it the correct format and so on.
With the MyFaces Extensions Validator framework (ExtVal in short), there is support for cross field validation. You can verify if two fields have the same or different content. Check the relative order of two dates and so on. For the feature we need 2 fields we can compare and this is done by specifying a reference in the annotation on one field to the other field.
And although the current possibilities to specify the other field are sufficient in 99% of your cases, I was already thinking about a mechanism for two years that allows greater flexibility and easier custom implementations.
ReferenceResolver
And since I now have almost completed the Reference Resolver add-on for ExtVal, the time has come to start blogging about the possibilities.
The add-on introduces an interface, the ReferenceResolver, when it comes to resolving the references to the other field in ExtVal. This allows the developer to implement any kind of reference he like. But since the default ExtVal functionality is enough in 99% of the cases, the requirement of the add-on was that it should recognize and correctly evaluates the current system. Backwards compatibility was in this case a requirement.
The Apache Commons JEXL project proved to be the ideal candidate. With some extensions, it correctly handles the default references of ExtVal and allowed some advanced references out of the box.
Cross field validation overview
But the details of the add-on will be explained in the next blog entry/entries I'll make. First I need to explain some concepts of the cross field validation of ExtVal before I can continue with the explanation of the add-on.
So the rest of this blog entry will only explain the default functionality and concepts of ExtVal. You don't need the add-on for this.
An example makes it more clear.
-- Managed Bean
@ManagedBean(name="bean")
@RequestScoped
public class ClassicGrammarBean {
@Equals(value = "target")
private String source;
private String target;
// setters and getters omitted
}
-- screen
<h:inputText id="source" value="#{bean.source}" label="source"/>
<h:inputText id="target" value="#{bean.target}" label="target"/>
If you use the above code, posting the screen will result in an error except when the contents in the 2 fields are the same.
How does it work? ExtVal installs a proxy for each renderer defined in the JSF system. That way, it can perform some action anytime there is a decode or encode request. One of the actions is that after the standard decode method is called, the value is 'verified' against the annotations that are present on the property in the managed bean to which the field is linked.
How is cross field validation then implemented? Another action which is performed after the decode, is that the value is stored by the ProcessedInformationRecorder for later usage. After the JSF validation lifecycle phase, there is a check for any cross field annotations on the properties used in the screen. If so, the required checks are performed based on the values stored by the ProcessedInformationRecorder. Later on I'll make some comments on this principle.
Reference methods
There are 2 options to refer to the other field that is needed in the cross field validation. One is based on EL expression, but first I'll explain the other one.
local reference (javaBean reference)
The example which is presented earlier in this text, is an example of the local reference type. In the value attribute of the annotation, we specify the property name of the other property we like to use in our comparison. Besides the referring to other simple properties (like target in the example) we can reference properties in another class as long as the object is a local property in the bean.
As always, the example makes it very clear what I mean.
public class SubBean {
private String targetInSub;
// setter and getter omitted
}
@ManagedBean(name="bean")
@RequestScoped
public class ClassicGrammarBean {
@Equals(value = "subBean.targetInSub")
private String source;
private SubBean subBean;
// setters and getters ommitted
}
But not all kind of java references are supported. Besides the above 2 example, the map notation is also supported. But only with a fixed key value, a literal and not a reference to another property. The contents in the value attribute of the annotation then looks like mapProperty.key where key is the string literal of the map key.
EL reference
The El references are more common because we all use them in the JSF pages. But the disadvantage is that the bean name is placed in a string attribute of the annotation. Changing the bean name will break your validation rules, which isn't the case if you can use the local reference method. But there you have the problems when you rename the properties of the bean.
Validation mode
Knowing the possible reference methods isn't enough to understand how the cross field validation works. You basically point to 2 properties of objects but the values aren't yet pushed into them. This is done in the update model phase of the JSF lifecycle which comes after the validation phase.
A very important piece of the cross field functionality is the matching of the EL references used in the JSF pages to link a component to a managed bean property and the reference specified in the attribute of the annotations.
In the case the reference of the annotation couldn't be matched to a value found in the current request, the reference is evaluated and the value stored in the model, the managed bean property in this case, is taken. This is called the model validation mode.
Conclusion
The new Reference Resolver add-on for ExtVal makes it possible to reference any kind of other value for the cross field validation functionality of ExtVal. If you have exotic requirement regarding the other party in the validation rule, you can implement them yourself using the ReferenceResolver interface.
And by default, by using the fine JEXL engine, the backward compatibility is guaranteed and opens the gate for very complex references.
In the next blog entry I'll explain how you can use the value of an MBean in the cross field validation with the new add-on.
Saturday, 13 August 2011
Some corner cases of cross field validation with the ExtVal framework
Introduction
ExtVal has the ability to perform some cross field validations. An example is the check if two fields have the same content or to verify the relation between two dates (is one date 'before' the other). Besides the standard field validation and the object validation, it is the third way of performing validations. The advantage of the cross field validation is that the update model phase isn't required to have all the values to perform the validation. Due to the ProcessedInformationRecorder concept, the framework can record all values entered in the screen during the model validation phase. And then in a PhaseListener, these values can be used to perform the cross field validation.
This text explains what happens when you use some more exotic expressions.
No managed bean
We all use a managed bean and his properties to store the values of the inputText tags as follows
<h:inputText value="#{bean.source}" label="source" id="source"/>
But this isn't the only way how we can define the associated property for an input tag. Suppose you define in the faces-config file a String value under a certain name, then you can use it as attribute value. Is it useful? Certainly, imagine the case that you ask for a password and the retyped password to be certain the user hasn't made a type error. But we aren't interested in the retyped password value; we only need to know if it is equals to the other typed value.
So we can created something like this
If you try this, you receive the message that the values are different, also when you put the same value in the fields. The cause for this behavior is that the cross field validation isn't implemented with this kind of usage in mind.
The cross field validation functionality supposes that the EL you have specified, contains always at least a base object and a property. It doesn't recognize that the same EL is used on the field, and thus during validation, the #{StringVal} is evaluated and not the screen value is taken. But the EL expression evaluates always to null, resulting in a difference in all cases. But there is a solution for this situation. You can place the bean scope in the EL expression. When you write #{requestScope.StringVal} in the managed bean (within the Equals annotation) and in the screen, the code behaves as expected. By the way, adding the bean scope is resulting in a better performance when the EL expression is resolved.
Model aware version
The cross field validation feature can use the entered value in the screen, but there is also a model aware version. In that case, the EL is evaluated when the system sees that the same expression isn't used on some inputText decoded in the same request. In this situation, the bean scope isn't required to be specified.
This is a possible use case: when we have defined in the faces-config a bean of type Date with the name startDate. It can contain some date, initialized by some mechanism that is used to mark the oldest date possible for a period. When the user enters a date in the screen, we can verify it is later then the value in the faces-config defined value. Here we don't need to specify the bean scope, although it is allowed.
Methods with unified expression language
With the Unified Expression Language, you can specify method calls in EL with (or without) parameters on containers that support EL 2.2. But these constructs can't be used in the value attribute of an input field.
The above construct shows the return value of the method when the screen is presented. But when submitting the page, you receive an exception (from JSF, not from ExtVal) saying that it can't find the property doMethod. After all, it searches a method setDoMethod with a single parameter.
Now we can continue our theoretical example to see how far we can go. If we do create that required method (and you have a use case in which you can set the value on the same place then you retrieved it with the doMethod), how should the expression that we put in the ExtVal annotation look like?
This format isn't working, because the ProcessedInformationRecorder can't understand method constructs in EL. So the cross field validation performs the model variant, but doesn't see the newly typed text on the screen. And without the brackets, it interprets it as a property and looks for the method getDoMethod.
So is this an issue of ExtVal? I don't think it because I never encountered a possible use case that requires an EL method expression in an inputText tag.
Can't we use then the new features of the Unified Expression Language? Yes it is possible, as we already mentioned in the previous section. If the container supports the UEL, ExtVal uses the result of the expression to compare it to the screen entered value.
Conclusion
I have presented here some rare use cases of cross field validation and how ExtVal reacts on them. As we saw, the feature can be used without the usage of a managed bean, as long as we specify the bean scope. And with the newly introduced method expressions in UEL, you are able to use it in the model aware variant. And thus can be used to retrieve the value from other resources like JNDI. But with the upcoming new add-on, it will be easier since you have the pluggable reference resolver for the cross field validation.
Have fun with ExtVal
ExtVal has the ability to perform some cross field validations. An example is the check if two fields have the same content or to verify the relation between two dates (is one date 'before' the other). Besides the standard field validation and the object validation, it is the third way of performing validations. The advantage of the cross field validation is that the update model phase isn't required to have all the values to perform the validation. Due to the ProcessedInformationRecorder concept, the framework can record all values entered in the screen during the model validation phase. And then in a PhaseListener, these values can be used to perform the cross field validation.
This text explains what happens when you use some more exotic expressions.
No managed bean
We all use a managed bean and his properties to store the values of the inputText tags as follows
<h:inputText value="#{bean.source}" label="source" id="source"/>
So we can created something like this
-- faces-config
<managed-bean>
<managed-bean-name>StringVal</managed-bean-name>
<managed-bean-class>java.lang.String</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
-- bean
@Equals(value = "#{StringVal}")
private String password;
-- screen
password <h:inputText value="#{bean.password}" label="password" id="password"/>
Retype <h:inputText value="#{StringVal}" label="retype" id="retype"/>
The cross field validation feature can use the entered value in the screen, but there is also a model aware version. In that case, the EL is evaluated when the system sees that the same expression isn't used on some inputText decoded in the same request. In this situation, the bean scope isn't required to be specified.
-- faces-config
<managed-bean>
<managed-bean-name>startDate</managed-bean-name>
<managed-bean-class>java.util.Date</managed-bean-class>
<managed-bean-scope>application</managed-bean-scope>
</managed-bean>
-- bean
@DateIs(valueOf = "#{startDate}", type = DateIsType.after)
private Date beginDate;
-- screen
Begin date <h:inputText value="#{bean.beginDate}" label="Begin date" id="beginDate"/> <br/><h:inputText value="#{methodBean.doMethod()}" label="method" id="method"/> <br/>
@Equals(value = "#{methodBean.doMethod()}")
private String source;
This format isn't working, because the ProcessedInformationRecorder can't understand method constructs in EL. So the cross field validation performs the model variant, but doesn't see the newly typed text on the screen. And without the brackets, it interprets it as a property and looks for the method getDoMethod.
So is this an issue of ExtVal? I don't think it because I never encountered a possible use case that requires an EL method expression in an inputText tag.
Can't we use then the new features of the Unified Expression Language? Yes it is possible, as we already mentioned in the previous section. If the container supports the UEL, ExtVal uses the result of the expression to compare it to the screen entered value.
Have fun with ExtVal
Subscribe to:
Posts (Atom)