DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workkloads.

Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • How To Build Web Service Using Spring Boot 2.x
  • Visually Designing Views for Java Web Apps
  • How to Activate New User Accounts by Email
  • How To Read the Properties File Outside the Jar in Spring Boot

Trending

  • It’s Not About Control — It’s About Collaboration Between Architecture and Security
  • Debugging Core Dump Files on Linux - A Detailed Guide
  • Analyzing “java.lang.OutOfMemoryError: Failed to create a thread” Error
  • Key Considerations in Cross-Model Migration
  1. DZone
  2. Coding
  3. Frameworks
  4. Validating JSF EL Expressions in JSF Pages with static-jsfexpression-validator

Validating JSF EL Expressions in JSF Pages with static-jsfexpression-validator

By 
Jakub Holý user avatar
Jakub Holý
·
Jun. 23, 11 · Interview
Likes (0)
Comment
Save
Tweet
Share
12.5K Views

Join the DZone community and get the full member experience.

Join For Free

update: version 0.9.3 with new group/artifactid released on 7/25 including native support for jsf 1.2 (reflected below in the pom snippet).
update: version 0.9.4 with function tolerance for jsf 1.2 released on 7/28 (it doesn't check functions are ok but checks their parameters etc.)

static-jsfexpression-validator is utility for verifying that el expressions in jsf pages, such as #{bean.property}, are correct, that means that they don’t reference undefined managed beans and nonexistent getters or action methods. the purpose is to make jsf-based web applications safer to refactor as the change of a method name will lead to the detection of an invalid expression without need for extensive manual ui tests. it can be run statically, for example from a test. currently it builds on the jsf implementation v. 1.1 but can be in few hours (or days) modified to support newer version of jsf. how does it work?

  1. defined managed beans (name + type) are extracted from faces-config files and/or spring application context files
  2. jsp pages are parsed by jasper , tomcat’s jsp parser
  3. for each jsf tag:
  4. if it defines local variables, they are recorded (such as var in h:datatable )
  5. all jsf el expressions in the tag’s attributes are validated by a real el resolver using two magic classes, namely custom variableresolver and propertyresolver, that – instead of looking up managed bean instances and invoking their getters – fabricate “fake values” of the expected types so that the “resolution” of an expression can proceed. the effect is that the existence of the referenced properties and action methods is verified against the target classes.
    • sometimes it is not possible to determine the type of a jsf variable or property (e.g. when it’s a collection element), in which case it is necessary to declare it beforehand.
    • you can also manually declare extra variables (managed beans) and override the detected type of properties.

minimal setup

add this dependency to your maven/ivy/…:

<dependency>
<groupid>net.jakubholy.jeeutils.jsfelcheck</groupid>
<artifactid>static-jsfexpression-validator-jsf11</artifactid>
<!-- <artifactid>static-jsfexpression-validator-jsf12</artifactid> -->
<!-- <artifactid>static-jsfexpression-validator-jsf20</artifactid> - now only reuses 1.2 -->
<version>0.9.3</version>
<scope>test</scope>
</dependency>

alternatively, you can fetch static-jsfexpression-validator-jsf11-0.9.3.jar (or -jsf12- or -jsf20-) and its dependencies yourself, see the appendix a.

run it:

java -cp static-jsfexpression-validator-jsf11-0.9.3.jar:... net.jakubholy.jeeutils.jsfelcheck.jsfstaticanalyzer --jsproot /path/to/jsp/files/dir

alternatively, run it from a java class to be able to configure everything:

public class jsfelvaliditytest {
   @test
    public void should_have_only_defined_beans_and_valid_properties_in_jsf_el_expressions() throws exception {
        jsfstaticanalyzer jsfstaticanalyzer = new jsfstaticanalyzer();
        jsfstaticanalyzer.setfacesconfigfiles(collections.singleton(new file("web/web-inf/faces-config.xml")));
        map<string, class<?>> none = collections.emptymap();
        collectedvalidationresults results = jsfstaticanalyzer.validateelexpressions("web", none, none, none);
        assertequals("there shall be no invalid jsf el expressions; check system.err/.out for details. failure " + results.failures()
                , 0, results.failures().size());
    }
}

run it and check the standard error and output for results, which should ideally look something like this:

info: >>> started for '/somefile.jsp #############################################
...
>>> local variables that you must declare type for [0] #########################################

>>> failed jsf el expressions [0] #########################################
(set logging to fine for class net.jakubholy.jeeutils.jsfelcheck.validator.validatingjsfelresolver to se failure details and stacktraces)
>>> total excluded expresions: 0 by filters: []
>>> total expressions checked: 5872 (failed: 0, ignored expressions: 0) in 0min 25s

standard usage

normally you will need to configure the validator because you will have cases where property type etc. cannot be derived automatically.

declaring local variable types, extra variables, property type overrides

local variables – h:datatable etc.

if your jsp includes a jsf tag that declares a new local variable (typically h:datatable), like vegetable in the example below:

<h:datatable value="#{vegetarion.favouritevegetable}" var="vegetable">
   <h:column>
       <h:outputtext value="#{vegetable.name}" escape="false"/>
   </h:column>
   ...
</h:datatable>

where favouritevegetable is a collection of vegetables then you must tell the validator what type of objects the collection contains:

map<string, class<?>> localvariabletypes = new hashtable<string, class<?>>();
localvariabletypes.put("vegetarion.favouritevegetable", vegetable.class);
jsfstaticanalyzer.validateelexpressions("web", localvariabletypes, extravariables, propertytypeoverrides);

the failure to do so would be indicated by a number of failed expression validations and a suggestion to register type for this variable:

>>> local variables that you must declare type for [6] #########################################
declare component type of 'vegetarion.favouritevegetable' assigned to the variable vegetable (file /favourites.jsp, tag line 109)
>>> failed jsf el expressions [38] #########################################
(set logging to fine for class net.jakubholy.jeeutils.jsfelcheck.validator.validatingjsfelresolver to se failure details and stacktraces)
failedvalidationresult [failure=invalidexpressionexception [invalid el expression '#{vegetable.name}': propertynotfoundexception - 
property 'name' not found on class net.jakubholy.jeeutils.jsfelcheck.expressionfinder.impl.jasper.variables.contextvariableregistry$error_youmustdelcaretypeforthisvariable$$enhancerbymockitowithcglib$$3c8d0e8f]; expression=#{vegetable.name}, file=/favourites.jsp, tagline=118]

defining variables not in faces-config

variable: the first element of an el expression.

if you happen to be using a variable that is not a managed bean defined in faces-config (or spring config file), for example because you create it manually, you need to declare it and its type:

map<string, class<?>> extravariables = new hashtable<string, class<?>>();
localvariabletypes.put("mymessages", map.class);
jsfstaticanalyzer.validateelexpressions("web", localvariabletypes, extravariables, propertytypeoverrides);

expressions like #{mymessages['whatever.key']} would be now ok.

overriding the detected type of properties, especially for collection elements

property: any but the first segment of an el expression (#{variable.propert1.property2['property3]….}).

sometimes you need to explicitely tell the validator the type of a property. this is necessary if the poperty is an object taken from a collection, where the type is unknown at the runtime, but it may be useful also at other times.

if you had:

<h:outputtext value="#{vegetablemap['carrot'].color}"/>

then you’d need to declare the type like this:

map<string, class<?>> propertytypeoverrides = new hashtable<string, class<?>>();
propertytypeoverrides.put("vegetablemap.*", vegetable.class);
//or just for 1 key: propertytypeoverrides.put("vegetablemap.carrot", vegetable.class);
jsfstaticanalyzer.validateelexpressions("web", localvariabletypes, extravariables, propertytypeoverrides);

using the .* syntax you indicate that all elements contained in the collection/map are of the given type. you can also override the type of a single property, whether it is contained in a collection or not, as shown on the third line.

excluding/including selected expressions for validation

you may supply the validator with filters that determine which expressions should be checked or ignored. this may be useful mainly if you it is not possible to check them, for example because a variable iterates over a collection with incompatible objects.

the ignored expressions are added to a separate report and the number of ignored expressions together with the filters responsible for them is printed.

example: ignore all expressions for the variable evilcollection:

jsfstaticanalyzer.addelexpressionfilter(new elexpressionfilter(){
   @override public boolean accept(parsedelexpression expression) {
       if (expression.size() == 1
          && expression.iterator().next().equals("evilcollection")) {
      return false;
       }
       return true;
   }

   @override public string tostring() {
       return "excludeevilcollectionwithincompatibleobjects";
   }
});

(i admit that the interface should be simplified.)

other configuration

in jsfstaticanalyzer:

  • setfacesconfigfiles(collection<file>): faces-config files where to look for defined managed beans; null/empty not to read any
  • setspringconfigfiles(collection<file>) spring applicationcontext files where to look for defined managed beans; null/empty not to read any
  • setsuppressoutput(boolean) – do not print to system.err/.out – used if you want to process the produced collectedvalidationresults on your own
  • setjspstoincludecommaseparated(string) – normally all jsps under the jspdir are processed, you can force processing only the ones you want by supplying thier names here (jspc setting)
  • setprintcorrectexpressions(boolean) – set to true to print all the correctly validated jsf el expressions

understanding the results

jsfstaticanalyzer.validateelexpressions prints the results into the standard output and error and also returnes them in a collectedvalidationresults with the following content:

  • resultsiterable<failedvalidationresult> failures() – expressions whose validation wasn’t successful
  • resultsiterable<successfulvalidationresult> goodresults() – expressions validated successfully
  • resultsiterable<expressionrejectedbyfilterresult> excluded() – expressions ignored due to a filter
  • collection<declaretypeofvariableexception> – local variables (h:datatable’s var) for which you need to declare their type

the resultsiterable have size() and the individual *result classes contain enough information to describe the problem (the expression, exception, location, …).

now we will look how the results appear in the output.

unknown managed bean (variable)

failedvalidationresult [failure=invalidexpressionexception [invalid el expression
'#{messages['message.res.ok']}': variablenotfoundexception - 
no variable 'messages' among the predefined ones.]; expression=#{messages['message.res.ok']}, file=/sample_failures.jsp, tagline=20]

solution : fix it or add the variable to the extravariables map parameter.

invalid property (no corresponding getter found on the variable/previous property)

a) invalid property on a correct target object class

this kind of failures is the raison d’être of this tool.

failedvalidationresult [failure=invalidexpressionexception 
[invalid el expression '#{segment.departuredatexxx}': propertynotfoundexception - 
property 'departuredatexxx' not found on class example.segment$$enhancerbymockitowithcglib$$5eeba04];
 expression=#{segment.departuredatexxx}, file=/sample_failures.jsp, tagline=92]

solution : fix it, i.e. correct the expression to reference an existing property of the class. if the validator is using different class then it should then you might need to define a propertytypeoverride.

b) invalid property on an unknown target object class – mockobjectofunknowntype

failedvalidationresult [failure=invalidexpressionexception 
[invalid el expression '#{carlist[1].price}': propertynotfoundexception -
 property 'price' not found on class net.jakubholy.jeeutils.jsfelcheck.validator.mockobjectofunknowntype$$enhancerbymockitowithcglib$$9fa876d1]; 
expression=#{carlist[1].price}, file=/cars.jsp, tagline=46]

solution : carlist is clearly a list whose element type cannot be determined and you must therefore declare it via the propertytypeoverrides map property.

local variable without defined type

failedvalidationresult [failure=invalidexpressionexception
 [invalid el expression '   #{traveler.name}': propertynotfoundexception -
 property 'name' not found on class net.jakubholy.jeeutils.jsfelcheck.expressionfinder.impl.jasper.variables.contextvariableregistry$error_youmustdelcaretypeforthisvariable$$enhancerbymockitowithcglib$$b8a846b2]; 
expression=   #{traveler.name}, file=/worldtravels.jsp, tagline=118]

solution : declare the type via the localvariabletypes map parameter.

more documentation

check the javadoc, especially in jsfstaticanalyzer .

limitations

  1. currently only local variables defined by h:datatable ‘s var are recognized. to add support for others you’d need create and register a class similar to datatablevariableresolver
  2. handling of included files isn’t perfect, the don’t know about local variables defined in the including file. but we have all info needed to implement this. static includes are handled by the jasper parser (though it likely parses the included files also as top-level files, if they are on its search path).

future

it depends on my project’s needs, your feedback and your contributions :-) .

where to get it

from the project’s github or from the project’s maven central repository, snapshots also may appear in the sonatype snapshots repo .

appendices

a. dependencies of v.0.9.0 (also mostly similar for later versions):

(note: spring is not really needed if you haven’t spring-managed jsf beans.)

aopalliance:aopalliance:jar:1.0:compile
commons-beanutils:commons-beanutils:jar:1.6:compile
commons-collections:commons-collections:jar:2.1:compile
commons-digester:commons-digester:jar:1.5:compile
commons-io:commons-io:jar:1.4:compile
commons-logging:commons-logging:jar:1.0:compile
javax.faces:jsf-api:jar:1.1_02:compile
javax.faces:jsf-impl:jar:1.1_02:compile
org.apache.tomcat:annotations-api:jar:6.0.29:compile
org.apache.tomcat:catalina:jar:6.0.29:compile
org.apache.tomcat:el-api:jar:6.0.29:compile
org.apache.tomcat:jasper:jar:6.0.29:compile
org.apache.tomcat:jasper-el:jar:6.0.29:compile
org.apache.tomcat:jasper-jdt:jar:6.0.29:compile
org.apache.tomcat:jsp-api:jar:6.0.29:compile
org.apache.tomcat:juli:jar:6.0.29:compile
org.apache.tomcat:servlet-api:jar:6.0.29:compile
org.mockito:mockito-all:jar:1.8.5:compile
org.springframework:spring-beans:jar:2.5.6:compile
org.springframework:spring-context:jar:2.5.6:compile
org.springframework:spring-core:jar:2.5.6:compile
xml-apis:xml-apis:jar:1.0.b2:compile

from http://theholyjava.wordpress.com/2011/06/22/validating-jsf-el-expressions-in-jsf-pages-with-static-jsfexpression-validator/

Property (programming) Spring Framework

Opinions expressed by DZone contributors are their own.

Related

  • How To Build Web Service Using Spring Boot 2.x
  • Visually Designing Views for Java Web Apps
  • How to Activate New User Accounts by Email
  • How To Read the Properties File Outside the Jar in Spring Boot

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!