[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Sobre #34 de Effective Java [1]



Hola,

En el desarrollo de un proyecto, me he encontrado con una situación en la que 
confluyen distintas problemáticas, en las que me vendría bien vuestra 
opinión. A pesar de que sea un poco largo, creo que es necesario que explique 
más o menos pormenorizadamente el contexto del problema.

En lineas generales, el propósito es suplantar la variable de instancia "out" 
accesible por un jsp. El contenido del jsp no se conoce a priori (se 
considera arbitrario), y es conveniente proporcionar a dicho jsp un entorno 
en el que no se devuelva nada por la red, hasta más adelante.

En mi opinión a estas alturas es difícil justificar ningún mecanismo de 
especificación (como la herencia) basada en variables protegidas. Soy 
consciente de que éste no es necesariamente el caso, ya que los jsp son 
servlets generados dinámicamente, y la variable "out" en general sería local 
al método "service" del servlet. Lo comento simplemente porque no es 
infrecuente encontrarse con APIs basadas en esa idea.

Pues bien, parece que, implementando un JspWriter independiente del 
HttpServletResponse, asignándolo a la variable "out" (confiando en que el 
compilador jsp no la declare "final"), y restaurándola posteriormente, 
conseguiría mi propósito.
Se da el caso de los taglibs utilizados por el jsp puedan utilizar la 
instancia de "PageContext", la cual proporcionaría el JspWriter original a 
través del método "getOut()".
El siguiente paso entonces es implementar un delegador sobre el PageContext, 
de forma que respete el comportamiento de la instancia original, salvo al 
proveer el JspWriter.
Al probar dicha implementación y ver que no funciona, me doy cuenta de que los 
taglibs problemáticos son los que acaban llamando a los métodos "include" o 
"forward", y éstos no estaban siendo particularizados.
El siguiente problema viene por el hecho de que, en contenedor de servlets 
concreto que vengo usando, el compilador JSP (Jasper), hace uso variables 
protegidas en la implementación de dicho método, con lo cual la tarea se 
complica significativamente.

En este punto, la única salida que evitaría la necesidad de "parchear" el 
compilador de JSP, sería utilizar Reflection para obtener las variables 
miembro del PageContext original, quedarme únicamente con los JspWriter,  
reemplazarlos antes del "include", y restaurarlos a continuación.

No sé si anticipáis el resultado (este punto es el único que hace referencia 
al asunto del mensaje).
La suplantación de la variable miembro falla por un detalle: en Jasper, ésta 
se declara como instancia de la implementación de JspWriter, y no de 
JspWriter. Es decir, no puedo asignar a esa variable otro valor de JspWriter, 
ya que está declarada no como JspWriter, sino como JspWriterImpl.
Este detalle hace difícil que pueda no depender de la implementación del 
compilador JSP concreto.
Lo único que se me ocurre en este punto es usar "proxies" dinámicos, 
interceptar las llamadas a los métodos de la implementación del JspWriter, y 
suplantarlas con la ejecución del JspWriter sustituto. Como podéis anticipar, 
esto supone un código elegantísimo del tipo:

if  (method.equals("aa")) {
  result = writer.aa(..);
else if  (method.equals("bb") {
  result = writer.bb(..);
}

Como conclusión, diría que algunos puntos de Effective Java, aparentemente 
recomendaciones, pueden acabar teniendo una importancia no prevista en 
determinadas situaciones.

Un saludo,
Jose.

[1] 
http://www.informit.com/isapi/product_id~%7B7DE69993-3EF5-4354-9E10-9F8A535909F1%7D/content/images/0201310058/samplechapter/blochch7.pdf