EL hack …
Možná, že je to tím že jsem si dostačně pořádně nepřečetl dokumnetaci k EL, ale nějak jsem nezjistil jak zavolat methodu objektu s parametrem a párkrát by se mi to hodilo. V EL přímo to asi nejde, ony na to budou nejspíš budou existovat nějak tag library, ale ty se mi většinou nelíbí, protože občas je dost horor k nim najít dokumentaci. Proto jsem přemýšlel jak to udělat bez tld přímo pomocí EL.
Určitě to není uplně nejčistější řešení a určitě nejsem jediný koho to napadlo, ale zajímal by mě váš názor na tento Hack.
Takže o co de. V podstatě jde o využití operátoru [], který EL využívá takto:
The JSP expression language unifies the treatment of the . and [] operators. expr-a.identifier-b is equivalent to expr-a["identifier-b"]; that is, the expression expr-b is used to construct a literal whose value is the identifier, and then the [] operator is used with that value.
To evaluate expr-a[expr-b], evaluate expr-a into value-a and evaluate expr-b into value-b. If either value-a or value-b is null, return null.
- If value-a is a Map, return value-a.get(value-b). If !value-a.containsKey(value-b), then return null.
- If value-a is a List or array, coerce value-b to int and return value-a.get(value-b) or Array.get(value-a, value-b), as appropriate. If the coercion couldn’t be performed, an error is returned. If the get call returns an IndexOutOfBoundsException, null is returned. If the get call returns another exception, an error is returned.
- If value-a is a JavaBeans object, coerce value-b to String. If value-b is a readable property of value-a, then return the result of a get call. If the get method throws an exception, an error is returned.
Já jsem využil první bod, podle kterého vrátím object třídy implementující rozhraní Map, této třídě jenom přepíšu methodu public Object get(Object arg0). Takže EL výraz ${myBean.methodName[paramValue]} zavolá myBean.getMethodName().get(paramValue); což je v důsledku volání methody s parametrem Object.
Zde je ukázka kontrétní implementace takového beanu (teď ale nevím jestli se tomu ještě může říkat java bean):
/—code java
package com_3rojka.demo.EL.hack;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
public class MyBean {
private String greeting;
private GreetingParamMapper greetingPM;
private class GreetingParamMapper implements Map {
private MyBean myBean;
public GreetingParamMapper(MyBean myBean) {
this.myBean=myBean;
}
public Object get(Object arg0) {
return myBean.getGreeting() + “ “ + arg0;
}
public boolean containsKey(Object arg0) {
return true;
}
/* … other unimplemented methods … */
}
public MyBean(String greeting) {
this.greeting = greeting;
this.greetingPM = new GreetingParamMapper(this);
}
public String getGreeting() {
return greeting;
}
public GreetingParamMapper getGreetingWithName() {
return greetingPM;
}
}
\—
A zde je ukázka myBean používajícího jsp:
/—code html
<%@page import="com_3rojka.demo.EL.hack.MyBean"%>
<%
request.setAttribute("myBean", new MyBean("Hello"));
%>
${myBean.greetingWithName["World"]}
\—
Celé demo si lze stáhnou EL-hack-demo.zip jako maven project. Po rozbalení lze spustit webapp pomocí >mvn jetty:run.
Scriptlety mají zase způsobují problémy zkombinované s iteračními a větvícími tagy.
Systém, které používám já, je vytvoření vlastního tagu pro volání metod. Když tag vytvořím pomocí JSP2.0, nemusím řešit TLD a stačí ho umístit do WEB-INF.
———-
Výsledné volání //jakékoliv// metody z //jakékoliv// třídy potom vypadá tak, jak je uvedeno níže.
>
>
> … zde inicializace modelu
>
>
Má tag library se jmenuje model, protože jsem ji vytvořil v rámci jednoho prototypového projektu, ve kterém jsem celý MVC pattern implementoval pomocí JSP2.0 a EL (pro možnost online editace funkčnosti), takže v JSP controllerech jsem potřeboval volat metody modelů.
Počet parametrů tagu je dynamický od 0 do 99, to se v tag souboru dělá pomocí
Samotná metoda se zavolá přes reflection API. Tag má dva nepovinné parametry, result pro možnost uložení výsledku do atributu requestu a paramCount pro specifikování počtu parametrů. Počet parametrů je nutný specifikovat v případě, kdy chci volat metody s např. 5 parametry a poslední tři z nich musí být prázdné stringy. EL by to potom bral, jako kdyby parametry byly jen dva a zavolal by jinou metodu.
———-
Pokud máte zájem, tak zdroják toho tagu je tady:
http://www.janvrsinsky.com/java/call.zip
Při jeho vytváření jsem vycházel z článku
http://www.javaworld.com/javaworld/jw-05-2003/jw-0523-calltag.html?page=1
a ještě z nějakého tutorialu k JSP2.0, bohužel už nevím.
Těším se na zpětnou vazbu a na další názory k tomuto tématu. Jak to řešíte vy?
Jinak já jsem tu svoji metodu zatím, nikdy nepoužil jenom mě to tak napadlo a zatím se mi to nezdá jako špatný nápad.
pouziti tagu
%@ taglib prefix=”model” tagdir=”/WEB-INF/tags/model” %
volani metody
model:call model=”myModel” method=”myMethod” p1=”hello” p2=”0.5” /
Nevím proč bych v různých projektech implementoval jinak methodu getGreetingWithName(), resp methodu get třídy GreetingParamMapper, která je implementace privatní třídy mého beanu. A s tím čtením implementace bych řekl, že to musím vždycky pokud nemáš popsaný interface takže tady taky nevidím rozdíl.
Takže správně by to vypadalo takhle:
/—code java
/**
* mappuje EL vyraz ${myBean.greetingWithName[name]}
* a vrací pozdrav uživateli se jmenem name
*/
public GreetingParamMapper getGreetingWithName()
\—
A kdyby GreetingParamMapper byl potomkem nějaké abstaktní třídy, třeba ParameterMapper (což jsem zda nedělal jenom pro přehlednost příkladu) tak by ti to ani nepřišlo divné.
Ale jinak máš pravdu je to hack.