简体   繁体   中英

Acquire method reference in JSF EL

In JSF 2 I have declared function inspect which takes one argument of type java.lang.reflect.Method and based on this argument it performs some annotation inspection and returns true or false . The catch is I want to call this function inspect from JSF EL to be able to modify UI according the return value but I am not able to get a reference of target method to pass it as an argument of the function, so I would like to ask how to do it?

Example

package some.pkg;

@ManagedBean( name = "someClass" )
public class SomeClass {

     @MyAnnotation
     public void someMethod( String arg1, Integer arg2 ) { /* ... */ }
}

JSF function declaration

<function>
    <function-name>inspect</function-name>
    <function-class>some.pkg.Inspector</function-class>
    <function-signature>boolean inspect(java.lang.reflect.Method)</function-signature>
</function>

Desired invocation from JSF, but it doesn't work

 <h:outputText 
    value="someMethod is annotated by @MyAnnotation" 
    rendered="#{inspect(someClass.someMethod)}"
 />

Acceptable would be also this, but it is less comfortable variant

 <h:outputText 
    value="someMethod is annotated by @MyAnnotation" 
    rendered="#{inspect(some.pkg.SomeClass.someMethod)}"
 />

If you are using EL > 2.2 you don't need your custom EL-function. You can call the method from your ManagedBean directly with parameters:

#{someClass.someMethod('foo', 42)}

Otherwise you must declare a namespace and use it before your function:

#{namespace:inspect(someClass.someMethod)}

You can find a good explanation here .

But I'm not sure if this will work in your case. Even if it's possible to pass java.lang.reflect.Method as Parameter (never tried) how should the Method get their parameters? Nobody is passing them.

Why don't you try it just in server side? You know before rendering the page if the method is annotated in the current bean or not, so:

@ManagedBean( name = "someClass" )
public class SomeClass {

    boolean annotated = false;

    public boolean isAnnotated(){
        return annotated;
    }

    @PostConstruct
    public void postConstruct(){
        if (inspect(this.getClass().getMethod("someMethod")){
            annotated=true;
        }
    }

}

And in your xhtml page:

<h:outputText 
    value="someMethod is annotated by @MyAnnotation" 
    rendered="#{someClass.annotated}"
 />

You can even adapt it to use a parameter and calculate it on-the-fly:

//Notice in this case we're using a METHOD, not a GETTER
public boolean annotated(String methodName){
    return inspect(this.getClass().getMethod(methodName);
}

Calling it like that:

<h:outputText 
        value="someMethod is annotated by @MyAnnotation" 
        rendered="#{someClass.annotated('methodName')}"
     />

Or you can use an @ApplicationScoped managed bean to have access to it from every single view:

@ManagedBean
@ApplicationScoped
public class InspectorBean{

    public boolean inspectMethod(String className, String methodName){
        return inspect(Class.forName(className).getMethod(methodName));
    }

}

Then you can access like that from all your views:

<h:outputText 
        value="someMethod is annotated by @MyAnnotation" 
        rendered="#{inspectorBean.inspectMethod('completeClassName','methodName')}"
     />

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM