How to invoke JSF action on an anonymous class? EL cannot access it
Asked Answered
T

2

7

I want to have a generic menu in my JSF (MyFaces 1.2) application.

<h:form>
  <h:dataTable id="dt1" value="#{portal.actionList}" var="item">
    <f:facet name="header">
        <h:outputText value="Menu" />
    </f:facet>
    <h:column>
        <h:commandLink action="#{item.action}">
            <h:outputText value="clickme"/>
        </h:commandLink>
     </h:column>
   </h:dataTable>
 </h:form>

Then my portal on session-scope would look like this:

 class Portal {
    private ArrayList<IAction> list = new ArrayList<IAction>();

    public Portal() {
       list.add(new IAction() {
                public action() {
                    log.info("called action here");
                }
        });
    }
    public ArrayList<IAction> getActionList() {
        return list;
    }
 }

When I run this code it will display fine. But when you try to execute the action by clicking the "clickme" command link - the following exception will occur:

  Class org.apache.el.parser.AstValue can not access a member of class Portal$1 with modifiers "public"

Is there any way to display a list of anonymous classes, from which an method (in this example ITemplate.action()) can be executed?

Edit:

It works when I use an (inner) class. Like for example:

    class Bla implements IAction {
         public void action() {
             log.info("yes, i am working");
         }

and in the Portal constructor

 public Portal() {
   list.add( new Bla() );
}

But this is not the way I want it...

Terpstra answered 8/6, 2010 at 15:24 Comment(0)
B
11

That's because anonymous classes are not accessible from outside the package containing the anonymous class.

Here's a demonstration what's happening behind the scenes:

public static void main(String[] args) throws Exception {
    Portal portal = new Portal();
    Object list = portal.getClass().getDeclaredMethod("getActionList", null).invoke(portal, null);
    Object action = list.getClass().getDeclaredMethod("get", new Class[] { int.class }).invoke(list, 0);
    action.getClass().getDeclaredMethod("action", null).invoke(action, null);
}

Try executing this in the same package as Portal class and then once again in another class outside the package. In the other package, the last line would then throw exactly the same exception. That's the problem EL is struggling with since it's based on reflection.

I don't see other ways to solve this nicely than just creating a public (inner) class. Reflection (and thus also EL) can access them from other packages.

public class Portal {

    private List<IAction> list = new ArrayList<IAction>();

    public Portal() {
        list.add(new IActionImpl());
    }

    public class IActionImpl implements IAction {
        public void action() {
            System.out.println("called action here");
        }
    }

    public List<IAction> getActionList() {
        return list;
    }

}
Boyt answered 10/6, 2010 at 15:25 Comment(1)
that's an understanding explanation and for this purpose, this solution works just fine. thanks++Terpstra
S
0

The question is quite old but I have met today the same issue but only because I have switch from Jetty 7 to Tomcat 7.

I solve the issue by replacing the Jasper EL library with the GlassFish EL library.

Scholl answered 5/10, 2012 at 16:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.