【问题标题】:taglib call to managedbean calltaglib 调用 managedbean 调用
【发布时间】:2012-03-21 12:50:24
【问题描述】:

我有一个像这样的托管 bean(会话范围):

class Home {// as homeBean
  public void doSomething(ActionEvent ae, int a, int b){
    System.out.println("result="+(a+b));
  }
}

我喜欢这样称呼

<a4j:commandLink actionListener="#{homeBean:doSomething(1,2)}"/>

我知道的是:不能使用 a 和 b 参数。

好的:例如,这应该是使用标记库调用它的“静态”可能性:

public class CoolTaglib implements TagLibrary{
   ...
  public static void doSomething(int a, int b) {
    getHomeBeanFromSession().doSomething(a,b);
  }
}

如何动态调用它?使用 bcel 或 URLClassLoader?

【问题讨论】:

    标签: jsf facelets taglib bcel


    【解决方案1】:

    此 EL 表达式语法仅适用于静态方法,必须在标记库中定义,并在视图中定义命名空间:

     #{namespacePrefix:fn(arg)}
    

    此 EL 表达式在对象实例上调用 parameterized method

    #{someInstance.method(arg)}
    

    第二种形式在Expression Language 2.2 或更高版本(Java EE 6)中可用。在此之前,一些第 3 方 JSF 库支持类似的表达式。

    只要在 JSF 上下文中执行,就可以从静态方法中查找托管 bean:

    FacesContext context = FacesContext.getCurrentInstance();
    SomeBean someBean = context.getApplication()
                               .evaluateExpressionGet(context, 
                                                      "#{someBean}", SomeBean.class);
    

    然而,这不是理想的方法。此代码是针对 JSF 2 编写的;以前的版本使用不同的动态查找调用。

    如果您需要静态方法中的 bean,请使用以下形式的表达式:

    #{namespacePrefix:fn(someBean, 1, 2)}
    

    【讨论】:

      【解决方案2】:

      哦,酷,我找到了一种工作方式:

      public class ... implements TagLibrary {
      
      @Override
      public Method createFunction(String taglib, String functionName) {
          if (!map.containsKey(functionName)) {
      
              String classname = "de.Test" + functionName;
              ClassGen _cg = new ClassGen(classname,
                      "java.lang.Object", "Test.java", ACC_PUBLIC | ACC_SUPER,
                      new String[] {});
              ConstantPoolGen _cp = _cg.getConstantPool();
              InstructionFactory _factory = new InstructionFactory(_cg, _cp);
      
              Method meth = find(functionName, getNavigation());
              Class<?>[] parameterTypes = meth.getParameterTypes();
              int countParams = parameterTypes.length;
              Type[] types = new Type[countParams];
              String[] names = new String[countParams];
              for (int i = 0; i < countParams; i++) {
                  types[i] = new ObjectType(parameterTypes[i].getName());
                  names[i] = "arg" + i;
              }
      
              InstructionList il = new InstructionList();
      
              MethodGen staticMethod = new MethodGen(ACC_PUBLIC | ACC_STATIC,
                      Type.OBJECT, types, names, functionName, getClass()
                              .getName(), il, _cp);
      
              InstructionHandle ih_1 = il.append(new PUSH(_cp, functionName));
              il.append(new PUSH(_cp, countParams));
      
              il.append(_factory.createNewArray(Type.OBJECT, (short) 1));
              il.append(InstructionConstants.DUP);
      
              for (int i = 0; i < countParams; i++) {
                  il.append(new PUSH(_cp, i));
      
                  il.append(_factory.createLoad(Type.OBJECT, i));
                  il.append(InstructionConstants.AASTORE);
                  if (i != countParams - 1)
                      il.append(InstructionConstants.DUP);
              }
      
              il.append(_factory.createInvoke(getClass().getName(),
                      "call", Type.OBJECT, new Type[] { Type.STRING,
                              new ArrayType(Type.OBJECT, 1) },
                      Constants.INVOKESTATIC));
              InstructionHandle ih_25 = il.append(_factory
                      .createReturn(Type.OBJECT));
              staticMethod.setMaxStack();
              staticMethod.setMaxLocals();
              _cg.addMethod(staticMethod.getMethod());
              il.dispose();
      
              try {
      
                  byte[] bytes = _cg.getJavaClass().getBytes();
      
                  InjectingClassLoader icl = new InjectingClassLoader();
      
                  Method find = 
                          find(functionName, icl.load(classname, bytes));
      
                  map.put(functionName, find);
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
          Method method = map.get(functionName);
          return method;
      
      }
      
      public static Object call(String functionname, Object[] arguments) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
          Navigation myTargetBean = getNavigation();
          Method proxyMethod = find(functionname,myTargetBean);
      
          Object result = proxyMethod.invoke(myTargetBean, arguments);
      
          return result;
      }
      

      现在,我可以调用 #{cms:doSomething(1,2)}

      【讨论】:

      • 你有 jsf 1.2 的“简单”方式吗? “简单”对我来说意味着没有所有这些 getter-setter-overhead。
      • 如果您碰巧运行 Servlet 2.5,您可以安装 JBoss EL 以获得类似 EL 2.2 的增强功能。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-12-18
      • 1970-01-01
      • 2023-03-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多