<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-2012232069289957092</id><updated>2012-01-23T17:07:20.873-08:00</updated><category term='prompt'/><category term='parametros'/><category term='certificacion'/><category term='web'/><category term='order by'/><category term='funciones de agregacion'/><category term='desarrollo'/><category term='convenciones'/><category term='dia del programador'/><category term='mapeos'/><category term='struts2'/><category term='interfaces'/><category term='scjp'/><category term='virtualizacion'/><category term='inversion de control'/><category term='muchos a uno'/><category term='modificadores'/><category term='spring'/><category term='colecciones'/><category term='hql'/><category term='servlet'/><category term='embeber'/><category term='herencia'/><category term='uno a muchos'/><category term='struts 2'/><category term='variables'/><category term='subreportes'/><category term='xml'/><category term='pie'/><category term='uno a uno'/><category term='variables de entorno'/><category term='java'/><category term='group by'/><category term='mysql'/><category term='IoC'/><category term='declaraciones'/><category term='jdk'/><category term='formularios'/><category term='estandares'/><category term='bash'/><category term='NetBeans'/><category term='donaciones'/><category term='clases'/><category term='pdf'/><category term='descarga'/><category term='DI'/><category term='orientacion a objetos'/><category term='aplicacion'/><category term='scopes'/><category term='jasperreports'/><category term='carga'/><category term='plugins'/><category term='request'/><category term='base de datos'/><category term='enums'/><category term='validaciones'/><category term='reportes'/><category term='datasource'/><category term='CX-310-065'/><category term='xls'/><category term='muchos a muchos'/><category term='interceptores'/><category term='VirtualBox'/><category term='parametros posicionales'/><category term='festividades'/><category term='conector'/><category term='tomcat'/><category term='ognl'/><category term='IDE'/><category term='anotaciones'/><category term='row value constructor'/><category term='download'/><category term='frameworks'/><category term='grupos'/><category term='sesion'/><category term='relaciones'/><category term='debian'/><category term='parametros por nombre'/><category term='ireports'/><category term='mod_jk'/><category term='sun certified java programmer'/><category term='apache'/><category term='hibernate'/><category term='personalización'/><category term='graficos'/><category term='jsp'/><category term='ssh'/><category term='servidor'/><category term='configuracion'/><category term='bitacoras'/><category term='rtf'/><category term='herramientas'/><category term='null'/><category term='log4j'/><category term='colores'/><category term='propiedades'/><category term='Linux'/><category term='servlets'/><category term='upload'/><category term='eventos'/><category term='var-args'/><category term='Inyeccion de dependencias'/><category term='inyeccion de colecciones'/><title type='text'>Tutoriales de Programacion Java</title><subtitle type='html'>Blog dedicado a temas de programación actuales usando el lenguaje de programación Java y las últimas versiones de sus APIs y Herramientas.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://www.javatutoriales.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2012232069289957092/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://www.javatutoriales.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Alex</name><uri>http://www.blogger.com/profile/06974037481671868076</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>43</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-2012232069289957092.post-3413005603812408821</id><published>2011-12-19T21:54:00.000-08:00</published><updated>2011-12-20T07:45:12.081-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='struts 2'/><category scheme='http://www.blogger.com/atom/ns#' term='scopes'/><category scheme='http://www.blogger.com/atom/ns#' term='request'/><category scheme='http://www.blogger.com/atom/ns#' term='aplicacion'/><category scheme='http://www.blogger.com/atom/ns#' term='sesion'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><category scheme='http://www.blogger.com/atom/ns#' term='servlets'/><title type='text'>Struts 2 - Parte 4: Scopes de Objetos Web</title><content type='html'>&lt;div style="text-align: justify;"&gt;Cuando estamos desarrollando una aplicación web debemos almacenar información que será procesada de distinta manera. Dependiendo de cuál sea el propósito de esta información querremos que tenga un tiempo de vida más corto o más largo, alguna información deberá permanecer disponible durante todo el momento que viva nuestra aplicación, mientras que otra solo nos interesará que viva durante una petición. Además habrá información que pertenecerá a cada usuario que acceda a la aplicación y que deberá estar disponible sólo para el usuario correspondiente.&lt;br /&gt;&lt;br /&gt;Estos tiempos de vida son llamados &lt;span class="codigo"&gt;scopes&lt;/span&gt;, y en las aplicaciones web tenemos un cierto número de ellos. Es importante conocer estos &lt;span class="codigo"&gt;scopes&lt;/span&gt; y ver qué tipo de información es conveniente colocar en cada uno de ellos. A la información que colocamos en los distintos &lt;span class="codigo"&gt;scopes&lt;/span&gt; les llamamos &lt;span class="negritas"&gt;atributos&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;También algunas veces es necesario tener un acceso directamente a los objetos del API de &lt;span class="codigo"&gt;Servlets&lt;/span&gt;, como el "&lt;span class="codigo"&gt;HttpServletRequest&lt;/span&gt;", o el "&lt;span class="codigo"&gt;ServletContext&lt;/span&gt;", o a los parámetros de la petición,&lt;br /&gt;&lt;br /&gt;&lt;span class="codigo"&gt;Struts 2&lt;/span&gt; nos proporciona una forma simple y elegante, además de diversa, para manejar todas estas cosas y en este tutorial aprenderemos estas maneras &lt;span class="codigo"&gt;^_^&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;Las aplicaciones web con Java tienen básicamente tres scopes o tiempos de vida:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="codigo"&gt;Application&lt;/span&gt;: Es el scope más largo ya que abarca &lt;span class="negritas"&gt;el tiempo de vida completo de la apicación&lt;/span&gt;; esto es, los datos vivirán mientras la aplicación esté activa.&lt;/li&gt;&lt;li&gt;&lt;span class="codigo"&gt;Session&lt;/span&gt;: Este scope nos permite tener datos que vivirán a lo largo de &lt;span class="negritas"&gt;múltiples peticiones HTTP para un mismo usuario&lt;/span&gt;, mientras el usuario esté dentro de la aplicación. Cada usuario verá únicamente sus datos y no habrá forma de que vea los de los demás.&lt;/li&gt;&lt;li&gt;&lt;span class="codigo"&gt;Request&lt;/span&gt;: Este es el scope más pequeño, los datos asociados con la petición únicamente estarán disponibles &lt;span class="negritas"&gt;mientras se realiza dicha petición&lt;/span&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Existen algunos otros scopes, pero estos son los más y importantes, además no todos los frameworks proporcionan acceso a los demás scopes.&lt;br /&gt;&lt;br /&gt;La información o atributos que se puede colocar dentro de estos scopes son &lt;span class="negritas"&gt;pares nombre valor&lt;/span&gt;, en donde &lt;span class="negritas"&gt;el nombre debe ser una cadena&lt;/span&gt; y &lt;span class="negritas"&gt;el valor puede ser cualquier objeto&lt;/span&gt; que nosotros queramos.&lt;br /&gt;&lt;br /&gt;&lt;span class="codigo"&gt;Struts 2&lt;/span&gt; nos proporciona tres formas para colocar y leer los atributos que se encuentren en estos scopes:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Implementación de interfaces &lt;span class="codigo"&gt;Aware&lt;/span&gt;&lt;/li&gt;&lt;li&gt;Uso del objeto "&lt;span class="codigo"&gt;ActionContext&lt;/span&gt;"&lt;/li&gt;&lt;li&gt;Uso del objeto "&lt;span class="codigo"&gt;ServletActionContext&lt;/span&gt;"&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Las tres son igual de sencillas y nos permiten obtener más o menos los mismos resultados.&lt;br /&gt;&lt;br /&gt;Además podemos usar dos de los métodos anteriores, las interfaces &lt;span class="codigo"&gt;Aware&lt;/span&gt; y el objeto "&lt;span class="codigo"&gt;ServletActionContext&lt;/span&gt;", para obtener acceso directo a los objetos "&lt;span class="codigo"&gt;HttpServletRequest&lt;/span&gt;" y "&lt;span class="codigo"&gt;ServletContext&lt;/span&gt;"&lt;br /&gt;&lt;br /&gt;Lo primero que haremos es crear un nuevo proyecto web en NetBeans. Vamos al menú "&lt;span class="codigo"&gt;File -&amp;gt; New Project...&lt;/span&gt;". En la ventana que aparece seleccionamos la categoría "&lt;span class="codigo"&gt;Java Web&lt;/span&gt;" y en el tipo de proyecto "&lt;span class="codigo"&gt;Web Application&lt;/span&gt;". Presionamos el botón "&lt;span class="codigo"&gt;Next &amp;gt;&lt;/span&gt;" y le damos un nombre y una ubicación a nuestro proyecto; presionamos nuevamente el botón "&lt;span class="codigo"&gt;Next &amp;gt;&lt;/span&gt;" y en este punto se nos preguntará el servidor que queremos usar. En nuestro caso usaremos el servidor "&lt;span class="codigo"&gt;Tomcat 7.0&lt;/span&gt;", con la versión 5 de &lt;span class="codigo"&gt;JEE&lt;/span&gt; y presionamos el botón "&lt;span class="codigo"&gt;Finish&lt;/span&gt;".&lt;br /&gt;&lt;br /&gt;Una vez que tengamos nuestro proyecto debemos recordar agregar la biblioteca "&lt;span class="codigo"&gt;Struts2&lt;/span&gt;" (o "&lt;span class="codigo"&gt;Struts2Anotaciones&lt;/span&gt;" si van a hacer uso de anotaciones, como es mi caso &lt;span class="codigo"&gt;^_^&lt;/span&gt;), que creamos en &lt;a href="http://www.javatutoriales.com/2011/06/struts-2-parte-1-configuracion.html"&gt;el primer tutorial de la serie de &lt;span class="codigo"&gt;Struts 2&lt;/span&gt;&lt;/a&gt;. Hacemos clic derecho sobre el nodo "&lt;span class="codigo"&gt;Libraries&lt;/span&gt;" del proyecto. En el menú que aparece seleccionamos la opción "&lt;span class="codigo"&gt;Add Library...&lt;/span&gt;". En la ventana que aparece seleccionamos la biblioteca "&lt;span class="codigo"&gt;Struts2&lt;/span&gt;" o "&lt;span class="codigo"&gt;Struts2Anotaciones&lt;/span&gt;" y presionamos "&lt;span class="codigo"&gt;Add Library&lt;/span&gt;". Con esto ya tendremos los jars de &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; en nuestro proyecto.&lt;br /&gt;&lt;br /&gt;Ahora configuramos el filtro "&lt;span class="codigo"&gt;struts2&lt;/span&gt;" en el deployment descriptor. Abrimos el archivo "&lt;span class="codigo"&gt;web.xml&lt;/span&gt;" y colocamos el siguiente contenido, como se explicó en &lt;a href="http://www.javatutoriales.com/2011/06/struts-2-parte-1-configuracion.html"&gt;el primer tutorial de la serie&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;filter&amp;gt;&lt;br /&gt;    &amp;lt;filter-name&amp;gt;struts2&amp;lt;/filter-name&amp;gt;&lt;br /&gt;    &amp;lt;filter-class&amp;gt;org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter&amp;lt;/filter-class&amp;gt;&lt;br /&gt;&amp;lt;/filter&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;filter-mapping&amp;gt;&lt;br /&gt;    &amp;lt;filter-name&amp;gt;struts2&amp;lt;/filter-name&amp;gt;&lt;br /&gt;    &amp;lt;url-pattern&amp;gt;/*&amp;lt;/url-pattern&amp;gt;&lt;br /&gt;&amp;lt;/filter-mapping&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Comenzaremos viendo cómo poder agregar y leer datos en los scopes anteriores, y cómo mostrarlos en nuestras JSPs.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="titulo"&gt;Manejo de Scopes&lt;/h2&gt;&lt;h3 class="subtitulo"&gt;Manejo de Scopes usando interfaces Aware&lt;/h3&gt;&lt;span class="codigo"&gt;Struts 2&lt;/span&gt; proporciona un conjunto de interfaces llamadas interfaces &lt;span class="codigo"&gt;Aware&lt;/span&gt; (bueno, creo que solo yo las llamo así &lt;span class="codigo"&gt;^_^&lt;/span&gt;) las cuales permite que nuestros &lt;span class="codigo"&gt;Actions&lt;/span&gt; reciban cierta información, al momento de inicializarlos. La mayoría de estas interfaces proporcionan un &lt;span class="codigo"&gt;Map&lt;/span&gt; con los pares nombre valor de los atributos de cada uno de los scopes. &lt;br /&gt;&lt;br /&gt;&lt;span class="codigo"&gt;Struts 2&lt;/span&gt; contiene las siguientes interfaces &lt;span class="codigo"&gt;Aware&lt;/span&gt; para obtener y leer atributos de los scopes:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="codigo"&gt;ApplicationAware&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="codigo"&gt;SessionAware&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="codigo"&gt;RequestAware&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Además de un par de interfaces para recibir el "&lt;span class="codigo"&gt;HttpServletRequest&lt;/span&gt;" y el "&lt;span class="codigo"&gt;ServletContext&lt;/span&gt;", pero hablaremos de ellas en su momento.&lt;br /&gt;&lt;br /&gt;El uso de estas interfaces es muy intuitivo, creamos un &lt;span class="codigo"&gt;Action&lt;/span&gt; que implemente la interface que nos interese. Cada una de estas interfaces proporciona un método &lt;span class="codigo"&gt;setter&lt;/span&gt; que permite inyectar el mapa con los atributos del scope correspondiente.&lt;br /&gt;&lt;br /&gt;Los métodos de estas interfaces se muestran a continuación:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public interface RequestAware&lt;br /&gt;{&lt;br /&gt;    public void setRequest(Map&amp;lt;String, Object&amp;gt; map);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public interface SessionAware&lt;br /&gt;{&lt;br /&gt;    public void setSession(Map&amp;lt;String, Object&amp;gt; map);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public interface ApplicationAware&lt;br /&gt;{&lt;br /&gt;    public void setApplication(Map&amp;lt;String, Object&amp;gt; map);&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;La forma de los tres métodos es prácticamente la misma: no regresan nada y reciben como único parámetro un &lt;span class="codigo"&gt;Map&lt;/span&gt; donde el nombre del atributo es un &lt;span class="codigo"&gt;String&lt;/span&gt; y el valor es un &lt;span class="codigo"&gt;Object&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Como la forma de trabajo con estas tres interfaces es también el mismo, hagamos un ejemplo de todo en uno.&lt;br /&gt;&lt;br /&gt;Lo primero que haremos es crear una nueva &lt;span class="codigo"&gt;JSP&lt;/span&gt; llamada "&lt;span class="codigo"&gt;datosScopesInterfaces.jsp&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-DSHLyhOfAuk/TvAhDjfsqBI/AAAAAAAABP0/fUCWhGul2h4/s1600/S4_1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="311" src="http://1.bp.blogspot.com/-DSHLyhOfAuk/TvAhDjfsqBI/AAAAAAAABP0/fUCWhGul2h4/s400/S4_1.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Esta página contendrá un formulario que nos permitirá establecer el valor de algunos datos que colocaremos posteriormente en cada uno de los scopes. Como usaremos las etiquetas de &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; para generar este formulario, lo primero que debemos hacer es indicar, con la directiva "&lt;span class="codigo"&gt;taglib&lt;/span&gt;", que usaremos la bibliotecas de etiquetas de &lt;span class="codigo"&gt;Struts 2&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;%@taglib prefix="s" uri="/struts-tags" %&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ahora crearemos un formulario con unos cuantos campos de texto, para colocar los valores que enviaremos a nuestro &lt;span class="codigo"&gt;Action&lt;/span&gt; para ser procesados. Cada uno de estos valores tendrá un nombre que indica en cuál scope quedará. Este formulario se enviará a un &lt;span class="codigo"&gt;Action&lt;/span&gt; llamado "&lt;span class="codigo"&gt;scopesInterfaces&lt;/span&gt;" que crearemos un poco más adelante:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:form action="scopesInterfaces"&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="datoSesion" label="Sesion" /&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="datoRequest" label="Request" /&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="datosAplicacion" label="Aplicacion" /&amp;gt;&lt;br /&gt;    &amp;lt;s:submit /&amp;gt;&lt;br /&gt;&amp;lt;/s:form&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ahora crearemos un nuevo paquete, llamado "&lt;span class="codigo"&gt;com.javatutoriales.actions&lt;/span&gt;",  para colocar nuestros &lt;span class="codigo"&gt;Actions&lt;/span&gt;. Dentro de este paquete crearemos una clase llamada "&lt;span class="codigo"&gt;ScopesInterfacesAction&lt;/span&gt;", esta clase deberá extender de "&lt;span class="codigo"&gt;ActionSupport&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class ScopesInterfacesAction extends ActionSupport&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Agregaremos un atributo de tipo &lt;span class="codigo"&gt;String&lt;/span&gt;, con sus correspondientes &lt;span class="codigo"&gt;setters&lt;/span&gt;, para cada uno de los campos del formulario:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class ScopesInterfacesAction extends ActionSupport&lt;br /&gt;{&lt;br /&gt;    private String datoSesion;&lt;br /&gt;    private String datoRequest;&lt;br /&gt;    private String datosAplicacion;&lt;br /&gt;&lt;br /&gt;    public void setDatoRequest(String datoRequest)&lt;br /&gt;    {&lt;br /&gt;        this.datoRequest = datoRequest;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setDatoSesion(String datoSesion)&lt;br /&gt;    {&lt;br /&gt;        this.datoSesion = datoSesion;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setDatosAplicacion(String datosAplicacion)&lt;br /&gt;    {&lt;br /&gt;        this.datosAplicacion = datosAplicacion;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Sólo hemos colocado los &lt;span class="codigo"&gt;setters&lt;/span&gt; porque estableceremos estos valores en los scopes correspondientes y, por lo tanto, los leeremos posteriormente de una manera diferente &lt;span class="codigo"&gt;^_^&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Ahora el tema que nos interesa, las interfaces. Como toda buena interface de Java, para implementar las interfaces &lt;span class="codigo"&gt;Aware&lt;/span&gt; lo primero que debemos hacer es declarar que nuestra clase implementará estas interfaces; implementaremos las tres interfaces de una sola vez:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class ScopesInterfacesAction extends ActionSupport implements RequestAware, SessionAware, ApplicationAware&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Como mencioné antes: estas interfaces tienen solo un método cada una (el método que mencioné anteriormente). Normalmente colocamos un atributo, de tipo "&lt;span class="codigo"&gt;Map&amp;lt;String, Object&amp;gt;&lt;/span&gt;" para almacenar el argumento que es establecido por el framework y poder usarlo posteriormente en el método "&lt;span class="codigo"&gt;execute&lt;/span&gt;" de nuestro &lt;span class="codigo"&gt;Action&lt;/span&gt;; después todo lo que hay que hacer es implementar cada uno de los métodos de estas interfaces de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;private Map&amp;lt;String, Object&amp;gt; sesion;&lt;br /&gt;private Map&amp;lt;String, Object&amp;gt; application;&lt;br /&gt;private Map&amp;lt;String, Object&amp;gt; request;&lt;br /&gt;&lt;br /&gt;public void setRequest(Map&amp;lt;String, Object&amp;gt; map)&lt;br /&gt;{&lt;br /&gt;    this.request = map;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setApplication(Map&amp;lt;String, Object&amp;gt; map)&lt;br /&gt;{&lt;br /&gt;    this.application = map;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setSession(Map&amp;lt;String, Object&amp;gt; map)&lt;br /&gt;{&lt;br /&gt;    this.sesion = map;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;En el método "&lt;span class="codigo"&gt;execute&lt;/span&gt;" lo único que haremos es agregar el valor recibido desde el formulario al scope correspondiente, usando el "&lt;span class="codigo"&gt;Map&lt;/span&gt;" apropiado:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Override&lt;br /&gt;public String execute() throws Exception&lt;br /&gt;{&lt;br /&gt;    application.put("datoAplicacion", datosAplicacion);&lt;br /&gt;    sesion.put("datoSesion", datoSesion);&lt;br /&gt;    request.put("datoRequest", datoRequest);&lt;br /&gt;        &lt;br /&gt;    return SUCCESS;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Así de simple &lt;span class="codigo"&gt;^^&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Para terminar este &lt;span class="codigo"&gt;Action&lt;/span&gt; debemos agregar las anotaciones que vimos en &lt;a href="http://www.javatutoriales.com/2011/06/struts-2-parte-1-configuracion.html"&gt;el primer tutorial de la serie&lt;/a&gt;, y que a estas alturas ya conocemos de memoria. El nombre de nuestro &lt;span class="codigo"&gt;Action&lt;/span&gt; será "&lt;span class="codigo"&gt;scopesInterfaces&lt;/span&gt;" y el resultado será enviado a la página "&lt;span class="codigo"&gt;resultado.jsp&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Namespace(value = "")&lt;br /&gt;@Action(value = "scopesInterfaces", results ={@Result(name = "success", location = "/resultado.jsp")})&lt;br /&gt;public class ScopesInterfacesAction extends ActionSupport implements RequestAware, SessionAware, ApplicationAware&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;La clase  "&lt;span class="codigo"&gt;ScopesInterfacesAction&lt;/span&gt;" completa queda de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Namespace(value = "")&lt;br /&gt;@Action(value = "scopesInterfaces", results ={@Result(name = "success", location = "/resultado.jsp")})&lt;br /&gt;public class ScopesInterfacesAction extends ActionSupport implements RequestAware, SessionAware, ApplicationAware&lt;br /&gt;{&lt;br /&gt;    private String datoSesion;&lt;br /&gt;    private String datoRequest;&lt;br /&gt;    private String datosAplicacion;&lt;br /&gt;    private Map&amp;lt;String, Object&amp;gt; sesion;&lt;br /&gt;    private Map&amp;lt;String, Object&amp;gt; application;&lt;br /&gt;    private Map&amp;lt;String, Object&amp;gt; request;&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    public String execute() throws Exception&lt;br /&gt;    {&lt;br /&gt;        application.put("datoAplicacion", datosAplicacion);&lt;br /&gt;        sesion.put("datoSesion", datoSesion);&lt;br /&gt;        request.put("datoRequest", datoRequest);&lt;br /&gt;&lt;br /&gt;        return SUCCESS;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setRequest(Map&amp;lt;String, Object&amp;gt; map)&lt;br /&gt;    {&lt;br /&gt;        this.request = map;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setApplication(Map&amp;lt;String, Object&amp;gt; map)&lt;br /&gt;    {&lt;br /&gt;        this.application = map;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setSession(Map&amp;lt;String, Object&amp;gt; map)&lt;br /&gt;    {&lt;br /&gt;        this.sesion = map;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setDatoRequest(String datoRequest)&lt;br /&gt;    {&lt;br /&gt;        this.datoRequest = datoRequest;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setDatoSesion(String datoSesion)&lt;br /&gt;    {&lt;br /&gt;        this.datoSesion = datoSesion;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setDatosAplicacion(String datosAplicacion)&lt;br /&gt;    {&lt;br /&gt;        this.datosAplicacion = datosAplicacion;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ahora crearemos la página "&lt;span class="codigo"&gt;resultado.jsp&lt;/span&gt;", en la raíz de las páginas web, para comprobar que los datos se han establecido correctamente. En esta página primero indicaremos que haremos uso de la biblioteca de etiquetas de &lt;span class="codigo"&gt;Struts 2&lt;/span&gt;, como lo hicimos anteriormente. Además usaremos la etiqueta "&lt;span class="codigo"&gt;&amp;lt;s:property&amp;gt;&lt;/span&gt;" para mostrar el valor en cada uno de los scopes. Para obtener el valor usaremos &lt;span class="codigo"&gt;OGNL&lt;/span&gt; con el cual, como recordarán del segundo tutorial de la serie, tiene una sintaxis especial para los objetos que se encuentran en los scopes anteriores. Si no recuerdan la sintaxis pueden regresar a ver &lt;a href="http://www.javatutoriales.com/2011/06/struts-2-parte-2-ognl.html"&gt;el tutorial correspondiente&lt;/a&gt;... o continuar leyendo este.&lt;br /&gt;&lt;br /&gt;Recuerden que &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; coloca en el "&lt;span class="codigo"&gt;ActionContext&lt;/span&gt;" algunos objetos extra además del objeto raíz, para acceder a estos objetos necesitamos usar un operador especial, el operador "&lt;span class="codigo"&gt;#&lt;/span&gt;", junto con el nombre del objeto al que queremos acceder. En este caso &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; coloca 3 objetos especiales que hacen referencia cada uno a uno a uno de los distintos scopes:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="codigo"&gt;application&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="codigo"&gt;session&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="codigo"&gt;request&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Y como habíamos visto, es posible obtener el valor de los atributos colocados en estos scopes usando el operador punto ("&lt;span class="codigo"&gt;.&lt;/span&gt;") o colocando el nombre del parámetro entre corchetes ("&lt;span class="codigo"&gt;[&lt;/span&gt;" y "&lt;span class="codigo"&gt;]&lt;/span&gt;"). &lt;br /&gt;&lt;br /&gt;En este caso, para mostrar el valor almacenado en el &lt;span class="codigo"&gt;request&lt;/span&gt; debemos hacer:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:property value="#request.datoRequest" /&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Para el resto de los parámetros se hace algo similar. Al final la página queda de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;Request: &amp;lt;s:property value="#request.datoRequest" /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;Sesión: &amp;lt;s:property value="#session.datoSesion" /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;Aplicacion: &amp;lt;s:property value="#application.datoAplicacion" /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Cuando ejecutemos la aplicación y entremos a la siguiente dirección:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&lt;a href="http://localhost:8080/scopes/datosScopesInterfaces.jsp"&gt;http://localhost:8080/scopes/datosScopesInterfaces.jsp&lt;/a&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Debemos ver el formulario que creamos anteriormente. Si colocamos los siguientes datos:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-4ubxaQe5mFA/TvAhD8752II/AAAAAAAABP8/48eMotEUrNY/s1600/S4_2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="283" src="http://3.bp.blogspot.com/-4ubxaQe5mFA/TvAhD8752II/AAAAAAAABP8/48eMotEUrNY/s640/S4_2.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Y presionamos el botón de enviar, veremos la siguiente salida:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-7JCHsi9CW7k/TvAhEVph3CI/AAAAAAAABQE/ZfUxF_kYssc/s1600/S4_3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="283" src="http://3.bp.blogspot.com/-7JCHsi9CW7k/TvAhEVph3CI/AAAAAAAABQE/ZfUxF_kYssc/s640/S4_3.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Ahora, ¿cómo podemos comprobar que cada dato está efectivamente en los scopes indicados? Bueno para esto hay varias formas. Primero, para comprobar el atributo del &lt;span class="codigo"&gt;request&lt;/span&gt; podemos entrar directamente a la página del resultado:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&lt;a href="http://localhost:8080/scopes/resultado.jsp"&gt;http://localhost:8080/scopes/resultado.jsp&lt;/a&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Con esto estamos creando una nueva petición, por lo que el atributo que teníamos anteriormente debería desaparecer:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-ZQrNjmjnfGQ/TvAhEzaxLzI/AAAAAAAABQM/qgcGprrVTLY/s1600/S4_4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="284" src="http://4.bp.blogspot.com/-ZQrNjmjnfGQ/TvAhEzaxLzI/AAAAAAAABQM/qgcGprrVTLY/s640/S4_4.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Para el dato de la &lt;span class="codigo"&gt;sesión&lt;/span&gt;, podemos esperar a que termine nuestra sesión de forma automática (después de 30 minutos), podemos usar otro navegador para entrar a la misma dirección, o simplemente podemos terminar las sesiones activas de nuestro navegador. Con esto los atributos de la sesión deben desaparecer: &lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-mZ9OLFpOYxk/TvAhFY62k4I/AAAAAAAABQU/OBlhJ40Du3U/s1600/S4_5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="516" src="http://3.bp.blogspot.com/-mZ9OLFpOYxk/TvAhFY62k4I/AAAAAAAABQU/OBlhJ40Du3U/s640/S4_5.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Finalmente, y como podemos ver por la imagen anterior del explorer, los atributos del scope aplicación permanecerán hasta que detengamos nuestro servidor (con lo cual, por cierto, ya no podremos entrar al sitio &lt;span class="codigo"&gt;^_^&lt;/span&gt;).&lt;br /&gt;&lt;br /&gt;Como podemos ver, esta forma de establecer (y leer) atributos de los distintos scopes es bastante sencilla pero, como dijimos al inicio del tutorial: no es la única forma. Ahora veremos la segunda forma de hacer esto: usado el objeto "&lt;span class="codigo"&gt;ActionContext&lt;/span&gt;"&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="subtitulo"&gt;Manejo de Atributos de Scope usando ActionContext&lt;/h2&gt;La segunda forma que tenemos de manejar los atributos de los scopes es a través de un objeto especial de &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; llamado "&lt;span class="codigo"&gt;ActionContext&lt;/span&gt;". Este objeto es el contexto en al cual el &lt;span class="codigo"&gt;Action&lt;/span&gt; se ejecuta. Cada contexto es básicamente un contenedor para objetos que un &lt;span class="codigo"&gt;Action&lt;/span&gt; necesita para su ejecución, como la sesión, sus parámetros, etc.&lt;br /&gt;&lt;br /&gt;Dentro de los objetos que se encuentran dentro del "&lt;span class="codigo"&gt;ActionContext&lt;/span&gt;" están justamente los mapas que contienen los atributos de &lt;span class="codigo"&gt;sesion&lt;/span&gt; y &lt;span class="codigo"&gt;aplicación&lt;/span&gt; (así es, no se pueden establecer los atributos de &lt;span class="codigo"&gt;request&lt;/span&gt; usando este objeto), que son los que nos interesan para esta pare del tutorial.&lt;br /&gt;&lt;br /&gt;Obtener una referencia al "&lt;span class="codigo"&gt;ActionContext&lt;/span&gt;" es en realidad muy sencillo ya que, aunque este objeto no es un singleton como tal, lo obtenemos como si fuera uno; veremos esto dentro de un momento, primero crearemos una nueva página que contendrá un formulario como el anterior.&lt;br /&gt;&lt;br /&gt;Creamos una nueva página llamada "&lt;span class="codigo"&gt;datosScopesActionContext.jsp&lt;/span&gt;". Esta página contendrá un formulario parecido al que creamos anteriormente, con la diferencia de que los datos de este serán procesados por un &lt;span class="codigo"&gt;Action&lt;/span&gt; distinto:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:form action="scopesActionContext"&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="datoSesion" label="Sesion" /&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="datosAplicacion" label="Aplicacion" /&amp;gt;&lt;br /&gt;    &amp;lt;s:submit /&amp;gt;&lt;br /&gt;&amp;lt;/s:form&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ahora crearemos, en el paquete "&lt;span class="codigo"&gt;actions&lt;/span&gt;", una nueva clase llamada "&lt;span class="codigo"&gt;ScopesActionContextAction&lt;/span&gt;" que extienda de "&lt;span class="codigo"&gt;ActionSupport&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class ScopesActionContextAction extends ActionSupport&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Esta clase tendrá dos atributos de tipo &lt;span class="codigo"&gt;String&lt;/span&gt;, uno para el dato que irá en sesión y otro para el dato que irá en el scope aplicación, con sus correspondientes &lt;span class="codigo"&gt;setters&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class ScopesActionContextAction extends ActionSupport&lt;br /&gt;{&lt;br /&gt;    private String datoSesion;&lt;br /&gt;    private String datosAplicacion;&lt;br /&gt;&lt;br /&gt;    public void setDatoSesion(String datoSesion)&lt;br /&gt;    {&lt;br /&gt;        this.datoSesion = datoSesion;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setDatosAplicacion(String datosAplicacion)&lt;br /&gt;    {&lt;br /&gt;        this.datosAplicacion = datosAplicacion;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Lo último que esta clase necesita es sobre-escribir su método "&lt;span class="codigo"&gt;execute&lt;/span&gt;" para, haciendo uso del "&lt;span class="codigo"&gt;ActionContext&lt;/span&gt;", establecer los valores en los scopes adecuados.&lt;br /&gt;&lt;br /&gt;Para obtener una instancia del "&lt;span class="codigo"&gt;ActionContext&lt;/span&gt;" se usa el método estático "&lt;span class="codigo"&gt;getContext()&lt;/span&gt;" que nos regresa la instancia de "&lt;span class="codigo"&gt;ActionContext&lt;/span&gt;" adecuada para el &lt;span class="codigo"&gt;Action&lt;/span&gt; que estamos ejecutando:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;ActionContext contexto = ActionContext.getContext();&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Y una vez teniendo una referencia al "&lt;span class="codigo"&gt;ApplicationContext&lt;/span&gt;" lo único que debemos hacer es usar el método "&lt;span class="codigo"&gt;getApplication()&lt;/span&gt;" para obtener un mapa con los atributos del scope &lt;span class="codigo"&gt;application&lt;/span&gt; y "&lt;span class="codigo"&gt;getSession()&lt;/span&gt;" para obtener un mapa con los atributos del scope &lt;span class="codigo"&gt;session&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;Map&amp;lt;String, Object&amp;gt; application = contexto.getApplication();&lt;br /&gt;Map&amp;lt;String, Object&amp;gt; sesion = contexto.getSession();&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;El resto es solo colocar los atributos que recibidos del formulario en los mapas correspondientes:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;application.put("datoAplicacion", datosAplicacion);&lt;br /&gt;sesion.put("datoSesion", datoSesion);&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;El método "&lt;span class="codigo"&gt;execute&lt;/span&gt;" queda de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Override&lt;br /&gt;public String execute() throws Exception&lt;br /&gt;{&lt;br /&gt;    ActionContext contexto = ActionContext.getContext();&lt;br /&gt;        &lt;br /&gt;    Map&amp;lt;String, Object&amp;gt; application = contexto.getApplication();&lt;br /&gt;    Map&amp;lt;String, Object&amp;gt; sesion = contexto.getSession();&lt;br /&gt;        &lt;br /&gt;    application.put("datoAplicacion", datosAplicacion);&lt;br /&gt;    sesion.put("datoSesion", datoSesion);&lt;br /&gt;&lt;br /&gt;    return SUCCESS;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Lo último que falta es anotar nuestro &lt;span class="codigo"&gt;Action&lt;/span&gt; para indicar que responderá al nombre de "&lt;span class="codigo"&gt;scopesActionContext&lt;/span&gt;" y que regresará a la página "&lt;span class="codigo"&gt;/resultado.jsp&lt;/span&gt;" (la cual creamos para el ejemplo anterior así que ahora la reutilizaremos):&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Namespace(value = "/")&lt;br /&gt;@Action(value = "scopesActionContext", results =&lt;br /&gt;{&lt;br /&gt;    @Result(name = "success", location = "/resultado.jsp")&lt;br /&gt;})&lt;br /&gt;public class ScopesActionContextAction extends ActionSupport&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;La clase "&lt;span class="codigo"&gt;ScopesActionContextAction&lt;/span&gt;" completa queda de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Namespace(value = "/")&lt;br /&gt;@Action(value = "scopesActionContext", results ={@Result(name = "success", location = "/resultado.jsp")})&lt;br /&gt;public class ScopesActionContextAction extends ActionSupport&lt;br /&gt;{&lt;br /&gt;    private String datoSesion;&lt;br /&gt;    private String datosAplicacion;&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    public String execute() throws Exception&lt;br /&gt;    {&lt;br /&gt;        ActionContext contexto = ActionContext.getContext();&lt;br /&gt;        &lt;br /&gt;        Map&amp;lt;String, Object&amp;gt; application = contexto.getApplication();&lt;br /&gt;        Map&amp;lt;String, Object&amp;gt; sesion = contexto.getSession();&lt;br /&gt;        &lt;br /&gt;        application.put("datoAplicacion", datosAplicacion);&lt;br /&gt;        sesion.put("datoSesion", datoSesion);&lt;br /&gt;&lt;br /&gt;        return SUCCESS;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setDatoSesion(String datoSesion)&lt;br /&gt;    {&lt;br /&gt;        this.datoSesion = datoSesion;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setDatosAplicacion(String datosAplicacion)&lt;br /&gt;    {&lt;br /&gt;        this.datosAplicacion = datosAplicacion;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ahora que ya tenemos todo listo ejecutamos la aplicación y al entrar a la siguiente dirección:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&lt;a href="http://localhost:8080/scopes/datosScopesActionContext.jsp"&gt;http://localhost:8080/scopes/datosScopesActionContext.jsp&lt;/a&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Debemos ver el siguiente formulario, muy parecido al anterior:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-MOzB6bdpZ60/TvAhF2Z2dXI/AAAAAAAABQc/Ms5ch0ERZD4/s1600/S4_6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="270" src="http://3.bp.blogspot.com/-MOzB6bdpZ60/TvAhF2Z2dXI/AAAAAAAABQc/Ms5ch0ERZD4/s640/S4_6.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Cuando ingresemos algunos valores y demos clic en el botón de enviar, veremos un resultado como el siguiente:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-IOCXVMrumWY/TvAhGXZ7vCI/AAAAAAAABQk/xrMh56eVsas/s1600/S4_7.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="284" src="http://1.bp.blogspot.com/-IOCXVMrumWY/TvAhGXZ7vCI/AAAAAAAABQk/xrMh56eVsas/s640/S4_7.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;El dato del &lt;span class="codigo"&gt;request&lt;/span&gt; queda vacio ya que no lo hemos establecido en esta ocasión.&lt;br /&gt;&lt;br /&gt;Podemos ver que esta segunda forma de establecer los datos es también muy simple de utilizar y da buenos resultados. &lt;br /&gt;&lt;br /&gt;Veremos la tercer y última forma de manejar los atributos de los scopes &lt;span class="codigo"&gt;request&lt;/span&gt;, &lt;span class="codigo"&gt;session&lt;/span&gt; y &lt;span class="codigo"&gt;application&lt;/span&gt;. Debo decir que esta tercer forma no es recomendable ya que rompe con el esquema de trabajo de &lt;span class="codigo"&gt;Struts 2&lt;/span&gt;, el cual oculta detalles de la especificación de &lt;span class="codigo"&gt;Servlets&lt;/span&gt;, pero eso lo veremos en un momento.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3 class="subtitulo"&gt;Manejo de Atributos de Scope usando ServletActionContext&lt;/h3&gt;Con esta última forma tendremos acceso directo a los objetos "&lt;span class="codigo"&gt;HttpServletRequest&lt;/span&gt;" y "&lt;span class="codigo"&gt;ServletContext&lt;/span&gt;", de la especificación de &lt;span class="codigo"&gt;Servlet&lt;/span&gt;s; haciendo uso de otro objeto especial de &lt;span class="codigo"&gt;Struts 2&lt;/span&gt;: "&lt;span class="codigo"&gt;ServletActionContext&lt;/span&gt;".&lt;br /&gt;&lt;br /&gt;Este objeto especial "&lt;span class="codigo"&gt;ServletActionContext&lt;/span&gt;" contiene una serie de métodos estáticos que nos dan acceso a otros objetos de utilidad (entre ellos "&lt;span class="codigo"&gt;ActionContext&lt;/span&gt;"). Los métodos que en este momento nos interesan son: "&lt;span class="codigo"&gt;getRequest&lt;/span&gt;", con el que podemos obtener el objeto "&lt;span class="codigo"&gt;HttpServletRequest&lt;/span&gt;" (desde el cual tenemos además acceso a la sesión) asociado con la petición que el &lt;span class="codigo"&gt;Action&lt;/span&gt; está sirviendo, y "&lt;span class="codigo"&gt;getServletContext&lt;/span&gt;", que nos regresa el objeto "&lt;span class="codigo"&gt;ServletContext&lt;/span&gt;" que representa el contexto de la aplicación web.&lt;br /&gt;&lt;br /&gt;El uso de estos dos métodos es muy directo y lo veremos en un momento, pero primero crearemos una nueva página &lt;span class="codigo"&gt;JSP&lt;/span&gt; que contendrá el formulario, como los anteriores, que nos permitirá introducir los datos que se agregarán como atributos de cada uno de los scopes. Esta página se llamará "&lt;span class="codigo"&gt;datosScopesServletActionContext.jsp&lt;/span&gt;" y contendrá un formulario como el primero que creamos con la diferencia de los datos de este formulario serán procesados por otro &lt;span class="codigo"&gt;Action&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:form action="scopesServletActionContext"&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="datoSesion" label="Sesion" /&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="datoRequest" label="Request" /&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="datosAplicacion" label="Aplicacion" /&amp;gt;&lt;br /&gt;    &amp;lt;s:submit /&amp;gt;&lt;br /&gt;&amp;lt;/s:form&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ahora creamos, en el paquete "&lt;span class="codigo"&gt;actions&lt;/span&gt;", una nueva clase llamada "&lt;span class="codigo"&gt;ScopesServletActionContextAction&lt;/span&gt;" que extienda de "&lt;span class="codigo"&gt;ActionSupport&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class ScopesServletActionContextAction extends ActionSupport&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Esta clase tendrá tres atributos de tipo &lt;span class="codigo"&gt;String&lt;/span&gt;, con sus correspondientes &lt;span class="codigo"&gt;setters&lt;/span&gt;, uno para cada valor que recibimos del formulario:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class ScopesServletActionContextAction extends ActionSupport&lt;br /&gt;{&lt;br /&gt;    private String datoSesion;&lt;br /&gt;    private String datoRequest;&lt;br /&gt;    private String datosAplicacion;&lt;br /&gt;&lt;br /&gt;    public void setDatoRequest(String datoRequest)&lt;br /&gt;    {&lt;br /&gt;        this.datoRequest = datoRequest;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setDatoSesion(String datoSesion)&lt;br /&gt;    {&lt;br /&gt;        this.datoSesion = datoSesion;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setDatosAplicacion(String datosAplicacion)&lt;br /&gt;    {&lt;br /&gt;        this.datosAplicacion = datosAplicacion;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ahora sobre-escribiremos el método "&lt;span class="codigo"&gt;execute&lt;/span&gt;" para, haciendo uso de los métodos estáticos de la clase "&lt;span class="codigo"&gt;ServletActionContext&lt;/span&gt;", obtener referencias al "&lt;span class="codigo"&gt;HttpServletRequest&lt;/span&gt;" y al "&lt;span class="codigo"&gt;ServletContext&lt;/span&gt;". Como había dicho "&lt;span class="codigo"&gt;ServletActionContext&lt;/span&gt;" nos proporciona métodos estáticos que nos regresan estas referencias de forma directa, por lo que lo único que tenemos que hacer es invocarlos:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;HttpServletRequest request = ServletActionContext.getRequest();&lt;br /&gt;ServletContext context = ServletActionContext.getServletContext();&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;La sesión (el objeto "&lt;span class="codigo"&gt;HttpSession&lt;/span&gt;") se obtiene usando el método "&lt;span class="codigo"&gt;getSession()&lt;/span&gt;" del objeto "&lt;span class="codigo"&gt;request&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;HttpSession sesion = request.getSession();&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Y ya con estas referencias podemos obtener los atributos de los scopes correspondientes como lo hacemos cuando trabajamos directamente con &lt;span class="codigo"&gt;Servlet&lt;/span&gt;s: usando el método "&lt;span class="codigo"&gt;setAttribute&lt;/span&gt;" de cada uno de los objetos:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;request.setAttribute("datoRequest", datoRequest);&lt;br /&gt;sesion.setAttribute("datoSesion", datoSesion);&lt;br /&gt;context.setAttribute("datoAplicacion", datosAplicacion);&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Y eso es todo lo que hay que hacer. El método "&lt;span class="codigo"&gt;execute&lt;/span&gt;" queda de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Override&lt;br /&gt;public String execute() throws Exception&lt;br /&gt;{&lt;br /&gt;    HttpServletRequest request = ServletActionContext.getRequest();&lt;br /&gt;    ServletContext context = ServletActionContext.getServletContext();&lt;br /&gt;    HttpSession sesion = request.getSession();&lt;br /&gt;        &lt;br /&gt;    request.setAttribute("datoRequest", datoRequest);&lt;br /&gt;    sesion.setAttribute("datoSesion", datoSesion);&lt;br /&gt;    context.setAttribute("datoAplicacion", datosAplicacion);&lt;br /&gt;        &lt;br /&gt;    return SUCCESS;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Lo único que resta hacer es colocar las anotaciones para indicar que esta clase será un &lt;span class="codigo"&gt;Action&lt;/span&gt;. Al igual que en los casos anteriores, reutilizaremos la página "&lt;span class="codigo"&gt;resultados.jsp&lt;/span&gt;". Como ya conocemos estas anotaciones de memoria, solo mostraré como queda finalmente la clase "&lt;span class="codigo"&gt;ScopesServletActionContextAction&lt;/span&gt;"&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Namespace(value = "")&lt;br /&gt;@Action(value = "scopesServletActionContext", results ={@Result(name = "success", location = "/resultado.jsp")})&lt;br /&gt;public class ScopesServletActionContextAction extends ActionSupport&lt;br /&gt;{&lt;br /&gt;    private String datoSesion;&lt;br /&gt;    private String datoRequest;&lt;br /&gt;    private String datosAplicacion;&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    public String execute() throws Exception&lt;br /&gt;    {&lt;br /&gt;        HttpServletRequest request = ServletActionContext.getRequest();&lt;br /&gt;        ServletContext context =   ServletActionContext.getServletContext();&lt;br /&gt;        HttpSession sesion = request.getSession();&lt;br /&gt;        &lt;br /&gt;        request.setAttribute("datoRequest", datoRequest);&lt;br /&gt;        sesion.setAttribute("datoSesion", datoSesion);&lt;br /&gt;        context.setAttribute("datoAplicacion", datosAplicacion);&lt;br /&gt;        &lt;br /&gt;        return SUCCESS;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;br /&gt;    &lt;br /&gt;    public void setDatoRequest(String datoRequest)&lt;br /&gt;    {&lt;br /&gt;        this.datoRequest = datoRequest;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setDatoSesion(String datoSesion)&lt;br /&gt;    {&lt;br /&gt;        this.datoSesion = datoSesion;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setDatosAplicacion(String datosAplicacion)&lt;br /&gt;    {&lt;br /&gt;        this.datosAplicacion = datosAplicacion;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Cuando ejecutemos nuestra aplicación y entremos a la siguiente dirección:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&lt;a href="http://localhost:8080/scopes/datosScopesServletActionContext.jsp"&gt;http://localhost:8080/scopes/datosScopesServletActionContext.jsp&lt;/a&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Debemos ver el mismo formulario que en el primer ejemplo:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-359fLIYbBqU/TvAhHB8pD-I/AAAAAAAABQs/nhjLs8-jbsk/s1600/S4_8.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="258" src="http://2.bp.blogspot.com/-359fLIYbBqU/TvAhHB8pD-I/AAAAAAAABQs/nhjLs8-jbsk/s640/S4_8.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Al rellenar los campos con algunos datos y enviar el formulario debemos ver el siguiente resultado:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-RB-79KGatws/TvAhHtPHflI/AAAAAAAABQ0/9BCDgaj_l1E/s1600/S4_9.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="258" src="http://1.bp.blogspot.com/-RB-79KGatws/TvAhHtPHflI/AAAAAAAABQ0/9BCDgaj_l1E/s640/S4_9.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Como podemos ver esta tercer forma abarca en realidad los dos temas del tutorial, establecer valores en los scopes de la aplicación web y obtener los objetos "&lt;span class="codigo"&gt;HttpServletRequest&lt;/span&gt;" y "&lt;span class="codigo"&gt;ServletContext&lt;/span&gt;", así que a continuación veremos la segunda forma de obtener estos objetos:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="titulo"&gt;Obtención de Objetos "&lt;span class="codigo"&gt;HttpServletRequest&lt;/span&gt;" y "&lt;span class="codigo"&gt;ServletContext&lt;/span&gt;"&lt;/h2&gt;&lt;br /&gt;&lt;h3 class="subtitulo"&gt;Obtención de Objetos de Servlet usando interfaces Aware&lt;/h3&gt;En la primer parte del tutorial vimos cómo trabajan las interfaces &lt;span class="codigo"&gt;Aware&lt;/span&gt;, y en el ejemplo anterior vimos cómo tener acceso directo a los objetos de la especificación de &lt;span class="codigo"&gt;Servlet&lt;/span&gt;s. Así que en este último ejemplo veremos una forma de obtener estos objetos, usando las interfaces &lt;span class="codigo"&gt;Aware&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Para no perder la costumbre de este tutorial, lo primero que haremos es crear una nueva &lt;span class="codigo"&gt;JSP&lt;/span&gt; llamada "&lt;span class="codigo"&gt;datosServletsInterfaces.jsp&lt;/span&gt;" que contendrá el formulario que también ya debemos conocer de memoria ^_^, en donde, nuevamente, lo único que cambiará es el valor del atributo "&lt;span class="codigo"&gt;action&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:form action="datosInterfaces"&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="datoSesion" label="Sesion" /&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="datoRequest" label="Request" /&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="datosAplicacion" label="Aplicacion" /&amp;gt;&lt;br /&gt;    &amp;lt;s:submit /&amp;gt;&lt;br /&gt;&amp;lt;/s:form&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ahora crearemos una nueva clase llamada "&lt;span class="codigo"&gt;ObjetosServletAction&lt;/span&gt;", en el paquete "&lt;span class="codigo"&gt;actions&lt;/span&gt;". Esta clase deberá extender "&lt;span class="codigo"&gt;ActionSupport&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class ObjetosServletAction extends ActionSupport&lt;br /&gt;{   &lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="codigo"&gt;Struts 2&lt;/span&gt; permite obtener una referencia al objeto "&lt;span class="codigo"&gt;HttpServletRequest&lt;/span&gt;", que representa la petición actual que está siendo atendida por el &lt;span class="codigo"&gt;Action&lt;/span&gt;, y al objeto "&lt;span class="codigo"&gt;ServletContext&lt;/span&gt;", que representa el contexto de la aplicación web, implementando las interfaces "&lt;span class="codigo"&gt;ServletRequestAware&lt;/span&gt;" y "&lt;span class="codigo"&gt;ServletContextAware&lt;/span&gt;" respectivamente.&lt;br /&gt;&lt;br /&gt;Ambas interfaces son igual de sencillas que sus contrapartes para los atributos de los scopes. La interface "&lt;span class="codigo"&gt;ServletContextAware&lt;/span&gt;" luce de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;interface ServletContextAware&lt;br /&gt;{  &lt;br /&gt;    public void setServletContext(ServletContext sc);&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Y la interface "&lt;span class="codigo"&gt;ServletRequestAware&lt;/span&gt;" se ve así:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;interface ServletRequestAware&lt;br /&gt;{&lt;br /&gt;    public void setServletRequest(HttpServletRequest hsr);&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Como podemos ver, ambas interfaces tienen tan solo un método que debemos implementar, y que reciben el objeto adecuado perteneciente a la especificación de &lt;span class="codigo"&gt;Servlet&lt;/span&gt;s (en vez de algún objeto propio de &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; o algún objeto genérico, como estamos acostumbrados al trabajar con este framework), por lo que al implementar estos métodos ya tenemos una referencia directa a estos objetos sin tener que hacer ningún otro proceso, conversión, o invocación.&lt;br /&gt;&lt;br /&gt;Junto con la implementación de estas interfaces proporcionaremos un par de atributos, uno de tipo "&lt;span class="codigo"&gt;ServletContext&lt;/span&gt;" y uno de tipo "&lt;span class="codigo"&gt;HttpServletRequest&lt;/span&gt;", para almacenar los valores recibidos con la implementación.&lt;br /&gt;&lt;br /&gt;Así que lo primero que hacemos entonces es declarar que nuestra clase "&lt;span class="codigo"&gt;ObjetosServletAction&lt;/span&gt;" implementará las interfaces "&lt;span class="codigo"&gt;ServletContextAware&lt;/span&gt;" y "&lt;span class="codigo"&gt;ServletRequestAware&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class ObjetosServletAction extends ActionSupport implements ServletContextAware, ServletRequestAware&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ahora colocaremos los atributos (sin &lt;span class="codigo"&gt;getters&lt;/span&gt; ni &lt;span class="codigo"&gt;setters&lt;/span&gt;) para almacenar las referencias recibidas por los métodos de las interfaces anteriores:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;private ServletContext application;&lt;br /&gt;private HttpServletRequest request;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Lo siguiente es proporcionar la implementación de las interfaces, en los cuales almacenaremos las referencias recibidas por estas, en los atributos que hemos colocado en nuestra clase:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public void setServletContext(ServletContext sc)&lt;br /&gt;{&lt;br /&gt;    this.application = sc;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setServletRequest(HttpServletRequest hsr)&lt;br /&gt;{&lt;br /&gt;    this.request = hsr;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ahora que ya tenemos las referencias que nos interesaban agregaremos los tres atributos, junto con sus &lt;span class="codigo"&gt;setters&lt;/span&gt;, que nos permitirán recibir los parámetros provenientes del formulario:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;private String datoSesion;&lt;br /&gt;private String datoRequest;&lt;br /&gt;private String datosAplicacion;&lt;br /&gt;&lt;br /&gt;public void setDatoRequest(String datoRequest)&lt;br /&gt;{&lt;br /&gt;    this.datoRequest = datoRequest;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setDatoSesion(String datoSesion)&lt;br /&gt;{&lt;br /&gt;    this.datoSesion = datoSesion;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setDatosAplicacion(String datosAplicacion)&lt;br /&gt;{&lt;br /&gt;    this.datosAplicacion = datosAplicacion;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;El siguiente paso es sobre-escribir el método "&lt;span class="codigo"&gt;execute&lt;/span&gt;" para establecer los valores de los atributos en cada uno de los scopes. Primero obtendremos el objeto "&lt;span class="codigo"&gt;HttpSession&lt;/span&gt;" usando el "&lt;span class="codigo"&gt;HttpServletRequest&lt;/span&gt;", como en el ejemplo anterior, para posteriormente poder establecer los atributos en los scopes usando los objetos apropiados:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Override&lt;br /&gt;public String execute() throws Exception&lt;br /&gt;{&lt;br /&gt;    HttpSession sesion = request.getSession();&lt;br /&gt;        &lt;br /&gt;    application.setAttribute("datoAplicacion", datosAplicacion);&lt;br /&gt;    sesion.setAttribute("datoSesion", datoSesion);&lt;br /&gt;    request.setAttribute("datoRequest", datoRequest);&lt;br /&gt;        &lt;br /&gt;    return SUCCESS;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Como ven, la lógica del método es tan sencilla como en todo el tutorial.&lt;br /&gt;&lt;br /&gt;El último paso es anotar esta clase para indicarle a &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; que se trata de un &lt;span class="codigo"&gt;Action&lt;/span&gt;. Una vez más reutilizaremos la página "&lt;span class="codigo"&gt;resultado.jsp&lt;/span&gt;" para mostrar los resultados de la ejecución del &lt;span class="codigo"&gt;Action&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Namespace(value = "")&lt;br /&gt;@Action(value = "datosInterfaces", results ={@Result(name = "success", location = "/resultado.jsp")})&lt;br /&gt;public class ObjetosServletAction extends ActionSupport implements ServletRequestAware, ServletContextAware&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Al final la clase "&lt;span class="codigo"&gt;ObjetosServletAction&lt;/span&gt;" queda de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Namespace(value = "")&lt;br /&gt;@Action(value = "datosInterfaces", results ={@Result(name = "success", location = "/resultado.jsp")})&lt;br /&gt;public class ObjetosServletAction extends ActionSupport implements ServletRequestAware, ServletContextAware&lt;br /&gt;{&lt;br /&gt;    private ServletContext application;&lt;br /&gt;    private HttpServletRequest request;&lt;br /&gt;    private String datoSesion;&lt;br /&gt;    private String datoRequest;&lt;br /&gt;    private String datosAplicacion;&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    public String execute() throws Exception&lt;br /&gt;    {&lt;br /&gt;        HttpSession sesion = request.getSession();&lt;br /&gt;        &lt;br /&gt;        application.setAttribute("datoAplicacion", datosAplicacion);&lt;br /&gt;        sesion.setAttribute("datoSesion", datoSesion);&lt;br /&gt;        request.setAttribute("datoRequest", datoRequest);&lt;br /&gt;        &lt;br /&gt;        return SUCCESS;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    public void setServletContext(ServletContext sc)&lt;br /&gt;    {&lt;br /&gt;        this.application = sc;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setServletRequest(HttpServletRequest hsr)&lt;br /&gt;    {&lt;br /&gt;        this.request = hsr;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setDatoRequest(String datoRequest)&lt;br /&gt;    {&lt;br /&gt;        this.datoRequest = datoRequest;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setDatoSesion(String datoSesion)&lt;br /&gt;    {&lt;br /&gt;        this.datoSesion = datoSesion;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setDatosAplicacion(String datosAplicacion)&lt;br /&gt;    {&lt;br /&gt;        this.datosAplicacion = datosAplicacion;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Cuando ejecutemos la aplicación y entremos a la siguiente dirección:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&lt;a href="http://localhost:8080/scopes/datosServletsInterfaces.jsp"&gt;http://localhost:8080/scopes/datosServletsInterfaces.jsp&lt;/a&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Debemos ver el formulario al que ahora ya debemos estar acostumbrados &lt;span class="codigo"&gt;^_^!&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-BNdCB4hGWAA/TvAhIJHDISI/AAAAAAAABQ8/XGCcbo9PwLQ/s1600/S4_10.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="270" src="http://3.bp.blogspot.com/-BNdCB4hGWAA/TvAhIJHDISI/AAAAAAAABQ8/XGCcbo9PwLQ/s640/S4_10.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Y, nuevamente, al ingresar algunos datos y presionar el botón enviar debemos ver la siguiente salida:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-syLoyfCluMg/TvAhIkmsffI/AAAAAAAABRE/MzV3E7Kd9gw/s1600/S4_11.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="270" src="http://4.bp.blogspot.com/-syLoyfCluMg/TvAhIkmsffI/AAAAAAAABRE/MzV3E7Kd9gw/s640/S4_11.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Como podemos ver, una vez más todo ha funcionado correctamente.&lt;br /&gt;&lt;br /&gt;Algunos se preguntarán ¿para qué queremos tener acceso a estos objetos si &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; se encarga de manejar todos los aspectos relacionados con &lt;span class="codigo"&gt;Servlet&lt;/span&gt;s por nosotros? Bueno me alegra que hagan esa pregunta &lt;span class="codigo"&gt;^_^&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;En realidad esto tiene varios usos, los dos más utilizados que se me ocurren en este momento es el poder obtener la ubicación absoluta de un recurso (un archivo o algún otro elemento) que se encuentra en nuestra aplicación y que por lo tanto no sabemos en qué directorio del disco duro está. Para esto se necesita el método "&lt;span class="codigo"&gt;getRealPath&lt;/span&gt;" del objeto "&lt;span class="codigo"&gt;ServletContext&lt;/span&gt;" de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;application.getRealPath("/recurso.ext");&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;El segundo y más común uso es para invalidar una sesión. &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; no nos da directamente una manera para invalidar la sesión de un usuario de nuestra aplicación web, así que para esto es necesario tener objeto al objeto "&lt;span class="codigo"&gt;HttpSession&lt;/span&gt;", y para esto al objeto "&lt;span class="codigo"&gt;HttpServletRequest&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;request.getSession().invalidate();&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Así que, como podemos ver, algunas veces es útil tener acceso a los objetos de la específicación de &lt;span class="codigo"&gt;Servlet&lt;/span&gt;s cuando el framework que estamos usando no nos pueda, por la razón que sea, darnos todas las facilidades que necesitemos para hacer algunas cosas específicas.&lt;br /&gt;&lt;br /&gt;Esto es todo para este tutorial, espero que les sea de utilidad. En el siguiente tutorial de la serie de &lt;span class="codigo"&gt;Struts 2&lt;/span&gt;, veremos los tipos de &lt;span class="codigo"&gt;results&lt;/span&gt; que vienen incluidos con &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; y para que pueden servirnos.&lt;br /&gt;&lt;br /&gt;No olviden dejar cualquier duda, comentario, o sugerencia que puedan tener.&lt;br /&gt;&lt;br /&gt;Saludos.&lt;br /&gt;&lt;br /&gt;&lt;span class="negritas"&gt;Descarga los archivos de  este tutorial desde aquí:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://sites.google.com/site/javatutoriales/struts2/ScopesDeObjetosWeb.zip?attredirects=0&amp;d=1"&gt;&lt;span class="ligaArchivo"&gt;ScopesDeObjetosWeb&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="negritas"&gt;Entradas Relacionadas:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.javatutoriales.com/2011/06/struts-2-parte-1-configuracion.html"&gt;Parte 1: Configuración&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.javatutoriales.com/2011/06/struts-2-parte-2-ognl.html"&gt;Parte 2: OGNL&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.javatutoriales.com/2011/10/struts-2-parte-3-trabajo-con.html"&gt;Parte 3: Trabajo con Formularios&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2012232069289957092-3413005603812408821?l=www.javatutoriales.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.javatutoriales.com/feeds/3413005603812408821/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.javatutoriales.com/2011/12/struts-2-parte-4-scopes-de-objetos-web.html#comment-form' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2012232069289957092/posts/default/3413005603812408821'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2012232069289957092/posts/default/3413005603812408821'/><link rel='alternate' type='text/html' href='http://www.javatutoriales.com/2011/12/struts-2-parte-4-scopes-de-objetos-web.html' title='Struts 2 - Parte 4: Scopes de Objetos Web'/><author><name>Alex</name><uri>http://www.blogger.com/profile/06974037481671868076</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-DSHLyhOfAuk/TvAhDjfsqBI/AAAAAAAABP0/fUCWhGul2h4/s72-c/S4_1.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2012232069289957092.post-1653317982061534085</id><published>2011-11-05T20:29:00.000-07:00</published><updated>2011-11-05T20:29:50.336-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='orientacion a objetos'/><category scheme='http://www.blogger.com/atom/ns#' term='scjp'/><category scheme='http://www.blogger.com/atom/ns#' term='certificacion'/><title type='text'>Sun Certified Java Programmer 6, CX-310-065 - Parte 2: Orientación a Objetos</title><content type='html'>&lt;div style="text-align: justify;"&gt;En este segundo post para la certificación de Java 6 hablaremos sobre conceptos de la orientación a objetos, que abarca temas como la herencia, el polimorfismo, la cohesión, bajo acoplamiento (loose coupling), etc.&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;Empezaremos hablando sobre la encapsulación:&lt;br /&gt;&lt;br /&gt;&lt;h2 class="titulo"&gt;Encapsulación&lt;/h2&gt;&lt;br /&gt;La encapsulación es un mecanismo que nos permite que, aunque nuestras clases utilicen muchas variables y métodos para su correcto funcionamiento, no todas sean visibles desde el exterior. O sea que solo exponemos lo que los clientes necesitan para poder hacer uso de los objetos de nuestra clase.&lt;br /&gt;&lt;br /&gt;Para entender mejor este concepto imaginemos el siguiente escenario:&lt;br /&gt;&lt;br /&gt;Tenemos la siguiente clase:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class Examen&lt;br /&gt;{&lt;br /&gt;    public String pregunta1;&lt;br /&gt;&lt;br /&gt;    public static void main(String... args)&lt;br /&gt;    {&lt;br /&gt;        Examen examen = new Examen();&lt;br /&gt;        examen.pregunta1 = "¿Que es Java?"; // Legal pero no recomendable&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;El ejemplo anterior compilará y se ejecutará de forma correcta. Sin embargo &lt;span class="negritas"&gt;no es recomendable que los atributos de la clase (las variables de instancia) estén expuestas de forma que los clientes puedan leer y escribir sus valores directamente&lt;/span&gt;. De esta forma cualquiera podría colocar el valor que quisiera en la variable "&lt;span class="codigo"&gt;pregunta1&lt;/span&gt;", aún valores que nuestra aplicación no puede o no está preparada para manejar.&lt;br /&gt;&lt;br /&gt;Ahora hagamos una pregunta: ¿Cómo poder cambiar la clase cuando alguien cambia el valor de "&lt;span class="codigo"&gt;pregunta1&lt;/span&gt;" por un valor incorrecto? La única forma es volver a la clase e implementar un método de sólo escritura (un método setter: "&lt;span class="codigo"&gt;setPregunta1(String pregunta1)&lt;/span&gt;") y ocultar la variable "&lt;span class="codigo"&gt;pregunta1&lt;/span&gt;" estableciéndola como privada, pero de esta manera al no establecerla desde un principio con los métodos "&lt;span class="codigo"&gt;set&lt;/span&gt;" o "&lt;span class="codigo"&gt;get&lt;/span&gt;" todas las personas que han utilizado este código anteriormente y de la manera en la que estaba implementada se encontraran perdidas.&lt;br /&gt;&lt;br /&gt;La capacidad de realizar cambios en el código de aplicación sin romper el código de otras personas que utilizan este código es un beneficio clave de la encapsulación. &lt;span class="negritas"&gt;Ocultando los detalles de la implementación a través de métodos de acceso nos brinda la ventaja de poder rehacer el código dentro de los métodos sin forzar a las demás personas a cambios, ya que ellas usan dichos métodos de acceso&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Con todo esto obtenemos las dos promesas/beneficios de la programación orientada a objetos: Flexibilidad y Mantenimiento, pero como vemos estos dos beneficios no llegan solos, nosotros tenemos que implementar nuestro código de manera que brinde y soporte estos beneficios.&lt;br /&gt;&lt;br /&gt;Estas son algunas recomendaciones para lograr la encapsulación:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Mantener las variables de instancia protegidas (mayormente con el modificador de acceso private).&lt;/li&gt;&lt;li&gt;Mantener publicos los métodos de acceso a las variables de instancia (modificador de acceso public), así forzamos a llamar a las variables de instancia y a la implementación del mismo a través de estos métodos en lugar de ir directamente por las variables de instancia.&lt;/li&gt;&lt;li&gt;Para los métodos de acceso se recomienda usar las reglas de las convenciones de nombres de &lt;span class="codigo"&gt;JavaBean&lt;/span&gt;: &lt;span class="codigo"&gt;set&amp;lt;nombrePropiedad&amp;gt;&lt;/span&gt; y &lt;span class="codigo"&gt;get&amp;lt;nombrePropiedad&amp;gt;&lt;/span&gt;, de las cuales se habló en el post anterior.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;A continuación mostramos un ejemplo más práctico de lo que nos estamos refiriendo:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-jyAuA-c6p7g/TrX5FWxHpXI/AAAAAAAABO4/UgvkUZ1IGWg/s1600/C2_1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-jyAuA-c6p7g/TrX5FWxHpXI/AAAAAAAABO4/UgvkUZ1IGWg/s1600/C2_1.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;La clase "&lt;span class="codigo"&gt;A&lt;/span&gt;" no puede acceder a las variables de instancia de la Clase "&lt;span class="codigo"&gt;B&lt;/span&gt;" sin antes ir a los métodos de acceso ("&lt;span class="codigo"&gt;set&lt;/span&gt;" y "&lt;span class="codigo"&gt;get&lt;/span&gt;") de dichas variables, las variables de instancia son marcadas privadas y los métodos de acceso son públicos.&lt;br /&gt;&lt;br /&gt;Debemos tener presente que el código de estos métodos no solo se utiliza para devolver o establecer los valores de las variables de instancia, también se puede establecer lógica o implementación de muchas más cosas o reglas que queramos definir, por ejemplo:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public void setTamanio(int tamanio)&lt;br /&gt;{&lt;br /&gt;    this.tamanio = tamanio * 0.10;&lt;br /&gt;    this.color = "negro";&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;El encapsulamiento es uno de los mecanismos que nos proporciona la orientación a objetos para poder darle una funcionalidad rica a nuestras clases sin que las personas que las utilicen sepan los detalles exactos de cómo está implementada dicha funcionalidad.&lt;br /&gt;&lt;br /&gt;Sin embargo, este no es el único mecanismo proporcionado por la orientación a objetos. A continuación veremos otro de ellos. La herencia.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="titulo"&gt;Herencia, ES–UN, TIENE–UN (IS–A, HAS-A)&lt;/h2&gt;&lt;br /&gt;En Java, la herencia se encuentra en todos. Es seguro decir que en Java casi nada se puede hacer sin hacer uso de la herencia. Para dar un ejemplo a continuación usaremos del operador "&lt;span class="codigo"&gt;instanceof&lt;/span&gt;" (por ahora no ahondaremos mucho en la explicación del uso de este operador ya que se tocará más adelante con mayor detalle, sólo cabe recordar ahora que este operador devuelve un "&lt;span class="codigo"&gt;true&lt;/span&gt;" si la variable puesta al principio es del tipo de la variable con la que se está comparando):&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class Test&lt;br /&gt;{&lt;br /&gt;    public static void main(String... args)&lt;br /&gt;    {&lt;br /&gt;        Test t1 = new Test();&lt;br /&gt;        Test t2 = new Test();&lt;br /&gt;        &lt;br /&gt;        if(!t1.equals(t2))&lt;br /&gt;        {&lt;br /&gt;            System.out.println("&lt;span class="codigo"&gt;No son iguales&lt;/span&gt;")&lt;br /&gt;        }&lt;br /&gt;        if(t1 instanceof  Object)&lt;br /&gt;        {&lt;br /&gt;            System.out.println("&lt;span class="codigo"&gt;t1 es un objeto&lt;/span&gt;");&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;¿De dónde saca "&lt;span class="codigo"&gt;t1&lt;/span&gt;" el método "&lt;span class="codigo"&gt;equals&lt;/span&gt;"? Si no hemos implementado ningún método dentro de la clase con ese nombre, ¿o sí? Por otro lado se pregunta si "&lt;span class="codigo"&gt;t1&lt;/span&gt;" es una instancia de la clase "&lt;span class="codigo"&gt;Object&lt;/span&gt;" y de ser así, la condición &lt;span class="codigo"&gt;if&lt;/span&gt; será exitosa.&lt;br /&gt;&lt;br /&gt;¿Cómo puede ser "&lt;span class="codigo"&gt;t1&lt;/span&gt;" del tipo "&lt;span class="codigo"&gt;Object&lt;/span&gt;" si solo lo declaramos que sea del tipo de la clase "&lt;span class="codigo"&gt;Test&lt;/span&gt;"? Esto ocurre porque todas las clases en java (las que ya están escritas, las que escribimos y las que escribiremos) son una subclase de la clase "&lt;span class="codigo"&gt;Object&lt;/span&gt;" (excepto por supuesto la clase "&lt;span class="codigo"&gt;Object&lt;/span&gt;" misma)  y siempre tendrán métodos como "&lt;span class="codigo"&gt;equals&lt;/span&gt;", "&lt;span class="codigo"&gt;clone&lt;/span&gt;", "&lt;span class="codigo"&gt;notify&lt;/span&gt;", "&lt;span class="codigo"&gt;wait&lt;/span&gt;" y otros más. Siempre que creamos una clase, esta hereda todos los métodos de la clase "&lt;span class="codigo"&gt;Object&lt;/span&gt;".&lt;br /&gt;&lt;br /&gt;El método "&lt;span class="codigo"&gt;equals&lt;/span&gt;" por ejemplo: Los creadores de Java asumieron correctamente que nosotros comúnmente desearíamos comparar instancias de las clases para comprobar la igualdad; si la clase "&lt;span class="codigo"&gt;Object&lt;/span&gt;" no tuviera un método "&lt;span class="codigo"&gt;equals&lt;/span&gt;" tendríamos que implementar nosotros mismos un método para este propósito.&lt;br /&gt;&lt;br /&gt;También debemos recordar que las 2 razones más importantes para el uso de la herencia son:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Reutilización de código&lt;/li&gt;&lt;li&gt;Uso del polimorfismo&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Empecemos con la reutilización. Un enfoque de diseño común es crear una versión de una clase bastante  genérica y después crear subclases muy especializadas que hereden de esta, por ejemplo:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class Animal&lt;br /&gt;{&lt;br /&gt;    public void muevete()&lt;br /&gt;    {&lt;br /&gt;        System.out.println("Me estoy moviendo");&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;public class Perro extends Animal&lt;br /&gt;{&lt;br /&gt;    public void ladra()&lt;br /&gt;    {&lt;br /&gt;        System.out.println("Estoy ladrando");&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class PruebaAnimal&lt;br /&gt;{&lt;br /&gt;    public static void main(String... args)&lt;br /&gt;    {&lt;br /&gt;        Perro perro = new Perro();&lt;br /&gt;        perro.muevete();&lt;br /&gt;        perro.ladra();&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;La salida del código anterior seria:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;Me estoy moviendo&lt;br /&gt;Estoy ladrando&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Como podemos ver, la clase "&lt;span class="codigo"&gt;Perro&lt;/span&gt;" está heredando el método "&lt;span class="codigo"&gt;muevete&lt;/span&gt;" de la clase "&lt;span class="codigo"&gt;Animal&lt;/span&gt;" y que también tiene su propio método agregado, en este caso es el método "&lt;span class="codigo"&gt;ladra&lt;/span&gt;". Aquí se está haciendo uso de  la reusabilidad al utilizar un método genérico de una clase padre que en este caso es el método "&lt;span class="codigo"&gt;muevete&lt;/span&gt;", con esto podemos crear diferentes tipos de animales y todos van a poder utilizar el método "&lt;span class="codigo"&gt;muevete&lt;/span&gt;" sin necesidad de implementarlo ellos mismos.&lt;br /&gt;&lt;br /&gt;El segundo objetivo de la herencia es poder acceder a las clases polimórficamente. Imaginemos este escenario: digamos que tenemos una clase llamada "&lt;span class="codigo"&gt;Entrenador&lt;/span&gt;" que quiere recorrer todos los diferentes tipos de animal e invocar al método "&lt;span class="codigo"&gt;muévete&lt;/span&gt;" en cada uno de ellos, al momento de escribir la clase "&lt;span class="codigo"&gt;Entrenador&lt;/span&gt;" no sabemos cuántas clases de "&lt;span class="codigo"&gt;Animal&lt;/span&gt;" podría haber  y seguro no vamos a querer cambiar el código sólo porque a alguien se le ocurrió crear un nuevo tipo de &lt;span class="codigo"&gt;Animal&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Lo bonito del polimorfismo es que podemos tratar cualquier tipo de "&lt;span class="codigo"&gt;Animal&lt;/span&gt;" como un "&lt;span class="codigo"&gt;Animal&lt;/span&gt;", en otras palabras podemos decir lo siguiente: No me importa qué tipo de &lt;span class="codigo"&gt;Animal&lt;/span&gt; se pueda crear, siempre y cuando extienda (herede) de &lt;span class="codigo"&gt;Animal&lt;/span&gt; todos van a poder moverse (método "&lt;span class="codigo"&gt;muevete&lt;/span&gt;").&lt;br /&gt;&lt;br /&gt;Ahora miremos esto con un ejemplo:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class Animal&lt;br /&gt;{&lt;br /&gt;    public void muevete()&lt;br /&gt;    {&lt;br /&gt;        System.out.println("Me estoy moviendo");&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class Perro extends Animal&lt;br /&gt;{&lt;br /&gt;    public void ladra()&lt;br /&gt;    {&lt;br /&gt;        System.out.println("Estoy ladrando");&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class Gato extends Animal&lt;br /&gt;{&lt;br /&gt;    public void ronronea()&lt;br /&gt;    {&lt;br /&gt;        System.out.println("Estoy ronroneando");&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ahora imaginemos una clase llamada "&lt;span class="codigo"&gt;Entrenador&lt;/span&gt;" que tiene un método que tiene como argumento un "&lt;span class="codigo"&gt;Animal&lt;/span&gt;", esto significa que puede tomar cualquier tipo de "&lt;span class="codigo"&gt;Animal&lt;/span&gt;", cualquier tipo de animal puede ser pasado a un método con un argumento del tipo "&lt;span class="codigo"&gt;Animal&lt;/span&gt;", ejemplo:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class Entrenador&lt;br /&gt;{&lt;br /&gt;    public static void main(String... args)&lt;br /&gt;    {&lt;br /&gt;        Gato gato = new Gato();&lt;br /&gt;        Perro perro = new Perro();&lt;br /&gt;        mueveteAnimal(gato);&lt;br /&gt;        mueveteAnimal(perro);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static void mueveteAnimal(Animal animal)&lt;br /&gt;    {&lt;br /&gt;        animal.muevete();&lt;br /&gt;    } &lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;La salida del código anterior es:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;Me estoy moviendo&lt;br /&gt;Me estoy moviendo&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;El método "&lt;span class="codigo"&gt;mueveteAnimal&lt;/span&gt;" está declarando un "&lt;span class="codigo"&gt;Animal&lt;/span&gt;" como argumento pero se le puede pasar cualquier sub-clase o sub-tipo de esta clase "&lt;span class="codigo"&gt;Animal&lt;/span&gt;", este método podría invocar a cualquier método dentro de la clase "&lt;span class="codigo"&gt;Animal&lt;/span&gt;". Lo que si debemos de tener en cuenta es que sólo podemos llamar a los métodos declarados por "&lt;span class="codigo"&gt;Animal&lt;/span&gt;", los métodos declarados dentro de las subclases de "&lt;span class="codigo"&gt;Animal&lt;/span&gt;" son dependiente del tipo declarado, esto significa que no podríamos llamar al método "&lt;span class="codigo"&gt;ladra&lt;/span&gt;" incluso si el "&lt;span class="codigo"&gt;Animal&lt;/span&gt;" que se está pasando es del tipo "&lt;span class="codigo"&gt;Perro&lt;/span&gt;".&lt;br /&gt;&lt;br /&gt;&lt;h2 class="subtitulo"&gt;Relaciones IS – A, HAS– A&lt;/h2&gt;&lt;br /&gt;&lt;h3 class="subtitulo"&gt;IS – A&lt;/h3&gt;&lt;br /&gt;En Orientación a objetos el concepto de "&lt;span class="codigo"&gt;IS-A&lt;/span&gt;" (es-un) esta basado en la herencia de una clase ("&lt;span class="codigo"&gt;extends&lt;/span&gt;") o en la implementación de una interface ("&lt;span class="codigo"&gt;implements&lt;/span&gt;"). &lt;span class="codigo"&gt;IS-A&lt;/span&gt; es una forma de decir "Esta cosa es del tipo de esta cosa" (o estos dos tipos pueden ser equivalentes), por ejemplo un "&lt;span class="codigo"&gt;Perro&lt;/span&gt;" es del tipo "&lt;span class="codigo"&gt;Animal&lt;/span&gt;", en OO nosotros podemos decir: "&lt;span class="codigo"&gt;Perro IS-A Animal&lt;/span&gt;", "&lt;span class="codigo"&gt;Lechuga IS-A Vegetal&lt;/span&gt;", en java podemos expresar esta relación &lt;span class="codigo"&gt;IS-A&lt;/span&gt; por medio de las palabras reservadas "&lt;span class="codigo"&gt;extends&lt;/span&gt;" (para la herencia de clases) y de "&lt;span class="codigo"&gt;implements&lt;/span&gt;" (para la implementación de interfaces), veamos un ejemplo:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class Carro&lt;br /&gt;{&lt;br /&gt;    //cualquier código aquí&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class Toyota extends Carro&lt;br /&gt;{&lt;br /&gt;    /*Toyota está heredando de carro, no olvidemos que Toyota &lt;br /&gt;    hereda los miembros de Carro incluido métodos y variables*/&lt;br /&gt;} &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;"&lt;span class="codigo"&gt;Carro&lt;/span&gt;" también es un vehículo así que se podría implementar un árbol de herencia de la siguiente manera:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class Vehiculo{...}&lt;br /&gt;public class Carro extends Vehiculo{...}&lt;br /&gt;public class Toyota extends Carro{...}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;En términos de OO podríamos decir lo siguiente:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="codigo"&gt;Vehículo&lt;/span&gt; es la súper clase de &lt;span class="codigo"&gt;Carro&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="codigo"&gt;Carro&lt;/span&gt; es la subclase de &lt;span class="codigo"&gt;Vehículo&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="codigo"&gt;Carro&lt;/span&gt; es la súper clase de &lt;span class="codigo"&gt;Toyota&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="codigo"&gt;Toyota&lt;/span&gt; es la subclase de &lt;span class="codigo"&gt;Carro&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="codigo"&gt;Toyota&lt;/span&gt; hereda de &lt;span class="codigo"&gt;Carro&lt;/span&gt; y de &lt;span class="codigo"&gt;Vehiculo&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="codigo"&gt;Toyota&lt;/span&gt; deriva de &lt;span class="codigo"&gt;Carro&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="codigo"&gt;Carro&lt;/span&gt; deriva de &lt;span class="codigo"&gt;Vehículo&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="codigo"&gt;Toyota&lt;/span&gt; es subtipo de &lt;span class="codigo"&gt;Carro&lt;/span&gt; y &lt;span class="codigo"&gt;Vehiculo&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;Retornando a la relación &lt;span class="codigo"&gt;IS-A&lt;/span&gt;, lo siguiente es correcto:&lt;br /&gt;&lt;br /&gt;&lt;span class="codigo"&gt;Toyota extends Carro&lt;/span&gt; significa     &lt;span class="codigo"&gt;Toyota IS-A Carro&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="codigo"&gt;Carro extends Vehiculo&lt;/span&gt; significa    &lt;span class="codigo"&gt;Carro IS-A Vehiculo&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;Ahora recordemos que al principio usamos el operador &lt;span class="codigo"&gt;instanceof&lt;/span&gt;, bueno, si la expresión "&lt;span class="codigo"&gt;Toyota instanceof Carro&lt;/span&gt;" es verdadera, entonces es lo mismo que decir "&lt;span class="codigo"&gt;Toyota IS-A Carro&lt;/span&gt;", la expresión "&lt;span class="codigo"&gt;Toyota instanceof Vehiculo&lt;/span&gt;" también es verdadera aunque explícitamente no dice esto ya que "&lt;span class="codigo"&gt;Toyota&lt;/span&gt;" extiende de "&lt;span class="codigo"&gt;Carro&lt;/span&gt;", pero por otro lado "&lt;span class="codigo"&gt;Carro&lt;/span&gt;" si extiende de "&lt;span class="codigo"&gt;Vehiculo&lt;/span&gt;" a esto se le llama herencia indirecta ya que una clase puede ser hijo, nieto, bisnieto, etc. de otra clase, una clase puede extender o heredar de otra directa o indirectamente ya que en el árbol de herencia pueden haber clases intermedias.&lt;br /&gt;&lt;br /&gt;&lt;h2 class="subtitulo"&gt;HAS–A&lt;/h2&gt;&lt;br /&gt;La relación &lt;span class="codigo"&gt;HAS-A&lt;/span&gt; esta basada en el uso en lugar de la herencia, por ejemplo "&lt;span class="codigo"&gt;A HAS-A B&lt;/span&gt;" si la clase "&lt;span class="codigo"&gt;A&lt;/span&gt;" tiene una referencia a una instancia de la clase "&lt;span class="codigo"&gt;B&lt;/span&gt;", por ejemplo:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class Animal{ }&lt;br /&gt;&lt;br /&gt;public class Gato extends Animal&lt;br /&gt;{&lt;br /&gt;    CajaDeArena miCajaDeArena;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;En el código anterior la clase "&lt;span class="codigo"&gt;Gato&lt;/span&gt;" tiene una referencia una variable de instancia del tipo "&lt;span class="codigo"&gt;CajaDeArena&lt;/span&gt;", entonces podemos decir "&lt;span class="codigo"&gt;Gato HAS-A CajaDeArena&lt;/span&gt;", en otra palabras, "&lt;span class="codigo"&gt;Gato&lt;/span&gt;" tiene una referencia a una "&lt;span class="codigo"&gt;CajaDeArena&lt;/span&gt;", la clase "&lt;span class="codigo"&gt;Gato&lt;/span&gt;" puede tener un método llamado "&lt;span class="codigo"&gt;llenarCaja(Arena miArena)&lt;/span&gt;", de esta manera los usuarios de la clase "&lt;span class="codigo"&gt;Gato&lt;/span&gt;" no podrán saber nunca que cuando se invoca al método "&lt;span class="codigo"&gt;llenarCaja&lt;/span&gt;" este método delega toda la responsabilidad a la clase "&lt;span class="codigo"&gt;CajaDeArena&lt;/span&gt;" llamando a su método "&lt;span class="codigo"&gt;llenarCaja&lt;/span&gt;", veamos esto con un ejemplo:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class Gato extends Animal&lt;br /&gt;{&lt;br /&gt;    private CajaDeArena miCajaDeArena;&lt;br /&gt;    &lt;br /&gt;    public void llenarCaja(Arena miArena)&lt;br /&gt;    {&lt;br /&gt;        miCajaDeArena.llenarCaja(miArena); /*delegando comportamiento al objeto CajaDeArena */&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class CajaDeArena&lt;br /&gt;{&lt;br /&gt;    public void llenarCaja(Arena miArena)&lt;br /&gt;    {&lt;br /&gt;        System.out.println("&lt;span class="codigo"&gt;Llenando la caja de arena&lt;/span&gt;");&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;En OO muchas veces no queremos que la gente se preocupe por cual clase u objeto está haciendo realmente el trabajo, los usuarios de la clase "&lt;span class="codigo"&gt;Gato&lt;/span&gt;" hacen llamado del método "&lt;span class="codigo"&gt;llenarCaja&lt;/span&gt;" pero estos no saben si la misma clase hace el trabajo o no, sin embargo a ellos les parece que la propia clase "&lt;span class="codigo"&gt;Gato&lt;/span&gt;" lo hace, no tienen ni idea de que existe algo como una clase llamada "&lt;span class="codigo"&gt;CajaDeArena&lt;/span&gt;" que es quien realmente hace el trabajo.&lt;br /&gt;&lt;br /&gt;Toda la explicación anterior nos servirá  para entender mejor otro de los conceptos de la programación orientada a objetos, uno de los más útiles si sabemos cómo utilizarlo correctamente: el &lt;span class="codigo"&gt;polimorfismo&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="titulo"&gt;Polimorfismo&lt;/h2&gt;Cualquier clase que pase la prueba de tener la relación "&lt;span class="codigo"&gt;IS-A&lt;/span&gt;" puede ser considerada polimórfica, todos los objetos en Java son polimórficos ya que pasan la prueba de la relación IS-A, tanto para su propio tipo como para con la clase "&lt;span class="codigo"&gt;Object&lt;/span&gt;". Debemos recordar la única forma de a un objeto es a través de una variable de referencia, hay algunas cosas claves que debemos recordar de las variables de referencia:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Una variable de referencia &lt;span class="negritas"&gt;puede ser sólo de un tipo y una vez declarado este tipo nunca podrá cambiar&lt;/span&gt; (aunque el objeto al que hace referencia puede cambiar).&lt;/li&gt;&lt;li&gt;Una referencia es una variable, por lo cual su valor puede ser reasignada a otros objetos a menos que esta sea declarada como &lt;span class="codigo"&gt;final&lt;/span&gt;.&lt;/li&gt;&lt;li&gt;Un tipo de variable de referencia determina los métodos que se pueden invocar en el objeto que esta variable está referenciando.&lt;/li&gt;&lt;li&gt;Una variable de referencia puede referirse a cualquier objeto del mismo tipo que el que está declarando, o puede referirse a cualquier subtipo del tipo declarado.&lt;/li&gt;&lt;li&gt;Una variable de referencia puede ser declarado como un tipo de clase o un tipo de interfaz. Si la variable se declara como un tipo de interfaz, se puede hacer referencia a cualquier objeto de cualquier clase que implementa la interfaz.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Anteriormente creamos una clase "&lt;span class="codigo"&gt;Animal&lt;/span&gt;" que era extendida por dos clases, "&lt;span class="codigo"&gt;Perro&lt;/span&gt;" y "&lt;span class="codigo"&gt;Gato&lt;/span&gt;", ahora imaginemos que tenemos una clase llamada "&lt;span class="codigo"&gt;Gaviota&lt;/span&gt;", después queremos hacer que algunos tipos de &lt;span class="codigo"&gt;Animal&lt;/span&gt; vuelen o se puedan elevar en el aire y otros no como el caso de "&lt;span class="codigo"&gt;Gaviota&lt;/span&gt;" que si puede elevar, por el contrario "&lt;span class="codigo"&gt;Perro&lt;/span&gt;" y "&lt;span class="codigo"&gt;Gato&lt;/span&gt;" no pueden hacerlo, para esto podríamos crear una clase llamada "&lt;span class="codigo"&gt;Elevable&lt;/span&gt;" con un método "&lt;span class="codigo"&gt;elevar&lt;/span&gt;" y hacer que unos tipos de &lt;span class="codigo"&gt;Animal&lt;/span&gt;es puedan elevarse y otros no, pero también queremos que todos los tipos de &lt;span class="codigo"&gt;Animal&lt;/span&gt; se muevan que es lo que nos permite el método "&lt;span class="codigo"&gt;muevete&lt;/span&gt;" de la clase "&lt;span class="codigo"&gt;Animal&lt;/span&gt;", pero esto no funcionaría ya que Java solo soporta la herencia simple, esto significa que una sub clase sólo puede tener una clase padre, es decir lo siguiente es incorrecto:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class Gaviota extends Animal, Elevable // NO!!&lt;br /&gt;{ &lt;br /&gt; //Cualquier codigo aquí&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="negritas"&gt;Una clase NO puede extender de más que de sólo una clase&lt;/span&gt;, ante estos casos la solución sería crearse una interface llamada "&lt;span class="codigo"&gt;Elevable&lt;/span&gt;" y solo las sub-clases de "&lt;span class="codigo"&gt;Animal&lt;/span&gt;" que puedan volar implementen esta interfaz, dicha interfaz quedaría de la siguiente manera:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public interface Elevable&lt;br /&gt;{&lt;br /&gt;    public void volar();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class Animal&lt;br /&gt;{&lt;br /&gt;    public void muevete()&lt;br /&gt;    {&lt;br /&gt;        System.out.println("Me estoymoviendo");&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A continuación mostramos la clase "&lt;span class="codigo"&gt;Gaviota&lt;/span&gt;" que implementa esta interfaz:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class Gaviota extends Animal implements Elevable&lt;br /&gt;{&lt;br /&gt;    public void volar()&lt;br /&gt;    {&lt;br /&gt;        System.out.println("¡Estoy volando!");&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ahora tenemos a la clase "&lt;span class="codigo"&gt;Gaviota&lt;/span&gt;" que pasa la prueba de la relación &lt;span class="codigo"&gt;IS-A&lt;/span&gt; tanto para la clase "&lt;span class="codigo"&gt;Animal&lt;/span&gt;" como para la interfaz "&lt;span class="codigo"&gt;Elevable&lt;/span&gt;", esto significa que una "&lt;span class="codigo"&gt;Gaviota&lt;/span&gt;" puede ser tratada polimórficamente como una de estas cuatro cosas en un momento dado, dependiendo del tipo declarado de la variable de referencia:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Como un "&lt;span class="codigo"&gt;Object&lt;/span&gt;" (ya que todas las clases heredan de la clase &lt;span class="codigo"&gt;Object&lt;/span&gt;).&lt;/li&gt;&lt;li&gt;Como un "&lt;span class="codigo"&gt;Animal&lt;/span&gt;" (ya que está extendiendo de la clase &lt;span class="codigo"&gt;Animal&lt;/span&gt;).&lt;/li&gt;&lt;li&gt;Como una "&lt;span class="codigo"&gt;Gaviota&lt;/span&gt;" (ya que es lo que es).&lt;/li&gt;&lt;li&gt;Como un "&lt;span class="codigo"&gt;Elevable&lt;/span&gt;" (ya que implementa de la interface &lt;span class="codigo"&gt;Elevable&lt;/span&gt;).&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Las siguientes declaraciones son legales:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;Gaviota gaviota = new Gaviota();&lt;br /&gt;Object object = gaviota;&lt;br /&gt;Animal animal = gaviota;&lt;br /&gt;Elevable elevable = gaviota;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Aquí solo hay un objeto &lt;span class="codigo"&gt;Gaviota&lt;/span&gt; pero cuatro diferentes variables de referencia, hagamos una pregunta: ¿Cuál de las cuatro variables de referencia puede llamar al método "&lt;span class="codigo"&gt;muevete&lt;/span&gt;"? Recuerden que las llamadas a métodos permitidos por el compilador se basan únicamente en el tipo declarado de la referencia, con independencia del tipo de objeto. Así que buscando en los cuatro tipos de referencia de nuevo, "&lt;span class="codigo"&gt;Object&lt;/span&gt;", "&lt;span class="codigo"&gt;Gaviota&lt;/span&gt;", "&lt;span class="codigo"&gt;Animal&lt;/span&gt;" y "&lt;span class="codigo"&gt;Elevable&lt;/span&gt;" ¿cuál de estos cuatro tipos puede llamar al método "&lt;span class="codigo"&gt;muevete()&lt;/span&gt;"? La respuesta es la siguiente: El objeto "&lt;span class="codigo"&gt;animal&lt;/span&gt;" como el objeto "&lt;span class="codigo"&gt;gaviota&lt;/span&gt;" son conocidos por el compilador para poder llamar o invocar al método "&lt;span class="codigo"&gt;muevete&lt;/span&gt;".&lt;br /&gt;&lt;br /&gt;¿Qué métodos pueden ser invocados cuando el objeto "&lt;span class="codigo"&gt;gaviota&lt;/span&gt;" está utilizando la referencia a la inteface "&lt;span class="codigo"&gt;Elevable&lt;/span&gt;"? Sólo al método "&lt;span class="codigo"&gt;volar()&lt;/span&gt;".&lt;br /&gt;&lt;br /&gt;Un beneficio es que cualquier clase desde cualquier lugar en el árbol de herencia puede invocar a la interface "&lt;span class="codigo"&gt;Elevable&lt;/span&gt;", que sucedería si tenemos un método que tiene como argumento declarado con tipo "&lt;span class="codigo"&gt;Elevable&lt;/span&gt;", podrías pasar una instancia de objeto del tipo "&lt;span class="codigo"&gt;gaviota&lt;/span&gt;" y cualquier otra instancia de clase que implemente a la interface "&lt;span class="codigo"&gt;Elevable&lt;/span&gt;",  podría usar el parámetro del tipo "&lt;span class="codigo"&gt;Elevable&lt;/span&gt;" para invocar al método "&lt;span class="codigo"&gt;volar()&lt;/span&gt;" pero no al método "&lt;span class="codigo"&gt;muevete()&lt;/span&gt;"  o cualquier otro objeto que se sabe que el compilador conocer basado en el tipo de referencia.&lt;br /&gt;&lt;br /&gt;Otra cosa que debemos saber es que si bien el compilador solo conoce al tipo de referencia declarado, la &lt;span class="codigo"&gt;JVM&lt;/span&gt; en tiempo de ejecución sabe lo que el objeto realmente es, y eso significa que incluso si el objeto "&lt;span class="codigo"&gt;gaviota&lt;/span&gt;" hace una llamada al método "&lt;span class="codigo"&gt;muevete&lt;/span&gt;" usando la variable de referencia "&lt;span class="codigo"&gt;animal&lt;/span&gt;", si el objeto "&lt;span class="codigo"&gt;gaviota&lt;/span&gt;" sobre-escribe el método "&lt;span class="codigo"&gt;muevete&lt;/span&gt;", la &lt;span class="codigo"&gt;JVM&lt;/span&gt; invocara a esa versión del método "&lt;span class="codigo"&gt;muevete&lt;/span&gt;". La &lt;span class="codigo"&gt;JVM&lt;/span&gt; mira al objeto real que se encuentra al otro extremo de la referencia, puede ver que se ha sobre escrito el método del tipo de variable de referencia declarado e invoca al método del objeto de la clase actual.&lt;br /&gt;&lt;br /&gt;Siempre se puede hacer referencia a un objeto con un tipo de referencia variable más general (una superclase o interfaz), pero en tiempo de ejecución, las únicas cosas que son seleccionadas dinámicamente basándose en el objeto real (en lugar de tipo de referencia) son métodos de instancia (no los métodos estáticos, no las variables), sólo los métodos de instancia sobre-escritos  se invocan de forma dinámica en función del tipo de objeto real.&lt;br /&gt;&lt;br /&gt;Ejemplo:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class Animal&lt;br /&gt;{&lt;br /&gt;    public void muevete()&lt;br /&gt;    {&lt;br /&gt;        System.out.println("Me estoy moviendo");&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static void respirar() //Método estático&lt;br /&gt;    { &lt;br /&gt;        System.out.println("Estoy respirando");&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class Gaviota extends Animal &lt;br /&gt;{&lt;br /&gt;    public void muevete()&lt;br /&gt;    {&lt;br /&gt;        System.out.println("La gaviota se mueve");&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static void respirar() //Método estático&lt;br /&gt;    {&lt;br /&gt;        System.out.println("La gaviota está respirando");&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class Prueba&lt;br /&gt;{&lt;br /&gt;    public static void main(String... args)&lt;br /&gt;    {&lt;br /&gt;        Animal a = new Gaviota();&lt;br /&gt;        a.muevete();&lt;br /&gt;        a.respirar();&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Salida:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;La gaviota se mueve &lt;br /&gt;Estoy respirando&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;El segundo resultado que vemos se trata de la invocación de un método estático. El comportamiento que vemos pasa porque cuando el compilador ve que se está invocando un método estático, cambia la referencia al objeto por el tipo de la clase, o sea que al final queda de la siguiente manera:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;Animal a = new Gaviota();&lt;br /&gt;Animal.respirar();&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;En el primer caso el método que se invoca es el de "&lt;span class="codigo"&gt;Gaviota&lt;/span&gt;" y no el de "&lt;span class="codigo"&gt;Animal&lt;/span&gt;", ya que el método "&lt;span class="codigo"&gt;muevete&lt;/span&gt;" no es estático sino un método de instancia; por eso dice se dice que  sólo los métodos de instancia sobrecargados  se invocan de forma dinámica en función del tipo de objeto real.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="titulo"&gt;Sobrecarga y sobre escritura&lt;/h2&gt;&lt;br /&gt;&lt;h3 class="subtitulo"&gt;Sobre escritura de métodos&lt;/h3&gt;En cualquier momento que se tenga un método que hereda de una superclase, se tendrá la oportunidad de realizar una sobre-escritura de métodos, a menos que el método este marcado con la palabra reservada &lt;span class="codigo"&gt;final&lt;/span&gt;. El principal beneficio de la sobre-escritura de métodos es que se puede definir un comportamiento especial para un método de una subclase. En el siguiente ejemplo veremos cómo la clase "&lt;span class="codigo"&gt;Gaviota&lt;/span&gt;" sobre-escribe el método "&lt;span class="codigo"&gt;muevete&lt;/span&gt;" de la clase "&lt;span class="codigo"&gt;Animal&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class Animal&lt;br /&gt;{&lt;br /&gt;    public void muevete()&lt;br /&gt;    {&lt;br /&gt;        System.out.println("Me estoy moviendo");&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class Gaviota extends Animal &lt;br /&gt;{&lt;br /&gt;    public void muevete()&lt;br /&gt;    {&lt;br /&gt;        System.out.println("La gaviota se mueve");&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Para métodos abstractos que se heredan desde una superclase, no se tiene otra opción más que sobre escribir-dichos métodos. Se deben implementar los métodos a menos que la subclase que los herede también este marcada como abstracta. Los métodos abstractos deben ser implementados por una subclase concreta, esto quiere decir que la subclase concreta sobre-escribe el método abstracto de la superclase. Entonces debemos pensar que los métodos abstractos son métodos que forzosamente deben ser sobre-escritos.&lt;br /&gt;&lt;br /&gt;El creador de la clase "&lt;span class="codigo"&gt;Animal&lt;/span&gt;" podría haber decidido que, a efectos de polimorfismo, todos los subtipos de &lt;span class="codigo"&gt;Animal&lt;/span&gt; deben implementar el método "&lt;span class="codigo"&gt;moverse&lt;/span&gt;", de una manera única y especifica. Polimórficamente, cuando alguien tiene una referencia de &lt;span class="codigo"&gt;Animal&lt;/span&gt; que no refiere a una instancia de &lt;span class="codigo"&gt;Animal&lt;/span&gt;, sino a una instancia de una subclase de &lt;span class="codigo"&gt;Animal&lt;/span&gt;, la persona que llama debe ser capaz de invocar al método "&lt;span class="codigo"&gt;muevete&lt;/span&gt;" en la referencia a "&lt;span class="codigo"&gt;Animal&lt;/span&gt;", pero el objeto en tiempo de ejecución real ejecutará su propio y especifico método "&lt;span class="codigo"&gt;muevete&lt;/span&gt;".  Marcando el método "&lt;span class="codigo"&gt;muevete&lt;/span&gt;" como abstracto es la forma que el programador de la clase "&lt;span class="codigo"&gt;Animal&lt;/span&gt;" dice a todos los desarrolladores de las demás subclases: "&lt;span class="codigo"&gt;No tiene ningún sentido para el nuevo subtipo utilizar  el método genérico "&lt;span class="codigo"&gt;muevete&lt;/span&gt;",  por lo que tú debes implementar tu propio método "&lt;span class="codigo"&gt;muevete&lt;/span&gt;"&lt;/span&gt;. A continuación mostraremos un ejemplo de clases no abstractas:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class Prueba&lt;br /&gt;{&lt;br /&gt;    public static void main(String... args)&lt;br /&gt;    {&lt;br /&gt;        Animal a = new Animal();&lt;br /&gt;       Animal b = new Gaviota(); //Referencia a Animal, pero objeto Gaviota&lt;br /&gt;        a.muevete();&lt;br /&gt;        b.muevete();&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class Animal&lt;br /&gt;{&lt;br /&gt;    public void muevete()&lt;br /&gt;    {&lt;br /&gt;        System.out.println("Me estoy moviendo");&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;public class Gaviota extends Animal &lt;br /&gt;{&lt;br /&gt;    public void muevete()&lt;br /&gt;    {&lt;br /&gt;        System.out.println("La gaviota se mueve");&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void volar()&lt;br /&gt;    {&lt;br /&gt;        System.out.println("La gaviota vuela");&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;En el código anterior la clase "&lt;span class="codigo"&gt;Prueba&lt;/span&gt;" utiliza una referencia a "&lt;span class="codigo"&gt;Animal&lt;/span&gt;" para invocar un método en el objeto "&lt;span class="codigo"&gt;Gaviota&lt;/span&gt;", hay que recordar que el compilador solo permitirá que se invoquen métodos que se encuentran en la clase "&lt;span class="codigo"&gt;Animal&lt;/span&gt;", cuando usas una referencia a un "&lt;span class="codigo"&gt;Animal&lt;/span&gt;". Por lo tanto, el siguiente código no es legal:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;Animal c = new Gaviota();&lt;br /&gt;c.volar();  // No puedes invocar a "volar()", Animal no tiene un método volar&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Para reiterar: &lt;span class="negritas"&gt;el compilar solo mira el tipo de referencia y no el tipo de instancia en tiempo de ejecución&lt;/span&gt;. El polimorfismo nos permite tener referencias a súper tipos o a tipos más abstractos (incluyendo las interfaces) para referir a uno de estos subtipos (incluyendo implementación de interfaces).&lt;br /&gt;&lt;br /&gt;El método que sobre-escribe no debe tener un modificador de acceso más restringido que el del método a ser sobre-escrito. Por ejemplo no se puede sobre-escribir un método marcado con el modificador de acceso &lt;span class="codigo"&gt;public&lt;/span&gt; y cambiarlo a &lt;span class="codigo"&gt;protected&lt;/span&gt;. Pensemos en los siguiente: si la clase "&lt;span class="codigo"&gt;Animal&lt;/span&gt;" tiene un método "&lt;span class="codigo"&gt;comer()&lt;/span&gt;" marcado "&lt;span class="codigo"&gt;public&lt;/span&gt;" y alguien tiene una referencia de "&lt;span class="codigo"&gt;Animal&lt;/span&gt;", es decir, una referencia declarada del tipo "&lt;span class="codigo"&gt;Animal&lt;/span&gt;", se asume que es seguro llamar al método "&lt;span class="codigo"&gt;comer()&lt;/span&gt;" en la referencia de "&lt;span class="codigo"&gt;Animal&lt;/span&gt;", independientemente de la instancia actual que la referencia a "&lt;span class="codigo"&gt;Animal&lt;/span&gt;" está invocando. Si una subclase cambia el modificador de acceso del método sobre-escrito, entonces cuando la &lt;span class="codigo"&gt;JVM&lt;/span&gt; invoque la verdadera versión del objeto "&lt;span class="codigo"&gt;Gaviota&lt;/span&gt;"  en lugar de la versión del  tipo de referencia "&lt;span class="codigo"&gt;Animal&lt;/span&gt;",  el programa perecerá, a continuación un ejemplo:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class Prueba&lt;br /&gt;{&lt;br /&gt;    public static void main(String... args)&lt;br /&gt;    {&lt;br /&gt;        Animal a = new Animal();&lt;br /&gt;        Animal b = new Gaviota(); // Referencia a Animal, pero objeto Gaviota&lt;br /&gt;        a.muevete();&lt;br /&gt;        b.muevete();&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class Animal&lt;br /&gt;{&lt;br /&gt;    public void muevete()&lt;br /&gt;    {&lt;br /&gt;        System.out.println("Me estoy moviendo");&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class Gaviota extends Animal &lt;br /&gt;{&lt;br /&gt;    private  void muevete() //Marcado como privado&lt;br /&gt;    {   &lt;br /&gt;        System.out.println("La gaviota se mueve");&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Si el código anterior compilara (cosa que no hará) obtendríamos el siguiente error en tiempo de ejecución:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;Animal b = new Gaviota(); //Referencia a Animal, pero objeto Gaviota&lt;br /&gt;a.muevete(); //Ocurre una crisis en tiempo de ejecución &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;La variable "&lt;span class="codigo"&gt;b&lt;/span&gt;" es del tipo "&lt;span class="codigo"&gt;Animal&lt;/span&gt;", el cual tiene un método público llamado "&lt;span class="codigo"&gt;muevete&lt;/span&gt;", pero hay que recordar que en tiempo de ejecución, Java utiliza la invocación de métodos virtuales para seleccionar dinámicamente la versión real del método que se ejecutará, basado en la del tipo del objeto en tiempo de ejecución. Una referencia  de "&lt;span class="codigo"&gt;Animal&lt;/span&gt;"  puede referir siempre a una instancia de "&lt;span class="codigo"&gt;Gaviota&lt;/span&gt;" porque "&lt;span class="codigo"&gt;Gaviota&lt;/span&gt;" &lt;span class="codigo"&gt;IS-A&lt;/span&gt; "&lt;span class="codigo"&gt;Animal&lt;/span&gt;" ("&lt;span class="codigo"&gt;Gaviota&lt;/span&gt;" ES UN "&lt;span class="codigo"&gt;Animal&lt;/span&gt;"). Lo que hace posible que una instancia de una superclase referencie a una instancia de la subclase es que la subclase es capaz de hacer todo lo que la superclase puede hacer (ya que recibe el comportamiento de esta por herencia). Esto quiere decir que cualquiera con una referencia a "&lt;span class="codigo"&gt;Gaviota&lt;/span&gt;" usando una instancia de &lt;span class="codigo"&gt;Animal&lt;/span&gt; (&lt;span class="codigo"&gt;Animal a = new Gaviota();&lt;/span&gt;) es libre de llamar a todos los métodos accesibles de "&lt;span class="codigo"&gt;Animal&lt;/span&gt;", no importa si "&lt;span class="codigo"&gt;Gaviota&lt;/span&gt;" sobre-escribe los métodos de "&lt;span class="codigo"&gt;Animal&lt;/span&gt;"  o simplemente los hereda. Un método-sobre escrito debe cumplir con el contrato de la superclase. &lt;br /&gt;&lt;br /&gt;Las reglas para sobre escribir un método son las siguientes:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;La lista de argumentos debe ser exactamente igual (del mismo tipo y en el mismo orden) que el método a sobre-escribir. Si esta lista no coincide en realidad lo que se está  haciendo es una sobrecarga del método (que puede que no sea nuestra intención).&lt;/li&gt;&lt;li&gt;El tipo de retorno del método sobre escrito debe ser el mismo o un subtipo del declarado en el método de la súper clase.&lt;/li&gt;&lt;li&gt;El modificador de acceso no debe ser más restrictivo que del método a sobre-escribir. Por ejemplo, si en la clase base tenemos un método "&lt;span class="codigo"&gt;public&lt;/span&gt;" NO podemos sobre-escribirlo poniéndole un modificador "&lt;span class="codigo"&gt;protected&lt;/span&gt;".&lt;/li&gt;&lt;li&gt;El modificador de acceso puede ser menos restrictivo que el del método a sobre-escribir. Por ejemplo, si en la clase base tenemos un método "&lt;span class="codigo"&gt;protected&lt;/span&gt;" SI podemos sobre-escribirlo poniéndole un modificador "&lt;span class="codigo"&gt;public&lt;/span&gt;".&lt;/li&gt;&lt;li&gt;Los métodos de instancia solo pueden ser sobre-escritos si estos son heredados por la subclase. Una subclase dentro del mismo paquete que su superclase puede sobre escribir cualquier método de la súper clase que NO esté marcado como &lt;span class="codigo"&gt;private&lt;/span&gt; o &lt;span class="codigo"&gt;final&lt;/span&gt;. Una subclase en diferente paquete puede sobre-escribir solo los métodos no finales marcados &lt;span class="codigo"&gt;public&lt;/span&gt; o &lt;span class="codigo"&gt;protected&lt;/span&gt; (los métodos &lt;span class="codigo"&gt;protected&lt;/span&gt; son heredados por la subclase).&lt;/li&gt;&lt;li&gt;Los métodos sobre-escritos no deben lanzar excepciones marcadas (en las que sean necesarias un &lt;span class="codigo"&gt;try&lt;/span&gt; &lt;span class="codigo"&gt;catch&lt;/span&gt;) que sean nuevas o más amplias que aquellas declaradas en el método que sobre-escribe. Por ejemplo un método que declara un "&lt;span class="codigo"&gt;FileNotFoundException&lt;/span&gt;" no puede ser sobre-escrito por un método que declara un "&lt;span class="codigo"&gt;SQLException&lt;/span&gt;", "&lt;span class="codigo"&gt;Exception&lt;/span&gt;", "&lt;span class="codigo"&gt;IOException&lt;/span&gt;" o cualquier otra excepción a menos que esta sea una subclase de "&lt;span class="codigo"&gt;FileNotFoundException&lt;/span&gt;".&lt;/li&gt;&lt;li&gt;Los métodos sobre-escritos pueden lanzar excepciones más específicas (excepciones que extiendan de la excepción que se está declarando) o lanzar menos excepciones. Solo porque el método a sobre-escribir puede lanzar excepciones no quiere decir que el método sobre-escrito lanzara estas mismas excepciones, un método sobre-escrito no tiene que declarar una excepción que nunca lanzará. Independientemente de que el método a sobre-escribir las declare.&lt;/li&gt;&lt;li&gt;No se puede sobre-escribir un método marcado con &lt;span class="codigo"&gt;final&lt;/span&gt;.&lt;/li&gt;&lt;li&gt;No se puede sobre-escribir un método marcado con &lt;span class="codigo"&gt;static&lt;/span&gt;.&lt;/li&gt;&lt;li&gt;Si un método no puede ser heredado entonces no puede ser sobre-escrito. Hay que recordar que la sobre-escritura implica que se está re-implementando un método que está heredanddo. Por ejemplo el siguiente código no es legal:&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class Prueba&lt;br /&gt;{&lt;br /&gt;    public static void main(String... args)&lt;br /&gt;    {&lt;br /&gt;        Gaviota a = new Gaviota(); &lt;br /&gt;        a.muevete(); //No es legal porque Gaviota no hereda muevete(), muevete() es declarado private en Animal&lt;br /&gt;    }    &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class Animal&lt;br /&gt;{&lt;br /&gt;    private void muevete()&lt;br /&gt;    {&lt;br /&gt;        System.out.println("Me estoy moviendo");&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class Gaviota extends Animal {}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4 class="subtitulo"&gt;Invocando a la versión de la superclase de un método sobre escrito&lt;/h4&gt;Tal vez queramos tomar ventaja de una parte del código en la versión de la súper clase de un método y aun así sobre-escribirlo para proveer algún comportamiento especifico adicional. Esto es como decir: "Ejecuta la versión de la superclase de un método, después vuelve y termina con mi código para hacer un comportamiento adicional en el método de la subclase", esto es fácil de hacer utilizando la palabra reservada &lt;span class="codigo"&gt;super&lt;/span&gt; como en el ejemplo siguiente:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class Prueba&lt;br /&gt;{&lt;br /&gt;    public static void main(String... args)&lt;br /&gt;    {&lt;br /&gt;        Gaviota a = new Gaviota(); &lt;br /&gt;        a.muevete();  &lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class Animal&lt;br /&gt;{&lt;br /&gt;    public void muevete()&lt;br /&gt;    {&lt;br /&gt;        System.out.println("Me estoy moviendo");&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class Gaviota extends Animal &lt;br /&gt;{&lt;br /&gt;    public  void muevete()&lt;br /&gt;    {  &lt;br /&gt;        //podemos agregar alguna cosa mas&lt;br /&gt;        super.muevete(); //invoca al código de la superclase (Animal)&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Usar la palabra reservada "&lt;span class="codigo"&gt;super&lt;/span&gt;" para invocar a un método sobre-escrito sólo se aplica para métodos de instancia, hay que recordar que &lt;span class="negritas"&gt;los métodos marcados con &lt;span class="codigo"&gt;static&lt;/span&gt; no pueden ser sobre escritos&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3 class="subtitulo"&gt;Sobrecarga de métodos&lt;/h3&gt;La sobrecarga de métodos permite usar el mismo nombre de un método en una clase, pero con diferentes argumentos y, opcionalmente, un tipo de retorno diferente, el código asume la carga de hacer frente a diferentes tipos de argumentos en lugar de obligar a la persona que llama a hacer las conversiones antes de invocar el método. Las reglas a seguir para la sobrecarga son simples:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Para sobrecargar métodos se debe cambiar la lista de argumentos.&lt;/li&gt;&lt;li&gt;Para sobrecargar métodos se puede cambiar el tipo de datos de retorno.&lt;/li&gt;&lt;li&gt;Para sobrecargar métodos se puede cambiar el modificador de acceso.&lt;/li&gt;&lt;li&gt;Para sobrecargar métodos se pueden declarar excepciones que sean nuevas o más amplias.&lt;/li&gt;&lt;li&gt;El método puede ser sobrecargado en la misma clase o en una subclase.&lt;/li&gt;&lt;li&gt;Si la clase "&lt;span class="codigo"&gt;A&lt;/span&gt;" define un método "&lt;span class="codigo"&gt;hacerAlgo(int i)&lt;/span&gt;",  la subclase "&lt;span class="codigo"&gt;B&lt;/span&gt;" puede definir un método llamado "&lt;span class="codigo"&gt;hacerAlgo(String s)&lt;/span&gt;",  sin sobre-escribir el método "&lt;span class="codigo"&gt;hacerAlgo(int i)&lt;/span&gt;" de la súper clase que toma como argumento un entero. Dos métodos con el mismo nombre pero en diferentes clases pueden ser consideradas sobrecargados, si la sub-clase hereda una versión del método y luego declara otra versión sobrecargada en la definición de la clase.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4 class="subtitulo"&gt;Formas legales de sobrecargar un método&lt;/h4&gt;El método que queremos sobrecargar es el siguiente:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public void unMetodo(String str, int t, double d){}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Los siguientes métodos son legales para sobrecargar el método anterior:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public void unMetodo(String str, int t){}&lt;br /&gt;&lt;br /&gt;public int unMetodo(String str, double d){}&lt;br /&gt;&lt;br /&gt;public void unMetodo(String str, int t)throws IOException{}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4 class="subtitulo"&gt;Invocando a métodos sobrecargados&lt;/h4&gt;Cuando un método es invocado, más de un método con el mismo nombre puede existir para el tipo de objeto que estamos invocando. Por ejemplo la clase "&lt;span class="codigo"&gt;Gaviota&lt;/span&gt;" puede tener tres métodos con el mismo nombre pero con diferente lista de argumentos, estos serán métodos sobrecargados. Definir cuál de los diferentes métodos se desea invocar dependerá de la lista de argumentos que contenga. Si estamos invocando a un método que tiene un "&lt;span class="codigo"&gt;String&lt;/span&gt;" como argumento, el método que tiene un "&lt;span class="codigo"&gt;String&lt;/span&gt;" como argumento será llamado. A continuación veremos un ejemplo:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class UnaClase&lt;br /&gt;{&lt;br /&gt;    public int unMetodo(int x, int y)&lt;br /&gt;    {&lt;br /&gt;        return x + y;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public double unMetodo(double x, double y)&lt;br /&gt;    {&lt;br /&gt;        return x + y;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class Prueba&lt;br /&gt;{&lt;br /&gt;    public static void main(String... args)&lt;br /&gt;    {&lt;br /&gt;        UnaClase a = new UnaClase();&lt;br /&gt;        int x = 9;&lt;br /&gt;        int y = 5;&lt;br /&gt;        &lt;br /&gt;        int resultado = a.unMetodo(x, y); //¿Qué versión de "unMetodo" es invocado?&lt;br /&gt;&lt;br /&gt;        double otroResultado = a.unMetodo(5.2, 3.6); //¿Qué versión es invocada?&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;En el primer caso se llama a la primera versión del método "&lt;span class="codigo"&gt;unMetodo(x,y)&lt;/span&gt;" ya que se está pasando a dos enteros y en el segundo caso se llama a la versión del método "&lt;span class="codigo"&gt;unMetodo&lt;/span&gt;" que recibe dos argumentos del tipo double.&lt;br /&gt;&lt;br /&gt;La invocación de métodos sobrecargados que reciben objetos en lugar de tipos primitivos es un poco más interesante. Si tenemos un método sobrecargado, que en un método toma un objeto del tipo "&lt;span class="codigo"&gt;Animal&lt;/span&gt;" y otro en el que toma un objeto del tipo "&lt;span class="codigo"&gt;Gaviota&lt;/span&gt;" (subclase de "&lt;span class="codigo"&gt;Animal&lt;/span&gt;"). Si pasamos un objeto del tipo &lt;span class="codigo"&gt;Gaviota&lt;/span&gt; cuando invocamos al método, invocaremos a la versión sobrecargada que toma una "&lt;span class="codigo"&gt;Gaviota&lt;/span&gt;". O al menos eso parece a primera vista:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;class  Animal{}&lt;br /&gt;&lt;br /&gt;class Gaviota extends Animal{}&lt;br /&gt;&lt;br /&gt;public class UsaAnimales&lt;br /&gt;{&lt;br /&gt;    public void muevete(Animal a)&lt;br /&gt;    {&lt;br /&gt;        System.out.println("Estas en la versión de Animal");&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void muevete(Gaviota g)&lt;br /&gt;    {&lt;br /&gt;        System.out.println("Estas en la versión de Gaviota");&lt;br /&gt;    }&lt;br /&gt; &lt;br /&gt;    public static void main(String... args)&lt;br /&gt;    {&lt;br /&gt;        UsaAnimales ua = new UsaAnimales();&lt;br /&gt;        Animal a = new Animal();&lt;br /&gt;        Gaviora g = new Gaviota():&lt;br /&gt;        ua.muevete(a);&lt;br /&gt;        ua.muevete(g);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;La salida es la que esperamos:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;Estas en la versión de Animal&lt;br /&gt;Estas en la versión de Gaviota&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;¿Pero qué sucede si usamos una referencia de "&lt;span class="codigo"&gt;Animal&lt;/span&gt;" para un objeto "&lt;span class="codigo"&gt;Gaviota&lt;/span&gt;"?&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;Animal animalReferenciaGaviota = new Gaviota();&lt;br /&gt;ua.muevete(animalReferenciaGaviota);&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;¿Cuál de las versiones del método "&lt;span class="codigo"&gt;muévete&lt;/span&gt;"  es invocada?, podríamos pensar que la respuesta es: "El que toma una "&lt;span class="codigo"&gt;Gaviota&lt;/span&gt;", ya que es un objeto del tipo "&lt;span class="codigo"&gt;Gaviota&lt;/span&gt;" el que en tiempo de ejecución está siendo pasado al método". Pero no es así como funciona. El código anterior imprime lo siguiente:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;Estas en la versión de Animal&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;El objeto en tiempo de ejecución es una "&lt;span class="codigo"&gt;Gaviota&lt;/span&gt;" y no un "&lt;span class="codigo"&gt;Animal&lt;/span&gt;". La elección de cuál método sobrecargado se deberá llamar &lt;span class="negritas"&gt;no es decidido dinámicamente en tiempo de ejecución&lt;/span&gt;. Sólo hay que recordar que &lt;span class="negritas"&gt;el tipo de referencia, no el tipo de objeto, determina qué método sobrecargado es llamado&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Para resumir lo que hemos visto hasta ahora de sobrecarga y sobre-escritura: cuál versión de un método sobre-escrito es llamado (en otras palabas, desde cuál clase en el árbol de herencia) es decidido en tiempo de ejecución por el tipo de objeto; pero cuál versión del método sobrecargado se llamará está basado en el tipo de referencia del argumento que se pasa en tiempo de compilación. Si invocamos un método pasando una referencia de "&lt;span class="codigo"&gt;Animal&lt;/span&gt;" para un objeto "&lt;span class="codigo"&gt;Gaviota&lt;/span&gt;", el compilador solo sabe que está recibiendo un "&lt;span class="codigo"&gt;Animal&lt;/span&gt;", por lo que elige la versión sobrecargada que toma un "&lt;span class="codigo"&gt;Animal&lt;/span&gt;".  No importa que en tiempo de ejecución realmente se pase una "&lt;span class="codigo"&gt;Gaviota&lt;/span&gt;".&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3 class="subtitulo"&gt;Polimorfismo en métodos sobrecargados y sobre-escritos&lt;/h3&gt;¿Cómo trabaja el polimorfismo en métodos sobrecargados? Si pasamos una referencia de "&lt;span class="codigo"&gt;Animal&lt;/span&gt;", el método que toma un "&lt;span class="codigo"&gt;Animal&lt;/span&gt;" será llamado, incluso si el objeto actual pasado es una "&lt;span class="codigo"&gt;Gaviota&lt;/span&gt;". Una vez que la "&lt;span class="codigo"&gt;Gaviota&lt;/span&gt;" disfrazada de "&lt;span class="codigo"&gt;Animal&lt;/span&gt;" entra en el método, sin embargo, el objeto "&lt;span class="codigo"&gt;Gaviota&lt;/span&gt;" sigue siendo una "&lt;span class="codigo"&gt;Gaviota&lt;/span&gt;" a pesar de ser pasado a un método que recibe un "&lt;span class="codigo"&gt;Animal&lt;/span&gt;". Entonces es verdad que el polimorfismo no determina que versión del método sobrecargado será llamado. El polimorfismo entra en juego cuando se decide cuál versión de un método sobre-escrito es llamado. Pero algunas veces un método puede ser ambos, sobre-escrito y sobrecargado. Imaginemos lo siguiente:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class Animal&lt;br /&gt;{&lt;br /&gt;    public void comer()&lt;br /&gt;    {&lt;br /&gt;        System.out.println("El Animal genérico está comiendo");&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class Gaviota extends Animal&lt;br /&gt;{&lt;br /&gt;    public void comer()&lt;br /&gt;    {&lt;br /&gt;         System.out.println("La gaviota está comiendo");&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void comer(String s)&lt;br /&gt;    {&lt;br /&gt;        System.out.println("La gaviota está comiendo esto: " + s);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Noten que la clase "&lt;span class="codigo"&gt;Gaviota&lt;/span&gt;" tiene sobrecargado y sobre-escrito el método "&lt;span class="codigo"&gt;comer&lt;/span&gt;" (el método sobrecargado es el que recibe un &lt;span class="codigo"&gt;String&lt;/span&gt; y el sobre-escrito el que no recibe nada).&lt;br /&gt;&lt;br /&gt;La siguiente tabla muestra cuál de las versiones del método "&lt;span class="codigo"&gt;comer&lt;/span&gt;" será llamado dependiendo de cómo sea invocado:&lt;br /&gt;&lt;br /&gt;&lt;table&gt;  &lt;thead&gt;    &lt;tr&gt;&lt;th&gt;Código de Invocación al método&lt;/th&gt;&lt;th&gt;Resultado&lt;/th&gt;&lt;/tr&gt;  &lt;/thead&gt;  &lt;tbody&gt;    &lt;tr&gt;&lt;td&gt;&lt;span class="codigo"&gt;Animal a = new Animal();&lt;br /&gt;a.comer();&lt;/span&gt;&lt;/td&gt;&lt;td&gt;"&lt;span class="codigo"&gt;el Animal genérico está comiendo&lt;/span&gt;"&lt;/td&gt;&lt;/tr&gt;    &lt;tr&gt;&lt;td&gt;&lt;span class="codigo"&gt;Gaviota g = new Gaviota();&lt;br /&gt;g.comer();&lt;/span&gt;&lt;/td&gt;&lt;td&gt;"&lt;span class="codigo"&gt;La gaviota está comiendo&lt;/span&gt;"&lt;/td&gt;&lt;/tr&gt;    &lt;tr&gt;&lt;td&gt;&lt;span class="codigo"&gt;Animal ag = new Gaviota();&lt;br /&gt;ag.comer();&lt;/span&gt;&lt;/td&gt;&lt;td&gt;"&lt;span class="codigo"&gt;La gaviota está comiendo&lt;/span&gt;"&lt;br /&gt;Polimorfismo trabajando: El objeto actual ("&lt;span class="codigo"&gt;Gaviota&lt;/span&gt;"), no el tipo de  referencia ("&lt;span class="codigo"&gt;Animal&lt;/span&gt;"), es usado para determinar cuál versión del método "&lt;span class="codigo"&gt;comer&lt;/span&gt;" es llamado.&lt;/td&gt;&lt;/tr&gt;    &lt;tr&gt;&lt;td&gt;&lt;span class="codigo"&gt;Gaviota gp = new Gaviota();&lt;br /&gt;gp.comer("peces")&lt;/span&gt;&lt;/td&gt;&lt;td&gt;"&lt;span class="codigo"&gt;La gaviota está comiendo esto: peces&lt;/span&gt;"&lt;br /&gt;El método sobre cargado "&lt;span class="codigo"&gt;comer(String s)&lt;/span&gt;" es llamado.&lt;/td&gt;&lt;/tr&gt;    &lt;tr&gt;&lt;td&gt;&lt;span class="codigo"&gt;Animal a2 = new Animal();&lt;br /&gt;a2.comer("manzanas");&lt;/span&gt;&lt;/td&gt;&lt;td&gt;¡¡Error de compilación!!&lt;br /&gt;El compilador mira la clase &lt;span class="codigo"&gt;Animal&lt;/span&gt; y ve que no tiene un método &lt;span class="codigo"&gt;comer&lt;/span&gt; que reciba un &lt;span class="codigo"&gt;String&lt;/span&gt;.&lt;/td&gt;&lt;/tr&gt;    &lt;tr&gt;&lt;td&gt;&lt;span class="codigo"&gt;Animal ag2 = new Gaviota();&lt;br /&gt;ag2.comer("peras");&lt;/span&gt;&lt;/td&gt;&lt;td&gt;¡¡Error de compilación!!&lt;br /&gt;El compilador ve solo la referencia y sabe que "&lt;span class="codigo"&gt;Animal&lt;/span&gt;" no tiene un método "&lt;span class="codigo"&gt;comer&lt;/span&gt;" que reciba un &lt;span class="codigo"&gt;String&lt;/span&gt;. Al compilador no le importa que el objeto actual pueda ser una "&lt;span class="codigo"&gt;Gaviota&lt;/span&gt;" en tiempo de ejecución.&lt;/td&gt;&lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3 class="subtitulo"&gt;Diferencias entre métodos sobre cargados y sobre escritos:&lt;/h3&gt;&lt;table&gt;  &lt;thead&gt;    &lt;tr&gt;      &lt;th&gt;&lt;/th&gt;      &lt;th&gt;Método sobrecargado&lt;/th&gt;      &lt;th&gt;Método sobre-escrito&lt;/th&gt;    &lt;/tr&gt;  &lt;/thead&gt;  &lt;tbody&gt;    &lt;tr&gt;&lt;td&gt;Argumento(s)&lt;/td&gt;&lt;td&gt;Debe cambiar.&lt;/td&gt;&lt;td&gt;No debe cambiar.&lt;/td&gt;&lt;/tr&gt;    &lt;tr&gt;&lt;td&gt;Tipo de retorno&lt;/td&gt;&lt;td&gt;Puede cambiar.&lt;/td&gt;&lt;td&gt;No puede cambiar, excepto para retornos covariantes.&lt;/td&gt;&lt;/tr&gt;    &lt;tr&gt;&lt;td&gt;Excepciones&lt;/td&gt;&lt;td&gt;Puede cambiar.&lt;/td&gt;&lt;td&gt;Pueden no declarar una excepción del método que sobre-escribe, o declarar una subclase de esta excepción. No debe lanzar nuevas excepciones o más "amplias" que aquellas declaradas en el método que sobre-escribe.&lt;/td&gt;&lt;/tr&gt;    &lt;tr&gt;&lt;td&gt;Nivel de Acceso&lt;/td&gt;&lt;td&gt;Puede cambiar.&lt;/td&gt;&lt;td&gt;No pueden tener un nivel de acceso más restrictivo, pero si uno igual o menos restrictivo.&lt;/td&gt;&lt;/tr&gt;    &lt;tr&gt;&lt;td&gt;Invocación&lt;/td&gt;&lt;td&gt;El tipo de referencia determina cuál método sobrecargado es seleccionado, basado en el tipo de argumentos declarados. &lt;span class="negritas"&gt;Sucede en tiempo de compilación&lt;/span&gt;.&lt;/td&gt;&lt;td&gt;El método real que se invoca es todavía una invocación de método virtual que siempre sucede en tiempo de ejecución, pero el compilador ya sabe la firma del método que se invoca. El tipo de objeto determina cuál método es seleccionado. &lt;span class="negritas"&gt;Sucede en tiempo de ejecución&lt;/span&gt;.&lt;/td&gt;&lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="titulo"&gt;Casting de variables de referencia&lt;/h2&gt;Hasta el momento hemos visto como es posible y común el uso de variables de referencia genéricas para referirse a tipos de objetos más específicos, eso es el corazón del polimorfismo,  como ejemplo veamos la siguiente línea de código:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;Animal animal = new Gaviota();&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;¿Pero qué sucede si queremos usar una variable de referencia "&lt;span class="codigo"&gt;Animal&lt;/span&gt;" para invocar un método que solo la clase "&lt;span class="codigo"&gt;Perro&lt;/span&gt;" tiene? Sabemos que nos estamos refiriendo a un &lt;span class="codigo"&gt;Perro&lt;/span&gt; y queremos hacer una cosa específica de &lt;span class="codigo"&gt;Perro&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;En la siguiente línea de código tendremos un arreglo de &lt;span class="codigo"&gt;Animal&lt;/span&gt;es y cada vez que encontremos una &lt;span class="codigo"&gt;Perro&lt;/span&gt; en el arreglo, haremos algo especial de &lt;span class="codigo"&gt;Perro&lt;/span&gt;. Asumamos por el momento que todo el código escrito a continuación esté correcto, solo que no estamos seguros de la línea de código que invocara al método "&lt;span class="codigo"&gt;hacerRuido&lt;/span&gt;".&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class Animal&lt;br /&gt;{&lt;br /&gt;    void hacerRuido()&lt;br /&gt;    {&lt;br /&gt;        System.out.println("Ruido Generico");&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class Perro extends Animal&lt;br /&gt;{&lt;br /&gt;    void hacerRuido()&lt;br /&gt;    {&lt;br /&gt;        System.out.println("Ladrando");&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    void hacerseElMuerto()&lt;br /&gt;    {&lt;br /&gt;        System.out.println("Muriendo");&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class Prueba&lt;br /&gt;{&lt;br /&gt;    public static void main(String... args)&lt;br /&gt;    {&lt;br /&gt;        Animal[] a = {new Animal(), new Perro(), new Animal()};&lt;br /&gt;&lt;br /&gt;        for(Animal animal: a)&lt;br /&gt;        {&lt;br /&gt;            animal.hacerRuido();&lt;br /&gt;&lt;br /&gt;            if(animal instanceof Perro)&lt;br /&gt;            {&lt;br /&gt;                animal.hacerseElMuerto(); //Se intenta invocar un metodo de Perro?&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Cuando compilemos el código anterior, el compilador nos enviara un mensaje como:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;Cannot find Symbol&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;El compilador nos está diciendo: "Oye, la clase "&lt;span class="codigo"&gt;Animal&lt;/span&gt;" no tiene un método "&lt;span class="codigo"&gt;hacerseElMuerto&lt;/span&gt;"".&lt;br /&gt;&lt;br /&gt;Ahora modifiquemos el bloque de la condicional &lt;span class="codigo"&gt;if&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;if(animal instanceof Perro)&lt;br /&gt;{&lt;br /&gt;    Perro perro = (Perro) animal; // Casteando la variable de referencia&lt;br /&gt;    perro.hacerseElMuerto();&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;El nuevo y mejorado bloque de código contiene un "&lt;span class="codigo"&gt;cast&lt;/span&gt;", el cual en algunos casos es llamado &lt;span class="codigo"&gt;down casting&lt;/span&gt;, porque estamos bajando en el árbol de herencia a una categoría mas especifica. &lt;br /&gt;&lt;br /&gt;Ahora el compilador no nos dará problemas, casteamos la variable "&lt;span class="codigo"&gt;animal&lt;/span&gt;" a un tipo "&lt;span class="codigo"&gt;Perro&lt;/span&gt;". El compilador nos está diciendo lo siguiente: "Sabemos que nos estamos refiriendo a un objeto del tipo &lt;span class="codigo"&gt;Perro&lt;/span&gt;, está bien hacer una nueva variable de referencia de tipo &lt;span class="codigo"&gt;Perro&lt;/span&gt;, para referirnos a este objeto", en este caso estamos bien, porque antes de intentar el "&lt;span class="codigo"&gt;cast&lt;/span&gt;" hicimos una prueba de &lt;span class="codigo"&gt;instanceof&lt;/span&gt; para asegurarnos.&lt;br /&gt;&lt;br /&gt;Es importante saber que el compilador confía en nosotros cuando hacemos un &lt;span class="codigo"&gt;down casting&lt;/span&gt; aun cuando pudiéramos hacer algo como lo siguiente:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class Animal{}&lt;br /&gt;&lt;br /&gt;public class Perro extends Animal{}&lt;br /&gt;&lt;br /&gt;public class Prueba&lt;br /&gt;{&lt;br /&gt;    public static void main(String... args)&lt;br /&gt;    {&lt;br /&gt;        Animal animal = new Animal();&lt;br /&gt;        Perro perro = (Perro)animal; //Compila pero fallara después &lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Este código compilara correctamente pero cuando intentemos ejecutarlo vamos a obtener una excepción como la siguiente:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;java.lang.ClassCastException&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;¿Por qué no podemos confiar en el compilador para que nos ayude en esto? ¿No puede ver que &lt;span class="codigo"&gt;animal&lt;/span&gt; es del tipo "&lt;span class="codigo"&gt;Animal&lt;/span&gt;"?  Todo lo que el compilador puede hacer es comprobar que los dos tipos &lt;span class="negritas"&gt;pertenezcan al mismo árbol de herencia&lt;/span&gt;, por lo que dependiendo de lo que el código puede hacer antes del &lt;span class="codigo"&gt;down casting&lt;/span&gt;, es posible de que "&lt;span class="codigo"&gt;animal&lt;/span&gt;" sea del tipo "&lt;span class="codigo"&gt;Perro&lt;/span&gt;". El compilador puede permitir cosas que posiblemente puedan funcionar en tiempo de ejecución. Sin embargo si el compilador sabe con certeza que el cast no puede funcionar, entonces la compilación fallara. El siguiente bloque de código NO compilará:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;Animal animal = new Animal();&lt;br /&gt;Perro p = (Perro) animal;&lt;br /&gt;String s = (String) animal; //animal nunca puede ser un String&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;En este caso obtendremos un error como el siguiente:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;inconvertible types&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A diferencia del &lt;span class="codigo"&gt;down-casting&lt;/span&gt;, el &lt;span class="codigo"&gt;up-casting&lt;/span&gt; (convertir a un tipo más general en el árbol de herencia) trabaja implícitamente porque cuando estmos haciendo &lt;span class="codigo"&gt;up-casting&lt;/span&gt; estamos implícitamente restringiendo el numero de métodos que podemos invocar, lo que impide que más adelante podamos invocar a un método más especifico, por ejemplo:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;class Animal{}&lt;br /&gt;&lt;br /&gt;class Perro extends Animal{}&lt;br /&gt;&lt;br /&gt;class Prueba&lt;br /&gt;{&lt;br /&gt;    public static void main(String … args)&lt;br /&gt;    {&lt;br /&gt;        Perro p = new Perro();&lt;br /&gt;        Animal a1 = p;  //upCasting, se puede sin conversión explicita&lt;br /&gt;        Animal a2 = (Animal)p; // upCasting, se puede con conversión explicita&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ambos &lt;span class="codigo"&gt;up-castings&lt;/span&gt; anteriores compilaran y se ejecutaran sin excepción, porque un "&lt;span class="codigo"&gt;Perro&lt;/span&gt;" ES-UN "&lt;span class="codigo"&gt;Animal&lt;/span&gt;", lo que significa que lo que cualquier "&lt;span class="codigo"&gt;Animal&lt;/span&gt;" pueda hacer, el "&lt;span class="codigo"&gt;Perro&lt;/span&gt;" lo hará. Un "&lt;span class="codigo"&gt;Perro&lt;/span&gt;" puede hacer más, pero en este punto, cualquiera con una referencia de "&lt;span class="codigo"&gt;Animal&lt;/span&gt;" puede llamar con seguridad a los métodos de "&lt;span class="codigo"&gt;Animal&lt;/span&gt;" en una instancia de "&lt;span class="codigo"&gt;Perro&lt;/span&gt;". Los métodos de "&lt;span class="codigo"&gt;Animal&lt;/span&gt;" pueden haber sido sobre-escritos en la clase "&lt;span class="codigo"&gt;Perro&lt;/span&gt;", pero todo lo que importa ahora es saber que un "&lt;span class="codigo"&gt;Perro&lt;/span&gt;" puede hacer todo lo que un "&lt;span class="codigo"&gt;Animal&lt;/span&gt;" puede hacer. El compilador y la &lt;span class="codigo"&gt;JVM&lt;/span&gt; saben esto también, entonces el &lt;span class="codigo"&gt;up-casting&lt;/span&gt; implícito es siempre legar para la asignación de un objeto de un subtipo para una referencia a su súper tipo o interface. Si "&lt;span class="codigo"&gt;Perro&lt;/span&gt;" implementa la interface "&lt;span class="codigo"&gt;Mascota&lt;/span&gt;", y "&lt;span class="codigo"&gt;Mascota&lt;/span&gt;" define el método "&lt;span class="codigo"&gt;seAmigable()&lt;/span&gt;", un "&lt;span class="codigo"&gt;Perro&lt;/span&gt;" puede implícitamente hacer casting a una "&lt;span class="codigo"&gt;Mascota&lt;/span&gt;", pero el único método de "&lt;span class="codigo"&gt;Perro&lt;/span&gt;" que se podrá invocar es "&lt;span class="codigo"&gt;seAmigable()&lt;/span&gt;", el cual "&lt;span class="codigo"&gt;Perro&lt;/span&gt;" fue forzado a implementar porque "&lt;span class="codigo"&gt;Perro&lt;/span&gt;" implementó a la interface "&lt;span class="codigo"&gt;Mascota&lt;/span&gt;".&lt;br /&gt;&lt;br /&gt;Una cosa más, si "&lt;span class="codigo"&gt;Perro&lt;/span&gt;" implementa a la interface "&lt;span class="codigo"&gt;Mascota&lt;/span&gt;", y si "&lt;span class="codigo"&gt;Sabueso&lt;/span&gt;" extiende a "&lt;span class="codigo"&gt;Perro&lt;/span&gt;", pero "&lt;span class="codigo"&gt;Sabueso&lt;/span&gt;" no declara que este implementando a "&lt;span class="codigo"&gt;Mascota&lt;/span&gt;", "&lt;span class="codigo"&gt;Sabueso&lt;/span&gt;" sigue siendo una "&lt;span class="codigo"&gt;Mascota&lt;/span&gt;", "&lt;span class="codigo"&gt;Sabueso&lt;/span&gt;" es una "&lt;span class="codigo"&gt;Mascota&lt;/span&gt;" simplemente porque este está extendiendo a "&lt;span class="codigo"&gt;Perro&lt;/span&gt;". La clase "&lt;span class="codigo"&gt;Sabueso&lt;/span&gt;" puede siempre sobre-escribir cualquier método que este heredando desde "&lt;span class="codigo"&gt;Perro&lt;/span&gt;", incluyendo los métodos que "&lt;span class="codigo"&gt;Perro&lt;/span&gt;" implementa para cumplir con el contrato de la interfaz.&lt;br /&gt;&lt;br /&gt;Por último, si "&lt;span class="codigo"&gt;Sabueso&lt;/span&gt;" declara que implementa a "&lt;span class="codigo"&gt;Mascota&lt;/span&gt;", es solamente para que los que busquen en "&lt;span class="codigo"&gt;Sabueso&lt;/span&gt;" puedan ver fácilmente que "&lt;span class="codigo"&gt;Sabueso&lt;/span&gt;" ES-UNA "&lt;span class="codigo"&gt;Mascota&lt;/span&gt;", sin tener que mirar a la superclase de "&lt;span class="codigo"&gt;Sabueso&lt;/span&gt;". "&lt;span class="codigo"&gt;Sabueso&lt;/span&gt;" no tiene la necesidad de implementar el método "&lt;span class="codigo"&gt;seAmigable()&lt;/span&gt;" si la clase "&lt;span class="codigo"&gt;Perro&lt;/span&gt;" (súper clase de "&lt;span class="codigo"&gt;Sabueso&lt;/span&gt;") ya se ha ocupado de eso. En otras palabras, si "&lt;span class="codigo"&gt;Sabueso&lt;/span&gt;" ES-UN "&lt;span class="codigo"&gt;Perro&lt;/span&gt;", y "&lt;span class="codigo"&gt;Perro&lt;/span&gt;" ES-UNA "&lt;span class="codigo"&gt;Mascota&lt;/span&gt;", entonces "&lt;span class="codigo"&gt;Sabueso&lt;/span&gt;" ES-UNA "&lt;span class="codigo"&gt;Mascota&lt;/span&gt;", y ya ha cumplido con los métodos de "&lt;span class="codigo"&gt;Mascota&lt;/span&gt;" para la aplicación del método "&lt;span class="codigo"&gt;seAmigable()&lt;/span&gt;", ya que hereda el método "&lt;span class="codigo"&gt;seAmigable()&lt;/span&gt;". El compilador es suficientemente inteligente para decir: "Sé que &lt;span class="codigo"&gt;Sabueso&lt;/span&gt; es un &lt;span class="codigo"&gt;Perro&lt;/span&gt;, pero está bien para que sea más obvio".&lt;br /&gt;&lt;br /&gt;Así que no hay que dejarse engañar por el código que muestra una clase concreta que declara que implementa una interfaz, pero no implementa el método de la interface, antes de poder decir si el código es legal, debemos mirar cuál es la superclase de la clase que esta implementado esta interface. Si alguna clase en el árbol de herencia ya ha implementado métodos concretos y ha declarado que ella (la superclase) implementa la interfaz, entonces la subclase no tiene ninguna obligación de volver a implementar (sobre-escribir) los métodos.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="titulo"&gt;Implementando una interface&lt;/h2&gt;Cuando implementamos una interface estamos aceptando el contrato definido por la interfaz. Eso quiere decir que estamos obligados a implementar todos los métodos definidos por la interfaz y que cualquiera que conozca los métodos de la interfaz (no como lo implementa pero si como se llaman y que retornan) puede invocar estos métodos en una clase que implementa la interfaz.&lt;br /&gt;&lt;br /&gt;Por ejemplo si creamos una clase que implemente a la interfaz "&lt;span class="codigo"&gt;Runnable&lt;/span&gt;" (para que el código pueda ejecutarse en otro un hilo), debemos implementar el método "&lt;span class="codigo"&gt;public void run()&lt;/span&gt;", de lo contrario el hilo verá que no tenemos implementado el método "&lt;span class="codigo"&gt;run&lt;/span&gt;" de la interface "&lt;span class="codigo"&gt;Runnable&lt;/span&gt;" y provocará un error. Afortunadamente, Java impide que esta crisis se produzca mediante la ejecución de un proceso de comprobación, en el compilador, de cualquier clase que pretende implementar una interfaz.&lt;br /&gt;&lt;br /&gt;Si la clase está implementando una interface, deberíamos tener una implementación para cada método de la interface, con unas pocas excepciones que veremos en un momento.&lt;br /&gt;&lt;br /&gt;Por ejemplo, imaginemos que tenemos la interfaz "&lt;span class="codigo"&gt;Rebotable&lt;/span&gt;", con dos métodos "&lt;span class="codigo"&gt;rebotar()&lt;/span&gt;" y "&lt;span class="codigo"&gt;setFactorRebote&lt;/span&gt;", la siguiente clase compilará:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class Pelota implements Rebotable  //palabra reservada implements&lt;br /&gt;{ &lt;br /&gt;    public void rebotar(){}&lt;br /&gt;    public void setFactorRebote(int fr){}&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;El contrato garantiza que una clase tenga todos los métodos de una interface pero no garantiza que tenga una buena o correcta implementación en el cuerpo del método. El compilador nunca se fijará que haya algo entre las llaves del método, nunca dirá que es un método y que debería hacer algo, solo se fija en que tenga los métodos que se describen en la interface, nada más.&lt;br /&gt;&lt;br /&gt;Las clases que implementan una interface deben de seguir las mismas reglas para una clase que extiende a una clase abstracta.&lt;br /&gt;&lt;br /&gt;Las reglas para que una clase &lt;span class="negritas"&gt;NO&lt;/span&gt; abstracta implemente correctamente una interface son las siguientes:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Proveer implementación para todos los métodos declarados en la interface.&lt;/li&gt;&lt;li&gt;Seguir todas las reglas para una sobre-escritura legal (overrides).&lt;/li&gt;&lt;li&gt;No declarar excepciones, en la implementación del método, que no estén en el método definido en la interface. Se pueden declarar subclases de las declaradas por el método de la interfaz.&lt;/li&gt;&lt;li&gt;Mantener el mismo nombre del método de la interface y el mismo tipo de dato de retorno (o un subtipo).&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Una clase que implementa una interface &lt;span class="negritas"&gt;puede ser abstracta&lt;/span&gt;. Por ejemplo:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;abstract class Pelota implements Rebotable{}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;¿Notan que algo falta?, pues no estamos implementando los métodos de la interfaz "&lt;span class="codigo"&gt;Rebotable&lt;/span&gt;", y no tenemos ningún error. Si la clase que implementa una interface es una clase abstracta esta puede simplemente pasar la implementación de los métodos a la primera clase concreta que se implemente. &lt;br /&gt;&lt;br /&gt;Por ejemplo si tenemos la clase "&lt;span class="codigo"&gt;PelotaPlaya&lt;/span&gt;" y esta extiende de la clase "&lt;span class="codigo"&gt;Pelota&lt;/span&gt;", entonces la clase "&lt;span class="codigo"&gt;PelotaPlaya&lt;/span&gt;" debe de implementar todos los métodos de la interfaz "&lt;span class="codigo"&gt;Rebotable&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class PelotaPlaya extends Pelota&lt;br /&gt;{&lt;br /&gt;    /*A pesar que no se dice en la declaración anterior (no hay implements a Rebotable)&lt;br /&gt;      PelotaPlaya tiene que implementar a la interface Rebotable ya que la super clase&lt;br /&gt;      abstracta de PelotaPlaya (Pelota) implementa a Rebotable */&lt;br /&gt;      &lt;br /&gt;    public void rebotar(){}&lt;br /&gt;    &lt;br /&gt;    public void setFactorRebote(int fr){} &lt;br /&gt;    &lt;br /&gt;    /*Si la clase Pelota hubiera declarado algun método abstracto, entonces&lt;br /&gt;     ese método debería estar implementado aquí también*/&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A menos que la implementación sea de una clase abstracta, la implementación debe tener todos los métodos definidos por la interface.&lt;br /&gt;&lt;br /&gt;Hay dos reglas más que debemos saber:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="negritas"&gt;1.&lt;/span&gt; Una clase puede implementar más de una interface, por ejemplo:&lt;/li&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class Pelota implements Rebotable, Runnable, Serializable{}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Podemos extender solo a una clase, pero implementar a muchas interfaces. Pero recuerden que la sub-clasificación (extends) define quién y qué es nuestra clase, mientras que la implementación (implements)  define una función que puede desempeñar o un sombrero que nuestra clase puede usar, a pesar de lo diferente que podría ser de la otra clase que implemente la misma interface  (pero de un árbol de herencia diferente). Por ejemplo: "&lt;span class="codigo"&gt;Persona extends SerHumano&lt;/span&gt;", pero una "&lt;span class="codigo"&gt;Persona&lt;/span&gt;" también puede ser (implements) "&lt;span class="codigo"&gt;Programador&lt;/span&gt;", "&lt;span class="codigo"&gt;Empleado&lt;/span&gt;", "&lt;span class="codigo"&gt;Pariente&lt;/span&gt;".&lt;br /&gt;&lt;li&gt;&lt;span class="negritas"&gt;2.&lt;/span&gt; Una interface puede también extender a otra interface, pero nunca implementar nada, por ejemplo:&lt;/li&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public interface Rebotable extends Movible{}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/ul&gt;¿Qué significa esto? La primera clase concreta que implemente "&lt;span class="codigo"&gt;Rebotable&lt;/span&gt;" debe implementar todos los métodos de esta interface, pero también debe implementar todos los métodos de la interface "&lt;span class="codigo"&gt;Movible&lt;/span&gt;". La sub-interface simplemente está agregando más requerimientos al contrato de la super-interface.&lt;br /&gt;&lt;br /&gt;Una interface puede extender a más  de una interface, pero sabemos que cuando hablamos de clases esto es ilegal, por ejemplo:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class Programador extends Empleado, Geek{} //Esto es ilegal!!&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Como mencionamos anteriormente una clase no permite extender a más de una clase en Java, una interface, sin embargo, puede implementar a más de una interface, por ejemplo:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public interface Rebotable extends Movible, Inflable //OK&lt;br /&gt;{ &lt;br /&gt;    void rebotar();&lt;br /&gt;    void setFactorRebote(int fr);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;interface Movible&lt;br /&gt;{&lt;br /&gt;    void muevete();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;interface Inflable&lt;br /&gt;{&lt;br /&gt;    void inflate();&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;En el próximo ejemplo, "&lt;span class="codigo"&gt;Pelota&lt;/span&gt;" requiere implementar la interface "&lt;span class="codigo"&gt;Rebotable&lt;/span&gt;", pero también debe implementar todos los métodos de las interfaces que "&lt;span class="codigo"&gt;Rebotable&lt;/span&gt;" ha extendido, incluyendo cualquier interface que aquellas interfaces extienden, y así sucesivamente hasta llegar a la parte superior de la pila. "&lt;span class="codigo"&gt;Pelota&lt;/span&gt;" debe tener lo siguiente:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class Pelota implements Rebotable&lt;br /&gt;{&lt;br /&gt;    public void rebotar(){}               //implementando metodos de la &lt;br /&gt;    public void setFactorRebote(int fr){} //interface Rebotable&lt;br /&gt;&lt;br /&gt;    public void muevete(){} //implementando de Movible&lt;br /&gt;&lt;br /&gt;    public void inflate(){} //implementando de Inflable&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Si la clase "&lt;span class="codigo"&gt;Pelota&lt;/span&gt;" no implementa cualquiera de los métodos de "&lt;span class="codigo"&gt;Rebotable&lt;/span&gt;", "&lt;span class="codigo"&gt;Movible&lt;/span&gt;" o "&lt;span class="codigo"&gt;Inflable&lt;/span&gt;", el compilador encontrará errores, al menos que "&lt;span class="codigo"&gt;Pelota&lt;/span&gt;" sea una clase abstracta. En el caso de que "&lt;span class="codigo"&gt;Pelota&lt;/span&gt;" sea una clase abstracta esta puede implementar todos, algunos o ningún método de las interfaces, puede dejar la implementación a una sub clase concreta de "&lt;span class="codigo"&gt;Pelota&lt;/span&gt;", por ejemplo:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;abstract class Pelota implements Rebotable&lt;br /&gt;{&lt;br /&gt;    public void rebotar(){}               //define comportamiento de la&lt;br /&gt;    public void setFactorRebote(int fr){} //interface Rebotable&lt;br /&gt;&lt;br /&gt;    /*no implementa el resto de los métodos, deja el resto para una sub-clase concreta*/&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class PelotaFutbol extends Pelota&lt;br /&gt;{&lt;br /&gt;    /*implementando métodos que pelota no hizo*/&lt;br /&gt;    public void muevete(){} //implementando de Movible&lt;br /&gt;&lt;br /&gt;    public void inflate(){} //implementando de Inflable&lt;br /&gt;&lt;br /&gt;    /*PelotaFutbol puede elegir sobre escribir el método rebotar implementado en pelota*/&lt;br /&gt;    public void rebotar(){} &lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Comparando ejemplos de abstracto y concreto de extender e implementar:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/--fRG0izkoJs/TrX5F3FiVOI/AAAAAAAABPA/_cji-8X7kTk/s1600/C2_2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="465" src="http://4.bp.blogspot.com/--fRG0izkoJs/TrX5F3FiVOI/AAAAAAAABPA/_cji-8X7kTk/s640/C2_2.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Ya que "&lt;span class="codigo"&gt;PelotaFutbol&lt;/span&gt;" es la primera clase concreta que Implementa "&lt;span class="codigo"&gt;Rebotable&lt;/span&gt;", esta debe implementar todos los métodos de la interface "&lt;span class="codigo"&gt;Rebotable&lt;/span&gt;", excepto aquellos definidos en la clase abstracta "&lt;span class="codigo"&gt;Pelota&lt;/span&gt;". Ya que "&lt;span class="codigo"&gt;Pelota&lt;/span&gt;" no provee implementación de los métodos  de la interface "&lt;span class="codigo"&gt;Rebotable&lt;/span&gt;", es necesario que "&lt;span class="codigo"&gt;PelotaFutbol&lt;/span&gt;" implemente todos aquellos métodos.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="titulo"&gt;Tipos Correctos de Retorno&lt;/h2&gt;El objetivo de esta sección es cubrir dos aspectos de los tipos de retorno:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="negritas"&gt;1.&lt;/span&gt; Qué se puede declarar como un tipo de retorno, y &lt;/li&gt;&lt;li&gt;&lt;span class="negritas"&gt;2.&lt;/span&gt; Qué se puede retornar como un valor.&lt;/li&gt;&lt;/ul&gt;Qué se puede y no se puede declarar es muy sencillo, pero esto depende si estamos sobre-escribiendo un método, heredado o simplemente declarando un método nuevo (el cual incluye sobrecarga de métodos). Daremos solo una pequeña mirada a las diferencias entre las reglas para los tipos de retorno para métodos sobre cargados y sobre-escritos (overloaded y overriding).&lt;br /&gt;&lt;br /&gt;&lt;h3 class="subtitulo"&gt;Declaración de tipos de retorno&lt;/h3&gt;Veremos qué está permitido para declarar como un tipo de retorno, lo cual depende primero en que si estamos sobre-escribiendo, sobrecargando o declarando un nuevo método.&lt;br /&gt;&lt;br /&gt;&lt;h3 class="subtitulo"&gt;Tipos de retorno en métodos sobre cargados&lt;/h3&gt;Recuerden que un método sobrecargado no es más que una forma para la reutilización del mismo nombre de un método pero con diferentes argumentos. Un método sobrecargado es un método completamente diferente de cualquier otro método con el mismo nombre. Si heredamos un método pero lo sobrecargamos este en una subclase, este no está sujeto a las restricciones de sobre-escritura, lo cual implica que podemos declarar cualquier tipo de retorno.  Lo que no podemos hacer es cambiar solo el tipo de retorno. Para sobre cargar un método solo debemos cambiar la lista de argumentos, por ejemplo:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class Animal&lt;br /&gt;{&lt;br /&gt;    void muevete(){};&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class Perro extends Animal&lt;br /&gt;{&lt;br /&gt;    String muevete(int numeroPasos)&lt;br /&gt;    {&lt;br /&gt;        return null;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Noten que el método de "&lt;span class="codigo"&gt;Animal&lt;/span&gt;" tiene un tipo de retorno diferente que el método de "&lt;span class="codigo"&gt;Perro&lt;/span&gt;". Esto está bien. En el momento que se ha cambiado la lista de argumentos, hemos sobrecargado el método, entonces el tipo de retorno no tiene que coincidir con el del método de la súper clase, pero por ejemplo, lo siguiente no está permitido: &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class Animal&lt;br /&gt;{&lt;br /&gt;    void muevete(){};&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class Perro extends Animal&lt;br /&gt;{&lt;br /&gt;    String muevete() //Error, no se puede cambiar solo el tipo de retorno&lt;br /&gt;    {  &lt;br /&gt;        return null;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3 class="subtitulo"&gt;Sobre escritura y tipos de retorno, retornos covariantes&lt;/h3&gt;Cuando una clase quiere cambiar la implementación del método de un método heredado (sobre-escrito), la subclase debe definir un método que debe coincidir exactamente con el método heredado. O, a partir de &lt;span class="codigo"&gt;Java 5&lt;/span&gt;, se le permite cambiar el tipo de retorno en el método sobre-escrito siempre y cuando el nuevo tipo de retorno es un subtipo del tipo de retorno declarado en el método a sobre-escribir (superclase).&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;class Alpha &lt;br /&gt;{&lt;br /&gt;    Alpha hacerAlgo(char c)&lt;br /&gt;    {&lt;br /&gt;        return new Alpha(); &lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class Beta extends Alpha&lt;br /&gt;{&lt;br /&gt;    Beta hacerAlgo(char c) //sobre escritura legal en Java 1.5&lt;br /&gt;    { &lt;br /&gt;        return new Beta();&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;En &lt;span class="codigo"&gt;Java 5&lt;/span&gt; este código compilara sin problemas, pero si intentamos compilar este código con &lt;span class="codigo"&gt;Java 1.4&lt;/span&gt;, mostrará el siguiente error:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;attempting to use incompatible return type&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Otras reglas aplicadas a la sobre-escritura, incluyen aquellas para modificadores de acceso y declaración de excepciones.&lt;br /&gt;&lt;br /&gt;&lt;h3 class="subtitulo"&gt;Retornando un valor&lt;/h3&gt;Tenemos que recordar solo &lt;span class="negritas"&gt;6 reglas&lt;/span&gt; para retornar un valor:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;  &lt;li&gt;&lt;span class="negritas"&gt;1. &lt;/span&gt; Podemos retornar &lt;span class="codigo"&gt;null&lt;/span&gt; a los métodos que tengan como tipo de retorno un objeto, ejemplo:&lt;/li&gt;  &lt;pre&gt;&lt;code&gt;&lt;br /&gt;public Button hacerAlgo&lt;br /&gt;{&lt;br /&gt;    return null;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;  &lt;li&gt;&lt;span class="negritas"&gt;2. &lt;/span&gt; Podemos declarar un arreglo como tipo de retorno sin problemas, ejemplo:&lt;/li&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public String[] go()&lt;br /&gt;{&lt;br /&gt;    return new String[]  {"Alan", "Alex", "Diego", "y Peke", "Henry", "Cesar", "Pedroww"};&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;li&gt;&lt;span class="negritas"&gt;3. &lt;/span&gt; En un método con un tipo de retorno primitivo, podemos retornar cualquier valor o variable que pueda ser implícitamente convertido al tipo de retorno declarado, ejemplo:&lt;/li&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public int go()&lt;br /&gt;{&lt;br /&gt;    char c = ‘c’;&lt;br /&gt;    return c; //char es compatible con int&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;li&gt;&lt;span class="negritas"&gt;4. &lt;/span&gt;En un método con un tipo de retorno primitivo, podemos retornar cualquier valor o variable que pueda ser explícitamente convertido al tipo de retorno declarado, ejemplo:&lt;/li&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public int go()&lt;br /&gt;{&lt;br /&gt;    float f = 32.5f;&lt;br /&gt;    return (int) f&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;li&gt;&lt;span class="negritas"&gt;5. &lt;/span&gt;No debemos retornar nada desde un método que tiene como tipo de retorno "&lt;span class="codigo"&gt;void&lt;/span&gt;", ejemplo:&lt;/li&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public void go()&lt;br /&gt;{&lt;br /&gt;    return "Esto es todo"; //Error, no es legal&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;li&gt;&lt;span class="negritas"&gt;6. &lt;/span&gt;En un método con un tipo de retorno con referencia a un objeto, podemos retornar cualquier tipo de objeto que pueda ser implícitamente convertido al tipo de retorno declarado, ejemplo:&lt;/li&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public Animal getAnimal()&lt;br /&gt;{&lt;br /&gt;    return new Perro(); //Asumiendo que Perro extiende de Animal&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public Object getObject()&lt;br /&gt;{&lt;br /&gt;    int[] nums =  {1, 2, 3};&lt;br /&gt;    return nums; //retorna un arreglo de enteros, el cual sigue siendo un //objeto&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public interface Rebotable{}&lt;br /&gt;&lt;br /&gt;public class Pelota implements Rebotable{}&lt;br /&gt;&lt;br /&gt;public class TestPelota&lt;br /&gt;{&lt;br /&gt;    //Método con una interface como tipo de retorno &lt;br /&gt;    public Rebotable getRebotable()&lt;br /&gt;    {&lt;br /&gt;        return new Pelota(); //Retorna un implementador de la interface&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/ul&gt;Y con eso terminamos todo lo concerniente con las reglas para el retorno de tipos de valor. Ahora veremos algunos detalles interesantes sobre constructores e instanciación de objetos.&lt;br /&gt;&lt;br /&gt;&lt;h2 class="titulo"&gt;Constructores e Instanciación&lt;/h2&gt;Los objetos son construidos. No podemos crear un nuevo objeto sin invocar a un constructor. No podemos crear un nuevo objeto sin invocar al constructor del objeto actual y a los constructores de sus superclases. &lt;br /&gt;&lt;br /&gt;Los constructores son código que se ejecuta cuando usamos la palabra reservada "&lt;span class="codigo"&gt;new&lt;/span&gt;". También pueden ser bloques de inicialización que se ejecutan al escribir "&lt;span class="codigo"&gt;new&lt;/span&gt;" (son como constructores pero un poco distintos), pero vamos a cubrir estos (bloques de inicialización), y sus homólogos de la inicialización estática, más adelante. Vamos a ver cómo se codifican los constructores y como trabajan en tiempo de ejecución.&lt;br /&gt;&lt;br /&gt;&lt;h3 class="subtitulo"&gt;Constructores Básicos&lt;/h3&gt;Todas las clases, incluyendo las clases abstractas, deben tener un constructor, pero solo porque una clase deba de tener un constructor no quiere decir que necesitamos escribirlo explícitamente. Un constructor es algo como esto:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class Rectangulo&lt;br /&gt;{&lt;br /&gt;    Rectangulo(){} //Constructor para la clase Rectangulo&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Un constructor no retorna ningún tipo de valor. Hay dos cosas que siempre debemos recordar acerca de los constructores: &lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;span class="codigo"&gt;1. &lt;/span&gt;No retornan ningún tipo de valor y &lt;/li&gt;&lt;li&gt;&lt;span class="codigo"&gt;2. &lt;/span&gt;Llevan el mismo nombre que la clase.&lt;/li&gt;&lt;/ol&gt;Típicamente los constructores son utilizados para inicializar el estado de las variables de instancia, por ejemplo:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class Rectangulo&lt;br /&gt;{&lt;br /&gt;    private int ancho;&lt;br /&gt;    private int altura;&lt;br /&gt;&lt;br /&gt;    public Rectangulo (int ancho, int altura) &lt;br /&gt;    {&lt;br /&gt;        this.ancho = ancho;&lt;br /&gt;        this.altura = altura;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;En el caso anterior, la clase "&lt;span class="codigo"&gt;Rectangulo&lt;/span&gt;" &lt;span class="negritas"&gt;no tienen un constructor sin argumentos&lt;/span&gt;, lo que significa que el siguiente código fallará en tiempo de compilación:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;Rectangulo r = new Rectangulo(); //No compila, no coinciden el constructor&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Pero el siguiente código, compilará correctamente: &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;Rectangulo r = new Rectangulo(4,2); //No hay problema, los argumentos coinciden con el constructor&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Es muy común (y deseable) tener un constructor sin argumentos, independientemente del número de constructores sobrecargados que nuestra clase pueda tener (sí, &lt;span class="negritas"&gt;los constructores pueden ser sobrecargados&lt;/span&gt;). De vez en cuando se tiene una clase en la que no tiene sentido crear una instancia sin necesidad de suministrar información al constructor. Un "&lt;span class="codigo"&gt;java.awt.Color&lt;/span&gt;", por ejemplo, no puede ser llamado mediante una llamada a un constructor sin argumentos, porque es como decirle a la JVM: "Hazme un nuevo color, y no me importa qué tipo de color sea este... tu decide", ¿realmente creen que la &lt;span class="codigo"&gt;JVM&lt;/span&gt; pueda tomar decisiones de ese tipo?&lt;br /&gt;&lt;br /&gt;&lt;h3 class="subtitulo"&gt;Encadenamiento de constructores&lt;/h3&gt;Sabemos que los constructores son invocados en tiempo de ejecución cuando usamos la palabra reservada "&lt;span class="codigo"&gt;new&lt;/span&gt;" de la siguiente manera:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;Perro p = new Perro();&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Pero ¿qué es lo que realmente sucede cuando escribimos "&lt;span class="codigo"&gt;new Rectangulo()&lt;/span&gt;"?&lt;br /&gt;&lt;br /&gt;Asumamos que "&lt;span class="codigo"&gt;Perro&lt;/span&gt;" extiende (hereda) de "&lt;span class="codigo"&gt;Animal&lt;/span&gt;" y "&lt;span class="codigo"&gt;Animal&lt;/span&gt;" extiende de "&lt;span class="codigo"&gt;Object&lt;/span&gt;"&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;span class="negritas"&gt;1. &lt;/span&gt;El constructor de "&lt;span class="codigo"&gt;Perro&lt;/span&gt;" es invocado. Cada constructor invoca al constructor de su superclase con una llamada implícita a "&lt;span class="codigo"&gt;super()&lt;/span&gt;", a menos que el constructor invoque a un constructor sobrecargado de la misma clase, pero esto lo veremos más adelante.&lt;/li&gt;&lt;li&gt;&lt;span class="negritas"&gt;2. &lt;/span&gt;El constructor de "&lt;span class="codigo"&gt;Animal&lt;/span&gt;" es invocado ("&lt;span class="codigo"&gt;Animal&lt;/span&gt;" es la superclase de "&lt;span class="codigo"&gt;Perro&lt;/span&gt;")&lt;/li&gt;&lt;li&gt;&lt;span class="negritas"&gt;3. &lt;/span&gt;El constructor de "&lt;span class="codigo"&gt;Object&lt;/span&gt;" es invocado ("&lt;span class="codigo"&gt;Object&lt;/span&gt;" es la última superclase de todas las clases, entonces "&lt;span class="codigo"&gt;Animal&lt;/span&gt;" extiende de "&lt;span class="codigo"&gt;Object&lt;/span&gt;" a pesar de que no escribimos explícitamente "&lt;span class="codigo"&gt;extends Object&lt;/span&gt;" en la declaración de la clase "&lt;span class="codigo"&gt;Animal&lt;/span&gt;". Esto es Implícito), en este punto estamos en el cima de la pila.&lt;/li&gt;&lt;li&gt;&lt;span class="negritas"&gt;4. &lt;/span&gt;Se asignan los valores explícitos a las variables de instancia. Nos referimos a las variables que declaramos como "&lt;span class="codigo"&gt;int x = 24&lt;/span&gt;", donde 24 es el valor explicito (en comparación con el valor por defecto) de la variable de instancia.&lt;/li&gt;&lt;li&gt;&lt;span class="negritas"&gt;5. &lt;/span&gt;El constructor de &lt;span class="codigo"&gt;Object&lt;/span&gt; se completa.&lt;/li&gt;&lt;li&gt;&lt;span class="negritas"&gt;6. &lt;/span&gt;Se asignan los valores explícitos a las variables de instancia de "&lt;span class="codigo"&gt;Animal&lt;/span&gt;" (si tuviera).&lt;/li&gt;&lt;li&gt;&lt;span class="negritas"&gt;7. &lt;/span&gt;El constructor de "&lt;span class="codigo"&gt;Animal&lt;/span&gt;" completa.&lt;/li&gt;&lt;li&gt;&lt;span class="negritas"&gt;8. &lt;/span&gt;Se asignan los valores explícitos a las variables de instancia de "&lt;span class="codigo"&gt;Perro&lt;/span&gt;" (si tuviera).&lt;/li&gt;&lt;li&gt;&lt;span class="negritas"&gt;9. &lt;/span&gt;El constructor de "&lt;span class="codigo"&gt;Perro&lt;/span&gt;" completa.&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;A continuación mostramos como trabajan los constructores en la pila de llamadas:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;span class="negritas"&gt;4.-&lt;/span&gt; &lt;span class="codigo"&gt;Object()&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="negritas"&gt;3.-&lt;/span&gt; &lt;span class="codigo"&gt;Animal()&lt;/span&gt; llamada a &lt;span class="codigo"&gt;super()&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="negritas"&gt;2.-&lt;/span&gt; &lt;span class="codigo"&gt;Perro()&lt;/span&gt; llamada a &lt;span class="codigo"&gt;super()&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="negritas"&gt;1.-&lt;/span&gt; &lt;span class="codigo"&gt;main()&lt;/span&gt; llamada a new &lt;span class="codigo"&gt;Perro()&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3 class="subtitulo"&gt;Reglas para los constructores:&lt;/h3&gt;A continuación mostramos lo que debemos recordar acerca de los constructores:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Un constructor puede tener cualquier modificador de acceso, incluso "&lt;span class="codigo"&gt;private&lt;/span&gt;" (un constructor privado quiere decir que solo el código dentro de la clase misma puede instanciar un objeto de ese tipo, así que si la clase con constructor privado quiere permitir que una clase pueda instanciarla, la clase debe proveer un método estático o variable que permitan acceder a una instancia creada dentro de la clase).&lt;/li&gt;&lt;li&gt;El constructor debe tener el mismo nombre que la clase.&lt;/li&gt;&lt;li&gt;El constructor no debe retornar ningún tipo de valor.&lt;/li&gt;&lt;li&gt;Es legal (pero tonto) tener un método con el mismo nombre de la clase, pero esto no hace que sea un constructor. &lt;span class="negritas"&gt;Si ven que tiene un tipo de retorno, entonces es un método en vez de un constructor&lt;/span&gt;. Podemos tener ambos, un método y un constructor con el mismo nombre (el nombre de la clase) en una misma clase y esto no es problema para Java.&lt;/li&gt;&lt;li&gt;Si no escribimos ningún constructor dentro de la clase, un constructor por defecto será automáticamente generado por el compilador.&lt;/li&gt;&lt;li&gt;El constructor por defecto SIEMPRE es un constructor sin argumentos.&lt;/li&gt;&lt;li&gt;Si deseamos tener un constructor sin argumentos y ya hemos escrito algún otro constructor dentro de la clase, el compilador NO proporcionara un constructor sin argumentos (o cualquier otro constructor). Es decir si hemos escrito algún constructor con argumentos no vamos a tener un constructor sin argumentos a menos que nosotros mismos lo declaremos. &lt;/li&gt;&lt;li&gt;Todos los constructores tienen como primera declaración ya sea una llamada a un constructor sobre cargado "&lt;span class="codigo"&gt;this()&lt;/span&gt;" o una llamada al constructor de la superclase "&lt;span class="codigo"&gt;super()&lt;/span&gt;", aunque recuerden que esta llamada puede ser insertada por el compilador.&lt;/li&gt;&lt;li&gt;Si escribimos un constructor (en lugar de confiar en el constructor por defecto generado por el compilador), y no escribimos una llamada a &lt;span class="codigo"&gt;this()&lt;/span&gt; o a &lt;span class="codigo"&gt;super()&lt;/span&gt;, el compilador insertará una llamada sin argumentos a &lt;span class="codigo"&gt;super()&lt;/span&gt; por nosotros, como una primera declaración en el constructor.&lt;/li&gt;&lt;li&gt;Una llamada a &lt;span class="codigo"&gt;super()&lt;/span&gt; puede ser una llamada sin argumentos o podemos incluir argumentos en él.&lt;/li&gt;&lt;li&gt;Un constructor sin argumentos no es necesariamente el constructor por defecto, aunque el constructor por defecto siempre es uno sin argumentos. El constructor por defecto es el único que el compilador provee, pero podemos insertar nuestro propio constructor sin argumentos.&lt;/li&gt;&lt;li&gt;No podemos hacer una llamada a un método de instancia o acceder a una variable de instancia hasta que se ejecute el constructor &lt;span class="codigo"&gt;super&lt;/span&gt;.&lt;/li&gt;&lt;li&gt;&lt;span class="negritas"&gt;Solo variables y métodos estáticos pueden ser accedidos como parte de la llamada a &lt;span class="codigo"&gt;super()&lt;/span&gt; o &lt;span class="codigo"&gt;this()&lt;/span&gt;&lt;/span&gt;. Por ejemplo: &lt;span class="codigo"&gt;super(Animal.NOMBRE)&lt;/span&gt; está bien ya que &lt;span class="codigo"&gt;NOMBRE&lt;/span&gt; está declarada como variable estática.&lt;/li&gt;&lt;li&gt;Las clases abstractas tienen constructores, y estos constructores son siempre llamados cuando una clase concreta es instanciada.&lt;/li&gt;&lt;li&gt;&lt;span class="negritas"&gt;Las interfaces no tienen constructores&lt;/span&gt;, las interfaces no son parte del árbol de herencia de un objeto.&lt;/li&gt;&lt;li&gt;La única forma de que un constructor pueda ser invocado es dentro de otro constructor, en decir, no podemos invocar a un constructor de la siguiente manera:&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class Perro&lt;br /&gt;{&lt;br /&gt;    public Perro(){} //Contructor&lt;br /&gt;    &lt;br /&gt;    public void hacerAlgo()&lt;br /&gt;    {&lt;br /&gt;        Perro(); //llamada al constructor. Error!!&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3 class="subtitulo"&gt;Determinar si un constructor por defecto será creado&lt;/h3&gt;El siguiente código muestra a la clase "&lt;span class="codigo"&gt;Perro&lt;/span&gt;" con dos constructores:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class Perro&lt;br /&gt;{&lt;br /&gt;    public Perro(){}&lt;br /&gt;    public Perro(String nombre){}&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;¿El compilador insertará un constructor por defecto para la clase anterior? &lt;span class="negritas"&gt;¡¡NO!!&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;¿Y para la siguiente modificación en la clase?&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class Perro&lt;br /&gt;{&lt;br /&gt;    public Perro(String nombre){}&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;¿Ahora el compilador insertará un constructor por defecto? &lt;span class="negritas"&gt;¡¡NO!!&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;¿Y qué hay de esta clase?&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class Perro&lt;br /&gt;{  &lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;El compilador &lt;span class="negritas"&gt;SI&lt;/span&gt; generará un constructor por defecto para la clase anterior, porque la clase no tiene ningún constructor definido. Y ahora ¿Qué hay de esta siguiente clase?:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class Perro&lt;br /&gt;{ &lt;br /&gt;    void Perro(){}&lt;br /&gt;} &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Podría parecer que el compilador no crea un constructor ya que ya hay un constructor en la clase "&lt;span class="codigo"&gt;Perro&lt;/span&gt;". ¿Pero realmente hay un constructor? Revisemos nuevamente la clase anterior, pues eso no es un constructor, es solo un método que tiene el mismo nombre que la clase. Recordemos que &lt;span class="negritas"&gt;el tipo de retorno es un claro indicador de que eso es un método y no un constructor&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;¿Cómo se sabe con seguridad que un constructor por defecto será creado?&lt;br /&gt;&lt;br /&gt;&lt;span class="negritas"&gt;Porque no declaramos NINGUN constructor en nuestra clase&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;¿Cómo se verá el constructor por defecto creado por el compilador?&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;El constructor por defecto tiene el mismo modificador de acceso que la clase.&lt;/li&gt;&lt;li&gt;El constructor por defecto no tiene argumentos.&lt;/li&gt;&lt;li&gt;El constructor por defecto incluye una llamada sin argumentos al súper constructor (&lt;span class="codigo"&gt;super()&lt;/span&gt;).&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;¿Qué sucede si el súper constructor tiene argumentos?&lt;br /&gt;&lt;br /&gt;Los constructores pueden tener argumentos así como los métodos, si tratamos de invocar a un método que toma por ejemplo un &lt;span class="codigo"&gt;int&lt;/span&gt; y no le pasamos nada al método, el compilador se comportará de la siguiente manera: &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;class Ejemplo&lt;br /&gt;{&lt;br /&gt;    void tomaUnInt(int valor){}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class Test&lt;br /&gt;{&lt;br /&gt;    public static void main(String … args)&lt;br /&gt;    {&lt;br /&gt;        Ejemplo e = new Ejemplo();&lt;br /&gt;        e.tomaUnInt();  //Se está tratando de invocar al metodo "tomaUnInt()" sin argumentos&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;El compilador nos dirá que estamos tratando de invocar a "&lt;span class="codigo"&gt;tomaUnInt()&lt;/span&gt;" sin pasarle ningún un &lt;span class="codigo"&gt;int&lt;/span&gt;. El compilador, según la versión de la &lt;span class="codigo"&gt;JVM&lt;/span&gt;, responderá más o menos de la siguiente manera:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;Test.java:7: tomaUnInt(int) in Ejemplo cannot be applied to ()e. tomaUnInt();&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Esto quiere decir que debemos pasar los mismos valores o variables que el método acepta y en el mismo orden en el que esté declarado en el método, a lo que queremos llegar es que este mecanismo funciona exactamente igual en los constructores.&lt;br /&gt;&lt;br /&gt;A continuación mostramos el código que genera el compilador con respecto a los constructores:&lt;br /&gt;&lt;br /&gt;&lt;table&gt;  &lt;thead&gt;    &lt;tr&gt;&lt;th&gt;Código de clase (lo que nosotros escribimos)&lt;/th&gt;&lt;th&gt;Código de constructor generado por el compilador&lt;/th&gt;&lt;/tr&gt;  &lt;/thead&gt;  &lt;tbody&gt;    &lt;tr&gt;&lt;td&gt;&lt;pre&gt;&lt;code&gt;class Perro { }&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;    &lt;td&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;    class Perro&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="negritas"&gt;Perro()&lt;br /&gt;        {&lt;br /&gt;           super();&lt;br /&gt;        }&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;    &lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;    &lt;tr&gt;&lt;td&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;    class Perro &lt;br /&gt;    {&lt;br /&gt;       Perro(){}&lt;br /&gt;    }&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;     &lt;td&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;    class Perro&lt;br /&gt;    {&lt;br /&gt;        Perro()&lt;br /&gt;        {&lt;br /&gt;           super();&lt;br /&gt;        }&lt;br /&gt;    }&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;    &lt;tr&gt;&lt;td&gt;&lt;pre&gt;&lt;code&gt;public class Perro { }&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;     &lt;td&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;    public class Perro&lt;br /&gt;    {&lt;br /&gt;        public Perro()&lt;br /&gt;        {&lt;br /&gt;           super();&lt;br /&gt;        }&lt;br /&gt;    }&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;    &lt;tr&gt;&lt;td&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;    class Perro &lt;br /&gt;    {&lt;br /&gt;        Perro(String nombre){}&lt;br /&gt;    }&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;     &lt;td&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;    class Perro&lt;br /&gt;    {&lt;br /&gt;        Perro(String nombre)&lt;br /&gt;        {&lt;br /&gt;           super();&lt;br /&gt;        }&lt;br /&gt;    }&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;    &lt;tr&gt;&lt;td&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;    class Perro&lt;br /&gt;    {&lt;br /&gt;        Perro(String nombre)&lt;br /&gt;        {&lt;br /&gt;           super();&lt;br /&gt;        }&lt;br /&gt;    }&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;    &lt;td&gt;Nada, el compilador no necesita insertar nada&lt;/td&gt;&lt;/tr&gt;    &lt;tr&gt;&lt;td&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;    class Perro &lt;br /&gt;    {&lt;br /&gt;        void Perro(){}&lt;br /&gt;    }&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;    &lt;td&gt;&lt;pre&gt;&lt;code&gt; &lt;br /&gt;    class Perro  &lt;br /&gt;    {&lt;br /&gt;        void Perro(){}&lt;br /&gt;    &lt;br /&gt;        Perro()&lt;br /&gt;        {&lt;br /&gt;            super();&lt;br /&gt;        }&lt;br /&gt;    }&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;("&lt;span class="codigo"&gt;void Perro()&lt;/span&gt;", es un método no un constructor)&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;Si el súper constructor (el constructor de su inmediata súper clase o clase padre) tiene argumentos, debemos escribir en la llamada a &lt;span class="codigo"&gt;super()&lt;/span&gt; los argumentos adecuados.&lt;br /&gt;&lt;br /&gt;&lt;span class="negritas"&gt;Un punto crucial&lt;/span&gt;: si nuestra superclase no tiene un constructor sin argumentos, debemos escribir un constructor en la clase (subclase), porque necesitamos un lugar donde insertar, en la llamada a &lt;span class="codigo"&gt;super&lt;/span&gt;, los argumentos adecuados.&lt;br /&gt;&lt;br /&gt;El siguiente código da un ejemplo del problema:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;class Animal&lt;br /&gt;{&lt;br /&gt;    Animal(String nombre){}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class Perro extends Animal&lt;br /&gt;{&lt;br /&gt;    Perro()&lt;br /&gt;    {&lt;br /&gt;        super(); //He aquí el problema&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;El compilador nos arrojará algo como esto:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;Perro.java:7: cannot resolve symbol&lt;br /&gt;symbol  : constructor Animal  ()&lt;br /&gt;location: class Animal&lt;br /&gt;       super();  // Problema! &lt;br /&gt;       ^  &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Otra forma de explicar es la siguiente: Si nuestra superclase no tiene un constructor sin argumentos entonces la subclase no será capaz de usar el constructor por defecto que te provee el compilador, es decir, el compilador puede solo insertar una llamada a "&lt;span class="codigo"&gt;super()&lt;/span&gt;" sin argumentos, no será capaz de compilar algo como esto:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;class Animal&lt;br /&gt;{&lt;br /&gt;    Animal(String nombre){}   &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class Perro extends Animal{}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;El compilador nos arrojará algo como esto:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;Animal.java:4: cannot resolve symbol&lt;br /&gt;symbol  : constructor Animal ()  &lt;br /&gt;location: class Animal&lt;br /&gt;class Perro extends Animal { }&lt;br /&gt;^&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;El compilador explícitamente está haciendo el código que se muestra a continuación, donde vamos a proveer a "&lt;span class="codigo"&gt;Perro&lt;/span&gt;" el mismo constructor que el compilador le proveerá:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;class Animal&lt;br /&gt;{&lt;br /&gt;    Animal(String nombre){}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class Perro extends Animal&lt;br /&gt;{&lt;br /&gt;    //el constructor a continuación es idéntico al que el compilador proveerá&lt;br /&gt;    Perro()&lt;br /&gt;    {&lt;br /&gt;        super(); //¡¡Se invoca al constructor sin argumentos de "Animal" el cual no existe!!&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Una última cosa que debemos recordar es que los constructores no se heredan, estos no son métodos los cuales si se heredan. Estos no pueden ser sobre-escritos pero, como hemos visto a lo largo de esta parte de constructores, estos si se pueden sobrecargar. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3 class="subtitulo"&gt;Sobrecarga de constructores&lt;/h3&gt;Sobrecargar un constructor quiere decir que escribimos diferentes versiones del constructor, cada uno tiene diferente número de argumentos, como por ejemplo:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;class Perro&lt;br /&gt;{&lt;br /&gt;    Perro(){} &lt;br /&gt;    &lt;br /&gt;    Perro(String nombre){}&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;La clase "&lt;span class="codigo"&gt;Perro&lt;/span&gt;" anterior muestra dos constructores sobrecargados, uno de ellos toma un &lt;span class="codigo"&gt;String&lt;/span&gt; como argumento y el otro no tiene argumentos; este es exactamente igual al constructor que el compilador provee, pero recordemos que una vez que nosotros escribamos un constructor en la clase, como por ejemplo el que toma el &lt;span class="codigo"&gt;String&lt;/span&gt;, el compilador ya no nos proveerá un constructor por defecto. Si queremos un constructor sin argumentos para sobrecargar el que tiene argumentos nosotros mismo tendremos que escribirlo como en el ejemplo anterior.&lt;br /&gt;&lt;br /&gt;Sobrecargando un constructor proveemos diferentes maneras de que se pueda instanciar un objeto de nuestra clase, por ejemplo si sabemos el nombre del &lt;span class="codigo"&gt;Perro&lt;/span&gt;, podemos pasarselo a un constructor de "&lt;span class="codigo"&gt;Perro&lt;/span&gt;" que toma una cadena. Pero si no sabemos el nombre podemos llamar al constructor sin argumentos para que nos provea un nombre por defecto, a continuación mostramos un ejemplo de lo que estamos hablando:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;1. public class Perro {&lt;br /&gt;2.      String nombre;&lt;br /&gt;3.      Perro (String nombre){&lt;br /&gt;4.              this.nombre = nombre;&lt;br /&gt;5.      }&lt;br /&gt;6. &lt;br /&gt;7.      Perro(){&lt;br /&gt;8.              this(tomaNombreAleatorio());&lt;br /&gt;9.      }&lt;br /&gt;10. &lt;br /&gt;11.      static  String tomaNombreAleatorio(){&lt;br /&gt;12.               int x = (int) (Math.random() * 5);&lt;br /&gt;13.               String nombre = new String[]{"fido", "tango", "aguao", "rex" , "lassy"}[x];&lt;br /&gt;14.               return nombre;&lt;br /&gt;15.       }&lt;br /&gt;16. &lt;br /&gt;17.      public static void main(String … args){&lt;br /&gt;18.               Perro a = new Perro();&lt;br /&gt;19.               System.out.println(a.nombre);&lt;br /&gt;20.               Perro b = new Perro("flafy");&lt;br /&gt;21.               System.out.println(b.nombre);&lt;br /&gt;22.       }&lt;br /&gt;23. }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ejecutando el código unas cuantas veces tendremos un resultado como el siguiente:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;% java Perro &lt;br /&gt;tango  &lt;br /&gt;flafy&lt;br /&gt;% java Perro &lt;br /&gt;lassy  &lt;br /&gt;flafy&lt;br /&gt;% java Perro &lt;br /&gt;rex  &lt;br /&gt;flafy&lt;br /&gt;% java Perro &lt;br /&gt;aguao&lt;br /&gt;flafy&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A continuación mostramos la pila de llamadas para la invocación del constructor cuando un constructor es sobrecargado.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="negritas"&gt;4. &lt;/span&gt;&lt;span class="codigo"&gt;Object&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="negritas"&gt;3. &lt;/span&gt;&lt;span class="codigo"&gt;Perro(String nombre)&lt;/span&gt; llamada a &lt;span class="codigo"&gt;super()&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="negritas"&gt;2. &lt;/span&gt;&lt;span class="codigo"&gt;Perro()&lt;/span&gt; llamada a &lt;span class="codigo"&gt;this(tomaNombreAleatorio())&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="negritas"&gt;1. &lt;/span&gt;&lt;span class="codigo"&gt;main()&lt;/span&gt; llamada a &lt;span class="codigo"&gt;new Perro()&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Ahora vamos a describir el código desde la parte superior:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="negritas"&gt;Línea 2:&lt;/span&gt; declaramos una variable de instancia &lt;span class="codigo"&gt;nombre&lt;/span&gt; de tipo &lt;span class="codigo"&gt;String&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="negritas"&gt;Línea 3 – 5:&lt;/span&gt; El constructor toma un &lt;span class="codigo"&gt;String&lt;/span&gt; y lo asigna a la variable de instancia &lt;span class="codigo"&gt;nombre&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="negritas"&gt;Línea 7:&lt;/span&gt; Aquí viene lo interesante. Asumiendo que cada &lt;span class="codigo"&gt;Animal&lt;/span&gt; necesita de un &lt;span class="codigo"&gt;nombre&lt;/span&gt;, pero la persona que lo invoca no siempre debe saber que nombre será (código de llamada), entonces nosotros establecemos un nombre aleatorio. El constructor sin argumentos genera un nombre aleatorio invocando al método "&lt;span class="codigo"&gt;tomaNombreAleatorio()&lt;/span&gt;".&lt;/li&gt;&lt;li&gt;&lt;span class="negritas"&gt;Línea 8:&lt;/span&gt; El constructor sin argumentos invoca a su propio constructor sobrecargado que toma un &lt;span class="codigo"&gt;String&lt;/span&gt; llamandolo de la misma manera que sería llamado si se hace una nueva instancia del objeto, pasándole un &lt;span class="codigo"&gt;String&lt;/span&gt; para el &lt;span class="codigo"&gt;nombre&lt;/span&gt;. La invocación al constructor sobrecargado se hace mediante la palabra reservada "&lt;span class="codigo"&gt;this&lt;/span&gt;", pero la utiliza como si fuese un nombre de método, &lt;span class="codigo"&gt;this()&lt;/span&gt;.  Entonces en la línea 8 simplemente se está llamando al constructor sin parámetros que está en la línea 3, pasándole un &lt;span class="codigo"&gt;nombre&lt;/span&gt; aleatorio en lugar nosotros establecer el &lt;span class="codigo"&gt;nombre&lt;/span&gt;.&lt;/li&gt;&lt;li&gt;&lt;span class="negritas"&gt;Línea 11:&lt;/span&gt; Notemos que el método  "&lt;span class="codigo"&gt;tomaNombreAleatorio()&lt;/span&gt;" está marcado como estático (&lt;span class="codigo"&gt;static&lt;/span&gt;), eso es porque no podemos invocar a un método de instancia  (en otras palabras, no estático) o acceder a una variable de instancia hasta después de que el super constructor haya sido ejecutado, y hasta que el súper constructor sea invocado desde el constructor en la línea 3, en lugar que de la línea 7, la línea 8 puede usar solo un método estático para generar un nombre. Si nosotros quisiéramos especificar algún nombre en específico en vez de que se genere aleatoriamente, por ejemplo, "&lt;span class="codigo"&gt;Thor&lt;/span&gt;", entonces en la línea 8 simplemente pondríamos &lt;span class="codigo"&gt;this("Thor")&lt;/span&gt; en lugar de llamar al método "&lt;span class="codigo"&gt;tomaNombreAleatorio()&lt;/span&gt;" para generar un &lt;span class="codigo"&gt;nombre&lt;/span&gt; aleatorio.&lt;/li&gt;&lt;li&gt;&lt;span class="negritas"&gt;Línea 12:&lt;/span&gt; Esto no tiene nada que ver con el constructor pero es bueno aprenderlo, esto genera un numero entero aleatorio entre 0 y 4;&lt;/li&gt;&lt;li&gt;&lt;br /&gt;&lt;span class="negritas"&gt;Línea 13:&lt;/span&gt; Estamos creando un nuevo &lt;span class="codigo"&gt;String&lt;/span&gt;, pero queremos que este &lt;span class="codigo"&gt;String&lt;/span&gt; sea seleccionado aleatoriamente desde una lista, entonces necesitamos hacer esto. Para explicarlo con mejor detalle, en esta sola línea de código hacemos lo siguiente:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;span class="negritas"&gt;1. &lt;/span&gt;Declaramos una variable del tipo &lt;span class="codigo"&gt;String&lt;/span&gt;.&lt;/li&gt;&lt;li&gt;&lt;span class="negritas"&gt;2. &lt;/span&gt;Creamos un arreglo de &lt;span class="codigo"&gt;Strings&lt;/span&gt; (anónimo ya que no asignamos el arreglo)&lt;/li&gt;&lt;li&gt;&lt;span class="negritas"&gt;3. &lt;/span&gt;Obtenemos el &lt;span class="codigo"&gt;String&lt;/span&gt; en index &lt;span class="codigo"&gt;[x]&lt;/span&gt; (&lt;span class="codigo"&gt;x&lt;/span&gt; contiene el numero aleatorio generado en la línea 12) del recientemente creado arreglo de &lt;span class="codigo"&gt;Strings&lt;/span&gt;.&lt;/li&gt;&lt;li&gt;&lt;span class="negritas"&gt;4. &lt;/span&gt;Asignamos el &lt;span class="codigo"&gt;String &lt;/span&gt;obtenido del arreglo a la variable de instancia "&lt;span class="codigo"&gt;nombre&lt;/span&gt;". Esto hubiera sido más fácil de leer si hubiéramos escrito esto:&lt;/li&gt;&lt;/ol&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;String[] lista  = {"fido", "tango", "aguao", "rex" , "lassy"};&lt;br /&gt;String nombre = lista[x];&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="negritas"&gt;Línea 18: &lt;/span&gt;Invocamos al constructor sin argumentos (generando un &lt;span class="codigo"&gt;nombre&lt;/span&gt; aleatorio que después será enviado al constructor que recibe un &lt;span class="codigo"&gt;String&lt;/span&gt;).&lt;/li&gt;&lt;li&gt;&lt;span class="negritas"&gt;Línea 20: &lt;/span&gt;Invocamos al constructor sobrecargado que toma un &lt;span class="codigo"&gt;String&lt;/span&gt; que representa el &lt;span class="codigo"&gt;nombre&lt;/span&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;El punto cable en el código antes escrito está en la línea &lt;span class="negritas"&gt;8&lt;/span&gt;, en lugar de llamar a &lt;span class="codigo"&gt;super()&lt;/span&gt;, estamos llamando a "&lt;span class="codigo"&gt;this()&lt;/span&gt;", y "&lt;span class="codigo"&gt;this()&lt;/span&gt;" siempre significa llamar a otro constructor en la misma clase. ¿Pero qué sucede al momento de llamar a "&lt;span class="codigo"&gt;this()&lt;/span&gt;"? Tarde o temprano el constructor "&lt;span class="codigo"&gt;super()&lt;/span&gt;" será llamado, una llamada a "&lt;span class="codigo"&gt;this()&lt;/span&gt;" solo significa que estamos retrasando lo inevitable, ya que algún constructor en algún lugar debe hacer una llamada a "&lt;span class="codigo"&gt;super()&lt;/span&gt;".&lt;br /&gt;&lt;br /&gt;La regla clave: &lt;span class="negritas"&gt;la primera línea de un constructor debe ser una llamada a "&lt;span class="codigo"&gt;super()&lt;/span&gt;" o una llamada a "&lt;span class="codigo"&gt;this()&lt;/span&gt;"&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Sin excepciones. Si el constructor "&lt;span class="codigo"&gt;A()&lt;/span&gt;" tiene una llamada a "&lt;span class="codigo"&gt;this()&lt;/span&gt;", el compilador sabe que el constructor "&lt;span class="codigo"&gt;A()&lt;/span&gt;" no será e que invoque a "&lt;span class="codigo"&gt;super()&lt;/span&gt;".&lt;br /&gt;&lt;br /&gt;La regla anterior significa que un constructor nunca podrá tener ambas llamadas, es decir no podrá llamar a la vez a "&lt;span class="codigo"&gt;this()&lt;/span&gt;" y a "&lt;span class="codigo"&gt;super()&lt;/span&gt;". Porque alguna de estas llamadas debe ser la primera sentencia en un constructor, no podemos usar ambas en un mismo constructor. El compilador tampoco insertará una llamada a "&lt;span class="codigo"&gt;super()&lt;/span&gt;" si el constructor tiene una llamada a "&lt;span class="codigo"&gt;this()&lt;/span&gt;".&lt;br /&gt;&lt;br /&gt;¿Qué sucederá si nosotros tratamos de compilar el siguiente código?&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;class A&lt;br /&gt;{&lt;br /&gt;    A()&lt;br /&gt;    {&lt;br /&gt;        this("test");&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    A(String s)&lt;br /&gt;    {&lt;br /&gt;        this();&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;El compilador puede que no capte el problema (esto depende del compilador).  Este asume que sabemos lo que estamos haciendo. ¿Captan el problema? Sabemos que el súper constructor siempre debe de ser llamado, entonces ¿Dónde podría ir la llamada a "&lt;span class="codigo"&gt;super()&lt;/span&gt;"? Recordemos que el compilador no inserta ningún constructor por defecto si nosotros ya insertamos uno o más constructores en nuestra clase, y cuando el compilador no inserta un constructor por defecto todavía puede insertar una llamada a &lt;span class="codigo"&gt;super()&lt;/span&gt; en algún constructor que no tenga explícitamente una llamada a &lt;span class="codigo"&gt;super()&lt;/span&gt;, a menos que, el constructor ya tenga una llamada a &lt;span class="codigo"&gt;this()&lt;/span&gt; y recordemos que un constructor no puede tener ambas llamadas (&lt;span class="codigo"&gt;this()&lt;/span&gt; y &lt;span class="codigo"&gt;super()&lt;/span&gt;). Entonces en el código anterior ¿Dónde va la llamada a &lt;span class="codigo"&gt;super()&lt;/span&gt;? Si los únicos dos constructores en la clase tienen una llamada a &lt;span class="codigo"&gt;this()&lt;/span&gt;, en efecto nosotros tenemos el mismo problema que tendríamos si escribimos los siguientes métodos: &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public void ir()&lt;br /&gt;{&lt;br /&gt;    hacerAlgo();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void hacerAlgo()&lt;br /&gt;{&lt;br /&gt; ir();&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;¿Ahora pueden ver el problema? Podemos ver que el stack explota. Ya que se llamaran uno a otro indefinidamente hasta que la maquina o la &lt;span class="codigo"&gt;JVM&lt;/span&gt; estalle (esperamos que lo segundo suceda primero… ¿o lo primero?).  Regresando al ejemplo de los constructores podemos decir que dos constructores sobrecargados y ambos con una llamada a &lt;span class="codigo"&gt;this()&lt;/span&gt; son dos constructores llamándose uno a otro una y otra y otra vez, resultando en:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;% java A&lt;br /&gt;Exception in thread "main" java.lang.StackOverflowError&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;El beneficio de tener constructores sobrecargados es que ofrecen formas flexibles de poder instanciar un objeto de nuestra clase. El beneficio de que un constructor invoque a otro constructor sobrecargado es evitar duplicación de código, en el ejemplo anterior no hubo algún otro código para establecer el nombre, pero imaginen que después de la línea 4 aún hay muchas cosas que podríamos hacer.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="titulo"&gt;Variables y métodos estáticos&lt;/h2&gt;El modificador "&lt;span class="codigo"&gt;static&lt;/span&gt;" tiene un impacto tan profundo en el comportamiento de un método o una variable que debemos tratando como un concepto totalmente separado de los demás modificadores. Para entender la manera en que un miembro estático trabaja, primero veremos las razones por las cuales utilizaríamos alguno. &lt;br /&gt;&lt;br /&gt;Imaginen que tenemos una clase de utilidad la cual siempre se ejecuta de la misma manera, su única función es devolver, digamos, un número al azar. No nos importa en cuál instancia de la clase se ejecuta el método, ya que siempre se comporta de la misma manera. En otras palabras, el comportamiento del método no tiene ninguna dependencia en el estado (valores de variable de instancia) de un objeto.  Entonces ¿Porque es necesario un objeto cuando el método nunca será instanciado? ¿Por qué no solo pedimos a la clase en si misma que ejecute el método?&lt;br /&gt;&lt;br /&gt;Ahora imaginemos otro escenario: supongamos que queremos mantener un contador corriendo para todas las instancias de una clase en particular. ¿En dónde incluiremos la variable? No va a trabajar si la incluimos como variable de instancia dentro de las clases en las cuales se quiere hacer el seguimiento, ya que el contador siempre se iniciara a un nuevo valor por defecto cada que nosotros creamos una nueva instancia.&lt;br /&gt;&lt;br /&gt;La respuesta a los dos escenarios anteriores (el método de utilidad que se ejecuta siempre de la misma manera, y el contador para mantener el total de instancias actualizado) es utilizar el modificador &lt;span class="codigo"&gt;static&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Las variables y métodos marcados con &lt;span class="codigo"&gt;static&lt;/span&gt; &lt;span class="negritas"&gt;pertenecen a la clase y no a una instancia en particular&lt;/span&gt;. Podemos usar un método o variable &lt;span class="codigo"&gt;static&lt;/span&gt; &lt;span class="negritas"&gt;sin tener instancias de esa clase&lt;/span&gt;, solo necesitamos que la clase esté disponible para invocar un método &lt;span class="codigo"&gt;static&lt;/span&gt; o acceder a una variable &lt;span class="codigo"&gt;static&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Una variable estática de una clase será compartida por todas las instancias de esa clase, sólo hay una copia.&lt;br /&gt;&lt;br /&gt;El siguiente código utiliza una variable &lt;span class="codigo"&gt;static&lt;/span&gt; que será utilizada como contador:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;class Oveja&lt;br /&gt;{&lt;br /&gt;    static int contadorOvejas = 0; //Declaramos e inicializamos la variable estática &lt;br /&gt; &lt;br /&gt;    public Oveja()&lt;br /&gt;    {&lt;br /&gt;        contadorOveja += 1; //Modificamos el valor en el constructor&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static void main(String … args)&lt;br /&gt;    {&lt;br /&gt;        new Oveja();&lt;br /&gt;        new Oveja();&lt;br /&gt;        new Oveja();&lt;br /&gt;&lt;br /&gt;        System.out.println("El contador de ovejas está ahora en: " + contadorOveja);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;En el código anterior, la variable estática "&lt;span class="codigo"&gt;contadorOveja&lt;/span&gt;" es establecida en cero cuando la clase "&lt;span class="codigo"&gt;Oveja&lt;/span&gt;" es cargada por primera vez por la &lt;span class="codigo"&gt;JVM&lt;/span&gt;, antes de que cualquier instancia de "&lt;span class="codigo"&gt;Oveja&lt;/span&gt;" sea creada (en realidad no se necesita inicializar la variable estática en cero, las variable estáticas obtienen los mismos valores por defecto que las variables de instancia obtienen). Cada vez que una instancia de la clase "&lt;span class="codigo"&gt;Oveja&lt;/span&gt;" es creada el constructor de "&lt;span class="codigo"&gt;Oveja&lt;/span&gt;" es ejecutado y la variable "&lt;span class="codigo"&gt;contadorOveja&lt;/span&gt;" es incrementada. Cuando este código es ejecutado, tres instancias de "&lt;span class="codigo"&gt;Oveja&lt;/span&gt;" son creadas en el "&lt;span class="codigo"&gt;main()&lt;/span&gt;", y el resultado es el siguiente:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;El contador de ovejas está ahora en: 3&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ahora imaginemos que sucedería si la variable "&lt;span class="codigo"&gt;contadorOveja&lt;/span&gt;" fuera una variable de instancia (es decir, una variable no estática):&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;class Oveja&lt;br /&gt;{&lt;br /&gt;    int contadorOvejas = 0; //Declaramos e inicializamos la variable de instancia  &lt;br /&gt; &lt;br /&gt;    public Oveja()&lt;br /&gt;    {&lt;br /&gt;        contadorOveja += 1; //Modificamos el valor en el constructor&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static void main(String... args)&lt;br /&gt;    {&lt;br /&gt;        new Oveja();&lt;br /&gt;        new Oveja();&lt;br /&gt;        new Oveja();&lt;br /&gt;&lt;br /&gt;        System.out.println("El contador de ovejas está ahora en: " + contadorOveja);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Cuando este código es ejecutado, este puede todavía crear tres instancias de la clase "&lt;span class="codigo"&gt;Oveja&lt;/span&gt;" en el "&lt;span class="codigo"&gt;main()&lt;/span&gt;", pero el resultado es un error de compilación. No podemos compilar este código, mucho menos ejecutarlo, porque obtenemos el siguiente error:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;Exception in thread "main" java.lang.RuntimeException: Uncompilable source code - non-static variable contadorOveja cannot be referenced from a static context&lt;br /&gt;System.out.println("El contador de ovejas está ahora en: " + contadorOveja);&lt;br /&gt;^&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;La &lt;span class="codigo"&gt;JVM&lt;/span&gt; no sabe a cuál objeto "&lt;span class="codigo"&gt;contadorOveja&lt;/span&gt;" de "&lt;span class="codigo"&gt;Oveja&lt;/span&gt;" estamos intentando de acceder. El problema está en que el método "&lt;span class="codigo"&gt;main()&lt;/span&gt;" en sí mismo es un método estático. Un método estático no puede acceder a una variable no estática (variable de instancia) porque hay que recordar que para acceder a una variable estática no se necesita una instancia de la clase, ya que la variable pertenece a la clase misma.&lt;br /&gt;&lt;br /&gt;Eso no quiere decir que no hay instancias de la clase con vida en la heap, si las hay, pero el método estático no sabe nada de ellas.&lt;br /&gt;&lt;br /&gt;Lo mismo se aplica a los métodos de instancia, un método estático no pueden invocar directamente un método no estático.&lt;br /&gt;&lt;br /&gt;Piensen que &lt;span class="negritas"&gt;static=clase&lt;/span&gt;, &lt;span class="negritas"&gt;no-estático=instancia&lt;/span&gt;. Haciendo que el método llamado por la &lt;span class="codigo"&gt;JVM&lt;/span&gt; ("&lt;span class="codigo"&gt;main()&lt;/span&gt;") sea un método estático la &lt;span class="codigo"&gt;JVM&lt;/span&gt; no tiene que crear una instancia de la clase sólo para iniciar la ejecución de código.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3 class="subtitulo"&gt;Accediendo a métodos y variables estáticos&lt;/h3&gt;Puesto que no es necesario tener una instancia para invocar un método estático o acceder a una variable estática, entonces ¿cómo invocar o utilizar un miembro estático? ¿Cuál es la sintaxis? Sabemos que con un método de instancia  regular, se utiliza el operador punto "&lt;span class="codigo"&gt;.&lt;/span&gt;"  en una referencia, por ejemplo:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;class Oveja&lt;br /&gt;{&lt;br /&gt;    static int contadorOvejas = 0; //Declaramos e inicializamos la variable estática  &lt;br /&gt; &lt;br /&gt;    public Oveja()&lt;br /&gt;    {&lt;br /&gt;        contadorOveja += 1; //Modificamos el valor en el constructor&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static void main(String... args)&lt;br /&gt;    {&lt;br /&gt;        new Oveja();&lt;br /&gt;        new Oveja();&lt;br /&gt;        new Oveja();&lt;br /&gt;        System.out.println("El contador de ovejas está en: " + Oveja.contadorOveja);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Pero para que sea realmente confuso, el lenguaje Java también permite el uso de una variable de referencia de objeto para acceder a un miembro estático:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;    Oveja ov = new Oveja();&lt;br /&gt;    ov.contadorOveja; //Accediendo a la variable estática contadorOveja usando o&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;En el código anterior, hemos instanciado una "&lt;span class="codigo"&gt;Oveja&lt;/span&gt;" asignando "&lt;span class="codigo"&gt;new Oveja&lt;/span&gt;" a la variable de referencia "&lt;span class="codigo"&gt;ov&lt;/span&gt;", y después usamos la referencia "&lt;span class="codigo"&gt;ov&lt;/span&gt;" para invocar al método estático. Pero a pesar de que se está utilizando una instancia específica para acceder al método estático, las reglas no han cambiado. Esto no es más que un truco de sintaxis que nos permite utilizar una variable de referencia a objeto (pero no el objeto que se refiere) para llegar a un método o variable estática, pero el miembro estático sigue ignorando la instancia utiliza para invocar al miembro estático. En el ejemplo de la &lt;span class="codigo"&gt;Oveja&lt;/span&gt;, el compilador sabe que la variable de referencia "&lt;span class="codigo"&gt;ov&lt;/span&gt;" es del tipo de &lt;span class="codigo"&gt;Oveja&lt;/span&gt;, por lo que el método estático de la clase &lt;span class="codigo"&gt;Oveja&lt;/span&gt; se ejecuta sin conocimiento o interés para la instancia de la &lt;span class="codigo"&gt;Oveja&lt;/span&gt; del otro extremo de la referencia "&lt;span class="codigo"&gt;ov&lt;/span&gt;". En otras palabras al compilador le importa solo que la variable de referencia "&lt;span class="codigo"&gt;ov&lt;/span&gt;" sea del tipo &lt;span class="codigo"&gt;Oveja&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;El compilador en realidad hace una transformación a la llamada que acabamos de hacer. Cuando ve que estamos tratando de invocar a un miembro estático, reemplaza la variable de instancia que estamos usando por la clase en la que está dicho miembro. Esto quiere decir que reemplazara esta llamada:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;    Oveja ov = new Oveja();&lt;br /&gt;    ov.contadorOveja;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Por esta otra:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;    Oveja ov = new Oveja();&lt;br /&gt;    Oveja.contadorOveja;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Así que como podemos ver, finalmente quedamos con una llamada al miembro estático, a través de la clase a la que pertenece dicho miembro.&lt;br /&gt;&lt;br /&gt;La siguiente imagen describe el efecto del modificador &lt;span class="codigo"&gt;static&lt;/span&gt; en métodos y variables:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-mWnZTL59rLY/TrX5Gc8veOI/AAAAAAAABPI/aiFf-cN8tN8/s1600/C3_3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-mWnZTL59rLY/TrX5Gc8veOI/AAAAAAAABPI/aiFf-cN8tN8/s1600/C3_3.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Finalmente, recuerden que los métodos estáticos no pueden ser sobrescritos. Pero esto no significa que no puedan ser redefinidos en una subclase. Redefinir y sobrescribir no son la misma cosa. A continuación mostramos un ejemplo sobre redefinir (no sobrescribir) un método marcado como &lt;span class="codigo"&gt;static&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;class Animal&lt;br /&gt;{&lt;br /&gt;    static void hacerAlgo()&lt;br /&gt;    {&lt;br /&gt;        System.out.println("a");&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class Perro extends Animal&lt;br /&gt;{&lt;br /&gt;    static void hacerAlgo()&lt;br /&gt;    {&lt;br /&gt;        System.out.println("b"); //Esto es redefinir, no sobrescribir&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static void main(String... args)&lt;br /&gt;    {&lt;br /&gt;        Animal[] a = {new Animal(), new Perro(), new Animal()};&lt;br /&gt;&lt;br /&gt;        for(int i = 0; i &amp;lt; a.length; i++ )&lt;br /&gt;        {&lt;br /&gt;            a[i].hacerAlgo(); //Invoca al método estático &lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ejecutando el código anterior se produce la siguiente salida:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;a   a   a&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Recuerden, la sintaxis "&lt;span class="codigo"&gt;a[i].hacerAlgo()&lt;/span&gt;" es solo un atajo (un truco de sintaxis). El compilador lo sustituye con algo como "&lt;span class="codigo"&gt;Animal.hacerAlgo()&lt;/span&gt;", como vimos hace un momento.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="titulo"&gt;Cohesión y acoplamiento (Coupling and Cohesion):&lt;/h2&gt;Estos dos temas, la cohesión y el acoplamiento, tienen que ver con &lt;span class="negritas"&gt;la calidad de un diseño orientado a objetos&lt;/span&gt;. En general un buen diseño pide un &lt;span class="negritas"&gt;acoplamiento bajo&lt;/span&gt; y evita un acoplamiento estrecho y un buen diseño orientado a objetos pide una &lt;span class="negritas"&gt;alta cohesión&lt;/span&gt; y evita la baja cohesión. Como con la mayoría de las discusiones sobre diseño de orientación a objetos, las metas de una aplicación son:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Facilidad de creación. &lt;/li&gt;&lt;li&gt;Facilidad de mantenimiento.&lt;/li&gt;&lt;li&gt;Facilidad de mejora.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3 class="subtitulo"&gt;Acoplamiento&lt;/h3&gt;Vamos a empezar haciendo un intento sobre la definición de acoplamiento. &lt;span class="negritas"&gt;Acoplamiento es el grado en el cual una clase sabe acerca de otra clase&lt;/span&gt;. Si el único conocimiento que la clase "&lt;span class="codigo"&gt;A&lt;/span&gt;" tiene acerca de la clase "&lt;span class="codigo"&gt;B&lt;/span&gt;", es lo que la clase "&lt;span class="codigo"&gt;B&lt;/span&gt;" ha puesto de manifiesto a través de su interface, se dice que la clase "&lt;span class="codigo"&gt;A&lt;/span&gt;" y "&lt;span class="codigo"&gt;B&lt;/span&gt;" están débilmente acopladas, lo cual es algo bueno. Si por otro lado, la clase "&lt;span class="codigo"&gt;A&lt;/span&gt;" se basa en una parte de la clase "&lt;span class="codigo"&gt;B&lt;/span&gt;", que no es parte de la interface de la clase "&lt;span class="codigo"&gt;B&lt;/span&gt;", entonces el acoplamiento entre estas dos clases es más estrecho, y esto no es algo bueno. En otras palabras, si la clase "&lt;span class="codigo"&gt;A&lt;/span&gt;" sabe más de lo que debería de la forma en que se implementó "&lt;span class="codigo"&gt;B&lt;/span&gt;", entonces "&lt;span class="codigo"&gt;A&lt;/span&gt;" y "&lt;span class="codigo"&gt;B&lt;/span&gt;" están estrechamente acopladas.&lt;br /&gt;&lt;br /&gt;Usando este segundo escenario, imaginemos lo que sucede cuando la clase "&lt;span class="codigo"&gt;B&lt;/span&gt;" sea mejorada. Es muy posible que el desarrollador que mejore a "&lt;span class="codigo"&gt;B&lt;/span&gt;" no tenga conocimiento acerca de "&lt;span class="codigo"&gt;A&lt;/span&gt;" ¿Y porque debería de tenerlo? El desarrollador de la clase "&lt;span class="codigo"&gt;B&lt;/span&gt;" debe pensar (y es correcto) que todas las mejoras que no quiebren o rompan  la interfaz de la clase deben ser seguras, por lo que podría cambiar alguna parte que no tenga que ver con la interface en la clase. Si las dos clases están estrechamente acopladas, este cambio provocaría que la clase "&lt;span class="codigo"&gt;A&lt;/span&gt;" se quiebre.&lt;br /&gt;&lt;br /&gt;Veamos un ejemplo obvio de acoplamiento fuerte, que ha sido posible gracias a una pobre encapsulación:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;class Impuestos&lt;br /&gt;{&lt;br /&gt;    float ratio;&lt;br /&gt;    &lt;br /&gt;    float calculaImpuestoVentaPeru()&lt;br /&gt;    {&lt;br /&gt;        RatioImpuestoVentas riv = new RatioImpuestoVentas(); &lt;br /&gt;        ratio = riv.ratioVentas;  /*Mal, esto debería ser una llamada a un &lt;br /&gt;                                    método get para obtener la variable, por ejemplo:&lt;br /&gt;                                    ratio = riv.getRatioVentas("PE");  */&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class RatiosImpuestoVentas&lt;br /&gt;{&lt;br /&gt;    public float ratioVentas;       //Debería ser privado&lt;br /&gt;    public float ajusteRatioVentas; //Debería ser privado&lt;br /&gt; &lt;br /&gt;    public float getRatioVentas(String pais)&lt;br /&gt;    {&lt;br /&gt;        ratioVentas = new Impuestos().calculaImpuestoVentaPeru(); //Mal otra vez hacer basado en los cálculos de la región.&lt;br /&gt;        &lt;br /&gt;        return ajusteRatioVentas;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Todas las aplicaciones orientadas a objetos  que no son triviales son una mezcla de muchas clases e interfaces trabajando juntas. Idealmente,  todas las interacciones entre los objetos en un sistema orientado a objetos deben utilizar sus APIs, en otras palabras, los contratos de las clases de los objetos respectivos. Teóricamente, si todas las clases en una aplicación tienen bien diseñada sus  APIs, entonces debería ser posible para todas las interacciones entre las clases el uso de las APIs de forma exclusiva. Como hemos comentado anteriormente en este capítulo, un aspecto de buen diseño de una clase y el diseño de la API es que las clases deben estar bien encapsuladas.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3 class="subtitulo"&gt;Cohesión&lt;/h3&gt;Mientras que el acoplamiento tiene que ver con cómo las clases interactúan con las otras clases, la cohesión es acerca de cómo una simple clase es diseñada. El termino cohesión es usado para indicar &lt;span class="negritas"&gt;el grado para el cual una clase tiene un propósito simple bien enfocado &lt;/span&gt;. Hay que mantener en mente que la cohesión es un concepto subjetivo al igual que el acoplamiento. Cuanto más enfocada sea la clase en una sola tarea, mayor su cohesión, lo cual es bueno.  El beneficio clave de la alta cohesión, es que estas clases son mucho más fáciles de mantener (y menos frecuentes a ser cambiadas) que las clases con baja cohesión. Otro beneficio de la alta cohesión es que las clases con un propósito bien enfocado tienden a ser más reutilizables que otras clases. Veamos un ejemplo:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;class ReportePresupuesto&lt;br /&gt;{&lt;br /&gt;    void conectarBaseDatos(){}&lt;br /&gt;    void generarReportePresupuesto(){}&lt;br /&gt;    void guardarArchivo(){}&lt;br /&gt;    void imprimir(){}&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ahora imaginen que su jefe llega y dice, "Eh, ¿sabes de la aplicación de contabilidad que estamos trabajando? Los clientes  decidieron que también van a querer generar un informe de proyección de ingresos, y que quieren hacer algunos informes de inventario también".&lt;br /&gt;&lt;br /&gt;También les dice que se aseguren de que todos estos informes les permitan elegir una base de datos, seleccione una impresora, y guardar los informes generados a ficheros de datos ... ¡Ouch!&lt;br /&gt;&lt;br /&gt;En lugar de poner todo el código de impresión en una clase de informe,  probablemente hubiera sido mejor usar el siguiente diseño desde el principio:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;class ReportePresupuesto&lt;br /&gt;{&lt;br /&gt;    Opciones getOpcionesReporte() {}&lt;br /&gt;    void generarReportePresupuesto(Opciones o){} &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class ConexionBaseDatos&lt;br /&gt;{&lt;br /&gt;    ConexionBD getConexion(){}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class Impresion&lt;br /&gt;{&lt;br /&gt;    OpcionesImpresion getOpcionesImpresion(){}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class AlmacenArchivos&lt;br /&gt;{&lt;br /&gt;    OpcionesGuardado getOpcionesGuardado(){}&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Este diseño es mucho más cohesivo. En lugar de una clase que hace todo, hemos roto el sistema en cuatro clases principales, cada uno con un rol muy específico (cohesión).&lt;br /&gt;&lt;br /&gt;Como hemos construido estas clases especializadas, reutilizables, y va a ser mucho más fácil escribir un nuevo informe, dado que ya tenemos la clase de conexión de bases de datos, la clase de impresión, y la clase para guardar archivos, y eso significa pueden ser reutilizados por otras clases pueden desear imprimir un informe.&lt;br /&gt;&lt;br /&gt;Este es el fin del segundo tutorial, donde hemos aprendido un poco sobre algunos de los conceptos más importantes de la orientación a objetos que son necesarios para el examen de certificación, y para nuestra vida como programadores en general.El la próxima entrega seguiremos aprendiendo más temas importantes para nosotros como programadores Java y en particular para los que deseen certificarse como programadores Java.&lt;br /&gt;&lt;br /&gt;Muchas gracias a Alan Cabrera Avanto, de Trujillo Perú por este tutorial.&lt;br /&gt;&lt;br /&gt;Saludos.&lt;br /&gt;&lt;br /&gt;&lt;span class="negritas"&gt;Entradas Relacionadas:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.javatutoriales.com/2010/10/sun-certified-java-programmer-6-cx-310_10.html"&gt;Parte 1: Declaraciones y Controles de Acceso&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2012232069289957092-1653317982061534085?l=www.javatutoriales.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.javatutoriales.com/feeds/1653317982061534085/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.javatutoriales.com/2011/11/sun-certified-java-programmer-6-cx-310.html#comment-form' title='4 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2012232069289957092/posts/default/1653317982061534085'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2012232069289957092/posts/default/1653317982061534085'/><link rel='alternate' type='text/html' href='http://www.javatutoriales.com/2011/11/sun-certified-java-programmer-6-cx-310.html' title='Sun Certified Java Programmer 6, CX-310-065 - Parte 2: Orientación a Objetos'/><author><name>Alex</name><uri>http://www.blogger.com/profile/06974037481671868076</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-jyAuA-c6p7g/TrX5FWxHpXI/AAAAAAAABO4/UgvkUZ1IGWg/s72-c/C2_1.png' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2012232069289957092.post-3346331665909045800</id><published>2011-10-22T14:19:00.000-07:00</published><updated>2012-01-08T11:00:21.328-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='download'/><category scheme='http://www.blogger.com/atom/ns#' term='descarga'/><category scheme='http://www.blogger.com/atom/ns#' term='carga'/><category scheme='http://www.blogger.com/atom/ns#' term='struts2'/><category scheme='http://www.blogger.com/atom/ns#' term='validaciones'/><category scheme='http://www.blogger.com/atom/ns#' term='formularios'/><category scheme='http://www.blogger.com/atom/ns#' term='upload'/><title type='text'>Struts 2 - Parte 3: Trabajo con Formularios</title><content type='html'>&lt;div style="text-align: justify;"&gt;En el desarrollo de aplicaciones web, una de las partes más importantes que existen (sino es que la más importante) es el manejo de datos que son recibidos del usuario a través de los formularios de nuestra aplicación.&lt;br /&gt;&lt;br /&gt;Aunque es algo que usamos (y hacemos) todos los días, el manejo de los datos de los formularios puede ser un poco engañoso, por no decir complicado, cuando comenzamos a trabajar con la recepción de múltiples valores para un mismo parámetro, o cuando de antemano no conocemos los nombres de los parámetros que recibiéremos; esto sin mencionar las validaciones para los distintos tipos de datos, la carga y descarga de archivos, etc.&lt;br /&gt;&lt;br /&gt;En este tutorial aprenderemos la forma en la que se trabaja con formularios en &lt;span class="codigo"&gt;Struts 2&lt;/span&gt;, y cómo manejar todas las situaciones mencionadas anteriormente. Concretamente aprenderemos cómo hacer &lt;span class="negritas"&gt;7 cosas&lt;/span&gt;: recepción de parámetros simples, cómo hacer que el framework llene de forma automática los atributos de un objeto si es que todos los datos del formulario pertenecen a ese objeto, a recibir múltiples valores para un mismo parámetro, cómo recibir parámetros cuando no conocemos el nombre de los mismos, a realizar validaciones de datos de varias maneras, cómo subir archivos al servidor, y cómo enviar archivos desde el servidor hacia nuestros clientes.&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;En &lt;a href="http://www.javatutoriales.com/2011/06/struts-2-parte-1-configuracion.html"&gt;el primer tutorial de la serie&lt;/a&gt; vimos los pasos básicos para enviar datos a nuestros &lt;span class="codigo"&gt;Action&lt;/span&gt;s a través de un formulario, sin embargo en esta ocasión veremos algunos conceptos un poco más avanzados que nos harán la vida más fácil cuando trabajemos con formularios.&lt;br /&gt;&lt;br /&gt;Lo primero que haremos es crear un nuevo proyecto en NetBeans. Vamos al menú "&lt;span class="codigo"&gt;File -&amp;gt; New Project...&lt;/span&gt;". En la ventana que aparece seleccionamos la categoría "&lt;span class="codigo"&gt;Java Web&lt;/span&gt;" y en el tipo de proyecto "&lt;span class="codigo"&gt;Web Application&lt;/span&gt;". Presionamos el botón "&lt;span class="codigo"&gt;Next &amp;gt;&lt;/span&gt;" y le damos un nombre y una ubicación a nuestro proyecto; presionamos nuevamente el botón "&lt;span class="codigo"&gt;Next &amp;gt;&lt;/span&gt;" y en este punto se nos preguntará el servidor que queremos usar. En nuestro caso usaremos el servidor "&lt;span class="codigo"&gt;Tomcat 7.0&lt;/span&gt;", con la versión 5 de JEE y presionamos el botón "&lt;span class="codigo"&gt;Finish&lt;/span&gt;".&lt;br /&gt;&lt;br /&gt;Una vez que tengamos nuestro proyecto debemos recordar agregar la biblioteca "&lt;span class="codigo"&gt;Struts2&lt;/span&gt;" (o "&lt;span class="codigo"&gt;Struts2Anotaciones&lt;/span&gt;" si van a hacer uso de anotaciones, como es mi caso ^_^), que creamos en &lt;a href="http://www.javatutoriales.com/2011/06/struts-2-parte-1-configuracion.html"&gt;el primer tutorial de la serie&lt;/a&gt;. Hacemos clic derecho sobre el nodo "&lt;span class="codigo"&gt;Libraries&lt;/span&gt;" del proyecto. En el menú que aparece seleccionamos la opción "&lt;span class="codigo"&gt;Add Library...&lt;/span&gt;". En la ventana que aparece seleccionamos la biblioteca "&lt;span class="codigo"&gt;Struts2&lt;/span&gt;" o "&lt;span class="codigo"&gt;Struts2Anotaciones&lt;/span&gt;" y presionamos "&lt;span class="codigo"&gt;Add Library&lt;/span&gt;". Con esto ya tendremos los jars de &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; en nuestro proyecto.&lt;br /&gt;&lt;br /&gt;Ahora configuramos el filtro "&lt;span class="codigo"&gt;struts2&lt;/span&gt;" en el deployment descriptor. Abrimos el archivo "&lt;span class="codigo"&gt;web.xml&lt;/span&gt;" y colocamos el siguiente contenido, como se explicó en el primer tutorial de la serie:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;filter&amp;gt;&lt;br /&gt;    &amp;lt;filter-name&amp;gt;struts2&amp;lt;/filter-name&amp;gt;&lt;br /&gt;    &amp;lt;filter-class&amp;gt;org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter&amp;lt;/filter-class&amp;gt;&lt;br /&gt;&amp;lt;/filter&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;filter-mapping&amp;gt;&lt;br /&gt;    &amp;lt;filter-name&amp;gt;struts2&amp;lt;/filter-name&amp;gt;&lt;br /&gt;    &amp;lt;url-pattern&amp;gt;/*&amp;lt;/url-pattern&amp;gt;&lt;br /&gt;&amp;lt;/filter-mapping&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ahora procedemos a crear una clase que nos servirá como modelo de datos. Esta será una clase "&lt;span class="codigo"&gt;Usuario&lt;/span&gt;" la cual tendrá atributos de varios tipos para que veamos como &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; realiza su "magia".&lt;br /&gt;&lt;br /&gt;Creamos un paquete para nuestro modelo de datos. En mi caso el primer paquete se llamará "&lt;span class="codigo"&gt;com.javatutoriales.struts2.formularios.modelo&lt;/span&gt;". Hacemos clic derecho sobre el nodo "&lt;span class="codigo"&gt;Source packages&lt;/span&gt;" del proyecto, en el menú que aparece seleccionamos la opción "&lt;span class="codigo"&gt;new -&amp;gt; package&lt;/span&gt;". En la ventana que aparece le damos el nombre correspondiente a nuestro paquete.&lt;br /&gt;&lt;br /&gt;Ahora, dentro de este paquete creamos la clase "&lt;span class="codigo"&gt;Usuario&lt;/span&gt;": sobre el paquete que acabamos de crear hacemos clic derecho y en el menú contextual que aparece seleccionaos la opción "&lt;span class="codigo"&gt;new -&amp;gt; Java Class&lt;/span&gt;". El la ventana que aparece le damos el nombre "&lt;span class="codigo"&gt;Usuario&lt;/span&gt;" y hacemos clic en el botón "&lt;span class="codigo"&gt;Finish&lt;/span&gt;". Con esto aparecerá en nuestro editor la clase "&lt;span class="codigo"&gt;Usuario&lt;/span&gt;" de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class Usuario&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Antes que nada hacemos que esta clase implemente la interface "&lt;span class="codigo"&gt;java.io.Serializable&lt;/span&gt;" como deben hacerlo todas las clases de transporte de datos:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class Usuario implements Serializable&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ahora agregaremos unos cuantos atributos a esta clase, de distintos tipos, representado algunas de las características de nuestro usuario. Dentro de estos atributos incluiremos su nombre, edad, y fecha de nacimiento:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class Usuario implements Serializable&lt;br /&gt;{&lt;br /&gt;    private String nombre;&lt;br /&gt;    private String username;&lt;br /&gt;    private String password;&lt;br /&gt;    private int edad;&lt;br /&gt;    private Date fechaNacimiento;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Recuerden que el "&lt;span class="codigo"&gt;Date&lt;/span&gt;" de "&lt;span class="codigo"&gt;fechaNacimiento&lt;/span&gt;" debe ser de tipo "&lt;span class="codigo"&gt;java.util.Date&lt;/span&gt;".&lt;br /&gt;&lt;br /&gt;Para terminar con la clase &lt;span class="codigo"&gt;Usuario&lt;/span&gt; agregaremos los &lt;span class="codigo"&gt;getters&lt;/span&gt; y los &lt;span class="codigo"&gt;setters&lt;/span&gt; de estos atributos, y adicionalmente dos constructores, uno que reciba todos los atributos, y uno vacio:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class Usuario implements Serializable&lt;br /&gt;{&lt;br /&gt;    private String nombre;&lt;br /&gt;    private String username;&lt;br /&gt;    private String password;&lt;br /&gt;    private int edad;&lt;br /&gt;    private Date fechaNacimiento;&lt;br /&gt;&lt;br /&gt;    public Usuario()&lt;br /&gt;    {&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public Usuario(String nombre, String username, String password, int edad, Date fechaNacimiento)&lt;br /&gt;    {&lt;br /&gt;        this.nombre = nombre;&lt;br /&gt;        this.username = username;&lt;br /&gt;        this.password = password;&lt;br /&gt;        this.edad = edad;&lt;br /&gt;        this.fechaNacimiento = fechaNacimiento;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public int getEdad()&lt;br /&gt;    {&lt;br /&gt;        return edad;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setEdad(int edad)&lt;br /&gt;    {&lt;br /&gt;        this.edad = edad;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public Date getFechaNacimiento()&lt;br /&gt;    {&lt;br /&gt;        return fechaNacimiento;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setFechaNacimiento(Date fechaNacimiento)&lt;br /&gt;    {&lt;br /&gt;        this.fechaNacimiento = fechaNacimiento;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public String getNombre()&lt;br /&gt;    {&lt;br /&gt;        return nombre;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setNombre(String nombre)&lt;br /&gt;    {&lt;br /&gt;        this.nombre = nombre;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public String getPassword()&lt;br /&gt;    {&lt;br /&gt;        return password;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setPassword(String password)&lt;br /&gt;    {&lt;br /&gt;        this.password = password;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public String getUsername()&lt;br /&gt;    {&lt;br /&gt;        return username;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setUsername(String username)&lt;br /&gt;    {&lt;br /&gt;        this.username = username;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Lo primero que haremos es recordar cómo podemos obtener parámetros planos o simples desde nuestros formularios:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="titulo"&gt;1. Recepción de parámetros simples&lt;/h2&gt;En &lt;a href="http://www.javatutoriales.com/2011/06/struts-2-parte-1-configuracion.html"&gt;el primer tutorial de la serie de &lt;span class="codigo"&gt;Struts 2&lt;/span&gt;&lt;/a&gt; vimos de una forma muy rápida cómo obtener parámetros de un formulario. Lo único que hay que hacer es:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Colocar un formulario en nuestra &lt;span class="codigo"&gt;JSP&lt;/span&gt; usando la etiqueta &lt;span class="codigo"&gt;&amp;lt;s:form&amp;gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;Colocar los campos del formulario usando las etiquetas correspondientes de &lt;span class="codigo"&gt;Struts&lt;/span&gt;&lt;/li&gt;&lt;li&gt;Crear un &lt;span class="codigo"&gt;Action&lt;/span&gt; y colocar &lt;span class="codigo"&gt;setters&lt;/span&gt; para cada uno de los elementos que recibiremos a través del formulario&lt;/li&gt;&lt;li&gt;Procesar los datos del formulario en el método "&lt;span class="codigo"&gt;execute&lt;/span&gt;"&lt;/li&gt;&lt;/ul&gt;Hagamos un pequeño ejemplo para refrescar la memoria.&lt;br /&gt;&lt;br /&gt;En este primer ejemplo obtendremos los datos para crear un nuevo objeto "&lt;span class="codigo"&gt;Usuario&lt;/span&gt;", el tipo que definimos anteriormente.&lt;br /&gt;&lt;br /&gt;Lo primero que hacemos es crear una nueva página &lt;span class="codigo"&gt;JSP&lt;/span&gt;, en la raíz de las páginas web, llamada "&lt;span class="codigo"&gt;nuevo-usuario.jsp&lt;/span&gt;". Hacemos clic derecho en el nodo "&lt;span class="codigo"&gt;Web Pages&lt;/span&gt;". En el menú que se abre seleccionamos la opción "&lt;span class="codigo"&gt;New –&amp;gt; JSP...&lt;/span&gt;". &lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-Po4hsKkqMT4/TqMlyuokLQI/AAAAAAAABGM/uvgf5oYITu4/s1600/S3_1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="307" src="http://3.bp.blogspot.com/-Po4hsKkqMT4/TqMlyuokLQI/AAAAAAAABGM/uvgf5oYITu4/s400/S3_1.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Colocamos "&lt;span class="codigo"&gt;nuevo-usuario&lt;/span&gt;" como nombre de la página y presionamos el botón "&lt;span class="codigo"&gt;Finish&lt;/span&gt;".&lt;br /&gt;&lt;br /&gt;En esta página indicamos que se usará la biblioteca de etiquetas de &lt;span class="codigo"&gt;Struts 2&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;%@taglib uri="/struts-tags" prefix="s" %&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Usamos la etiqueta "&lt;span class="codigo"&gt;&amp;lt;s:form&amp;gt;&lt;/span&gt;" para colocar un formulario en nuestra página. En su atributo "&lt;span class="codigo"&gt;action&lt;/span&gt;" colocamos el nombre del &lt;span class="codigo"&gt;Action&lt;/span&gt; que se encargará de procesar los datos de este formulario:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:form action="datosUsuario"&amp;gt;            &lt;br /&gt;&amp;lt;/s:form&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Dentro de este formulario colocaremos un campo para cada uno de los atributos que puede recibir un Usuario:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:form action="datosUsuario"&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="nombre" label="Nombre" /&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="username" label="Username" /&amp;gt;&lt;br /&gt;    &amp;lt;s:password name="password" label="Password" /&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="edad" label="Edad" /&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="fechaNacimiento" label="Fecha de Nacimiento" /&amp;gt;&lt;br /&gt;    &amp;lt;s:submit value="Enviar" /&amp;gt;&lt;br /&gt;&amp;lt;/s:form&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ya que nuestro formulario está listo, crearemos el &lt;span class="codigo"&gt;Action&lt;/span&gt; que se encargará de procesar los datos del mismo. &lt;br /&gt;&lt;br /&gt;Creamos un nuevo paquete, llamado "&lt;span class="codigo"&gt;actions&lt;/span&gt;", a la misma altura que el paquete "&lt;span class="codigo"&gt;modelo&lt;/span&gt;". Dentro de este paquete creamos una nueva clase Java llamada "&lt;span class="codigo"&gt;Usuario&lt;span class="codigo"&gt;Action&lt;/span&gt;&lt;/span&gt;". Haremos que esta clase extienda de "&lt;span class="codigo"&gt;ActionSupport&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class UsuarioAction extends ActionSupport&lt;br /&gt;{    &lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Recuerden que para recibir los datos del formulario debemos colocar los atributos en los que se almacenarán estos datos, y &lt;span class="codigo"&gt;setters&lt;/span&gt; para que los interceptores correspondientes puedan inyectar los valores dentro del &lt;span class="codigo"&gt;Action&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class UsuarioAction extends ActionSupport&lt;br /&gt;{&lt;br /&gt;    private String nombre;&lt;br /&gt;    private String username;&lt;br /&gt;    private String password;&lt;br /&gt;    private int edad;&lt;br /&gt;    private Date fechaNacimiento;&lt;br /&gt;&lt;br /&gt;    public void setEdad(int edad)&lt;br /&gt;    {&lt;br /&gt;        this.edad = edad;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setFechaNacimiento(Date fechaNacimiento)&lt;br /&gt;    {&lt;br /&gt;        this.fechaNacimiento = fechaNacimiento;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setNombre(String nombre)&lt;br /&gt;    {&lt;br /&gt;        this.nombre = nombre;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setPassword(String password)&lt;br /&gt;    {&lt;br /&gt;        this.password = password;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setUsername(String username)&lt;br /&gt;    {&lt;br /&gt;        this.username = username;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Cuando esté &lt;span class="codigo"&gt;Action&lt;/span&gt; termine su ejecución (la cual aún no hemos implementado), queremos poder crear un &lt;span class="codigo"&gt;Usuario&lt;/span&gt; y mostrar sus datos en otra página. Para hacer eso debemos colocar un atributo que almacene una referencia al &lt;span class="codigo"&gt;Usuario&lt;/span&gt;, y un &lt;span class="codigo"&gt;getter&lt;/span&gt; para poder obtener esta referencia:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;private Usuario usuario;&lt;br /&gt;&lt;br /&gt;public Usuario getUsuario()&lt;br /&gt;{&lt;br /&gt;    return usuario;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ahora sí, sobre-escribimos el método "&lt;span class="codigo"&gt;execute&lt;/span&gt;" para crear un nuevo objeto de tipo &lt;span class="codigo"&gt;Usuario&lt;/span&gt; y establecer sus datos usando los valores que recibimos del formulario:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Override&lt;br /&gt;public String execute() throws Exception&lt;br /&gt;{&lt;br /&gt;    usuario = new Usuario();&lt;br /&gt;    usuario.setNombre(nombre);&lt;br /&gt;    usuario.setUsername(username);&lt;br /&gt;    usuario.setPassword(password);&lt;br /&gt;    usuario.setEdad(edad);&lt;br /&gt;    usuario.setFechaNacimiento(fechaNacimiento);&lt;br /&gt;&lt;br /&gt;    return SUCCESS;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Y eso es todo, ya hemos creado un nuevo &lt;span class="codigo"&gt;Usuario&lt;/span&gt; con los datos que recibimos a través del formulario de captura.&lt;br /&gt;&lt;br /&gt;Para que este ejemplo funcione aún tenemos que hacer un par de cosas. Primero marcaremos nuestra clase con la anotación "&lt;span class="codigo"&gt;@Action&lt;/span&gt;" para indicar que esta clase debe ser tratada con un &lt;span class="codigo"&gt;Action&lt;/span&gt; de &lt;span class="codigo"&gt;Struts 2&lt;/span&gt;, como lo vimos en &lt;a href="http://www.javatutoriales.com/2011/06/struts-2-parte-1-configuracion.html"&gt;el primer tutorial de la serie&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Namespace(value="/")&lt;br /&gt;@Action(value="datosUsuario", results={@Result(name="success", location="/datos-usuario.jsp")})&lt;br /&gt;public class UsuarioAction extends ActionSupport&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Como podemos ver, el nombre de nuestro &lt;span class="codigo"&gt;Action&lt;/span&gt; es "&lt;span class="codigo"&gt;datosUsuario&lt;/span&gt;" (que es el mismo que colocamos en el atributo "&lt;span class="codigo"&gt;action&lt;/span&gt;" del formulario que creamos hace un momento). Si todo el proceso de nuestro &lt;span class="codigo"&gt;Action&lt;/span&gt; sale bien seremos enviados a la página "&lt;span class="codigo"&gt;datosUsuario.jsp&lt;/span&gt;". Esta página solamente mostrará los datos del usuario que se acaba de crear. Antes de ver esta página veamos cómo queda la clase "&lt;span class="codigo"&gt;UsuarioAction&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Namespace(value="/")&lt;br /&gt;@Action(value="datosUsuario", results={@Result(name="success", location="/datos-usuario.jsp")})&lt;br /&gt;public class UsuarioAction extends ActionSupport&lt;br /&gt;{&lt;br /&gt;    private String nombre;&lt;br /&gt;    private String username;&lt;br /&gt;    private String password;&lt;br /&gt;    private int edad;&lt;br /&gt;    private Date fechaNacimiento;&lt;br /&gt;&lt;br /&gt;    private Usuario usuario;&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    public String execute() throws Exception&lt;br /&gt;    {&lt;br /&gt;        usuario = new Usuario();&lt;br /&gt;        usuario.setNombre(nombre);&lt;br /&gt;        usuario.setUsername(username);&lt;br /&gt;        usuario.setPassword(password);&lt;br /&gt;        usuario.setEdad(edad);&lt;br /&gt;        usuario.setFechaNacimiento(fechaNacimiento);&lt;br /&gt;&lt;br /&gt;        return SUCCESS;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    public Usuario getUsuario()&lt;br /&gt;    {&lt;br /&gt;        return usuario;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setEdad(int edad)&lt;br /&gt;    {&lt;br /&gt;        this.edad = edad;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setFechaNacimiento(Date fechaNacimiento)&lt;br /&gt;    {&lt;br /&gt;        this.fechaNacimiento = fechaNacimiento;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setNombre(String nombre)&lt;br /&gt;    {&lt;br /&gt;        this.nombre = nombre;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setPassword(String password)&lt;br /&gt;    {&lt;br /&gt;        this.password = password;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setUsername(String username)&lt;br /&gt;    {&lt;br /&gt;        this.username = username;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ahora sí, creamos una nueva página &lt;span class="codigo"&gt;JSP&lt;/span&gt;; el nombre de esta página será "&lt;span class="codigo"&gt;datos-usuario&lt;/span&gt;". En esta página haremos uso de algunas etiquetas de &lt;span class="codigo"&gt;Struts&lt;/span&gt;, por lo que deberemos indicarlo usando la directiva "&lt;span class="codigo"&gt;taglib&lt;/span&gt;" correspondiente: &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;%@taglib uri="/struts-tags" prefix="s" %&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;En esta página solamente mostraremos los datos del usuario que acabamos de crear. Recordemos que para esto debemos usar la etiqueta "&lt;span class="codigo"&gt;&amp;lt;s:property&amp;gt;&lt;/span&gt;". Mostramos cada uno de los datos anteriores del usuario:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;Nombre: &amp;lt;strong&amp;gt;&amp;lt;s:property value="&lt;span class="negritas"&gt;usuario.nombre&lt;/span&gt;" /&amp;gt;&amp;lt;/strong&amp;gt; &amp;lt;br /&amp;gt;&lt;br /&gt;Username: &amp;lt;strong&amp;gt;&amp;lt;s:property value="&lt;span class="negritas"&gt;usuario.username&lt;/span&gt;" /&amp;gt;&amp;lt;/strong&amp;gt; &amp;lt;br /&amp;gt;&lt;br /&gt;Password: &amp;lt;strong&amp;gt;&amp;lt;s:property value="&lt;span class="negritas"&gt;usuario.password&lt;/span&gt;" /&amp;gt;&amp;lt;/strong&amp;gt; &amp;lt;br /&amp;gt;&lt;br /&gt;Edad: &amp;lt;strong&amp;gt;&amp;lt;s:property value="&lt;span class="negritas"&gt;usuario.edad&lt;/span&gt;" /&amp;gt;&amp;lt;/strong&amp;gt; &amp;lt;br /&amp;gt;&lt;br /&gt;Fecha de Nacimiento: &amp;lt;strong&amp;gt;&amp;lt;s:property value="&lt;span class="negritas"&gt;usuario.fechaNacimiento&lt;/span&gt;" /&amp;gt;&amp;lt;/strong&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Cuando entremos a la siguiente página:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&lt;a href="http://localhost:8080/formularios/nuevo-usuario.jsp"&gt;http://localhost:8080/formularios/nuevo-usuario.jsp&lt;/a&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Veremos el formulario para capturar los datos del usuario. En mi caso, con los siguientes datos:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-azbNFNVsSS4/TqMlzTrChmI/AAAAAAAABGU/Nrteut4Ngw8/s1600/S3_3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="207" src="http://2.bp.blogspot.com/-azbNFNVsSS4/TqMlzTrChmI/AAAAAAAABGU/Nrteut4Ngw8/s400/S3_3.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Obtengo la siguiente salida:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-z81Ac1WFrEs/TqMlznu0y1I/AAAAAAAABGc/_a0Nv4zQTtU/s1600/S3_4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="207" src="http://2.bp.blogspot.com/-z81Ac1WFrEs/TqMlznu0y1I/AAAAAAAABGc/_a0Nv4zQTtU/s400/S3_4.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;En el ejemplo anterior podemos ver que aunque hemos pasado pocos datos al formulario, todos los hemos establecido en el objeto "&lt;span class="codigo"&gt;Usuario&lt;/span&gt;", que se creó dentro método "&lt;span class="codigo"&gt;execute&lt;/span&gt;", y los pasamos "como van", es decir sin realizar ninguna transformación o procesamiento sobre ellos. Cuando tenemos 5 o 6 atributos esto puede no ser algo muy pesado. Pero ¿qué pasa si tenemos que llenar un objeto con 30 o 40 propiedades? Nuestro &lt;span class="codigo"&gt;Action&lt;/span&gt; sería muy grande por todos los atributos y los &lt;span class="codigo"&gt;setters&lt;/span&gt; y &lt;span class="codigo"&gt;getters&lt;/span&gt; de las propiedades; el trabajo dentro del método "&lt;span class="codigo"&gt;execute&lt;/span&gt;" también sería bastante cansado llamar a los &lt;span class="codigo"&gt;setters&lt;/span&gt; de nuestro modelos para pasarle los parámetros.&lt;br /&gt;&lt;br /&gt;Para esos casos &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; proporciona una forma de simplificarnos estas situaciones usando un mecanismo conocido como "&lt;span class="codigo"&gt;Model Driven&lt;/span&gt;" el cual veremos a continuación.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="titulo"&gt;2. Model Driven&lt;/h2&gt;&lt;span class="codigo"&gt;Model Driven&lt;/span&gt; es una forma que &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; proporciona para poder establecer todos los parámetros que se reciben de un formulario directamente dentro de un objeto. Este objeto es conocido como el &lt;span class="negritas"&gt;modelo&lt;/span&gt;. &lt;br /&gt;&lt;br /&gt;Usando este modelo nos evitamos estar llamando nosotros mismos a los &lt;span class="codigo"&gt;setters&lt;/span&gt; de este objeto modelo. &lt;br /&gt;&lt;br /&gt;Esto también permite que si realizamos validaciones de datos del formulario (lo cual veremos cómo hacer un poco más adelante) estas se realizarán sobre este objeto modelo.&lt;br /&gt;&lt;br /&gt;Un interceptor especial, llamado model driven interceptor, se encarga de manejar todo esto de forma automática ^_^.&lt;br /&gt;&lt;br /&gt;Extenderemos nuestro ejemplo para usar model driven.&lt;br /&gt;&lt;br /&gt;Creamos una nueva clase Java, en el paquete "&lt;span class="codigo"&gt;actions&lt;/span&gt;", llamada "&lt;span class="codigo"&gt;UsuarioActionMD&lt;/span&gt;". Esta clase extenderá de "&lt;span class="codigo"&gt;ActionSupport&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class UsuarioActionMD extends ActionSupport&lt;br /&gt;{    &lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Para indicarle a &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; que este &lt;span class="codigo"&gt;Action&lt;/span&gt; será &lt;span class="codigo"&gt;Model Driven&lt;/span&gt;, la clase "&lt;span class="codigo"&gt;UsuarioActionMD&lt;/span&gt;" debe implementar la interface "&lt;span class="codigo"&gt;ModelDriven&lt;/span&gt;", indicando de qué tipo de objeto será usado como modelo:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class UsuarioActionMD extends ActionSupport implements ModelDriven&amp;lt;Usuario&amp;gt;&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ahora pondremos un objeto &lt;span class="codigo"&gt;Usuario&lt;/span&gt; dentro de nuestra clase, con una variable de instancia, que será el objeto que usaremos como modelo:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class UsuarioActionMD extends ActionSupport implements ModelDriven&amp;lt;Usuario&amp;gt;&lt;br /&gt;{&lt;br /&gt;    private Usuario usuario = new Usuario();    &lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Es importante tener creado este objeto antes de que nuestro &lt;span class="codigo"&gt;Action&lt;/span&gt; reciba alguna petición, por lo que podemos inicializarlo en la misma declaración o en el constructor del &lt;span class="codigo"&gt;Action&lt;/span&gt;, en caso de tener alguno.&lt;br /&gt;&lt;br /&gt;La interface "&lt;span class="codigo"&gt;ModelDriven&lt;/span&gt;" tiene tan solo un método: "&lt;span class="codigo"&gt;getModel&lt;/span&gt;". Esté método no recibe ningún parámetro, y regresa el objeto que estamos usando como modelo:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public Usuario getModel()&lt;br /&gt;{&lt;br /&gt;    return usuario;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Lo único que queda es realizar algún proceso en el método "&lt;span class="codigo"&gt;execute&lt;/span&gt;", que podría ser almacenar al &lt;span class="codigo"&gt;Usuario&lt;/span&gt; en alguna base de datos, enviarlo por algún stream, etc. Como en este caso no haremos nada con el &lt;span class="codigo"&gt;Usuario&lt;/span&gt; más que regresarlo para poder mostrar sus datos en una página, nuestro método "&lt;span class="codigo"&gt;execute&lt;/span&gt;" solo regresará un valor de "&lt;span class="codigo"&gt;SUCCESS&lt;/span&gt;". &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Override&lt;br /&gt;public String execute() throws Exception&lt;br /&gt;{&lt;br /&gt;    return SUCCESS;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Noten que en esta ocasión no es necesario tener un &lt;span class="codigo"&gt;getter&lt;/span&gt; para poder obtener la instancia del "&lt;span class="codigo"&gt;Usuario&lt;/span&gt;" desde nuestra &lt;span class="codigo"&gt;JSP&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Finalmente, anotamos nuestra clase para que &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; lo reconozca como un &lt;span class="codigo"&gt;Action&lt;/span&gt;. El nombre del &lt;span class="codigo"&gt;Action&lt;/span&gt; será "&lt;span class="codigo"&gt;datosUsuario&lt;/span&gt;". Para diferenciar este &lt;span class="codigo"&gt;Action&lt;/span&gt; del anterior (que tiene el mismo nombre) lo colocaremos en el namespace "&lt;span class="codigo"&gt;modeldriven&lt;/span&gt;".&lt;br /&gt;&lt;br /&gt;El &lt;span class="codigo"&gt;Action&lt;/span&gt; al terminar de ejecutarse nos enviará a la página "&lt;span class="codigo"&gt;/modeldriven/datos-usuario.jsp&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Namespace(value = "/modeldriven")&lt;br /&gt;@Action(value="datosUsuario", results={@Result(location="/modeldriven/datos-usuario.jsp")})&lt;br /&gt;public class UsuarioActionMD extends ActionSupport implements ModelDriven&amp;lt;Usuario&amp;gt;&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;La clase "&lt;span class="codigo"&gt;UsuarioActionMD&lt;/span&gt;" completa (omitiendo los imports) queda de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Namespace(value = "/modeldriven")&lt;br /&gt;@Action(value="datosUsuario", results={@Result(location="/modeldriven/datos-usuario.jsp")})&lt;br /&gt;public class UsuarioActionMD extends ActionSupport implements ModelDriven&amp;lt;Usuario&amp;gt;&lt;br /&gt;{&lt;br /&gt;    private Usuario usuario = new Usuario();&lt;br /&gt;&lt;br /&gt;    public Usuario getModel()&lt;br /&gt;    {&lt;br /&gt;        return usuario;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    public String execute() throws Exception&lt;br /&gt;    {&lt;br /&gt;        return SUCCESS;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Podemos ver que el código de este &lt;span class="codigo"&gt;Action&lt;/span&gt; es mucho más pequeño que el que hicimos para el ejemplo anterior.&lt;br /&gt;&lt;br /&gt;Ahora antes de crear la página que se encargará de mostrar el resutado, creamos un nuevo directorio para nuestras páginas web. Para eso hacemos clic derecho sobre el nodo "&lt;span class="codigo"&gt;WebPages&lt;/span&gt;" de nuestro proyecto. En el menú que aparece seleccionamos la opción "&lt;span class="codigo"&gt;New -&amp;gt; Folder&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-Jit9c0yjjtA/TqMl0B89WeI/AAAAAAAABGk/5M1pcP5b-Hc/s1600/S3_5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="321" src="http://1.bp.blogspot.com/-Jit9c0yjjtA/TqMl0B89WeI/AAAAAAAABGk/5M1pcP5b-Hc/s400/S3_5.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Damos "&lt;span class="codigo"&gt;modeldriven&lt;/span&gt;" como nombre del directorio y presionamos el botón "&lt;span class="codigo"&gt;Finish&lt;/span&gt;".&lt;br /&gt;&lt;br /&gt;Dentro de este directorio crearemos dos páginas. Primero crearemos la página que contendrá el formulario que nos permitirá capturar los datos del usuario. Hacemos clic derecho en el directorio "&lt;span class="codigo"&gt;modeldriven&lt;/span&gt;" del nodo "&lt;span class="codigo"&gt;Web Pages&lt;/span&gt;". En el menú que se abre seleccionamos la opción "&lt;span class="codigo"&gt;New –&amp;gt; JSP...&lt;/span&gt;". Damos "&lt;span class="codigo"&gt;nuevo-usuario&lt;/span&gt;" como nombre de la página y presionamos el botón "&lt;span class="codigo"&gt;Finish&lt;/span&gt;".&lt;br /&gt;&lt;br /&gt;El formulario de la página será  idéntico al que creamos en la primer parte del tutorial, con la única diferencia de que enviará los datos al &lt;span class="codigo"&gt;Action&lt;/span&gt; "&lt;span class="codigo"&gt;datosUsuarioMD&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:form action="datosUsuario"&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="&lt;span class="negritas"&gt;nombre&lt;/span&gt;" label="Nombre" /&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="&lt;span class="negritas"&gt;username&lt;/span&gt;" label="Username" /&amp;gt;&lt;br /&gt;    &amp;lt;s:password name="&lt;span class="negritas"&gt;password&lt;/span&gt;" label="Password" /&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="&lt;span class="negritas"&gt;edad&lt;/span&gt;" label="Edad" /&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="&lt;span class="negritas"&gt;fechaNacimiento&lt;/span&gt;" label="Fecha de Nacimiento" /&amp;gt;&lt;br /&gt;    &amp;lt;s:submit value="Enviar" /&amp;gt;&lt;br /&gt;&amp;lt;/s:form&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;La segunda página, que se llamará "&lt;span class="codigo"&gt;datos-usuario.jsp&lt;/span&gt;" y que también estará en el directorio "&lt;span class="codigo"&gt;modeldriven&lt;/span&gt;", mostrará los valores de los atributos del objeto "&lt;span class="codigo"&gt;usuario&lt;/span&gt;" que se usa como modelo. Esta página también será muy parecida a la que creamos anteriormente, solo que en esta ocasión no será necesario indicar que los atributos que estamos usando corresponden al objeto "&lt;span class="codigo"&gt;usuario&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;Nombre: &amp;lt;strong&amp;gt;&amp;lt;s:property value="nombre" /&amp;gt;&amp;lt;/strong&amp;gt; &amp;lt;br /&amp;gt;&lt;br /&gt;Username: &amp;lt;strong&amp;gt;&amp;lt;s:property value="username" /&amp;gt;&amp;lt;/strong&amp;gt; &amp;lt;br /&amp;gt;&lt;br /&gt;Password: &amp;lt;strong&amp;gt;&amp;lt;s:property value="password" /&amp;gt;&amp;lt;/strong&amp;gt; &amp;lt;br /&amp;gt;&lt;br /&gt;Edad: &amp;lt;strong&amp;gt;&amp;lt;s:property value="edad" /&amp;gt;&amp;lt;/strong&amp;gt; &amp;lt;br /&amp;gt;&lt;br /&gt;Fecha de Nacimiento: &amp;lt;strong&amp;gt;&amp;lt;s:property value="fechaNacimiento" /&amp;gt;&amp;lt;/strong&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Al ejecutar la aplicación y entrar en la siguiente dirección:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&lt;a href="http://localhost:8080/formularios/modeldriven/nuevo-usuario.jsp"&gt;http://localhost:8080/formularios/modeldriven/nuevo-usuario.jsp&lt;/a&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Veremos un formulario muy parecido al anterior:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/--X5izPS5Lxw/TqMl0u_r_iI/AAAAAAAABGs/jxd9Pqd6B-E/s1600/S3_6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="202" src="http://3.bp.blogspot.com/--X5izPS5Lxw/TqMl0u_r_iI/AAAAAAAABGs/jxd9Pqd6B-E/s400/S3_6.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Cuando llenemos los datos y enviemos el formulario, deberemos ver una salida también muy parecida a la anterior:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-EoRMKo5MVX4/TqMl1PmIGSI/AAAAAAAABG0/ajvJYNeqzo8/s1600/S3_7.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="202" src="http://1.bp.blogspot.com/-EoRMKo5MVX4/TqMl1PmIGSI/AAAAAAAABG0/ajvJYNeqzo8/s400/S3_7.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Pero ¿qué ocurre si queremos recibir un parámetro que no sea un atributo del "&lt;span class="codigo"&gt;usuario&lt;/span&gt;"? En ese caso, solo tenemos que agregar un nuevo atributo, con su correspondiente &lt;span class="codigo"&gt;setter&lt;/span&gt; para establecer su valor (y su &lt;span class="codigo"&gt;getter&lt;/span&gt; si es que pensamos recuperarlo posteriormente) dentro de nuestro &lt;span class="codigo"&gt;Action&lt;/span&gt;. &lt;br /&gt;&lt;br /&gt;Modifiquemos un poco el ejemplo anterior para ver esto. Agregaremos al formulario un campo de texto para que el usuario proporcione un número de confirmación:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:form action="datosUsuario"&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="nombre" label="Nombre" /&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="username" label="Username" /&amp;gt;&lt;br /&gt;    &amp;lt;s:password name="password" label="Password" /&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="edad" label="Edad" /&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="fechaNacimiento" label="Fecha de Nacimiento" /&amp;gt;&lt;br /&gt;    &lt;span class="negritas"&gt;&amp;lt;s:textfield name="numero" label="Número de Confirmación" /&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;br /&gt;    &amp;lt;s:submit value="Enviar" /&amp;gt;&lt;br /&gt;&amp;lt;/s:form&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;También cambiaremos nuestro &lt;span class="codigo"&gt;Action&lt;/span&gt;. Colocamos un atributo de tipo entero para contener este número, junto con sus correspondientes &lt;span class="codigo"&gt;setter&lt;/span&gt; (para establecer el valor desde el formulario) y &lt;span class="codigo"&gt;getter&lt;/span&gt; (para obtener el valor desde la &lt;span class="codigo"&gt;JSP&lt;/span&gt;):&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;private int numero;&lt;br /&gt;&lt;br /&gt;public void setNumero(int numero)&lt;br /&gt;{&lt;br /&gt;    this.numero = numero;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public int getNumero()&lt;br /&gt;{&lt;br /&gt;    return numero;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;De igual forma modificaremos la página "&lt;span class="codigo"&gt;datos-usuarios.jsp&lt;/span&gt;" del directorio "&lt;span class="codigo"&gt;modeldriven&lt;/span&gt;" para poder mostrar el valor del número de confirmación:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;Nombre: &amp;lt;strong&amp;gt;&amp;lt;s:property value="nombre" /&amp;gt;&amp;lt;/strong&amp;gt; &amp;lt;br /&amp;gt;&lt;br /&gt;Username: &amp;lt;strong&amp;gt;&amp;lt;s:property value="username" /&amp;gt;&amp;lt;/strong&amp;gt; &amp;lt;br /&amp;gt;&lt;br /&gt;Password: &amp;lt;strong&amp;gt;&amp;lt;s:property value="password" /&amp;gt;&amp;lt;/strong&amp;gt; &amp;lt;br /&amp;gt;&lt;br /&gt;Edad: &amp;lt;strong&amp;gt;&amp;lt;s:property value="edad" /&amp;gt;&amp;lt;/strong&amp;gt; &amp;lt;br /&amp;gt;&lt;br /&gt;Fecha de Nacimiento: &amp;lt;strong&amp;gt;&amp;lt;s:property value="fechaNacimiento" /&amp;gt;&amp;lt;/strong&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;&lt;span class="negritas"&gt;Número de confirmación: &amp;lt;strong&amp;gt;&amp;lt;s:property value="numero" /&amp;gt;&amp;lt;/strong&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Al ejecutar la aplicación y entrar al formulario, veremos el campo que hemos agregado:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-isCHnjgiEdU/TqMl1wuGIZI/AAAAAAAABG8/RB9iI3EHAfU/s1600/S3_8.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="202" src="http://3.bp.blogspot.com/-isCHnjgiEdU/TqMl1wuGIZI/AAAAAAAABG8/RB9iI3EHAfU/s400/S3_8.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Al enviar los datos del formulario obtendremos la siguiente pantalla: &lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-aD-7q4Yz55s/TqMl2pGS73I/AAAAAAAABHE/Ke8O879-A8A/s1600/S3_9.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="202" src="http://4.bp.blogspot.com/-aD-7q4Yz55s/TqMl2pGS73I/AAAAAAAABHE/Ke8O879-A8A/s400/S3_9.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Ahora veremos cómo podemos hacer para recibir un conjunto de valores en un solo atributo de nuestro &lt;span class="codigo"&gt;Action&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="titulo"&gt;3. Recepción de múltiples parámetros&lt;/h2&gt;En los ejemplos anteriores cada uno de nuestros atributos recibe solo un valor de algún tipo. Sin embargo algunas veces nos será conveniente recibir un conjunto de parámetros, ya sea como un arreglo de valores, o como una lista de valores para poder procesar cada uno de sus elementos.&lt;br /&gt;&lt;br /&gt;Esto es útil para cuando, por ejemplo, tenemos campos de formulario que se van generando dinámicamente, o que tienen el mismo significado en datos (por ejemplo cuando tenemos varios campos para cargar archivos adjuntos en correos electrónicos, o para poder subir varias imágenes de una vez a un sitio):&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-ycRWHiw1-fI/TqMl3clJRvI/AAAAAAAABHM/3UhVfpCwnkY/s1600/S3_10.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="296" src="http://2.bp.blogspot.com/-ycRWHiw1-fI/TqMl3clJRvI/AAAAAAAABHM/3UhVfpCwnkY/s400/S3_10.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Poder obtener estos parámetros es sencillo gracias a los interceptores de &lt;span class="codigo"&gt;Struts 2&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Veamos un ejemplo parecido a la pantalla anterior. Tendremos un formulario que nos permitirá recibir un conjunto de correos electrónicos de personas para ser procesados en el servidor. Colocaremos de forma estática 5 campos (claro que estos podrían ir aumentando de forma dinámica usando JavaScript).&lt;br /&gt;&lt;br /&gt;Aunque el formulario tendrá 5 campos para correos, el usuario podría no llenarlos todos, por lo que no sabremos cuántos elementos estaremos recibiendo.&lt;br /&gt;&lt;br /&gt;El formulario tendrá además un campo que permitirá que el usuario coloque su correo nombre, para saber quién está enviando los correos.&lt;br /&gt;&lt;br /&gt;Comencemos primero con el formulario que mostrará los campos para los correos. Crearemos un nuevo directorio, en la raíz de las páginas web del proyecto, llamado "&lt;span class="codigo"&gt;multidatos&lt;/span&gt;" (lo sé, no es un nombre muy original, pero refleja el cometido del ejemplo):&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-JlU9lDmGGxE/TqMl3hdgqoI/AAAAAAAABHU/_NVoqjkFeQg/s1600/S3_11.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-JlU9lDmGGxE/TqMl3hdgqoI/AAAAAAAABHU/_NVoqjkFeQg/s1600/S3_11.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;En este directorio crearemos una nueva JSP llamada "&lt;span class="codigo"&gt;datos.jsp&lt;/span&gt;". Esta página contendrá el formulario con los 6 campos mencionados antes: un campo para que el usuario coloque su nombre, y 5 para colocar una dirección de correo electrónico:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:form action="envioCorreo"&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="nombre" label="Nombre" /&amp;gt;&lt;br /&gt;    &lt;br /&gt;    &amp;lt;s:textfield name="correo" label="Correo" /&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="correo" label="Correo" /&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="correo" label="Correo" /&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="correo" label="Correo" /&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="correo" label="Correo" /&amp;gt;&lt;br /&gt;            &lt;br /&gt;    &amp;lt;s:submit value="Enviar" /&amp;gt;&lt;br /&gt;&amp;lt;/s:form&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;No olviden indicar que usaremos las etiquetas de &lt;span class="codigo"&gt;Struts 2&lt;/span&gt;, con la directiva &lt;span class="codigo"&gt;taglib&lt;/span&gt; correspondiente:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;%@taglib uri="/struts-tags" prefix="s" %&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Podemos ver en el formulario que los 5 campos para colocar los correos electrónicos son exactamente iguales, todos tienen por nombre "&lt;span class="codigo"&gt;correo&lt;/span&gt;". Esto es necesario para podamos recibir los valores como un solo conjunto de datos. &lt;br /&gt;&lt;br /&gt;Veamos el &lt;span class="codigo"&gt;Action&lt;/span&gt; que recibirá estos valores. Primero crearemos una nueva clase java, llamada "&lt;span class="codigo"&gt;MultiplesDatosAction&lt;/span&gt;", en el paquete "&lt;span class="codigo"&gt;&lt;span class="codigo"&gt;Action&lt;/span&gt;s&lt;/span&gt;". Esta clase extenderá de &lt;span class="codigo"&gt;ActionSupport&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class MultiplesDatosAction extends ActionSupport&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ahora colocaremos el atributo que nos permitirá recibir los múltiples parámetros. Para esto debemos colocar un arreglo del tipo de datos que estemos esperando. En este caso será un arreglo de &lt;span class="codigo"&gt;Strings&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;private String[] correos;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;En realidad, ese es todo el secreto para poder recibir estos múltiples parámetros ^_^. Uno de los interceptores de &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; se encargará de recibir los parámetros del formulario que tienen el mismo nombre; este interceptor colocará los parámetros en un arreglo o una colección, dependiendo de qué es lo que estemos esperando, y lo colocará en nuestro &lt;span class="codigo"&gt;Action&lt;/span&gt; usando el &lt;span class="codigo"&gt;setter&lt;/span&gt; apropiado.&lt;br /&gt;&lt;br /&gt;Según la explicación anterior, debemos colocar el &lt;span class="codigo"&gt;setter&lt;/span&gt; del atributo llamado "&lt;span class="codigo"&gt;correos&lt;/span&gt;" para poder establecer el arreglo de correos, y su getter para poder obtenerlo posteriormente:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public String[] getCorreos()&lt;br /&gt;{&lt;br /&gt;    return correos;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setCorreos(String[] correos)&lt;br /&gt;{&lt;br /&gt;    this.correos = correos;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ahora que tenemos el arreglo de valores colocaremos un atributo para mantener el nombre del usuario, con su correspondiente &lt;span class="codigo"&gt;getter&lt;/span&gt; y &lt;span class="codigo"&gt;setter&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;private String nombre;&lt;br /&gt;&lt;br /&gt;public String getNombre()&lt;br /&gt;{&lt;br /&gt;    return nombre;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setNombre(String nombre)&lt;br /&gt;{&lt;br /&gt;    this.nombre = nombre;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Como en esta ocasión no se realizará ningún proceso sobre los datos, por lo que nuestro método "&lt;span class="codigo"&gt;execute&lt;/span&gt;" solo regresará un valor de "&lt;span class="codigo"&gt;SUCCESS&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Override&lt;br /&gt;public String execute() throws Exception&lt;br /&gt;{&lt;br /&gt;    return SUCCESS;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Para terminar anotaremos esta clase. Primero indicamos que este &lt;span class="codigo"&gt;Action&lt;/span&gt; estará en el namespace "&lt;span class="codigo"&gt;multidatos&lt;/span&gt;". Además responderá al nombre de "&lt;span class="codigo"&gt;envioCorreo&lt;/span&gt;" (el mismo que pusimos en el formulario). Al terminar el proceso, el &lt;span class="codigo"&gt;Action&lt;/span&gt; nos enviará a una página llamada "&lt;span class="codigo"&gt;datos-enviados.jsp&lt;/span&gt;" del directorio "&lt;span class="codigo"&gt;multidatos&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Namespace(value="/multidatos")&lt;br /&gt;@Action(value="envioCorreo", results={@Result(location="/multidatos/datos-enviados.jsp")})&lt;br /&gt;public class MultiplesDatosAction extends ActionSupport&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;El código completo de la clase "&lt;span class="codigo"&gt;MultiplesDatosAction&lt;/span&gt;" queda de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Namespace(value="/multidatos")&lt;br /&gt;@Action(value="envioCorreo", results={@Result(location="/multidatos/datos-enviados.jsp")})&lt;br /&gt;public class MultiplesDatosAction extends ActionSupport&lt;br /&gt;{&lt;br /&gt;    private String[] correos;&lt;br /&gt;    private String nombre;&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    public String execute() throws Exception&lt;br /&gt;    {&lt;br /&gt;        return SUCCESS;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public String getNombre()&lt;br /&gt;    {&lt;br /&gt;        return nombre;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setNombre(String nombre)&lt;br /&gt;    {&lt;br /&gt;        this.nombre = nombre;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public String[] getCorreos()&lt;br /&gt;    {&lt;br /&gt;        return correos;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setCorreos(String[] correos)&lt;br /&gt;    {&lt;br /&gt;        this.correos = correos;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ahora solo falta crear la página a la que regresaremos al terminar el &lt;span class="codigo"&gt;Action&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Creamos, en el directorio "&lt;span class="codigo"&gt;multidatos&lt;/span&gt;" de las páginas web, una nueva &lt;span class="codigo"&gt;JSP&lt;/span&gt; llamada "&lt;span class="codigo"&gt;datos-enviados.jsp&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-bn53E-tKmKs/TqMl54fFpgI/AAAAAAAABHc/HJnFiwVTzuk/s1600/S3_12.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="400" src="http://2.bp.blogspot.com/-bn53E-tKmKs/TqMl54fFpgI/AAAAAAAABHc/HJnFiwVTzuk/s400/S3_12.png" width="201" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;En esta página lo que haremos será mostrar los mismos datos que recibimos del formulario. &lt;br /&gt;&lt;br /&gt;Recuerden que primero debemos indicar que usaremos las etiquetas de &lt;span class="codigo"&gt;Struts 2&lt;/span&gt;, usando el &lt;span class="codigo"&gt;taglib&lt;/span&gt; correspondiente:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;%@taglib uri="/struts-tags" prefix="s" %&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Primero mostraremos el valor del nombre del usuario, de la misma manera en la que hemos venido haciéndolo a lo largo de los ejemplos del tutorial:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:property value="nombre" /&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ahora mostraremos los valores de nuestro arreglo de cadenas, para eso &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; proporciona una etiqueta especial que nos permite iterar a través de todos los valores de un arreglo o colección, la etiqueta "&lt;span class="codigo"&gt;iterator&lt;/span&gt;". &lt;br /&gt;&lt;br /&gt;La etiqueta "&lt;span class="codigo"&gt;iterator&lt;/span&gt;" recibirá el arreglo o colección a través del cual ciclaremos para obtener sus valores. Indicamos este arreglo o colección usando el atributo "&lt;span class="codigo"&gt;value&lt;/span&gt;". En este caso indicaremos que el valor a través del cual queremos iterar es arreglo llamado "&lt;span class="codigo"&gt;correos&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:iterator value="correos"&amp;gt;&lt;br /&gt;&amp;lt;/s:iterator&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ya podemos ciclar a través de todos los elementos del arreglo, ahora necesitamos una manera de obtener el elemento actual dentro del ciclo. Para esto usamos el atributo "&lt;span class="codigo"&gt;var&lt;/span&gt;", en este indicaremos el nombre de la variable que mantendrá el valor del elemento actual. No debemos de preocuparnos por crear esta variable, ya que &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; la creara automáticamente y la pondrá a nuestra disposición. Esta variable será del tipo de elementos que sea mantenido por nuestro arreglo o colección:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:iterator value="correos" var="correo"&amp;gt;&lt;br /&gt;&amp;lt;/s:iterator&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Algunas veces querremos poder obtener alguna información relativa a la iteración, como el índice del elemento actual, el número total de elementos que tiene el arreglo o colección, si el elemento actual es par o impar, etc. Para obtener esta información podemos indicarle a la etiqueta "&lt;span class="codigo"&gt;iterator&lt;/span&gt;" que la coloque, como una instancia de la clase "&lt;span class="codigo"&gt;IteratorStatus&lt;/span&gt;" y que la ponga a nuestra disposición en una variable. Para esto, indicamos el nombre de la variable en el atributo "&lt;span class="codigo"&gt;status&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:iterator value="correos" var="correo" status="estatus"&amp;gt;&lt;br /&gt;&amp;lt;/s:iterator&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;El estatus es una variable que no será colocada dentro en la raíz del stack de &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; (el cual explicamos en &lt;a href="http://www.javatutoriales.com/2011/06/struts-2-parte-2-ognl.html"&gt;el segundo tutorial de la serie&lt;/a&gt;), por lo que es necesario hacer referencia a el usando el operador "&lt;span class="codigo"&gt;#&lt;/span&gt;".&lt;br /&gt;&lt;br /&gt;Ahora que podemos iterar a través de cada uno de los elementos de nuestro arreglo, solo hace falta mostrar el valor de cada uno de estos elementos, adicionalmente también mostraremos su índice. Colocaremos estos valores en una lista para que se vea más presentable:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;ul&amp;gt;&lt;br /&gt;    &amp;lt;s:iterator value="correos" var="correo" status="estatus"&amp;gt;&lt;br /&gt;        &amp;lt;li&amp;gt;&amp;lt;s:property value="#estatus.index" /&amp;gt; - &amp;lt;s:property value="correo" /&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;    &amp;lt;/s:iterator&amp;gt;&lt;br /&gt;&amp;lt;/ul&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ahora, cuando coloquemos los siguientes datos en el formulario:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-ELdQ1SgSneU/TqMl6dvkOHI/AAAAAAAABHk/Vl4Kjwbm1gc/s1600/S3_13.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="170" src="http://2.bp.blogspot.com/-ELdQ1SgSneU/TqMl6dvkOHI/AAAAAAAABHk/Vl4Kjwbm1gc/s400/S3_13.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Obtendremos la siguiente salida:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-wlmsNS5B4so/TqMl6yI1Q-I/AAAAAAAABHs/UoJQpGC82zs/s1600/S3_14.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="170" src="http://2.bp.blogspot.com/-wlmsNS5B4so/TqMl6yI1Q-I/AAAAAAAABHs/UoJQpGC82zs/s400/S3_14.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Podemos ver que de una forma sencilla colocamos el conjunto de valores dentro del arreglo. Pero qué pasa si por alguna razón no podemos o no queremos usar un arreglo, y preferimos trabajar con una colección, como un &lt;span class="codigo"&gt;Set&lt;/span&gt; o un &lt;span class="codigo"&gt;List&lt;/span&gt;, lo único que tenemos que hacer es cambiar el tipo del atributo "&lt;span class="codigo"&gt;correos&lt;/span&gt;" (junto con sus correspondientes &lt;span class="codigo"&gt;getters&lt;/span&gt; y &lt;span class="codigo"&gt;setters&lt;/span&gt;). Usemos un "&lt;span class="codigo"&gt;Set&lt;/span&gt;", el cual es una colección que no permite elementos duplicados.&lt;br /&gt;&lt;br /&gt;Modifiquemos el atributo "&lt;span class="codigo"&gt;correos&lt;/span&gt;" para que quede de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;private Set&amp;lt;String&amp;gt; correos;&lt;br /&gt;&lt;br /&gt;public Set&amp;lt;String&amp;gt; getCorreos()&lt;br /&gt;{&lt;br /&gt;    return correos;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setCorreos(Set&amp;lt;String&amp;gt; correos)&lt;br /&gt;{&lt;br /&gt;    this.correos = correos;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Al introducir los siguientes datos en el formulario:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-zX1Y-Y846Co/TqMl7Ees8nI/AAAAAAAABH0/61sQhxPP494/s1600/S3_15.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="170" src="http://2.bp.blogspot.com/-zX1Y-Y846Co/TqMl7Ees8nI/AAAAAAAABH0/61sQhxPP494/s400/S3_15.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Obtendremos la siguiente salida:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-6WKXJ2a7Z6Y/TqMl7nknIsI/AAAAAAAABH8/mUR4QDwPGhM/s1600/S3_16.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="170" src="http://1.bp.blogspot.com/-6WKXJ2a7Z6Y/TqMl7nknIsI/AAAAAAAABH8/mUR4QDwPGhM/s400/S3_16.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Podemos ver que en realidad no fue necesario realizar grandes cambios para modificar la forma en la que recibimos los datos. Si quisiéramos que "&lt;span class="codigo"&gt;correos&lt;/span&gt;" fuera una Lista, lo único que debemos hacer es, nuevamente, cambiar solo el tipo de dato.&lt;br /&gt;&lt;br /&gt;El arreglo o la colección que usemos para mantener los valores, pueden ser de cualquier tipo de dato (cadenas, fechas, wrappers, archivos, etc).&lt;br /&gt;&lt;br /&gt;Los ejemplos anteriores funcionan bien cuándo sabemos cuántos y cuáles serán los parámetros que estamos esperando recibir. Pero ¿y si no supiéramos de antemano los parámetros que recibiremos?&lt;br /&gt;&lt;br /&gt;Como pueden imaginarse, &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; proporciona una manera elegante de manejar estas situaciones.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="titulo"&gt;4. Recepción de Parámetros Desconocidos&lt;/h2&gt;Algunas veces estamos esperando recibir, dentro de nuestro &lt;span class="codigo"&gt;Action&lt;/span&gt;, un conjunto de parámetros de los cuales no conocemos ni su cantidad ni sus nombres, como por ejemplo cuando estamos haciendo un filtrado de datos y no sabes qué filtros recibiremos y cuáles serán los valores de estos filtros, o cuando la generación de componentes se realiza de forma dinámica.&lt;br /&gt;&lt;br /&gt;Para estos casos &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; proporciona una manera de indicar que deberá entregarnos todos los parámetros en un objeto tipo "&lt;span class="codigo"&gt;java.util.Map&lt;/span&gt;".  Las llaves de este mapa representarán los nombres de los parámetros, y sus valores representarán un arreglo de &lt;span class="codigo"&gt;Strings&lt;/span&gt; con los valores correspondientes de cada parámetro. ¿Por qué un arreglo de &lt;span class="codigo"&gt;Strings&lt;/span&gt;? Porque como acabamos de ver, algunos de los parámetros que recibimos pueden tener más de un valor.&lt;br /&gt;&lt;br /&gt;Para lograr que &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; nos proporcione estos parámetros, nuestro &lt;span class="codigo"&gt;Action&lt;/span&gt; debe implementar la interface "&lt;span class="codigo"&gt;ParameterAware&lt;/span&gt;". Esta interface se ve de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public interface ParameterAware&lt;br /&gt;{&lt;br /&gt;    void setParameters(Map&amp;lt;String, String[]&amp;gt; parameters);&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;O sea, que esta interface solo tiene un método llamado "&lt;span class="codigo"&gt;setParameters&lt;/span&gt;", que tiene como argumento el mapa de parámetros recibidos en la petición.&lt;br /&gt;&lt;br /&gt;Veamos un ejemplo para entender cómo funciona esta interface.&lt;br /&gt;&lt;br /&gt;Primero crearemos un nuevo directorio, dentro de nuestras páginas web, llamado "&lt;span class="codigo"&gt;multiparametros&lt;/span&gt;". Dentro de este directorio crearemos dos nuevas &lt;span class="codigo"&gt;JSP&lt;/span&gt;s. La primera, llamada "&lt;span class="codigo"&gt;datos.jsp&lt;/span&gt;" contendrá un pequeño formulario que nos permitirá enviar los parámetros dinámicos a nuestro &lt;span class="codigo"&gt;Action&lt;/span&gt;. La segunda, llamada "&lt;span class="codigo"&gt;parametros.jsp&lt;/span&gt;", mostrara el nombre y el valor de cada uno de los parámetros que hemos colocado en el formulario. Comencemos creando la pagina "&lt;span class="codigo"&gt;datos.jsp&lt;/span&gt;". &lt;br /&gt;&lt;br /&gt;Primero, indicaremos que haremos uso de las etiquetas de &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; usando el taglib correspondiente:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;%@taglib prefix="s" uri="/struts-tags" %&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ahora crearemos un formulario, de una forma un poco distinta a como lo hemos estado haciendo hasta ahora. Primero indicaremos, con la etiqueta "&lt;span class="codigo"&gt;&amp;lt;s:form&amp;gt;&lt;/span&gt;" que haremos uso de un formulario, los datos del mismo serán procesados por un &lt;span class="codigo"&gt;Action&lt;/span&gt; cuyo nombre será "&lt;span class="codigo"&gt;multiparametros&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:form action="multiparametros"&amp;gt;&lt;br /&gt;&amp;lt;/s:form&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Para que sea más claro entender un paso que haremos un poco más adelante, en vez de dejar que &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; sea quien defina la estructura de nuestro formulario, lo haremos nosotros mismos. Para eso debemos indicar, en el atributo "&lt;span class="codigo"&gt;theme&lt;/span&gt;" del formulario, el valor "&lt;span class="codigo"&gt;simple&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:form action="multiparametros" theme="simple"&amp;gt;&lt;br /&gt;&amp;lt;/s:form&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ahora colocaremos un elemento en el formulario, un campo de entrada de texto usando el la etiqueta "&lt;span class="codigo"&gt;&amp;lt;s:textfield&amp;gt;&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:form action="multiparametros" id="formulario" theme="simple"&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield id="valor1" name="valor1" /&amp;gt; &lt;br /&gt;&amp;lt;/s:form&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Como en esta ocasión no se colocará una etiqueta de forma automática en el campo de texto, deberemos ponerla nosotros mismos, usando la etiqueta "&lt;span class="codigo"&gt;&amp;lt;s:label&amp;gt;&lt;/span&gt;", de la siguiente manera:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:form action="multiparametros" theme="simple"&amp;gt;&lt;br /&gt;    &amp;lt;s:label for="valor1" value="Valor 1: " /&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield id="valor1" name="valor1" /&amp;gt;&lt;br /&gt;&amp;lt;/s:form&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Como pueden ver hemos tenido que colocar un valor en el atributo "&lt;span class="codigo"&gt;id&lt;/span&gt;" del textfield, y poner este mismo valor en el atributo "&lt;span class="codigo"&gt;for&lt;/span&gt;" de la etiqueta "&lt;span class="codigo"&gt;&amp;lt;s:label&amp;gt;&lt;/span&gt;". &lt;br /&gt;&lt;br /&gt;Como estamos haciendo nosotros mismos el acomodo de los componentes, también debemos colocar un salto de línea entre los elementos del formulario; de lo contrario aparecerían todos en la misma línea. Para eso usamos la etiqueta "&lt;span class="codigo"&gt;&amp;lt;br&amp;gt;&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:form action="multiparametros" theme="simple"&amp;gt;&lt;br /&gt;    &amp;lt;s:label for="valor1" value="Valor 1: " /&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield id="valor1" name="valor1" /&amp;gt; &amp;lt;br /&amp;gt; &lt;br /&gt;&amp;lt;/s:form&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;El siguiente paso consiste en colocar el botón de envió del formulario, usando la etiqueta "&lt;span class="codigo"&gt;&amp;lt;s:submit&amp;gt;&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:form action="multiparametros" theme="simple"&amp;gt;&lt;br /&gt;    &amp;lt;s:label for="valor1" value="Valor 1: " /&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield id="valor1" name="valor1" /&amp;gt; &amp;lt;br /&amp;gt; &lt;br /&gt;    &amp;lt;s:submit value="Enviar" /&amp;gt;    &lt;br /&gt;&amp;lt;/s:form&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Hasta ahora tenemos un formulario que se ve de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-LQjM8sYoEwk/TqMl8hvoiQI/AAAAAAAABIE/Jwt7zRnA2ro/s1600/S3_17.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="217" src="http://1.bp.blogspot.com/-LQjM8sYoEwk/TqMl8hvoiQI/AAAAAAAABIE/Jwt7zRnA2ro/s400/S3_17.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Podemos ver que tenemos un solo parámetro, sin embargo para el ejemplo necesitamos varios campos de texto. Haremos que estos se agreguen de forma dinámica usando una biblioteca de JavaScript: &lt;a href="http://jquery.com/"&gt;&lt;span class="codigo"&gt;jQuery&lt;/span&gt;&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Colocaremos un botón que al presionarlo agregará un nuevo campo para introducir texto, junto con su etiqueta y salto de línea correspondiente.&lt;br /&gt;&lt;br /&gt;El &lt;span class="codigo"&gt;HTML&lt;/span&gt; del botón es el siguiente:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;button id="btnAgregar"&amp;gt;Agregar Elemento&amp;lt;/button&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Y el código de &lt;span class="codigo"&gt;jQuery&lt;/span&gt; para agregar los elementos al formulario es el siguiente:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;$(document).ready(function () &lt;br /&gt;{&lt;br /&gt;    $("#btnAgregar").click(function() &lt;br /&gt;    {&lt;br /&gt;        var num = $("input[type=text]").length;&lt;br /&gt;        var numeroSiguiente = num + 1;&lt;br /&gt;        var elementoNuevo = $("#valor" + num).clone().attr('id', 'valor'+numeroSiguiente).attr("name", "valor"+numeroSiguiente);&lt;br /&gt;        var etiquetaNueva = $("label[for=valor"+num+"]").clone().attr("for", "valor"+numeroSiguiente).text("Valor " + numeroSiguiente + ": ");&lt;br /&gt;                           &lt;br /&gt;        $("#valor" + num).after(elementoNuevo);&lt;br /&gt;        elementoNuevo.before(etiquetaNueva);&lt;br /&gt;        etiquetaNueva.before("&amp;lt;br /&amp;gt;");&lt;br /&gt;    });&lt;br /&gt;});&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Como este no es un tutorial de &lt;span class="codigo"&gt;jQuery&lt;/span&gt; no explicaré el código anterior ^_^. Pero el resultado es el siguiente:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-wNW4YFVxB4Q/TqMl8z58wxI/AAAAAAAABIM/Vhb06o4Ih4M/s1600/S3_18.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="217" src="http://3.bp.blogspot.com/-wNW4YFVxB4Q/TqMl8z58wxI/AAAAAAAABIM/Vhb06o4Ih4M/s400/S3_18.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Cada vez que presionemos el botón "&lt;span class="codigo"&gt;Agregar Elemento&lt;/span&gt;" se agregará un nuevo campo de entrada, de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-8k11veCGf5o/TqMl9WZG8cI/AAAAAAAABIU/hHUTg4zmy2c/s1600/S3_19.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="217" src="http://2.bp.blogspot.com/-8k11veCGf5o/TqMl9WZG8cI/AAAAAAAABIU/hHUTg4zmy2c/s400/S3_19.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Ahora que tenemos un formulario pasemos a crear nuestro &lt;span class="codigo"&gt;Action&lt;/span&gt;. Creamos una nueva clase &lt;span class="codigo"&gt;Java&lt;/span&gt;, en el paquete "&lt;span class="codigo"&gt;&lt;span class="codigo"&gt;Action&lt;/span&gt;s&lt;/span&gt;". El nombre de esta clase será "&lt;span class="codigo"&gt;MultiplesParametrosAction&lt;/span&gt;", extenderá de "&lt;span class="codigo"&gt;ActionSupport&lt;/span&gt;" e implementará la interface "&lt;span class="codigo"&gt;ParameterAware&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class MultiplesParametrosAction extends ActionSupport implements ParameterAware&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Debemos colocar una variable que nos permita almacenar la referencia al mapa que los interceptores inyectarán con la lista de parámetros recibidos:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;private Map&amp;lt;String, String[]&amp;gt; parametros;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Además debemos implementar el método "&lt;span class="codigo"&gt;setParameters&lt;/span&gt;" de la interface "&lt;span class="codigo"&gt;ParameterAware&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public void setParameters(Map&amp;lt;String, String[]&amp;gt; parametros)&lt;br /&gt;{&lt;br /&gt;    this.parametros = parametros;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Adicionalmente pondremos un &lt;span class="codigo"&gt;getter&lt;/span&gt; para el mapa de parámetros, para poder recuperarlo desde la &lt;span class="codigo"&gt;JSP&lt;/span&gt; correspondiente:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public Map&amp;lt;String, String[]&amp;gt; getParametros()&lt;br /&gt;{&lt;br /&gt;    return parametros;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Nuestro método "&lt;span class="codigo"&gt;execute&lt;/span&gt;" nuevamente será muy simple y solo regresara el valor "&lt;span class="codigo"&gt;SUCESS&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Override&lt;br /&gt;public String execute() throws Exception&lt;br /&gt;{   &lt;br /&gt;    return SUCCESS;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;El siguiente paso es anotar nuestra clase para convertirla en un &lt;span class="codigo"&gt;Action&lt;/span&gt;. Las anotaciones (y la explicación) serán las mismas que hemos venido usando hasta ahora:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Namespace(value="/multiparametros")&lt;br /&gt;@Action(value="multiparametros", results={@Result(location="/multiparametros/parametros.jsp")})&lt;br /&gt;public class MultiplesParametrosAction extends ActionSupport implements ParameterAware&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;La clase "&lt;span class="codigo"&gt;MultiplesParametrosAction&lt;/span&gt;" completa queda de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Namespace(value="/multiparametros")&lt;br /&gt;@Action(value="multiparametros", results={@Result(location="/multiparametros/parametros.jsp")})&lt;br /&gt;public class MultiplesParametrosAction extends ActionSupport implements ParameterAware&lt;br /&gt;{&lt;br /&gt;    private Map&amp;lt;String, String[]&amp;gt; parametros;&lt;br /&gt;    &lt;br /&gt;    public void setParameters(Map&amp;lt;String, String[]&amp;gt; parametros)&lt;br /&gt;    {&lt;br /&gt;        this.parametros = parametros;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public Map&amp;lt;String, String[]&amp;gt; getParametros()&lt;br /&gt;    {&lt;br /&gt;        return parametros;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    @Override&lt;br /&gt;    public String execute() throws Exception&lt;br /&gt;    {   &lt;br /&gt;        return SUCCESS;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Finalmente debemos crear el contenido de la pagina "&lt;span class="codigo"&gt;parametros.jsp&lt;/span&gt;". Nuevamente usaremos una etiqueta "&amp;lt;&lt;span class="codigo"&gt;s:iterator&lt;/span&gt;&amp;gt;". En este caso en vez de pasarle una lista, le pasaremos el  mapa con los parámetros que recibimos desde el &lt;span class="codigo"&gt;Action&lt;/span&gt;, y nuevamente colocaremos una variable en donde se colocará el valor del elemento actual del ciclo:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:iterator value="parametros" var="parametro"&amp;gt;&lt;br /&gt;&amp;lt;/s:iterator&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Como un &lt;span class="codigo"&gt;Map&lt;/span&gt; tiene dos elementos importantes, la llave y el valor, debemos obtener cada uno de estos valores para mostrarlos en nuestra página. Para tener acceso a la llave usamos la propiedad "&lt;span class="codigo"&gt;key&lt;/span&gt;" del elemento actual,  y para obtener el valor, usamos la propiedad "&lt;span class="codigo"&gt;value&lt;/span&gt;" la cual nos regresará el arreglo de cadenas asociado con el parámetro. Para obtener el primer valor de este parámetro debemos accederlo usando la sintaxis de los arreglos, como vimos en el segundo tutorial de la serie:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:iterator value="parametros" var="parametro"&amp;gt;&lt;br /&gt;    &amp;lt;s:property value="#parametro.key" /&amp;gt;: &amp;lt;s:property value="#parametro.value[0]" /&amp;gt;&lt;br /&gt;&amp;lt;/s:iterator&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Para que todo se vea más ordenado, colocaremos los resultados en una lista:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;ul&amp;gt;&lt;br /&gt;    &amp;lt;s:iterator value="parametros" var="parametro"&amp;gt;&lt;br /&gt;        &amp;lt;li&amp;gt;&amp;lt;s:property value="#parametro.key" /&amp;gt;: &amp;lt;s:property value="#parametro.value[0]" /&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;    &amp;lt;/s:iterator&amp;gt;&lt;br /&gt;&amp;lt;/ul&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ahora que ya tenemos el código listo ejecutemos la aplicación; cuando entremos a la dirección:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&lt;a href="http://localhost:8080/formularios/multiparametros/datos.jsp"&gt;http://localhost:8080/formularios/multiparametros/datos.jsp&lt;/a&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Veremos el formulario que creamos:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-gj2KdcPNsuo/TqMmYcfdSsI/AAAAAAAABOc/PS9O4uoDwdQ/s1600/S3_68.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="165" src="http://2.bp.blogspot.com/-gj2KdcPNsuo/TqMmYcfdSsI/AAAAAAAABOc/PS9O4uoDwdQ/s400/S3_68.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Si ingresamos los siguientes datos, y enviamos el formulario:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-OP5dgxH-2mc/TqMmY9rWyAI/AAAAAAAABOk/tR7jbicv-8Q/s1600/S3_69.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="165" src="http://3.bp.blogspot.com/-OP5dgxH-2mc/TqMmY9rWyAI/AAAAAAAABOk/tR7jbicv-8Q/s400/S3_69.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Veremos la siguiente salida:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-xPPf1FrBQaw/TqMmZbU8HSI/AAAAAAAABOs/QIa9_o1yPks/s1600/S3_70.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="165" src="http://3.bp.blogspot.com/-xPPf1FrBQaw/TqMmZbU8HSI/AAAAAAAABOs/QIa9_o1yPks/s400/S3_70.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Como podemos ver, aunque no tenemos ni idea del nombre o la cantidad de parámetros que recibiremos en la petición, &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; aún nos proporciona una forma sencilla y elegante de manejarlos. &lt;br /&gt;&lt;br /&gt;Hasta ahora hemos visto varias maneras de recibir parámetros desde nuestros formularios. Sin embargo otra parte muy importante del trabajo con estos últimos es el poder realizar algunas validaciones sobre los datos que recibimos. En la siguiente sección veremos cómo usar validaciones en nuestros formularios.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="titulo"&gt;5. Validaciones&lt;/h2&gt;Una parte importante del trabajo con formularios es que podamos asegurarnos que la información de los mismos cumpla con ciertos requisitos para poder procesarlos. Por ejemplo que las direcciones de correo electrónico cumplan con el formato establecido, o que ciertos valores estén dentro de un rango valido, o simplemente que se estén proporcionando los campos obligatorios del formulario.&lt;br /&gt;&lt;br /&gt;Hacer esto con &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; es muy simple, ya que proporciona varias maneras de realizar validaciones de forma automática para los datos de nuestros formularios.&lt;br /&gt;&lt;br /&gt;Las validaciones son realizadas por dos interceptores: "&lt;span class="codigo"&gt;validation&lt;/span&gt;" y "&lt;span class="codigo"&gt;workfllow&lt;/span&gt;". El primero realiza las validaciones y crea una lista de errores específicos para cada uno de los campos que no pase la validación. Posteriormente el interceptor "&lt;span class="codigo"&gt;workflow&lt;/span&gt;" verifica si hay errores de validación; si encuentra algún error regresa un resultado "&lt;span class="codigo"&gt;input&lt;/span&gt;", por lo que &lt;span class="negritas"&gt;es necesario que proporcionemos un result con este nombre&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span class="codigo"&gt;Struts 2&lt;/span&gt; tiene básicamente tres formas de realizar validaciones:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Validaciones mediante un archivo &lt;span class="codigo"&gt;XML&lt;/span&gt;&lt;/li&gt;&lt;li&gt;Validaciones mediante anotaciones&lt;/li&gt;&lt;li&gt;Validaciones manuales&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Primero comencemos creando la estructura con los elementos que usaremos en las validaciones:&lt;br /&gt;&lt;br /&gt;Lo primero que haremos será crear un nuevo directorio en las páginas web, llamado "&lt;span class="codigo"&gt;validaciones&lt;/span&gt;". Dentro de este directorio crearemos una nueva &lt;span class="codigo"&gt;JSP&lt;/span&gt; llamada "&lt;span class="codigo"&gt;formulario.jsp&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-pUJE3uDt0hA/TqMl94N-MxI/AAAAAAAABIc/_-kAdhfjvwI/s1600/S3_20.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://3.bp.blogspot.com/-pUJE3uDt0hA/TqMl94N-MxI/AAAAAAAABIc/_-kAdhfjvwI/s320/S3_20.png" width="221" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Dentro de esta página crearemos un formulario sencillo que solicitará al usuario algunos datos básicos como nombre, correo electrónico, teléfono, etc. No olviden colocar en la JSP la directiva taglib correspondiente para indicar que esta hará uso de las bibliotecas de etiquetas de Struts. El formulario quedará, por el momento, de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:form action="validacionDatos"&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="nombre" label="Nombe" /&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="username" label="Username" /&amp;gt;&lt;br /&gt;    &amp;lt;s:password  name="password" label="Password" /&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="email" label="Email" /&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="edad" label="Edad" /&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="telefono" label="Telefono" /&amp;gt;&lt;br /&gt;    &amp;lt;s:submit value="Enviar" /&amp;gt;&lt;br /&gt;&amp;lt;/s:form&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Otra de las pequeñas ayudas que nos proporcionan las etiquetas de &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; es que nos permiten indicar si cuáles campos son obligatorios, con lo que se le colocará una pequeña marca en la etiqueta para que el usuario sepa cuáles campos son los que está obligado a llenar. Esta marca es solo una ayuda visual, no realizará ningún proceso de validación del campo.&lt;br /&gt;&lt;br /&gt;Para agregar dicha marca e indicar que el campo será obligatorio, debemos colocar el valor de "&lt;span class="codigo"&gt;true&lt;/span&gt;" en el atributo "&lt;span class="codigo"&gt;required&lt;/span&gt;" de las etiquetas del formulario. En este caso todos los campos, con excepción del teléfono, serán requeridos:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:form action="validacionDatos"&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="nombre" label="Nombe" required="true" /&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="username" label="Username" required="true" /&amp;gt;&lt;br /&gt;    &amp;lt;s:password  name="password" label="Password" required="true" /&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="email" label="Email" required="true" /&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="edad" label="Edad" required="true" /&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="telefono" label="Telefono" /&amp;gt;&lt;br /&gt;    &amp;lt;s:submit value="Enviar" /&amp;gt;&lt;br /&gt;&amp;lt;/s:form&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Con el código anterior obtenemos el siguiente formulario:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-tOiJqgVVDoM/TqMl-QDBG1I/AAAAAAAABIk/SnOKLSFVRk4/s1600/S3_21.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="226" src="http://2.bp.blogspot.com/-tOiJqgVVDoM/TqMl-QDBG1I/AAAAAAAABIk/SnOKLSFVRk4/s400/S3_21.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Debido al tema ("&lt;span class="codigo"&gt;theme&lt;/span&gt;") que se usa por default para construir el formulario, los errores serán mostrados directamente sobre los campos que no pasen la validación. Sin embargo, si quisiéramos mostrar, de manera adicional, una lista con todos los errores del formulario, debemos agregar en nuestra &lt;span class="codigo"&gt;JSP&lt;/span&gt; la etiqueta "&lt;span class="codigo"&gt;&amp;lt;s:fielderror /&amp;gt;&lt;/span&gt;". Solo la colocamos sobre el formulario, de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:fielderror /&amp;gt;&lt;br /&gt;        &lt;br /&gt;&amp;lt;s:form &lt;span class="codigo"&gt;Action&lt;/span&gt;="validacionDatos"&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="nombre" label="Nombre" required="true" /&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="username" label="Username" required="true" /&amp;gt;&lt;br /&gt;    &amp;lt;s:password  name="password" label="Password" required="true" /&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="email" label="Email" required="true" /&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="edad" label="Edad" required="true" /&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="telefono" label="Telefono" /&amp;gt;&lt;br /&gt;    &amp;lt;s:submit value="Enviar" /&amp;gt;&lt;br /&gt;&amp;lt;/s:form&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ahora creamos el &lt;span class="codigo"&gt;Action&lt;/span&gt; que se encargará de procesar los datos anteriores. Para eso creamos una nueva clase llamada "&lt;span class="codigo"&gt;ValidacionDatos&lt;/span&gt;" en el paquete "&lt;span class="codigo"&gt;&lt;span class="codigo"&gt;Action&lt;/span&gt;s&lt;/span&gt;". Esta clase extenderá de "&lt;span class="codigo"&gt;ActionSupport&lt;/span&gt;" y tendrá las anotaciones que para este momento ya deben sernos más que familiares:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Namespace(value="/validaciones")&lt;br /&gt;@Action(value="validacionDatos", results={@Result(location="/validaciones/alta-exitosa.jsp")})&lt;br /&gt;public class ValidacionDatos extends ActionSupport&lt;br /&gt;{&lt;br /&gt;    &lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;La clase "&lt;span class="codigo"&gt;ValidacionDatos&lt;/span&gt;" tendrá &lt;span class="codigo"&gt;setters&lt;/span&gt; y &lt;span class="codigo"&gt;getters&lt;/span&gt; para cada uno de los valores que recibiremos del formulario. En este caso los &lt;span class="codigo"&gt;getters&lt;/span&gt; son importantes por dos razones, la primera es que queremos que el formulario sea repoblado con los valores que el usuario ya habia introducido (los cuales solo pueden obtenerse a partir de los &lt;span class="codigo"&gt;getters&lt;/span&gt;); la segunda es que, por alguna razón que no alcanzo a entender, las validaciones se realizan sobre los &lt;span class="codigo"&gt;getters&lt;/span&gt; de las propiedades. La case "&lt;span class="codigo"&gt;ValidacionDatos&lt;/span&gt;" hasta ahora se ve de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class ValidacionDatos extends ActionSupport&lt;br /&gt;{&lt;br /&gt;    private String nombre;&lt;br /&gt;    private String username;&lt;br /&gt;    private String password;&lt;br /&gt;    private String email;&lt;br /&gt;    private int edad;&lt;br /&gt;    private String telefono;&lt;br /&gt;&lt;br /&gt;    public void setEdad(int edad)&lt;br /&gt;    {&lt;br /&gt;        this.edad = edad;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setEmail(String email)&lt;br /&gt;    {&lt;br /&gt;        this.email = email;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setNombre(String nombre)&lt;br /&gt;    {&lt;br /&gt;        this.nombre = nombre;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setPassword(String password)&lt;br /&gt;    {&lt;br /&gt;        this.password = password;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setTelefono(String telefono)&lt;br /&gt;    {&lt;br /&gt;        this.telefono = telefono;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setUsername(String username)&lt;br /&gt;    {&lt;br /&gt;        this.username = username;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public int getEdad()&lt;br /&gt;    {&lt;br /&gt;        return edad;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public String getEmail()&lt;br /&gt;    {&lt;br /&gt;        return email;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public String getNombre()&lt;br /&gt;    {&lt;br /&gt;        return nombre;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public String getPassword()&lt;br /&gt;    {&lt;br /&gt;        return password;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public String getTelefono()&lt;br /&gt;    {&lt;br /&gt;        return telefono;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public String getUsername()&lt;br /&gt;    {&lt;br /&gt;        return username;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;En su método "&lt;span class="codigo"&gt;execute&lt;/span&gt;" esta clase solo se encargará de imprimir los valores que se han recibido a través del formulario:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Override&lt;br /&gt;public String execute() throws Exception&lt;br /&gt;{&lt;br /&gt;    System.out.println("nombre: " + nombre);&lt;br /&gt;    System.out.println("username: " + username);&lt;br /&gt;    System.out.println("password: " + password);&lt;br /&gt;    System.out.println("email: " + email);&lt;br /&gt;    System.out.println("edad: " + edad);&lt;br /&gt;    System.out.println("telefono: " + telefono);&lt;br /&gt;        &lt;br /&gt;    return SUCCESS;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ahora crearemos la página que se encargará de mostrar el resultado del alta de usuario. Para esto crearemos una &lt;span class="codigo"&gt;JSP&lt;/span&gt; llamada "&lt;span class="codigo"&gt;alta-exitosa.jsp&lt;/span&gt;" en el directorio "&lt;span class="codigo"&gt;validaciones&lt;/span&gt;". Esta página será muy sencilla y solo mostrará el mensaje "&lt;span class="codigo"&gt;Usuario dado de alta exitosamente.&lt;/span&gt;"&lt;br /&gt;&lt;br /&gt;Finalmente, recordemos que si existe un error de validación el interceptor correspondiente regresará un resultado con valor "&lt;span class="codigo"&gt;input&lt;/span&gt;". Este resultado debe enviarnos a una página en la que se mostrará la lista de errores de datos de entrada. Normalmente esta página es el mismo formulario de entrada para que el usuario pueda corregir los datos que introdujo de forma incorrecta. Asi que modificaremos la anotación "&lt;span class="codigo"&gt;@Action&lt;/span&gt;" de la clase "&lt;span class="codigo"&gt;ValidacionDatos&lt;/span&gt;" para aregar un segundo resultado, que en caso de un error de entrada ("&lt;span class="codigo"&gt;input&lt;/span&gt;") nos regrese al formulario:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Action(value = "validacionDatos", results =&lt;br /&gt;{&lt;br /&gt;    @Result(location = "/validaciones/alta-exitosa.jsp"),&lt;br /&gt;    @Result(name="input", location="/validaciones/formulario.jsp")&lt;br /&gt;})&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Como podemos ver, en este caso si es necesario indicar de forma explícita el nombre del result usando el atributo "&lt;span class="codigo"&gt;name&lt;/span&gt;".&lt;br /&gt;&lt;br /&gt;Al ejecutar nuestra aplicación y entrar en la siguiente dirección:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&lt;a href="http://localhost:8080/formularios/validaciones/formulario.jsp"&gt;http://localhost:8080/formularios/validaciones/formulario.jsp&lt;/a&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Deberemos ver el formulario que creamos hace un momento. Llenemos un par de campos para ver el resultado obtenido:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-37Dzi18JUgY/TqMl-wihHOI/AAAAAAAABIs/xU-tYn6ykGA/s1600/S3_22.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="226" src="http://4.bp.blogspot.com/-37Dzi18JUgY/TqMl-wihHOI/AAAAAAAABIs/xU-tYn6ykGA/s400/S3_22.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Al enviar los datos del formulario deberemos ver la siguiente salida:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-yJDElD0Li4o/TqMl_f6pwCI/AAAAAAAABI0/T4x34Hiycw0/s1600/S3_23.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="226" src="http://2.bp.blogspot.com/-yJDElD0Li4o/TqMl_f6pwCI/AAAAAAAABI0/T4x34Hiycw0/s400/S3_23.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Si analizamos la salida anterior veremos que esta no es correcta, ya que el usuario no ha proporcionado todos los datos requeridos, por lo que debería ver un mensaje de error. Solucionaremos esto agregando validaciones en los datos. Primero veremos cómo hacer validaciones usando archivos &lt;span class="codigo"&gt;XML&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3 class="subtitulo"&gt;5.1 Validaciones usando archivos XML&lt;/h3&gt;Para realizar validaciones usando archivos en &lt;span class="codigo"&gt;XML&lt;/span&gt; debemos crear un archivo por cada una de las clases que será validada. El nombre de este archivo debe seguir una convención muy sencilla:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;NombreDeNuestroAction&amp;gt;-validation.xml&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;O sea, que debe tener el mismo nombre del &lt;span class="codigo"&gt;Action&lt;/span&gt; + la cadena "&lt;span class="codigo"&gt;-validation&lt;/span&gt;" y la extensión "&lt;span class="codigo"&gt;.xml&lt;/span&gt;". El archivo debe estar colocado en el mismo directorio que la clase &lt;span class="codigo"&gt;Action&lt;/span&gt; que validará.&lt;br /&gt;&lt;br /&gt;Dentro de este archivo se indicará cuáles campos serán validados y qué validaciones se le aplicarán. Cada una de estas validaciones tiene un parámetro obligatorio, que es el nombre del campo que validará. Adicionalmente pueden o no tener más parámetros. &lt;br /&gt;&lt;br /&gt;&lt;span class="codigo"&gt;Struts 2&lt;/span&gt; ya viene con algunas validaciones predeterminadas que podemos usar, aunque también tenemos la posibilidad de crear nuestras propias validaciones en caso de ser necesario. Las validaciones incuidas con &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; se muestran en la siguiente tabla: &lt;br /&gt;&lt;br /&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Validador&lt;/th&gt;&lt;th&gt;Descripción&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;   &lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span class="codigo"&gt;required&lt;/span&gt;&lt;/td&gt;&lt;td&gt;Verifica que el campo especificado no sea nulo.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span class="codigo"&gt;requiredstring&lt;/span&gt;&lt;/td&gt;&lt;td&gt;Verifica que un campo de tipo &lt;span class="codigo"&gt;String&lt;/span&gt; no sea nulo y que tenga un longitud mayor a &lt;span class="codigo"&gt;0&lt;/span&gt;.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span class="codigo"&gt;stringlength&lt;/span&gt;&lt;/td&gt;&lt;td&gt;Verifica que una cadena tenga una cierta longitud.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span class="codigo"&gt;int, long, y short&lt;/span&gt;&lt;/td&gt;&lt;td&gt;Verifica que el &lt;span class="codigo"&gt;int&lt;/span&gt;, &lt;span class="codigo"&gt;long&lt;/span&gt;, o &lt;span class="codigo"&gt;short&lt;/span&gt; especificado estén dentro de un rango determinado.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span class="codigo"&gt;double&lt;/span&gt;&lt;/td&gt;&lt;td&gt;Verifica que el valor &lt;span class="codigo"&gt;double&lt;/span&gt; especificado esté dentro de cierto rango.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span class="codigo"&gt;date&lt;/span&gt;&lt;/td&gt;&lt;td&gt;Verifica que la fecha proporcionada esté dentro del rango proporcionado. Por default se usa el formato &lt;span class="codigo"&gt;Date.SHORT&lt;/span&gt;   para indicar las fechas.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span class="codigo"&gt;email&lt;/span&gt;&lt;/td&gt;&lt;td&gt;Verifica que el campo cumpla con el formato de una dirección de email válida&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span class="codigo"&gt;url&lt;/span&gt;&lt;/td&gt;&lt;td&gt;Verifica que el campo cumpla con el formato de una &lt;span class="codigo"&gt;URL&lt;/span&gt; válida.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span class="codigo"&gt;visitor&lt;/span&gt;&lt;/td&gt;&lt;td&gt;Permite enviar la validación a las propiedades del objeto del &lt;span class="codigo"&gt;Action&lt;/span&gt; usando los propios de archivos de validación del objeto. Esto permite usar &lt;span class="codigo"&gt;ModelDriven&lt;/span&gt; y administrar las validaciones de los objetos de modelo en un solo lugar. &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span class="codigo"&gt;conversion&lt;/span&gt;&lt;/td&gt;&lt;td&gt;Verifica si ocurre un error de conversión en el campo.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span class="codigo"&gt;expression&lt;/span&gt;&lt;/td&gt;&lt;td&gt;Realiza una validación basada en una expresión regular en &lt;span class="codigo"&gt;OGNL&lt;/span&gt;.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span class="codigo"&gt;fieldexpression&lt;/span&gt;&lt;/td&gt;&lt;td&gt;Valida un campo usando una expresión &lt;span class="codigo"&gt;OGNL&lt;/span&gt;.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span class="codigo"&gt;regex&lt;/span&gt;&lt;/td&gt;&lt;td&gt;Valida un campo usando una expresión regular.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt; &lt;/table&gt;&lt;br /&gt;&lt;br /&gt;Sabiendo qué validadores podemos aplicar a los campos del formulario, pasemos a crear nuestro archivo de validación.&lt;br /&gt;&lt;br /&gt;Creamos en el paquete "&lt;span class="codigo"&gt;actions&lt;/span&gt;" un nuevo archivo &lt;span class="codigo"&gt;XML&lt;/span&gt; llamado "&lt;span class="codigo"&gt;ValidacionDatos-validation.xml&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-0xSzG5P6zDQ/TqMl_3aBQEI/AAAAAAAABI8/l1fG1JNhiAA/s1600/S3_24.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://2.bp.blogspot.com/-0xSzG5P6zDQ/TqMl_3aBQEI/AAAAAAAABI8/l1fG1JNhiAA/s320/S3_24.png" width="309" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Todas las validaciones deben estar contenidas dentro del elemento "&lt;span class="codigo"&gt;&amp;lt;validators&amp;gt;&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&amp;lt;!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN" "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd"&amp;gt;&lt;br /&gt;&amp;lt;validators&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/validators&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Lo siguiente es indicar cada campo que será validado usando el elemento "&lt;span class="codigo"&gt;&amp;lt;field&amp;gt;&lt;/span&gt;", e indicamos el nombre del campo que queremos validar en su atributo "&lt;span class="codigo"&gt;name&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;field name="nombre"&amp;gt;&lt;br /&gt;&amp;lt;/field&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Posteriormente indicamos cada una de las validaciones que se aplicarán a ese campo, usando el elemento "&lt;span class="codigo"&gt;&amp;lt;field-validator&amp;gt;&lt;/span&gt;" y su atributo "&lt;span class="codigo"&gt;type&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;field name="nombre"&amp;gt;&lt;br /&gt;    &amp;lt;field-validator type="requiredstring"&amp;gt;&lt;br /&gt;            &lt;br /&gt;    &amp;lt;/field-validator&amp;gt;&lt;br /&gt;&amp;lt;/field&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Para agregar un parámetro a la validación usamos el elemento "&lt;span class="codigo"&gt;&amp;lt;param&amp;gt;&lt;/span&gt;" y colocamos el nombre del parámetro en su atributo "&lt;span class="codigo"&gt;name&lt;/span&gt;". En este caso usaremos el parámetro "&lt;span class="codigo"&gt;trim&lt;/span&gt;" del validador "&lt;span class="codigo"&gt;requiredstring&lt;/span&gt;" para indicar que deseamos que se eliminen los espacios en blanco del inicio y fin de la cadena (en caso de existir) antes de que la validación sea aplicada:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;field-validator type="requiredstring"&amp;gt;&lt;br /&gt;    &amp;lt;param name="trim"&amp;gt;true&amp;lt;/param&amp;gt;&lt;br /&gt;&amp;lt;/field-validator&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Para terminar, debemos agregar un mensaje que será mostrado en caso de que la validación no sea exitosa. Para esto usamos el elemento "&lt;span class="codigo"&gt;&amp;lt;message&amp;gt;&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;field-validator type="requiredstring"&amp;gt;&lt;br /&gt;    &amp;lt;param name="trim"&amp;gt;true&amp;lt;/param&amp;gt;&lt;br /&gt;    &amp;lt;message&amp;gt;El nombre del usuario es un campo obligatorio.&amp;lt;/message&amp;gt;&lt;br /&gt;&amp;lt;/field-validator&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Y esto es todo, con esto el campo "&lt;span class="codigo"&gt;nombre&lt;/span&gt;" del formulario ha quedado validado.&lt;br /&gt;&lt;br /&gt;Si necesitáramos agregar más validaciones a este campo, solo bastaría con agregar un segundo elemento "&lt;span class="codigo"&gt;&amp;lt;field-validator&amp;gt;&lt;/span&gt;". Agregamos un validador de tipo "&lt;span class="codigo"&gt;stringlength&lt;/span&gt;" para asegurarnos que el nombre que introduzca el usuario tenga una longitud mínima de &lt;span class="codigo"&gt;4&lt;/span&gt; caracteres, y una longitud máxima de &lt;span class="codigo"&gt;12&lt;/span&gt;. El proceso es básicamente el mismo por lo que no lo explicaré, pero al final la validación queda de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;field-validator type="stringlength"&amp;gt;&lt;br /&gt;    &amp;lt;param name="trim"&amp;gt;true&amp;lt;/param&amp;gt;&lt;br /&gt;    &amp;lt;param name="minLength"&amp;gt;4&amp;lt;/param&amp;gt;&lt;br /&gt;    &amp;lt;param name="maxLength"&amp;gt;12&amp;lt;/param&amp;gt;&lt;br /&gt;    &amp;lt;message&amp;gt;El nombre del usuario debe tener entre 4 y 12 caracteres&amp;lt;/message&amp;gt;&lt;br /&gt;&amp;lt;/field-validator&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Hasta ahora nuestro archivo de validaciones se ve de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&amp;lt;!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN" "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd"&amp;gt;&lt;br /&gt;&amp;lt;validators&amp;gt;&lt;br /&gt;    &amp;lt;field name="nombre"&amp;gt;&lt;br /&gt;        &amp;lt;field-validator type="requiredstring"&amp;gt;&lt;br /&gt;            &amp;lt;param name="trim"&amp;gt;true&amp;lt;/param&amp;gt;&lt;br /&gt;            &amp;lt;message&amp;gt;El nombre del usuario es un campo obligatorio.&amp;lt;/message&amp;gt;&lt;br /&gt;        &amp;lt;/field-validator&amp;gt;&lt;br /&gt;        &lt;br /&gt;        &amp;lt;field-validator type="stringlength"&amp;gt;&lt;br /&gt;            &amp;lt;param name="trim"&amp;gt;true&amp;lt;/param&amp;gt;&lt;br /&gt;            &amp;lt;param name="minLength"&amp;gt;4&amp;lt;/param&amp;gt;&lt;br /&gt;            &amp;lt;param name="maxLength"&amp;gt;12&amp;lt;/param&amp;gt;&lt;br /&gt;            &amp;lt;message&amp;gt;El nombre del usuario debe tener entre 4 y 12 caracteres&amp;lt;/message&amp;gt;&lt;br /&gt;        &amp;lt;/field-validator&amp;gt;&lt;br /&gt;    &amp;lt;/field&amp;gt;&lt;br /&gt;&amp;lt;/validators&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;El proceso es básicamente el mismo para todos los campos del formulario que vamos a validar. No explicaré cada una de las validaciones de los campos porque creo que la idea se entiende bastante en este momento, pero el archivo final de validaciones queda de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&amp;lt;!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN" "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd"&amp;gt;&lt;br /&gt;&amp;lt;validators&amp;gt;&lt;br /&gt;    &amp;lt;field name="nombre"&amp;gt;&lt;br /&gt;        &amp;lt;field-validator type="requiredstring"&amp;gt;&lt;br /&gt;            &amp;lt;param name="trim"&amp;gt;true&amp;lt;/param&amp;gt;&lt;br /&gt;            &amp;lt;message&amp;gt;El nombre del usuario es un campo obligatorio.&amp;lt;/message&amp;gt;&lt;br /&gt;        &amp;lt;/field-validator&amp;gt;&lt;br /&gt;        &lt;br /&gt;        &amp;lt;field-validator type="stringlength"&amp;gt;&lt;br /&gt;            &amp;lt;param name="trim"&amp;gt;true&amp;lt;/param&amp;gt;&lt;br /&gt;            &amp;lt;param name="minLength"&amp;gt;4&amp;lt;/param&amp;gt;&lt;br /&gt;            &amp;lt;param name="maxLength"&amp;gt;12&amp;lt;/param&amp;gt;&lt;br /&gt;            &amp;lt;message&amp;gt;El nombre del usuario debe tener entre 4 y 12 caracteres&amp;lt;/message&amp;gt;&lt;br /&gt;        &amp;lt;/field-validator&amp;gt;&lt;br /&gt;    &amp;lt;/field&amp;gt;&lt;br /&gt;    &lt;br /&gt;    &amp;lt;field name="username"&amp;gt;&lt;br /&gt;        &amp;lt;field-validator type="requiredstring"&amp;gt;&lt;br /&gt;            &amp;lt;param name="trim"&amp;gt;true&amp;lt;/param&amp;gt;&lt;br /&gt;            &amp;lt;message&amp;gt;El username es un campo obligatorio.&amp;lt;/message&amp;gt;&lt;br /&gt;        &amp;lt;/field-validator&amp;gt;&lt;br /&gt;        &lt;br /&gt;        &amp;lt;field-validator type="stringlength"&amp;gt;&lt;br /&gt;            &amp;lt;param name="trim"&amp;gt;true&amp;lt;/param&amp;gt;&lt;br /&gt;            &amp;lt;param name="minLength"&amp;gt;6&amp;lt;/param&amp;gt;&lt;br /&gt;            &amp;lt;message&amp;gt;El username debe tener al menos 6 caracteres&amp;lt;/message&amp;gt;&lt;br /&gt;        &amp;lt;/field-validator&amp;gt;&lt;br /&gt;    &amp;lt;/field&amp;gt;&lt;br /&gt;    &lt;br /&gt;    &amp;lt;field name="password"&amp;gt;&lt;br /&gt;        &amp;lt;field-validator type="requiredstring"&amp;gt;&lt;br /&gt;            &amp;lt;param name="trim"&amp;gt;true&amp;lt;/param&amp;gt;&lt;br /&gt;            &amp;lt;message&amp;gt;La contraseña es un campo obligatorio.&amp;lt;/message&amp;gt;&lt;br /&gt;        &amp;lt;/field-validator&amp;gt;&lt;br /&gt;        &lt;br /&gt;        &amp;lt;field-validator type="stringlength"&amp;gt;&lt;br /&gt;            &amp;lt;param name="trim"&amp;gt;true&amp;lt;/param&amp;gt;&lt;br /&gt;            &amp;lt;param name="minLength"&amp;gt;6&amp;lt;/param&amp;gt;&lt;br /&gt;            &amp;lt;param name="maxLength"&amp;gt;8&amp;lt;/param&amp;gt;&lt;br /&gt;            &amp;lt;message&amp;gt;La contraseña debe tener entre 6  y 8 caracteres&amp;lt;/message&amp;gt;&lt;br /&gt;        &amp;lt;/field-validator&amp;gt;&lt;br /&gt;        &lt;br /&gt;        &amp;lt;field-validator type="regex"&amp;gt;&lt;br /&gt;            &amp;lt;param name="expression"&amp;gt;^\w*(?=\w*\d)(?=\w*[a-z])(?=\w*[A-Z])\w*$&amp;lt;/param&amp;gt;&lt;br /&gt;            &amp;lt;message&amp;gt;La contraseña debe ser alfanumérica, debe tener al menos una letra mayúscula, una letra minúscula, y al menos un número.&amp;lt;/message&amp;gt;&lt;br /&gt;        &amp;lt;/field-validator&amp;gt;&lt;br /&gt;    &amp;lt;/field&amp;gt;&lt;br /&gt;    &lt;br /&gt;    &amp;lt;field name="email"&amp;gt;&lt;br /&gt;        &amp;lt;field-validator type="requiredstring"&amp;gt;&lt;br /&gt;            &amp;lt;param name="trim"&amp;gt;true&amp;lt;/param&amp;gt;&lt;br /&gt;            &amp;lt;message&amp;gt;El correo electrónico es un campo obligatorio.&amp;lt;/message&amp;gt;&lt;br /&gt;        &amp;lt;/field-validator&amp;gt;&lt;br /&gt;        &lt;br /&gt;        &amp;lt;field-validator type="email"&amp;gt;&lt;br /&gt;            &amp;lt;message&amp;gt;El correo electrónico está en un formato inválido.&amp;lt;/message&amp;gt;&lt;br /&gt;        &amp;lt;/field-validator&amp;gt;&lt;br /&gt;    &amp;lt;/field&amp;gt;&lt;br /&gt;    &lt;br /&gt;    &amp;lt;field name="edad"&amp;gt;&lt;br /&gt;        &amp;lt;field-validator type="required"&amp;gt;&lt;br /&gt;            &amp;lt;message&amp;gt;La edad es un campo obligatorio.&amp;lt;/message&amp;gt;&lt;br /&gt;        &amp;lt;/field-validator&amp;gt;&lt;br /&gt;&lt;br /&gt;        &amp;lt;field-validator type="conversion"&amp;gt;&lt;br /&gt;            &amp;lt;message&amp;gt;La edad debe contener solo números enteros.&amp;lt;/message&amp;gt;&lt;br /&gt;        &amp;lt;/field-validator&amp;gt;&lt;br /&gt;        &lt;br /&gt;        &amp;lt;field-validator type="int"&amp;gt;&lt;br /&gt;            &amp;lt;param name="min"&amp;gt;0&amp;lt;/param&amp;gt;&lt;br /&gt;            &amp;lt;param name="max"&amp;gt;200&amp;lt;/param&amp;gt;&lt;br /&gt;            &amp;lt;message&amp;gt;La edad proporcionada no está dentro del rango permitido.&amp;lt;/message&amp;gt;&lt;br /&gt;        &amp;lt;/field-validator&amp;gt;&lt;br /&gt;    &amp;lt;/field&amp;gt;&lt;br /&gt;    &lt;br /&gt;&amp;lt;/validators&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ahora que todo está listo podemos ejecutar nuestra aplicación y entrar a la siguiente dirección:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&lt;a href="http://localhost:8080/formularios/validaciones/formulario.jsp"&gt;http://localhost:8080/formularios/validaciones/formulario.jsp&lt;/a&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Nuevamente veremos nuestro formulario anterior. Si no colocamos ningún valor en ningún campo y simplemente presionamos el botón "&lt;span class="codigo"&gt;Enviar&lt;/span&gt;" veremos la siguiente lista de errores:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-GPLyZ29I_nk/TqMmATlIRNI/AAAAAAAABJE/7D5dXAkT4wg/s1600/S3_25.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="288" src="http://2.bp.blogspot.com/-GPLyZ29I_nk/TqMmATlIRNI/AAAAAAAABJE/7D5dXAkT4wg/s400/S3_25.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Podemos ver que estamos obteniendo los errores que definimos en el archivo de validaciones, con los mensajes correspondientes. Si observamos el código fuente de la pagina generada veremos que cada uno de los errores marcados está colocado en un elemento que tiene como clase CSS "&lt;span class="codigo"&gt;errorMessage&lt;/span&gt;", por lo que podemos personalizar la forma en la que se muestran los errores de validación de la aplicación a través de una hoja de estilos.&lt;br /&gt;&lt;br /&gt;Si ahora colocamos algunos valores incorrectos en los campos del formulario:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-4vxn8InYDYo/TqMmAksGirI/AAAAAAAABJM/XAPiTWTOXqM/s1600/S3_26.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="158" src="http://3.bp.blogspot.com/-4vxn8InYDYo/TqMmAksGirI/AAAAAAAABJM/XAPiTWTOXqM/s400/S3_26.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Obtendremos una lista distinta de errores:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-0d_mxOL_apg/TqMmBJWtbGI/AAAAAAAABJU/MoZF3JJ3CUk/s1600/S3_27.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="251" src="http://1.bp.blogspot.com/-0d_mxOL_apg/TqMmBJWtbGI/AAAAAAAABJU/MoZF3JJ3CUk/s400/S3_27.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Si ahora colocamos datos correctos:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-GvrX4aC4Ipw/TqMmBgJZXnI/AAAAAAAABJc/stcGV5Cplk0/s1600/S3_28.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="157" src="http://3.bp.blogspot.com/-GvrX4aC4Ipw/TqMmBgJZXnI/AAAAAAAABJc/stcGV5Cplk0/s400/S3_28.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Veremos la página correspondiente:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-vQD30ADPO30/TqMmCBvK6GI/AAAAAAAABJk/6Ql8dlXRV1A/s1600/S3_29.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="157" src="http://4.bp.blogspot.com/-vQD30ADPO30/TqMmCBvK6GI/AAAAAAAABJk/6Ql8dlXRV1A/s400/S3_29.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Por lo que los datos han sido validados correctamente.&lt;br /&gt;&lt;br /&gt;A pesar de que la mayoría de las veces realizaremos validaciones como las anteriores, o sea validaciones sobre los campos de un formulario, algunas veces será necesario realizar validaciones que no son sobre los campos (llamadas &lt;span class="negritas"&gt;validaciones planes&lt;/span&gt;).&lt;br /&gt;&lt;br /&gt;Las validaciones planas son un tipo especial de validación que no está atada a un campo específico, como la validación de expresiones. Por ejemplo, agreguemos una validación extra que verifique que el "&lt;span class="codigo"&gt;nombre&lt;/span&gt;" y el "&lt;span class="codigo"&gt;username&lt;/span&gt;" no sean iguales. &lt;br /&gt;&lt;br /&gt;Para agregar una validación plana en vez de usar el elemento "&lt;span class="codigo"&gt;&amp;lt;field&amp;gt;&lt;/span&gt;" usamos el elemento "&lt;span class="codigo"&gt;&amp;lt;validator&amp;gt;&lt;/span&gt;", que es muy similar a "&lt;span class="codigo"&gt;&amp;lt;field-validator&amp;gt;&lt;/span&gt;", indicamos usando su atributo "&lt;span class="codigo"&gt;type&lt;/span&gt;" el tipo de validación que se realizará; si la validación necesita algún parámetro lo agregamos con el elemento "&lt;span class="codigo"&gt;&amp;lt;param&amp;gt;&lt;/span&gt;"; el mensaje que se mostrará en caso de que la validación no pase lo colocamos con el elemento "&lt;span class="codigo"&gt;&amp;lt;message&amp;gt;&lt;/span&gt;".&lt;br /&gt;&lt;br /&gt;La validación para verificar que el nombre del &lt;span class="codigo"&gt;usuario&lt;/span&gt; y el &lt;span class="codigo"&gt;username&lt;/span&gt; no sean iguales queda de la siguiente forma (pueden colocarla después de todas las validaciones "&lt;span class="codigo"&gt;field&lt;/span&gt;"):&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;validator type="expression"&amp;gt;&lt;br /&gt;    &amp;lt;param name="expression"&amp;gt;!nombre.equals(username)&amp;lt;/param&amp;gt;&lt;br /&gt;    &amp;lt;message&amp;gt;El nombre de usuario y el username no deben ser iguales.&amp;lt;/message&amp;gt;&lt;br /&gt;&amp;lt;/validator&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Como estas validaciones no son realizadas sobre ningún campo, sus mensajes de error no se mostrarán usando la etiqueta "&lt;span class="codigo"&gt;&amp;lt;s:fielderror /&amp;gt;&lt;/span&gt;", si queremos verlos en la &lt;span class="codigo"&gt;JSP&lt;/span&gt; debemos usar la etiqueta "&lt;span class="codigo"&gt;&amp;lt;s:actionerror /&amp;gt;&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:fielderror /&amp;gt;&lt;br /&gt;&amp;lt;s:actionerror /&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ahora, si volvemos a ejecutar la aplicación e introducimos el mismo nombre de usuario y contraseña:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-BBakRWnqmqk/TqMmCm-nIeI/AAAAAAAABJs/zDQobaL-aU4/s1600/S3_30.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="157" src="http://4.bp.blogspot.com/-BBakRWnqmqk/TqMmCm-nIeI/AAAAAAAABJs/zDQobaL-aU4/s400/S3_30.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Y presionamos el botón enviar obtendremos el siguiente resultado:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-oEFrPAhxrEY/TqMmDGYbOGI/AAAAAAAABJ0/AVMc5MkktwM/s1600/S3_31.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="157" src="http://4.bp.blogspot.com/-oEFrPAhxrEY/TqMmDGYbOGI/AAAAAAAABJ0/AVMc5MkktwM/s400/S3_31.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Con lo que podemos comprobar que estas validaciones también funcionan correctamente.&lt;br /&gt;&lt;br /&gt;Ahora que vimos cómo realizar validaciones usando archivos &lt;span class="codigo"&gt;XML&lt;/span&gt; veamos cómo realizar esto mismo usando anotaciones.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3 class="subtitulo"&gt;5.2 Validaciones usando anotaciones&lt;/h3&gt;Realizar validaciones de los datos de un formulario usando anotaciones es un proceso muy simple. Modificaremos un poco la clase "&lt;span class="codigo"&gt;ValidacionDatos&lt;/span&gt;" que creamos hace un momento (de hecho yo crearé una clase aparte para no modificar el código que ya teníamos).&lt;br /&gt;&lt;br /&gt;Las anotaciones que podemos usar para realizar las validaciones se encuentran en el paquete "&lt;span class="codigo"&gt;com.opensymphony.xwork2.validator.annotations&lt;/span&gt;", y tenemos las siguientes validaciones disponibles:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="codigo"&gt;@ConversionErrorFieldValidator&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="codigo"&gt;@DateRangeFieldValidator&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="codigo"&gt;@DoubleRangeFieldValidator&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="codigo"&gt;@EmailValidator&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="codigo"&gt;@ExpressionValidator&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="codigo"&gt;@FieldExpressionValidator&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="codigo"&gt;@IntRangeFieldValidator&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="codigo"&gt;@RegexFieldValidator&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="codigo"&gt;@RequiredFieldValidator&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="codigo"&gt;@RequiredStringValidator&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="codigo"&gt;@StringLengthFieldValidator&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="codigo"&gt;@UrlValidator&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="codigo"&gt;@VisitorFieldValidator&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Como podemos ver, existe una anotación por cada una de las validaciones que se tienen cuando trabajamos con los archivos &lt;span class="codigo"&gt;XML&lt;/span&gt;; la explicación para cada una de las validaciones también es la misma que para el caso anterior.&lt;br /&gt;&lt;br /&gt;Esta anotación puede ser colocada tanto en el &lt;span class="codigo"&gt;setter&lt;/span&gt; como en el &lt;span class="codigo"&gt;getter&lt;/span&gt; de la propiedad que queremos validar. También podemos usar varias validaciones para una misma propiedad.&lt;br /&gt;&lt;br /&gt;Veamos un primer ejemplo validando el campo "&lt;span class="codigo"&gt;nombre&lt;/span&gt;". En la clase "&lt;span class="codigo"&gt;ValidacionDatos&lt;/span&gt;" primero verificaremos que el nombre del usuario no esté vacio cuando se reciba del fomulario, para esto usaremos la anotación "&lt;span class="codigo"&gt;@RequiredStringValidator&lt;/span&gt;", yo la pondré en el &lt;span class="codigo"&gt;setter&lt;/span&gt; de la propiedad:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@RequiredStringValidator    &lt;br /&gt;public void setNombre(String nombre)&lt;br /&gt;{&lt;br /&gt;    this.nombre = nombre;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Todas las anotaciones de validaciones proporcionan una serie de atributos que nos permiten configurar el comportamiento de la validación. Casi en todos los casos lo único que tendremos que configurar es el mensaje que se mostrará en caso de que la validación no sea correcta. Para eso usamos el atributo "&lt;span class="codigo"&gt;message&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@RequiredStringValidator(message = "El nombre de usuario es un campo obligatorio.")&lt;br /&gt;public void setNombre(String nombre)&lt;br /&gt;{&lt;br /&gt;    this.nombre = nombre;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;También validaremos que el nombre tenga una cierta longitud, o sea que sea mayor a cierto número de caracteres y menor a otro cierto número. Para eso usamos la anotación la anotación "&lt;span class="codigo"&gt;@StringLengthFieldValidator&lt;/span&gt;" que colocamos justo debajo de la anotación anterior:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@RequiredStringValidator(message = "El nombre de usuario es un campo obligatorio.")&lt;br /&gt;@StringLengthFieldValidator(minLength="4", maxLength="12", message="El nombre del usuario debe tener entre 4 y 12 caracteres")&lt;br /&gt;public void setNombre(String nombre)&lt;br /&gt;{&lt;br /&gt;    this.nombre = nombre;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Haremos lo mismo para cada uno de los campos que necesitemos validar. Nuevamente, no explicaré cada una de las anotaciones ya que son bastante intuitivas, pero al final quedan de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@RequiredFieldValidator(message="La edad es un campo obligatorio.")&lt;br /&gt;@ConversionErrorFieldValidator(message="La edad debe contener solo números enteros.")&lt;br /&gt;@IntRangeFieldValidator(min="0", max="200", message="La edad proporcionada no está dentro del rango permitido.")&lt;br /&gt;public void setEdad(int edad)&lt;br /&gt;{&lt;br /&gt;    this.edad = edad;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@RequiredStringValidator(message="El correo electrónico es un campo obligatorio.")&lt;br /&gt;@EmailValidator(message="El correo electrónico está en un formato inválido.")&lt;br /&gt;public void setEmail(String email)&lt;br /&gt;{&lt;br /&gt;    this.email = email;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@RequiredStringValidator(message = "El nombre de usuario es un campo obligatorio.")&lt;br /&gt;@StringLengthFieldValidator(minLength = "4", maxLength = "12", message = "El nombre del usuario debe tener entre 4 y 12 caracteres")&lt;br /&gt;public void setNombre(String nombre)&lt;br /&gt;{&lt;br /&gt;    this.nombre = nombre;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@RequiredStringValidator(message="La contraseña es un campo obligatorio.")&lt;br /&gt;@StringLengthFieldValidator(minLength="6", maxLength="8", message="La contraseña debe tener entre 6  y 8 caracteres")&lt;br /&gt;@RegexFieldValidator(expression="^\\w*(?=\\w*\\d)(?=\\w*[a-z])(?=\\w*[A-Z])\\w*$", message="La contraseña debe ser alfanumérica, debe tener al menos una letra mayúscula, una letra minúscula, y al menos un número.")&lt;br /&gt;public void setPassword(String password)&lt;br /&gt;{&lt;br /&gt;    this.password = password;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setTelefono(String telefono)&lt;br /&gt;{&lt;br /&gt;    this.telefono = telefono;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@RequiredStringValidator(message="El username es un campo obligatorio.")&lt;br /&gt;@StringLengthFieldValidator(minLength="6", message="El username debe tener al menos 6 caracteres")&lt;br /&gt;public void setUsername(String username)&lt;br /&gt;{&lt;br /&gt;    this.username = username;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Probemos nuevamente que todo funcione correctamente. Al ejecutar la aplicación y entrar en nuestro formulario, en la siguiente dirección:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&lt;a href="http://localhost:8080/formularios/validaciones/formulario.jsp"&gt;http://localhost:8080/formularios/validaciones/formulario.jsp&lt;/a&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;(Bueno, de hecho mi dirección es un poco distinto porque cree el contenido en una página alterna ^^) Debemos ver el formulario que ya teníamos anteriormente:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-QhtstNSPO2s/TqMmDqgX2yI/AAAAAAAABJ8/zYZG64zHsIs/s1600/S3_32.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="130" src="http://4.bp.blogspot.com/-QhtstNSPO2s/TqMmDqgX2yI/AAAAAAAABJ8/zYZG64zHsIs/s400/S3_32.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Al hacer clic en el botón "&lt;span class="codigo"&gt;Enviar&lt;/span&gt;", con los campos vacios, obtendremos la siguiente salida:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-Pa56aKkp1bw/TqMmEK8DrgI/AAAAAAAABKE/hF3vwhyFLH8/s1600/S3_33.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="231" src="http://3.bp.blogspot.com/-Pa56aKkp1bw/TqMmEK8DrgI/AAAAAAAABKE/hF3vwhyFLH8/s400/S3_33.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Podemos ver que, hasta el momento, las validaciones han funcionado correctamente. Si colocamos algunos datos de forma equivocada:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-6p2Df_HMYEs/TqMmEm1eZlI/AAAAAAAABKM/64yRYmjRtVI/s1600/S3_34.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="138" src="http://3.bp.blogspot.com/-6p2Df_HMYEs/TqMmEm1eZlI/AAAAAAAABKM/64yRYmjRtVI/s400/S3_34.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Obtendremos la siguiente salida:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-rsB_c2OJWa0/TqMmFO5dToI/AAAAAAAABKU/Ivi_VVE2DKk/s1600/S3_35.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="191" src="http://3.bp.blogspot.com/-rsB_c2OJWa0/TqMmFO5dToI/AAAAAAAABKU/Ivi_VVE2DKk/s400/S3_35.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Si ahora, colocamos los datos de forma correcta:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-vIyHMA8I7nw/TqMmF3YxyUI/AAAAAAAABKc/KWwTiYQnoA8/s1600/S3_36.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="191" src="http://1.bp.blogspot.com/-vIyHMA8I7nw/TqMmF3YxyUI/AAAAAAAABKc/KWwTiYQnoA8/s400/S3_36.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Obtendremos la salida que estamos esperando:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-J64_mMSNFfA/TqMmGfLxoCI/AAAAAAAABKk/8sbCzaHxhMc/s1600/S3_37.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="191" src="http://2.bp.blogspot.com/-J64_mMSNFfA/TqMmGfLxoCI/AAAAAAAABKk/8sbCzaHxhMc/s400/S3_37.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Como podrán imaginar, todas las validaciones anteriores son validaciones de campos. Usando anotaciones también podemos realizar validaciones planas (las validaciones que no están relacionadas con algún campo del formulario). Solo que en este caso las validaciones planas se colocan directamente en el método "&lt;span class="codigo"&gt;execute&lt;/span&gt;" del &lt;span class="codigo"&gt;Action&lt;/span&gt;, usando una anotación especial: "&lt;span class="codigo"&gt;@Validations&lt;/span&gt;". En los atributos de esta anotación podemos indicar cada una de las validaciones que se necesiten en la aplicación (campos requeridos, emails, urls, longitud de las cadenas, rango de enteros, fechas, etc.). En nuestro caso lo que nos interesa es realizar una validación sobre una expresión. Para esto usamos el atributo "&lt;span class="codigo"&gt;expressions&lt;/span&gt;" de la anotación "&lt;span class="codigo"&gt;@Validations&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Override&lt;br /&gt;@Validations(expressions={})&lt;br /&gt;public String execute() throws Exception&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;En este atributo colocamos, usando la anotación "&lt;span class="codigo"&gt;@ExpressionValidator&lt;/span&gt;", la expresión que será validada, en este caso queremos asegurarnos de que el nombre del usuario y su username no son iguales, por lo que la validación queda de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@ExpressionValidator(expression="!nombre.equals(username)", message="El nombre de usuario y el username no deben ser iguales.")&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;La anotación completa queda de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Override&lt;br /&gt;@Validations(expressions =&lt;br /&gt;{&lt;br /&gt;    @ExpressionValidator(expression = "!nombre.equals(username)", message = "El nombre de usuario y el username no deben ser iguales.")&lt;br /&gt;})&lt;br /&gt;public String execute() throws Exception&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Cuando ejecutemos nuevamente la aplicación, poniendo el mismo nombre de usuario y contraseña:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-k7SvdLiG5mg/TqMmGq1N6UI/AAAAAAAABKs/Dknq8N42RfI/s1600/S3_38.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="191" src="http://2.bp.blogspot.com/-k7SvdLiG5mg/TqMmGq1N6UI/AAAAAAAABKs/Dknq8N42RfI/s400/S3_38.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Obtendremos el mensaje correspondiente de error:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-JbQkZN8yzBE/TqMmHSu72EI/AAAAAAAABK0/HN6x85LY8Xk/s1600/S3_39.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="191" src="http://3.bp.blogspot.com/-JbQkZN8yzBE/TqMmHSu72EI/AAAAAAAABK0/HN6x85LY8Xk/s400/S3_39.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Cuando coloquemos los datos correctos deberíamos dejar de ver mensajes de error.&lt;br /&gt;&lt;br /&gt;Los dos tipos de validaciones que hemos visto nos permiten verificar que los datos que proporcionemos sean correctos, siempre y cuando conozcamos de antemano los valores, los rangos, o las reglas que los campos del formulario pueden tener pero ¿qué pasa si no conocemos estos valores? por ejemplo, en el caso de que debamos comparar un valor contra un registro de la base de datos o contra algún web service o alguna cosa más sofisticada, las validaciones anteriores nos servirán de poco.&lt;br /&gt;&lt;br /&gt;Afortunadamente, para esos casos, &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; nos permite realizar un tercer tipo de validación: las validaciones manuales.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3 class="subtitulo"&gt;5.3 Validaciones Manuales&lt;/h3&gt;Ya sé qué es lo que deben estar pensando: que las validaciones manuales son las que estamos acostumbrados a realizar, que no es un mecanismo automático que nos ayude a simplificar nuestro trabajo de validación de datos. Si es así, no están tan equivocados ^_^; bueno, más o menos.&lt;br /&gt;&lt;br /&gt;Las validaciones manuales son aquellas que son tan particulares a nuestro proceso de negocio que estas no se pueden tomar de alguna plantilla, como los ejemplos que mencioné anteriormente.&lt;br /&gt;&lt;br /&gt;Este tipo de validación, aunque las tenemos que realizar nosotros mismos, sigue siendo administrado por el framework. Para ello nos proporciona una interface llamada "&lt;span class="codigo"&gt;Validateable&lt;/span&gt;", que proporciona únicamente un método:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public void validate();&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Afortunadamente para nosotros, la clase "&lt;span class="codigo"&gt;ActionSupport&lt;/span&gt;" implementa esta interface, por lo que lo unico que tenemos que hacer es sobre-escribirlo en nuestros &lt;span class="codigo"&gt;Action&lt;/span&gt;s y, ayudados de algunos métodos auxiliares de la clase "&lt;span class="codigo"&gt;ActionSupport&lt;/span&gt;", enviar los errores correspondientes en caso de que estos existan.&lt;br /&gt;&lt;br /&gt;Para poder indicar si existe algún error en las validaciones nos ayudamos del método "&lt;span class="codigo"&gt;addFieldError&lt;/span&gt;", en caso de que exista un error de la validación de un campo, y de "&lt;span class="codigo"&gt;addActionError&lt;/span&gt;", en caso de existir un error que no esté relacionado con un campo.&lt;br /&gt;&lt;br /&gt;"&lt;span class="codigo"&gt;addFieldError&lt;/span&gt;" recibe dos parámetros, el primero es el nombre del campo que generó el error y el segundo es la descripción del error. "&lt;span class="codigo"&gt;addActionError&lt;/span&gt;" recibe un solo parámetro que es la descripción del error.&lt;br /&gt;&lt;br /&gt;Como se podrán imaginar, si existe algún error en un campo este se mostrará en el campo correspondiente del formulario y en la etiqueta "&lt;span class="codigo"&gt;&amp;lt;s:fielderror /&amp;gt;&lt;/span&gt;". Si existe un error de otro tipo este se mostrará en la etiqueta "&lt;span class="codigo"&gt;&amp;lt;s:actionerror /&amp;gt;&lt;/span&gt;".&lt;br /&gt;&lt;br /&gt;Ahora que conocemos la teoría sobre las validaciones manuales pasemos verlas en la práctica. Para esto modificaremos las validaciones que ya tenemos en nuestra clase.&lt;br /&gt;&lt;br /&gt;Lo primero que debemos hacer es sobre-escribir el método "&lt;span class="codigo"&gt;validate&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Override&lt;br /&gt;public void validate()&lt;br /&gt;{        &lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Las validaciones que realizaremos serán muy simples: si el username es "&lt;span class="codigo"&gt;programadorjava&lt;/span&gt;" (supongamos que este fue un nombre que se trajo de la base de datos, para comprobar que no haya nombres repetidos) o el correo es "&lt;span class="codigo"&gt;&lt;a href="mailto:programadorjavablog@gmail.com"&gt;programadorjavablog@gmail.com&lt;/a&gt;&lt;/span&gt;" entonces no se le permitirá al usuario completar el registro:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Override&lt;br /&gt;public void validate()&lt;br /&gt;{&lt;br /&gt;    if("programadorjava".equals(username))&lt;br /&gt;    {&lt;br /&gt;        addFieldError("username", "El username seleccionado ya se encuentra ocupado, por favor seleccione otro.");&lt;br /&gt;    }&lt;br /&gt;    if("programadorjavablog@gmail.com".equals(email))&lt;br /&gt;    {&lt;br /&gt;        addFieldError("email", "El correo electrónico proporcionado ya ha sido registrado anteriormente.");&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;El framework detectará de forma automática si hemos agregado algo a los campos de error, si es así regresará esta lista de errores a nuestro resultado "&lt;span class="codigo"&gt;input&lt;/span&gt;", de lo contrario continuará con la ejecución del método "&lt;span class="codigo"&gt;execute&lt;/span&gt;".&lt;br /&gt;&lt;br /&gt;Si ejecutamos la aplicación y entramos a nuestro formulario, proporcionando alguno de los datos reservados y que son validados dentro del método "&lt;span class="codigo"&gt;validate&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-zrvWokLR90M/TqMmH2oPBeI/AAAAAAAABK8/HMySl8PDLXg/s1600/S3_40.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="202" src="http://1.bp.blogspot.com/-zrvWokLR90M/TqMmH2oPBeI/AAAAAAAABK8/HMySl8PDLXg/s400/S3_40.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Veremos los mensajes de error que hemos establecido:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-cHpIzantLTs/TqMmIk9GCaI/AAAAAAAABLE/gvZ6UfDtPtE/s1600/S3_41.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="202" src="http://2.bp.blogspot.com/-cHpIzantLTs/TqMmIk9GCaI/AAAAAAAABLE/gvZ6UfDtPtE/s400/S3_41.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Podemos comprobar nuevamente que las validaciones han funcionado correctamente ^_^.&lt;br /&gt;&lt;br /&gt;Como vemos, realizar validaciones usando &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; es muy sencillo y puede ahorrarnos bastante tiempo que podemos dedicar a mejorar otros aspectos de nuestra aplicación.&lt;br /&gt;&lt;br /&gt;Ahora veremos cómo realizar otro de los trabajos que normalmente hacemos al hacer uso de formularios, la carga de archivos desde el cliente al servidor:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="titulo" name="uploadArchivos"&gt;6. Carga de archivos&lt;/h2&gt;Hacer carga o upload de archivos desde un cliente hacia nuestro servidor, ya sea para almacenarlos o para procesarlos, es una operación que no siempre es sencilla de realizar. Sin embargo &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; cuenta con una manera que hace que lograr esto sea tan sencillo como el resto de las cosas que hasta ahora hemos aprendido.&lt;br /&gt;&lt;br /&gt;&lt;span class="codigo"&gt;Struts 2&lt;/span&gt; proporciona el soporte para la carga de archivos conforme a la especificación de &lt;span class="codigo"&gt;HTML&lt;/span&gt;, esto nos permite subir uno o varios archivos desde el cliente al servidor.&lt;br /&gt;&lt;br /&gt;Cuando un archivo es cargado, este será almacenado en un directorio temporal por el interceptor correspondiente (&lt;span class="codigo"&gt;fileUpload&lt;/span&gt;). El archivo deberá entonces ser procesado o movido a otra ubicación, por nuestro &lt;span class="codigo"&gt;Action&lt;/span&gt;, ya que al terminar la petición el interceptor se encargará de eliminar este archivo temporal.&lt;br /&gt;&lt;br /&gt;Veamos cómo realizar la carga de archivos con un ejemplo.&lt;br /&gt;&lt;br /&gt;Lo primero que haremos será crear un nuevo directorio en las páginas web, llamado "&lt;span class="codigo"&gt;carga&lt;/span&gt;". Dentro de este directorio crearemos una nueva &lt;span class="codigo"&gt;JSP&lt;/span&gt; llamada "&lt;span class="codigo"&gt;formulario.jsp&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-w039RmfJE1s/TqMmJEVS3ZI/AAAAAAAABLM/oBzZZaxG_4Y/s1600/S3_42.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-w039RmfJE1s/TqMmJEVS3ZI/AAAAAAAABLM/oBzZZaxG_4Y/s1600/S3_42.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Como hasta ahora, debemos indicar en la &lt;span class="codigo"&gt;JSP&lt;/span&gt; que haremos uso de la biblioteca de etiquetas de &lt;span class="codigo"&gt;Struts 2&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;%@taglib prefix="s" uri="/struts-tags" %&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Lo siguiente es crear un formulario. Este será un poco distinto a los que hemos creado hasta ahora. Lo primero es que los datos del formulario deben codificarse de una forma especial antes de que estos sean enviados al servidor. Afortunadamente es el navegador el que se encarga de hacer esta codificación, lo único que nosotros debemos hacer es indicar, usando el atributo "&lt;span class="codigo"&gt;enctype&lt;/span&gt;" del formulario, cuál codificación será; cuando cargamos archivos estos deben ir codificados en "&lt;span class="codigo"&gt;multipart/form-data&lt;/span&gt;". &lt;br /&gt;&lt;br /&gt;Además los datos deben ser enviados por &lt;span class="codigo"&gt;POST&lt;/span&gt; (en los formularios &lt;span class="codigo"&gt;HTML&lt;/span&gt; el método por default para enviar datos es &lt;span class="codigo"&gt;GET&lt;/span&gt; (por la &lt;span class="codigo"&gt;URL&lt;/span&gt;), pero en &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; por default se envían por &lt;span class="codigo"&gt;POST&lt;/span&gt; (en el cuerpo del mensaje de la petición), así que no debemos agregarle ninguna cosa extra en este caso). El formulario, hasta ahora, se ve de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:form enctype="multipart/form-data"&amp;gt;&lt;br /&gt;&amp;lt;/s:form&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Los archivos son cargados con un tipo de campo especial el cual es generado usado la etiqueta "&lt;span class="codigo"&gt;&amp;lt;s:file /&amp;gt;&lt;/span&gt;". Esta etiqueta funciona de la misma forma que las demás que hemos venido usando hasta el momento:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:form action="cargaArchivo" enctype="multipart/form-data"&amp;gt;&lt;br /&gt;    &amp;lt;s:file name="archivo" label="Archivo" /&amp;gt;&lt;br /&gt;&amp;lt;/s:form&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;En este caso he llamado a mi archivo "&lt;span class="codigo"&gt;archivo&lt;/span&gt;" pero podría tener cualquier nombre, como "&lt;span class="codigo"&gt;imagen&lt;/span&gt;", "&lt;span class="codigo"&gt;reporte&lt;/span&gt;", "&lt;span class="codigo"&gt;datos&lt;/span&gt;", etc.&lt;br /&gt;&lt;br /&gt;Agregaré otro campo solo para que vemos que podemos subir archivos junto con datos "&lt;span class="codigo"&gt;planos&lt;/span&gt;" del formulario:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:form action="cargaArchivo" enctype="multipart/form-data"&amp;gt;&lt;br /&gt;    &amp;lt;s:file name="archivo" label="Archivo" /&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="autor" label="Autor" /&amp;gt;&lt;br /&gt;&amp;lt;/s:form&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Terminaremos el formulario agregando un botón de envío de formulario y una etiqueta que nos mostrará cualquier error que pudiera ocurrir en el proceso de carga:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:actionerror /&amp;gt;&lt;br /&gt;&amp;lt;s:form action="cargaArchivo" enctype="multipart/form-data"&amp;gt;&lt;br /&gt;    &amp;lt;s:file name="archivo" label="Archivo" /&amp;gt;&lt;br /&gt;    &amp;lt;s:textfield name="autor" label="Autor" /&amp;gt;&lt;br /&gt;    &amp;lt;s:submit value="Enviar" /&amp;gt;&lt;br /&gt;&amp;lt;/s:form&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Como ven, el formulario es tan sencillo como todos los que hemos estado haciendo a lo largo del tutorial.&lt;br /&gt;&lt;br /&gt;Ahora crearemos el &lt;span class="codigo"&gt;Action&lt;/span&gt; que se encargará de procesar los datos de este formulario, y que es donde se encuentra la parte interesante del ejemplo ^^.&lt;br /&gt;&lt;br /&gt;Creamos una nueva clase en el paquete "&lt;span class="codigo"&gt;actions&lt;/span&gt;" llamada "&lt;span class="codigo"&gt;CargaArchivo&lt;/span&gt;". Esta clase extenderá de "&lt;span class="codigo"&gt;ActionSupport&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class CargaArchivo extends ActionSupport&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Agregaremos una propiedad de tipo &lt;span class="codigo"&gt;String&lt;/span&gt; para almacenar el nombre del autor:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class CargaArchivo extends ActionSupport&lt;br /&gt;{&lt;br /&gt;    private String autor;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ahora viene la parte importante, &lt;span class="negritas"&gt;para poder obtener una referencia al archivo, debemos colocar, en nuestro &lt;span class="codigo"&gt;Action&lt;/span&gt;, una propiedad de tipo "&lt;span class="codigo"&gt;File&lt;/span&gt;"&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class CargaArchivo extends ActionSupport&lt;br /&gt;{&lt;br /&gt;    private String autor;&lt;br /&gt;    private File archivo;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Con esto, cada vez que se cargue un archivo usando el formulario, la variable de tipo "&lt;span class="codigo"&gt;File&lt;/span&gt;" que tenemos, hará referencia a este archivo. Lo que nos queda es agregar los respectivos &lt;span class="codigo"&gt;setters&lt;/span&gt; para las dos propiedades anteriores:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class CargaArchivo extends ActionSupport&lt;br /&gt;{&lt;br /&gt;    private String autor;&lt;br /&gt;    private File archivo;&lt;br /&gt;&lt;br /&gt;    public void setArchivo(File archivo)&lt;br /&gt;    {&lt;br /&gt;        this.archivo = archivo;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setAutor(String autor)&lt;br /&gt;    {&lt;br /&gt;        this.autor = autor;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ahora sobrecargaremos el método "&lt;span class="codigo"&gt;execute&lt;/span&gt;" de nuestro &lt;span class="codigo"&gt;Action&lt;/span&gt; para mover el archivo a ua nueva ubicación en nuestro sistema de archivos:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Override&lt;br /&gt;public String execute() throws Exception&lt;br /&gt;{&lt;br /&gt;    File nuevoArchivo = new File("/", archivo.getName());&lt;br /&gt;    archivo.renameTo(nuevoArchivo);&lt;br /&gt;        &lt;br /&gt;    return SUCCESS;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Podemos ver que colocaremos el nuevo archivo en el directorio raíz del sistema operativo y que el nombre del archivo será el mismo que el del archivo que estamos subiendo.&lt;br /&gt;&lt;br /&gt;Al terminar el proceso mostraremos un poco de información con respecto al archivo. La información del archivo se verá en la página que enviemos como resultado "&lt;span class="codigo"&gt;SUCCESS&lt;/span&gt;", por lo que deberemos proporcionar los &lt;span class="codigo"&gt;getters&lt;/span&gt; correspondientes para esta información; en este caso mostraremos el nombre del archivo y la ruta en la que queda almacenado:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public String getNombre()&lt;br /&gt;{&lt;br /&gt;    return archivo.getName();&lt;br /&gt;}&lt;br /&gt;    &lt;br /&gt;public String getRuta()&lt;br /&gt;{&lt;br /&gt;    return archivo.getAbsolutePath();&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Como ven estamos obteniendo la información directamente del objeto &lt;span class="codigo"&gt;File&lt;/span&gt; que representa al archivo que estamos cargando.&lt;br /&gt;&lt;br /&gt;Crearemos la página que mostrará los resultados por lo que en el directorio "&lt;span class="codigo"&gt;carga&lt;/span&gt;" creamos una nueva &lt;span class="codigo"&gt;JSP&lt;/span&gt; llamada "&lt;span class="codigo"&gt;archivoCargado&lt;/span&gt;". Dentro de este archivo hacemos indicamos usando la directiva "&lt;span class="codigo"&gt;taglib&lt;/span&gt;" que haremos uso de la biblioteca de etiquetas de &lt;span class="codigo"&gt;Struts 2&lt;/span&gt;. Después, usando la etiqueta "&lt;span class="codigo"&gt;&amp;lt;s:property&amp;gt;&lt;/span&gt;" mostraremos los dos valores de los atributos anteriores:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;Nombre: &amp;lt;s:property value="nombre" /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;Ruta: &amp;lt;s:property value="ruta" /&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Anotaremos este clase como ya sabemos hacerlo, para que el framework la trate como un &lt;span class="codigo"&gt;Action&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Namespace(value = "/carga")&lt;br /&gt;@Action(value = "cargaArchivo", results =&lt;br /&gt;{&lt;br /&gt;    @Result(location = "/carga/archivoCargado.jsp"),&lt;br /&gt;    @Result(name="input", location = "/carga/formulario.jsp")&lt;br /&gt;}) &lt;br /&gt;public class CargaArchivo extends ActionSupport&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ya tenemos todo asi que procedemos a ejecutar la aplicación y a ingresar a la siguiente dirección:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&lt;a href="http://localhost:8080/formularios/carga/formulario.jsp"&gt;http://localhost:8080/formularios/carga/formulario.jsp&lt;/a&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Con lo que veremos el formulario que creamos:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-hrrVVJFafhg/TqMmJiHixfI/AAAAAAAABLU/BCKLLHNhLfs/s1600/S3_43.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="198" src="http://4.bp.blogspot.com/-hrrVVJFafhg/TqMmJiHixfI/AAAAAAAABLU/BCKLLHNhLfs/s400/S3_43.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Podemos ver que en el campo de tipo "&lt;span class="codigo"&gt;file&lt;/span&gt;" que declaramos, existe un pequeño botón que dice "&lt;span class="codigo"&gt;Examinar...&lt;/span&gt;". Al presionar este botón se abrirá un cuadro de dialogo que nos permitirá seleccionar un archivo; en mi caso seleccionaré una imagen al azar de mi biblioteca de imágenes:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-3niIt2RfiTk/TqMmKc1VbxI/AAAAAAAABLc/WJdKXyKj_Jw/s1600/S3_44.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="280" src="http://4.bp.blogspot.com/-3niIt2RfiTk/TqMmKc1VbxI/AAAAAAAABLc/WJdKXyKj_Jw/s400/S3_44.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Cuando presionemos el botón "&lt;span class="codigo"&gt;Enviar&lt;/span&gt;" de nuestro formulario, veremos en la página resultante una salida similar a la siguiente:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-eFA_nIwezMI/TqMmLFzOgiI/AAAAAAAABLk/_8gkVssuMuQ/s1600/S3_45.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="168" src="http://1.bp.blogspot.com/-eFA_nIwezMI/TqMmLFzOgiI/AAAAAAAABLk/_8gkVssuMuQ/s400/S3_45.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Podemos notar antes que nada que el archivo que habíamos subido, llamado "&lt;span class="codigo"&gt;logoJT.png&lt;/span&gt;", ahora se llama "&lt;span class="codigo"&gt;upload_5829876d_132a34219c9__7ffb_00000000.tmp&lt;/span&gt;". Esto ocurre porque cuando enviamos un archivo usando un formulario, el archivo no viaja como tal por la red; son sus bytes los que son enviados (lo sé técnicamente sería lo mismo ya que un archivo es un conjunto de bytes), el interceptor "&lt;span class="codigo"&gt;fileUpload&lt;/span&gt;" toma estos bytes y los coloca en un archivo nuevo al cual le coloca un nombre extraño. &lt;br /&gt;&lt;br /&gt;Si observamos el directorio a donde hemos movido el archivo que habíamos obtenido notaremos que nuestro archivo efectivamente ha quedado ahí, pero con el nuevo nombre (y extensión) que le ha colocado el interceptor:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-G-xXTc6voMo/TqMmL3BJaII/AAAAAAAABLs/jobeniHh-cc/s1600/S3_46.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="281" src="http://1.bp.blogspot.com/-G-xXTc6voMo/TqMmL3BJaII/AAAAAAAABLs/jobeniHh-cc/s400/S3_46.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Podemos ver que no tenemos información del nombre original del archivo ni de su tipo de contenido. Como podemos imaginar, ambos son datos muy importantes que nos pueden servir en algún momento.&lt;br /&gt;&lt;br /&gt;Afortunadamente para nosotros, &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; proporciona una forma en la que podemos obtener esta información de una forma fácil y sencilla (como nos tiene mal acostumbrados este framework ^^).&lt;br /&gt;&lt;br /&gt;Para obtener esta información debemos proporcionar dos atributos extra para el archivo (con sus correspondientes &lt;span class="codigo"&gt;getters&lt;/span&gt;). El nombre de estos atributos (en realidad solo los &lt;span class="codigo"&gt;setters&lt;/span&gt;, pero creo que es más fácil entender de esta forma) debe seguir una cierta convención si queremos que &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; proporcione la información de manera correcta.&lt;br /&gt;&lt;br /&gt;Para obtener el nombre original del archivo debemos proporcionar un atributo, de tipo &lt;span class="codigo"&gt;String&lt;/span&gt;, cuyo identificador sea "&lt;span class="codigo"&gt;&amp;lt;nombre_del_campo_del_archivo&amp;gt;FileName&lt;/span&gt;"; o sea que si el identificador del campo del archivo es "&lt;span class="codigo"&gt;documento&lt;/span&gt;", el identificador del campo para el nombre del archivo debe ser "&lt;span class="codigo"&gt;documentoFileName&lt;/span&gt;", si el identificador del campo es "&lt;span class="codigo"&gt;miArchivo&lt;/span&gt;", el campo para el nombre debe ser "&lt;span class="codigo"&gt;miArchivoFileName&lt;/span&gt;".&lt;br /&gt;&lt;br /&gt;Para obtener el tipo de contenido del archivo, o sea el "&lt;span class="codigo"&gt;content type&lt;/span&gt;", debemos hacer algo similar y proporcionar un campo cuyo nombre sea "&lt;span class="codigo"&gt;&amp;lt;nombre_del_campo_del_archivo&amp;gt;ContentType&lt;/span&gt;". Los campos para estos dos datos, junto con sus &lt;span class="codigo"&gt;setters&lt;/span&gt;, queda de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;private String archivoFileName;&lt;br /&gt;private String archivoContentType;&lt;br /&gt;&lt;br /&gt;public void setArchivoContentType(String archivoContentType)&lt;br /&gt;{&lt;br /&gt;    this.archivoContentType = archivoContentType;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setArchivoFileName(String archivoFileName)&lt;br /&gt;{&lt;br /&gt;    this.archivoFileName = archivoFileName;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ahora con estos datos podemos modificar un poco nuestro &lt;span class="codigo"&gt;Action&lt;/span&gt; dejando el método "&lt;span class="codigo"&gt;execute&lt;/span&gt;" de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public String execute() throws Exception&lt;br /&gt;{&lt;br /&gt;    File nuevoArchivo = new File("/", archivoFileName);&lt;br /&gt;    archivo.renameTo(nuevoArchivo);&lt;br /&gt;        &lt;br /&gt;    return SUCCESS;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ahora el nombre con el que guardaremos el archivo que recibimos, es el mismo nombre del archivo original.&lt;br /&gt;&lt;br /&gt;Agregaremos también un &lt;span class="codigo"&gt;getter&lt;/span&gt; para cada una de las propiedades que no hemos utilizado aún, o sea para "&lt;span class="codigo"&gt;autor&lt;/span&gt;" y "&lt;span class="codigo"&gt;archivoContentType&lt;/span&gt;" para poder leerlos desde la &lt;span class="codigo"&gt;JSP&lt;/span&gt; del resultado:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public String getArchivoContentType()&lt;br /&gt;{&lt;br /&gt;    return archivoContentType;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public String getAutor()&lt;br /&gt;{&lt;br /&gt;    return autor;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Al final, nuestra clase "&lt;span class="codigo"&gt;CargaArchivo&lt;/span&gt;" queda de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Namespace(value = "/carga")&lt;br /&gt;@Action(value = "cargaArchivo", results =&lt;br /&gt;{&lt;br /&gt;    @Result(location = "/carga/archivoCargado.jsp"),&lt;br /&gt;    @Result(name="input", location = "/carga/formulario.jsp")&lt;br /&gt;}) &lt;br /&gt;public class CargaArchivo extends ActionSupport&lt;br /&gt;{&lt;br /&gt;    private String autor;&lt;br /&gt;    private File archivo;&lt;br /&gt;    private String archivoFileName;&lt;br /&gt;    private String archivoContentType;&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    public String execute() throws Exception&lt;br /&gt;    {&lt;br /&gt;        File nuevoArchivo = new File("/", archivoFileName);&lt;br /&gt;        archivo.renameTo(nuevoArchivo);&lt;br /&gt;        &lt;br /&gt;        return SUCCESS;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public String getArchivoContentType()&lt;br /&gt;    {&lt;br /&gt;        return archivoContentType;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public String getAutor()&lt;br /&gt;    {&lt;br /&gt;        return autor;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;br /&gt;    public void setArchivoContentType(String archivoContentType)&lt;br /&gt;    {&lt;br /&gt;        this.archivoContentType = archivoContentType;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setArchivoFileName(String archivoFileName)&lt;br /&gt;    {&lt;br /&gt;        this.archivoFileName = archivoFileName;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public String getNombre()&lt;br /&gt;    {&lt;br /&gt;        return archivoFileName;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    public String getRuta()&lt;br /&gt;    {&lt;br /&gt;        return archivo.getAbsolutePath();&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    public void setArchivo(File archivo)&lt;br /&gt;    {&lt;br /&gt;        this.archivo = archivo;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setAutor(String autor)&lt;br /&gt;    {&lt;br /&gt;        this.autor = autor;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Debemos modificar ahora la &lt;span class="codigo"&gt;JSP&lt;/span&gt; "&lt;span class="codigo"&gt;archivoCargado&lt;/span&gt;" del directorio "&lt;span class="codigo"&gt;carga&lt;/span&gt;" para que quede de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;Nombre: &amp;lt;s:property value="nombre" /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;Ruta: &amp;lt;s:property value="ruta" /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;Autor: &amp;lt;s:property value="autor" /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;Content Type: &amp;lt;s:property value="archivoContentType" /&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Con todos los datos que necesitamos. volvemos a ejecutar la aplicación, y debemos ver el mismo formulario de las últimas veces:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-jUOb8b2tPyI/TqMmMKOeE9I/AAAAAAAABL0/-hsm4P9tcKc/s1600/S3_47.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="172" src="http://3.bp.blogspot.com/-jUOb8b2tPyI/TqMmMKOeE9I/AAAAAAAABL0/-hsm4P9tcKc/s400/S3_47.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Subimos nuevamente nuestro archivo, y al presionar el botón "&lt;span class="codigo"&gt;Enviar&lt;/span&gt;" deberemos ver la siguiente pantalla:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-h89tOzBImcQ/TqMmMxz8WWI/AAAAAAAABL8/NQofvT9qKdk/s1600/S3_48.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="135" src="http://1.bp.blogspot.com/-h89tOzBImcQ/TqMmMxz8WWI/AAAAAAAABL8/NQofvT9qKdk/s400/S3_48.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Como podemos observar, ahora se está indicando el nombre original de la imagen, y el tipo de archivo que se subió (que en este caso es "&lt;span class="codigo"&gt;image/png&lt;/span&gt;"). Si vamos nuevamente al directorio raíz de nuestro sistema operativo veremos que ahora la imagen se ha almacenado de forma correcta, y podemos ver un preview de la misma:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-7is-TM-gMI4/TqMmNSm063I/AAAAAAAABME/fHxOUFeOku8/s1600/S3_49.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="196" src="http://3.bp.blogspot.com/-7is-TM-gMI4/TqMmNSm063I/AAAAAAAABME/fHxOUFeOku8/s400/S3_49.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Con lo que podemos comprobar que la carga se realizó de forma correcta ^_^.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Hagamos una segunda prueba, intentemos subir el siguiente archivo (&lt;span class="negritas"&gt;como tip para lo que viene a continuación, fíjense en el tamaño del archivo&lt;/span&gt;).&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-OHAioFEgyCY/TqMmOLGheDI/AAAAAAAABMM/Th563VteVd4/s1600/S3_50.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="281" src="http://4.bp.blogspot.com/-OHAioFEgyCY/TqMmOLGheDI/AAAAAAAABMM/Th563VteVd4/s400/S3_50.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Al tratar de enviar este archivo veremos que obtenemos... un mensaje de error:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-fzeqI3Hx4Lw/TqMmOtBuFaI/AAAAAAAABMU/bQYi8w3og5g/s1600/S3_51.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="175" src="http://2.bp.blogspot.com/-fzeqI3Hx4Lw/TqMmOtBuFaI/AAAAAAAABMU/bQYi8w3og5g/s400/S3_51.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Lo que el mensaje básicamente dice es que el tamaño de nuestro archivo excede el tamaño máximo de &lt;span class="codigo"&gt;2MB&lt;/span&gt; que &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; tiene configurado por defecto. ¿Qué podemos hacer entonces para subir archivos que sean más grandes? Como deben estarse imaginando, &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; proporciona una forma de configurar el tamaño máximo de los archivos que se pueden cargar, a través de una constante o a través de un parámetro del interceptor "&lt;span class="codigo"&gt;fileUpload&lt;/span&gt;". Estos dos valores no son exactamente para lo mismo, pero lo explicaremos en su debido momento.&lt;br /&gt;&lt;br /&gt;Primero veamos cómo establecer este valor como una constante.&lt;br /&gt;&lt;br /&gt;Como recordarán, del primer tutorial de la serie, hay dos formas de definir las constantes de &lt;span class="codigo"&gt;Struts 2&lt;/span&gt;, la primera es en el archivo "&lt;span class="codigo"&gt;struts.xml&lt;/span&gt;" que normalmente usamos cuando realizamos una configuración con &lt;span class="codigo"&gt;XML&lt;/span&gt;. El nombre de la constante que debemos definir es "&lt;span class="codigo"&gt;struts.multipart.maxSize&lt;/span&gt;". &lt;br /&gt;&lt;br /&gt;Esta variable quedaría de la siguiente forma en el archivo "&lt;span class="codigo"&gt;struts.xml&lt;/span&gt;" si quisiéramos que el tamaño máximo del archivo fuera de &lt;span class="codigo"&gt;10MB&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;constant name="struts.multipart.maxSize" value="10485760" /&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;En donde el valor indica el peso máximo que puede tener el archivo el bytes (así es, leyeron bien: bytes). El valor es calculado de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;10 * 1024 * 1024&lt;br /&gt;//MB   KB   Bytes&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Si no estamos usando un archivo de configuración, como es nuestro caso, la constante se define como un parámetro de inicialización en el filtro de &lt;span class="codigo"&gt;Struts 2&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;filter&amp;gt;&lt;br /&gt;    &amp;lt;filter-name&amp;gt;struts2&amp;lt;/filter-name&amp;gt;&lt;br /&gt;    &amp;lt;filter-class&amp;gt;org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter&amp;lt;/filter-class&amp;gt;&lt;br /&gt;    &lt;span class="negritas"&gt;&amp;lt;init-param&amp;gt;&lt;br /&gt;        &amp;lt;param-name&amp;gt;struts.multipart.maxSize&amp;lt;/param-name&amp;gt;&lt;br /&gt;        &amp;lt;param-value&amp;gt;5097152&amp;lt;/param-value&amp;gt;&lt;br /&gt;    &amp;lt;/init-param&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;lt;/filter&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Si intentamos nuevamente subir nuestro archivo, veremos la siguiente salida:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-rq8CybsE4jA/TqMmPFIEzPI/AAAAAAAABMc/bTcaoA3KEWY/s1600/S3_52.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="135" src="http://3.bp.blogspot.com/-rq8CybsE4jA/TqMmPFIEzPI/AAAAAAAABMc/bTcaoA3KEWY/s400/S3_52.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Podemos ver que en esta ocasión logramos subir el archivo de forma correcta.&lt;br /&gt;&lt;br /&gt;El utilizar la constante anterior modifica el límite del tamaño de los archivos en toda la aplicación. Esto es bueno si deseamos aumentar el límite en el tamaño de los archivos que se vaya a subir en cualquier formulario de la aplicación. ¿Pero qué pasaría si necesitáramos que en algún formulario particular el tamaño máximo de los archivos a subir fuera menor que en el resto de la aplicación? Para estos casos es que existe una forma para especificar un límite para un &lt;span class="codigo"&gt;Action&lt;/span&gt; particular, estableciendo el parámetro "&lt;span class="codigo"&gt;maximumSize&lt;/span&gt;" del interceptor "&lt;span class="codigo"&gt;fileUpload&lt;/span&gt;" en el &lt;span class="codigo"&gt;Action&lt;/span&gt; que queremos modificar.&lt;br /&gt;&lt;br /&gt;Ojo con lo dicho anteriormente, esta segunda forma &lt;span class="negritas"&gt;lo único que permite es hacer que el tamaño máximo para un &lt;span class="codigo"&gt;Action&lt;/span&gt; particular sea menor que el resto de la aplicación&lt;/span&gt;, lo contrario (que el tamaño máximo para un &lt;span class="codigo"&gt;Action&lt;/span&gt; sea mayor que para el resto de la aplicación) no se puede hacer.&lt;br /&gt;&lt;br /&gt;Para personalizar el valor de este interceptor para un &lt;span class="codigo"&gt;Action&lt;/span&gt;, cuando trabajamos con el archivo "&lt;span class="codigo"&gt;struts.xml&lt;/span&gt;", usamos el elemento "&lt;span class="codigo"&gt;&amp;lt;interceptor-ref&amp;gt;&lt;/span&gt;" para indicar qué interceptores son los que queremos aplicar a un &lt;span class="codigo"&gt;Action&lt;/span&gt; particular y los valores de los parámetros de dichos interceptores. Por ejemplo, para el &lt;span class="codigo"&gt;Action&lt;/span&gt; "&lt;span class="codigo"&gt;cargaArchivo&lt;/span&gt;", si estuviéramos trabajando con un el archivo "&lt;span class="codigo"&gt;struts.xml&lt;/span&gt;" quedaría de la siguiente forma para que el tamaño máximo de un archivo sea de &lt;span class="codigo"&gt;2MB (2* 1024 * 1024)&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;action name="cargaArchivo" class="com.javatutoriales.struts2.formularios.actions.CargaArchivo"&amp;gt;&lt;br /&gt;    &amp;lt;interceptor-ref name="fileUpload"&amp;gt;&lt;br /&gt;        &amp;lt;param name="maximumSize"&amp;gt;2097152&amp;lt;/param&amp;gt;&lt;br /&gt;    &amp;lt;/interceptor-ref&amp;gt; &lt;br /&gt;    &amp;lt;interceptor-ref name="defaultStack"/&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;result&amp;gt;/carga/archivoCargado.jsp&amp;lt;/result&amp;gt;&lt;br /&gt;    &amp;lt;result name="input"&amp;gt;/carga/formulario.jsp&amp;lt;/result&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/action&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Para cuando trabajamos con anotaciones la configuración queda de la siguiente forma:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@InterceptorRefs(value =&lt;br /&gt;{&lt;br /&gt;    @InterceptorRef(value = "fileUpload", params =&lt;br /&gt;    {&lt;br /&gt;        "maximumSize", "2097152"&lt;br /&gt;    }),&lt;br /&gt;    @InterceptorRef(value = "defaultStack")&lt;br /&gt;})&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Como de esta forma lo que hacemos es indicar los interceptores que se le aplicarán a este &lt;span class="codigo"&gt;Action&lt;/span&gt;, debemos decir que además del interceptor "&lt;span class="codigo"&gt;fileUpload&lt;/span&gt;" queremos aplicar el resto de los interceptores que se aplican normalmente a un &lt;span class="codigo"&gt;Action&lt;/span&gt; y que se encuentran en el "&lt;span class="codigo"&gt;defaultStack&lt;/span&gt;", como explicamos en &lt;a href="http://www.javatutoriales.com/2011/06/struts-2-parte-1-configuracion.html"&gt;el primer tutorial de la serie&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Si intentamos subir nuevamente nuestro archivo obtendremos el siguiente mensaje de error:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-m9o9IzjozAs/TqMmPg2nfmI/AAAAAAAABMk/TEVC_ixKf7A/s1600/S3_53.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="135" src="http://3.bp.blogspot.com/-m9o9IzjozAs/TqMmPg2nfmI/AAAAAAAABMk/TEVC_ixKf7A/s400/S3_53.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Podemos ver que este mensaje es ligeramente distinto al que habíamos obtenido anteriormente, pero nos sirve para comprobar que efectivamente el límite se ha modificado.&lt;br /&gt;&lt;br /&gt;Si estamos realizando la carga de varios archivos, el tamaño máximo será el de la suma del tamaño de todos los archivos, y no de cada archivo individual. Además el tamaño máximo de archivos que el framework soporta, según la documentación oficial, es de &lt;span class="codigo"&gt;2GB&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Adicionalmente a restringir el tamaño máximo de los archivos que podemos cargar, &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; nos permite limitar también el tipo (&lt;span class="codigo"&gt;content-type&lt;/span&gt;) de los archivos que se cargarán, estableciendo el parámetro "&lt;span class="codigo"&gt;allowedTypes&lt;/span&gt;" del interceptor "&lt;span class="codigo"&gt;fileUpload&lt;/span&gt;". Supongamos que para el &lt;span class="codigo"&gt;Action&lt;/span&gt; anterior, solo queremos permitir que se carguen archivos de imagen en formato "&lt;span class="codigo"&gt;png&lt;/span&gt;". Para lograr esto debemos configurar el interceptor "&lt;span class="codigo"&gt;fileUpload&lt;/span&gt;" para nuestro &lt;span class="codigo"&gt;Action&lt;/span&gt; de la siguiente forma:&lt;br /&gt;&lt;br /&gt;Si usamos el archivo "&lt;span class="codigo"&gt;struts.xml&lt;/span&gt;":&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;action name="cargaArchivo" class="com.javatutoriales.struts2.formularios.actions.CargaArchivo"&amp;gt;&lt;br /&gt;    &amp;lt;interceptor-ref name="fileUpload"&amp;gt;&lt;br /&gt;        &amp;lt;param name="maximumSize"&amp;gt;2097152&amp;lt;/param&amp;gt;&lt;br /&gt;        &amp;lt;param name="allowedTypes"&amp;gt;image/png&amp;lt;/param&amp;gt;&lt;br /&gt;    &amp;lt;/interceptor-ref&amp;gt; &lt;br /&gt;    &amp;lt;interceptor-ref name="defaultStack"/&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;result&amp;gt;/carga/archivoCargado.jsp&amp;lt;/result&amp;gt;&lt;br /&gt;    &amp;lt;result name="input"&amp;gt;/carga/formulario.jsp&amp;lt;/result&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/action&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Si usamos anotaciones:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@InterceptorRefs(value =&lt;br /&gt;{&lt;br /&gt;    @InterceptorRef(value = "fileUpload", params =&lt;br /&gt;    {&lt;br /&gt;        "maximumSize", "2097152", "allowedTypes","image/png"&lt;br /&gt;    }),&lt;br /&gt;    @InterceptorRef(value = "defaultStack")&lt;br /&gt;})&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Al intentar subir cualquier archivo que no sea una imagen en formato &lt;span class="codigo"&gt;png&lt;/span&gt;, obtendremos el siguiente error:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-SfY_pKqQ6ow/TqMmQAO_XxI/AAAAAAAABMs/7k2NE-LqeHs/s1600/S3_54.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="135" src="http://4.bp.blogspot.com/-SfY_pKqQ6ow/TqMmQAO_XxI/AAAAAAAABMs/7k2NE-LqeHs/s400/S3_54.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Podemos indicar varios formatos permitidos separando cada elemento con comas, por ejemplo:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;"image/jpg, image/png, image/ico"&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Para terminar de hablar de carga de archivos debemos saber cómo personalizar los mensajes de error que se generan al cargar archivos. Los mensajes que vimos anteriormente, aunque bastante claros tal vez no sean los que querremos que nuestros usuarios finales vean en la aplicación. Para personalizar estos mensajes tenemos tres llaves que nos permiten indicar los mensajes que queremos mostrar en cada caso. Estas llaves son:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="codigo"&gt;struts.messages.error.uploading&lt;/span&gt; - Un error general que ocurre y que impide subir un archivo&lt;/li&gt;&lt;li&gt;&lt;span class="codigo"&gt;struts.messages.error.file.too.large&lt;/span&gt; - Ocurre cuando un archivo cargado es más grande que el tamaño máximo especificado&lt;/li&gt;&lt;li&gt;&lt;span class="codigo"&gt;struts.messages.error.content.type.not.allowed&lt;/span&gt; - Ocurre cuando el archivo cargado no es del tipo permitido (content-type) para la carga&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Estas llaves debemos colocarlas en un archivo de propiedades que contendrá los mensajes de error de la aplicación. Para crear este archivo hacemos clic derecho sobre el nodo "&lt;span class="codigo"&gt;Source Package&lt;/span&gt;" del panel de proyectos. En el menú contextual que aparece seleccionamos la opción "&lt;span class="codigo"&gt;New -&amp;gt; Properties File...&lt;/span&gt;" (si no tienen esa opción en el menú, seleccionen la opción "&lt;span class="codigo"&gt;Other...&lt;/span&gt;" y en la ventana que se abre seleccionen la categoría "&lt;span class="codigo"&gt;Other&lt;/span&gt;" y el tipo de archivo "&lt;span class="codigo"&gt;Properties File&lt;/span&gt;"):&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-GOZ6y0H2qY0/TqMmQtx5XsI/AAAAAAAABM0/MlGEaGk6W8I/s1600/S3_55.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="305" src="http://3.bp.blogspot.com/-GOZ6y0H2qY0/TqMmQtx5XsI/AAAAAAAABM0/MlGEaGk6W8I/s400/S3_55.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Llamaremos a este archivo "&lt;span class="codigo"&gt;struts-mensajes&lt;/span&gt;" (el IDE se encargará de colocar automáticamente la extensión &lt;span class="codigo"&gt;.properties&lt;/span&gt;). Damos clic en el botón "&lt;span class="codigo"&gt;Finish&lt;/span&gt;" y veremos aparecer en el editor nuestro archivo de propiedades. En este archivo colocaremos los textos que los usuarios verán en caso de que ocurra algún error, por ejemplo podemos poner:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;struts.messages.error.file.too.large=El archivo proporcionado supera el tamaño máximo&lt;br /&gt;struts.messages.error.content.type.not.allowed=El archivo proporcionado no es del tipo adecuado&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ya que tenemos definidos los mensajes, lo siguiente que debemos hacer es indicarle a &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; dónde se localiza este archivo. Para ello (si, adivinaron) usamos una constante para indicar el nombre del archivo (&lt;span class="negritas"&gt;el cual será buscado a partir del directorio raíz de los paquetes de la aplicación, o sea en el nodo "&lt;span class="codigo"&gt;Source Packages&lt;/span&gt;"&lt;/span&gt;. La constante que usamos es "&lt;span class="codigo"&gt;struts.custom.i18n.resources&lt;/span&gt;", y como ya hemos visto, podemos colocarle en el archivo "&lt;span class="codigo"&gt;struts.xml&lt;/span&gt;" de la sigueinte forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;constant name="struts.custom.i18n.resources" value="struts-mensajes" /&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;O como un parámetro de inicialización en el filtro de &lt;span class="codigo"&gt;struts&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;filter&amp;gt;&lt;br /&gt;    &amp;lt;filter-name&amp;gt;struts2&amp;lt;/filter-name&amp;gt;&lt;br /&gt;    &amp;lt;filter-class&amp;gt;org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter&amp;lt;/filter-class&amp;gt;&lt;br /&gt;    &amp;lt;init-param&amp;gt;&lt;br /&gt;        &amp;lt;param-name&amp;gt;struts.custom.i18n.resources&amp;lt;/param-name&amp;gt;&lt;br /&gt;        &amp;lt;param-value&amp;gt;struts-mensajes&amp;lt;/param-value&amp;gt;&lt;br /&gt;    &amp;lt;/init-param&amp;gt;&lt;br /&gt;&amp;lt;/filter&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Cuando volvamos a ejecutar la aplicación veremos los siguientes mensajes de error:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-mJiqcmdQSBU/TqMmRRJoSbI/AAAAAAAABM8/TOGvFjblwwU/s1600/S3_56.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://3.bp.blogspot.com/-mJiqcmdQSBU/TqMmRRJoSbI/AAAAAAAABM8/TOGvFjblwwU/s400/S3_56.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Esto ya está mejor, ya que podemos colocar un texto tan descriptivo como queramos, sin embargo ahora hemos perdido algo de información importante que los otros mensajes nos daban, como el nombre del archivo que estamos subiendo, y algunos parámetros particulares para cada error.&lt;br /&gt;&lt;br /&gt;Afortunadamente una vez más &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; nos da una solución a esto ya que dentro de los mensajes podemos colocar algo llamado "&lt;span class="codigo"&gt;placeholders&lt;/span&gt;" o contenedores, que básicamente es un espacio en nuestro mensaje donde &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; se encargará de colocar un parámetro. Los parámetros que proporciona cada tipo de error son:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;ul&gt;Para "&lt;span class="codigo"&gt;struts.messages.error.file.too.large&lt;/span&gt;":&lt;li&gt;&lt;span class="codigo"&gt;0&lt;/span&gt; - Nombre del parámetro que causó el error (en nuestro ejemplo "&lt;span class="codigo"&gt;archivo&lt;/span&gt;")&lt;/li&gt;&lt;li&gt;&lt;span class="codigo"&gt;1&lt;/span&gt; - Nombre del archivo que causó el error &lt;/li&gt;&lt;li&gt;&lt;span class="codigo"&gt;2&lt;/span&gt; - Nombre del archivo en el servidor (el archivo temporal creado por el interceptor)&lt;/li&gt;&lt;li&gt;&lt;span class="codigo"&gt;3&lt;/span&gt; - Tamaño del archivo cargado&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;ul&gt;Para "&lt;span class="codigo"&gt;struts.messages.error.content.type.not.allowed&lt;/span&gt;":&lt;li&gt;&lt;span class="codigo"&gt;0&lt;/span&gt; - Nombre del parámetro que causó el error (en nuestro ejemplo "&lt;span class="codigo"&gt;archivo&lt;/span&gt;")&lt;/li&gt;&lt;li&gt;&lt;span class="codigo"&gt;1&lt;/span&gt; -  Nombre del archivo que causó el error&lt;/li&gt;&lt;li&gt;&lt;span class="codigo"&gt;2&lt;/span&gt; - Nombre del archivo en el servidor (el archivo temporal creado por el interceptor)&lt;/li&gt;&lt;li&gt;&lt;span class="codigo"&gt;3&lt;/span&gt; - &lt;span class="codigo"&gt;Content-type&lt;/span&gt; del archivo cargado&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Como podemos ver, en ambos casos los parámetros son prácticamente los mismos.&lt;br /&gt;&lt;br /&gt;Podemos modificar los mensajes anteriores para que queden de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;struts.messages.error.file.too.large=El archivo "{1}" supera el tamaño máximo permitido 2097152 bytes (2MB). El tamaño de su archivo es de {3} bytes&lt;br /&gt;struts.messages.error.content.type.not.allowed=El archivo "{1}" no es de un tipo permitido (image/png). Su archivo es de tipo "{3}"&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Con lo que obtendríamos los siguientes mensajes de error:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-Bl74jW87Iy4/TqMmSDHy3JI/AAAAAAAABNE/Z4b3V7y0fAQ/s1600/S3_57.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://3.bp.blogspot.com/-Bl74jW87Iy4/TqMmSDHy3JI/AAAAAAAABNE/Z4b3V7y0fAQ/s400/S3_57.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Que ya son mucho más claros para nuestros usuarios finales ^_^.&lt;br /&gt;&lt;br /&gt;Como una nota final sobre la carga de archivos debemos decir que existe una constante más, "&lt;span class="codigo"&gt;struts.multipart.saveDir&lt;/span&gt;", que podemos usar para indicar dónde queremos que se guarden los archivos temporales de las cargas que genera &lt;span class="codigo"&gt;Struts 2&lt;/span&gt;. El uso de esta variable sale del propósito de este tutorial ^_^.&lt;br /&gt;&lt;br /&gt;Ahora que hemos hablado bastante de la carga de archivos, pasemos al último tema del tutorial. Veamos como envías archivos desde nuestro servidor a los clientes usando &lt;span class="codigo"&gt;Struts 2&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="titulo"&gt;7. Descarga de Archivos&lt;/h2&gt;El poder enviar información binaria o archivos a los usuarios, aunque no es estrictamente parte del trabajo con formularios, es también una parte importante del desarrollo de aplicaciones web ya que tiene muchas aplicaciones prácticas como el enviar un reporte que generamos de forma dinámica, o un archivo que tengamos almacenado en algún lugar, como una base de datos o un directorio externo de la aplicación, o también mostrar imagenes que se hayan cargado o generado de forma dinámica en el sistema.&lt;br /&gt;&lt;br /&gt;El realizar la descarga o envío de archivos es una tarea muy simple de hacer cuando trabajamos con &lt;span class="codigo"&gt;Struts 2&lt;/span&gt;, ya que nos proporciona un tipo de resultado especial que permite enviar bytes directamente al "&lt;span class="codigo"&gt;ServletOutputStream&lt;/span&gt;" del "&lt;span class="codigo"&gt;HttpServletResponse&lt;/span&gt;".&lt;br /&gt;&lt;br /&gt;Dedicaremos un tutorial completo a hablar de tipos de resultados, así que no entraré en muchos detalles de cómo funcionan estos, pero debemos saber que existen varios tipos de resultados, cada uno de los cuales altera de alguna forma la respuesta que enviamos al cliente. Podemos establecer algunos parámetros para indicar alguna información a nuestro &lt;span class="codigo"&gt;result&lt;/span&gt;, entre otras cosas.&lt;br /&gt;&lt;br /&gt;El &lt;span class="codigo"&gt;result&lt;/span&gt; que nos ayudará en este caso es llamado "&lt;span class="codigo"&gt;Stream Result&lt;/span&gt;", y básicamente es un &lt;span class="codigo"&gt;result&lt;/span&gt; que permite enviar un flujo de bytes al cliente. Los parámetros que acepta este &lt;span class="codigo"&gt;result&lt;/span&gt; son:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="codigo"&gt;contentType&lt;/span&gt;: El tipo de contenido que se está enviando al usuario, por default es "&lt;span class="codigo"&gt;text/plain&lt;/span&gt;" &lt;/li&gt;&lt;li&gt;&lt;span class="codigo"&gt;contentLength&lt;/span&gt;: En número de bytes que se le enviarán al usuario (el navegador lo usa para mostrar de forma correcta una barra de progreso).&lt;/li&gt;&lt;li&gt;&lt;span class="codigo"&gt;contentDisposition&lt;/span&gt;: Establece la cabecera "&lt;span class="codigo"&gt;content disposition&lt;/span&gt;" que especifica el nombre del archivo, por lo regular ponemos algo como "&lt;span class="codigo"&gt;attachment;filename="documento.pdf"&lt;/span&gt;" que muestra un cuadro de dialogo para guardar el documento, su valor por default es "&lt;span class="codigo"&gt;inline&lt;/span&gt;" que nos muestra el documento en el mismo navegador&lt;/li&gt;&lt;li&gt;&lt;span class="codigo"&gt;inputName&lt;/span&gt;: El nombre del "&lt;span class="codigo"&gt;InputStream&lt;/span&gt;" que tiene los bytes del archivo que enviaremos al usuario (quedará más claro con el ejemplo), por default es "&lt;span class="codigo"&gt;inputStream&lt;/span&gt;"&lt;/li&gt;&lt;li&gt;&lt;span class="codigo"&gt;bufferSize&lt;/span&gt;: El tamaño del buffer que se usa para del flujo de entrada al de salida, por default es "&lt;span class="codigo"&gt;1024&lt;/span&gt;"&lt;/li&gt;&lt;li&gt;&lt;span class="codigo"&gt;allowCaching&lt;/span&gt;: Indica si el archivo debe ser guardado en caché por el cliente, por default es "&lt;span class="codigo"&gt;true&lt;/span&gt;"&lt;/li&gt;&lt;li&gt;&lt;span class="codigo"&gt;contentCharSet&lt;/span&gt;: El tipo de caracteres que tiene el contenido que enviamos al archivo, no tiene valor por default y si no lo establecemos no pasa nada ^_^.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Todos los atributos anteriores son opcionales, y por lo regular solo establecemos dos o tres.&lt;br /&gt;&lt;br /&gt;Veremos tres ejemplos de este tipo de &lt;span class="codigo"&gt;result&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Lo primero que haremos es crear un nuevo directorio, dentro de las páginas, llamado "&lt;span class="codigo"&gt;descarga&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-OUcJOwQSAhw/TqMmSZ7-0xI/AAAAAAAABNM/uw8hHqLfuC8/s1600/S3_58.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-OUcJOwQSAhw/TqMmSZ7-0xI/AAAAAAAABNM/uw8hHqLfuC8/s1600/S3_58.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Para el primer ejemplo tomaremos un archivo que se encuentra en un directorio de nuestra aplicación y se lo enviaremos al usuario. Pueden tomar cualquier archivo que les guste, de preferencia alguno que puedan ver en el navegador como un&lt;span class="codigo"&gt;PDF&lt;/span&gt;. Yo tomaré un archivo al azar de mi máquina y lo colocaré en el directorio raíz de la aplicación web, o sea en el directorio "&lt;span class="codigo"&gt;web&lt;/span&gt;" de la aplicación que estamos desarrollando:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-lkcL298AF1U/TqMmTGA4ymI/AAAAAAAABNU/k21-6fRrA5o/s1600/S3_59.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="345" src="http://4.bp.blogspot.com/-lkcL298AF1U/TqMmTGA4ymI/AAAAAAAABNU/k21-6fRrA5o/s400/S3_59.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Abriré este archivo solo para ver el contenido y que cuando lo descarguemos podamos ver que es el mismo:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-Q1vfApoUFFY/TqMmT2rJqSI/AAAAAAAABNc/toSH1WypB8g/s1600/S3_60.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="400" src="http://4.bp.blogspot.com/-Q1vfApoUFFY/TqMmT2rJqSI/AAAAAAAABNc/toSH1WypB8g/s400/S3_60.png" width="311" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Ahora crearemos una nueva clase llamada "&lt;span class="codigo"&gt;MuestraArchivo&lt;/span&gt;", en el paquete "&lt;span class="codigo"&gt;actions&lt;/span&gt;". Esta clase extenderá de "&lt;span class="codigo"&gt;ActionSupport&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class MuestraArchivo extends ActionSupport&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Lo primero que debemos hacer es colocar en nuestro &lt;span class="codigo"&gt;Action&lt;/span&gt; un atributo de tipo "&lt;span class="codigo"&gt;java.io.InputStream&lt;/span&gt;". Esta variable contendrá los bytes del archivo que se le enviará al cliente. Existen muchas formas de obtener una referencia a un "&lt;span class="codigo"&gt;InputStream&lt;/span&gt;" de manera que solo tengamos que indicar la fuente donde está el archivo, y alguna clase especial se encargue del resto. En el peor de los casos tendremos que obtener estos bytes uno a uno y colocarlos en un objeto especial, pero tampoco es tan complicado; nosotros usaremos las dos formas en distintos ejemplos. &lt;br /&gt;&lt;br /&gt;Si le damos a esta variable el nombre de "&lt;span class="codigo"&gt;inputStream&lt;/span&gt;" no tendremos que declarar nada más en la configuración del &lt;span class="codigo"&gt;result&lt;/span&gt;. Como es lo más fácil para el momento, lo haremos así y agregaremos el correspondiente &lt;span class="codigo"&gt;getter&lt;/span&gt; de la propiedad:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class MuestraArchivo extends ActionSupport&lt;br /&gt;{&lt;br /&gt;    private InputStream inputStream;&lt;br /&gt;&lt;br /&gt;    public InputStream getInputStream()&lt;br /&gt;    {&lt;br /&gt;        return inputStream;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ahora sobre-escribiremos el método "&lt;span class="codigo"&gt;execute&lt;/span&gt;" para poder obtener un flujo de lectura ("&lt;span class="codigo"&gt;InputStream&lt;/span&gt;") a un archivo, usando una clase especial, un "&lt;span class="codigo"&gt;FileInputStream&lt;/span&gt;". Para obtener este flujo lo único que debemos saber es la ubicación del archivo. Aquí hay que hacer un paréntesis para explicar un poco cómo se obtienen las rutas dentro de nuestra aplicación cuando estamos trabajando con aplicaciones web.&lt;br /&gt;&lt;br /&gt;Dentro de la especificación de &lt;span class="codigo"&gt;Servlets&lt;/span&gt; y &lt;span class="codigo"&gt;JSP&lt;/span&gt;s se indica que cuando se hace la instalación o deploy de una aplicación web en un servidor (más específicamente en un contenedor de &lt;span class="codigo"&gt;Servlets&lt;/span&gt; y &lt;span class="codigo"&gt;JSP&lt;/span&gt;s) este debe quedar en un directorio de la máquina donde está instalado el servidor. ¿En cuál directorio?... esa es la cuestión interesante.&lt;br /&gt;&lt;br /&gt;En la especificación no se indica dónde debe quedar cada aplicación que despleguemos, así que una vez instalada la aplicación, no podemos estar seguros de en dónde se encuentra físicamente dentro del servidor, por lo tanto si quisiéramos simplemente leer un archivo de nuestra aplicación no podríamos hacerlo ya que no sabríamos que ruta indicar; y todo esto en nuestro servidor local, si hiciéramos la instalación en un servidor remoto, rentado, o del cliente, sería aún peor ya que tal vez ni siquiera sabríamos el sistema operativo del mismo. &lt;br /&gt;&lt;br /&gt;Para remediar esto, la especificación también proporciona una forma de obtener la ruta a cualquier recurso de nuestra aplicación. Para hacer esto debemos obtener una referencia al "&lt;span class="codigo"&gt;ServletContext&lt;/span&gt;" de la aplicación y luego usar su método "&lt;span class="codigo"&gt;getRealPath&lt;/span&gt;" indicando el recurso que del cual queremos obtener la ruta, iniciando desde la raíz de la aplicación (lo que vendría siendo el directorio "&lt;span class="codigo"&gt;web&lt;/span&gt;" en &lt;span class="codigo"&gt;NetBeans&lt;/span&gt;).&lt;br /&gt;&lt;br /&gt;Ahora bien, como estamos usando un framework que se encarga de ocultar algunos detalles de la implementación web de la aplicación (como todo buen framework), no podemos obtener de una forma directa el "&lt;span class="codigo"&gt;ServletContext&lt;/span&gt;" ya que no tenemos ninguna referencia a la interface de &lt;span class="codigo"&gt;Servlets&lt;/span&gt; dentro de nuestros &lt;span class="codigo"&gt;Action&lt;/span&gt;s.&lt;br /&gt;&lt;br /&gt;Para remediar esto, &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; nos proporciona una clase auxiliar que ayuda a obtener la referencia al "&lt;span class="codigo"&gt;ServletContext&lt;/span&gt;" de una forma sencilla (de hecho también podemos obtener la referencia al "&lt;span class="codigo"&gt;HttpServletRequest&lt;/span&gt;" y al "&lt;span class="codigo"&gt;HttpServletResponse&lt;/span&gt;"). Esta clase es "&lt;span class="codigo"&gt;ServletActionContext&lt;/span&gt;", y tiene una serie de métodos estáticos que permiten obtener referencias a los objetos anteriores.&lt;br /&gt;&lt;br /&gt;Después de toda esa explicación, espero que quede claro el siguiente paso dentro de nuestro ejemplo.&lt;br /&gt;&lt;br /&gt;Ya tenemos declarada una instancia de "&lt;span class="codigo"&gt;InputStream&lt;/span&gt;" y hemos colocado un archivo &lt;span class="codigo"&gt;.pdf&lt;/span&gt;, llamado "&lt;span class="codigo"&gt;Ingenieria de software&lt;/span&gt;",  en la raíz de la aplicación web, ahora crearemos un flujo de entrada para leer ese archivo y así enviarlo al cliente. Hacerlo en realidad es más fácil que decirlo, ya que &lt;span class="codigo"&gt;Java&lt;/span&gt; proporciona una clase llamada "&lt;span class="codigo"&gt;FileInputStream&lt;/span&gt;" que hace todo esto de forma automática, lo  único que debemos hacer es indicarle la ruta en la que está almacenado nuestro archivo, de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Override&lt;br /&gt;public String execute() throws Exception&lt;br /&gt;{&lt;br /&gt;    String ruta = Servlet&lt;span class="codigo"&gt;Action&lt;/span&gt;Context.getServletContext().getRealPath("/Ingenieria de software.pdf");&lt;br /&gt;&lt;br /&gt;    inputStream = new FileInputStream(ruta);&lt;br /&gt;&lt;br /&gt;    return SUCCESS;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Esto es todo lo que debemos hacer para poder enviar el archivo al usuario, el framework se encargará de hacer el resto.&lt;br /&gt;&lt;br /&gt;El paso final en este &lt;span class="codigo"&gt;Action&lt;/span&gt; es colocar las anotaciones, que en este momento ya debemos conocer de memoria, para indicarle a &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; que debe tratar esta clase como un &lt;span class="codigo"&gt;Action&lt;/span&gt;. Primero que nada indicamos el namespace en el que se colocará al &lt;span class="codigo"&gt;Action&lt;/span&gt;, y se le dará un nombre al mismo:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Namespace(value = "/descarga")&lt;br /&gt;@Action(value = "muestraArchivo)&lt;br /&gt;public class MuestraArchivo extends ActionSupport&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Lo siguiente es indicar el resultado de la ejecución de esté &lt;span class="codigo"&gt;Action&lt;/span&gt;, la respuesta que será enviada al cliente, para lo cual usamos el atributo "&lt;span class="codigo"&gt;results&lt;/span&gt;" y la anotación "&lt;span class="codigo"&gt;@Result&lt;/span&gt;". En esta ocasión, como estamos usando un tipo distinto de &lt;span class="codigo"&gt;result&lt;/span&gt;, debemos indicarlo dentro de la anotación usando su atributo "&lt;span class="codigo"&gt;type&lt;/span&gt;". En este caso debemos indicar que el result es de tipo "&lt;span class="codigo"&gt;stream&lt;/span&gt;" o flujo de bytes, de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Namespace(value = "/descarga")&lt;br /&gt;@Action(value = "muestraArchivo", results =&lt;br /&gt;{&lt;br /&gt;    @Result(type = "stream")&lt;br /&gt;})&lt;br /&gt;public class MuestraArchivo extends ActionSupport&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;El último paso es establecer alguno de los parámetros en el &lt;span class="codigo"&gt;result&lt;/span&gt;, para eso usamos el atributo "&lt;span class="codigo"&gt;params&lt;/span&gt;" de esta anotación. Este atributo recibe como argumento &lt;span class="negritas"&gt;un arreglo de cadenas&lt;/span&gt;, donde &lt;span class="negritas"&gt;los elementos nones representan el nombre del argumento que se quiere establecer&lt;/span&gt;, y &lt;span class="negritas"&gt;los pares representan el valor de dicho argumento&lt;/span&gt;. En este ejemplo solo usaré el atributo "&lt;span class="codigo"&gt;contentType&lt;/span&gt;" para indicar que el tipo de archivo que regresaré al usuario es un archivo &lt;span class="codigo"&gt;pdf&lt;/span&gt; ("&lt;span class="codigo"&gt;application/pdf&lt;/span&gt;"). Si están usando un archivo de algún otro tipo, una búsqueda rápida en Google les dará el tipo de contenido de su archivo:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Namespace(value = "/descarga")&lt;br /&gt;@Action(value = "muestraArchivo", results =&lt;br /&gt;{&lt;br /&gt;    @Result(type = "stream", params =&lt;br /&gt;    {&lt;br /&gt;        "contentType", "application/pdf"&lt;br /&gt;    })&lt;br /&gt;})&lt;br /&gt;public class MuestraArchivo extends ActionSupport&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Nuestra clase "&lt;span class="codigo"&gt;MuestraArchivo&lt;/span&gt;" queda de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Namespace(value = "/descarga")&lt;br /&gt;@Action(value = "muestraArchivo", results =&lt;br /&gt;{&lt;br /&gt;    @Result(type = "stream", params =&lt;br /&gt;    {&lt;br /&gt;        "contentType", "application/pdf"&lt;br /&gt;    })&lt;br /&gt;})&lt;br /&gt;public class MuestraArchivo extends ActionSupport&lt;br /&gt;{&lt;br /&gt;    private InputStream inputStream;&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    public String execute() throws Exception&lt;br /&gt;    {&lt;br /&gt;        String ruta = ServletActionContext.getServletContext().getRealPath("/Ingenieria de software.pdf");&lt;br /&gt;&lt;br /&gt;        inputStream = new FileInputStream(ruta);&lt;br /&gt;&lt;br /&gt;        return SUCCESS;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public InputStream getInputStream()&lt;br /&gt;    {&lt;br /&gt;        return inputStream;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Si estuviéramos trabajando con archivos de configuración, el &lt;span class="codigo"&gt;Action&lt;/span&gt; quedaría de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;action name="muestraArchivo" class="com.javatutoriales.struts2.formularios.actions.MuestraArchivo "&amp;gt;&lt;br /&gt;    &amp;lt;result type="stream"&amp;gt;&lt;br /&gt;        &amp;lt;param name="contentType"&amp;gt;application/pdf&amp;lt;/param&amp;gt;&lt;br /&gt;    &amp;lt;/result&amp;gt;&lt;br /&gt;&amp;lt;/action&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Para este tipo de &lt;span class="codigo"&gt;result&lt;/span&gt;, hablando estrictamente, no se necesita una página para mostrarlo, basta con colocar el nombre del &lt;span class="codigo"&gt;Action&lt;/span&gt; en la barra de direcciones del navegador; nosotros crearemos una solo para ver cómo podemos invocarlos. Dentro del directorio "&lt;span class="codigo"&gt;descarga&lt;/span&gt;" de las páginas web del proyecto creamos una nueva &lt;span class="codigo"&gt;JSP&lt;/span&gt; llamada "&lt;span class="codigo"&gt;archivo&lt;/span&gt;". Dentro de esta &lt;span class="codigo"&gt;JSP&lt;/span&gt;, indicamos que haremos uso de la biblioteca de etiquetas de &lt;span class="codigo"&gt;Struts 2&lt;/span&gt;, con la directiva "&lt;span class="codigo"&gt;taglib&lt;/span&gt;" correspondiente:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;%@taglib prefix="s" uri="/struts-tags" %&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ahora usaremos la etiqueta "&lt;span class="codigo"&gt;&amp;lt;s:a&amp;gt;&lt;/span&gt;" para crear un enlace a nuestro &lt;span class="codigo"&gt;Action&lt;/span&gt;. Esta etiqueta es smuy fácil de utilizar, solo hay que indicar el nombre del &lt;span class="codigo"&gt;Action&lt;/span&gt;, en su atributo "&lt;span class="codigo"&gt;action&lt;/span&gt;", su namespace, en su atributo "&lt;span class="codigo"&gt;namespace&lt;/span&gt;", junto con el texto que tendrá el enlace, de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:a action="muestraArchivo" namespace="/descarga"&amp;gt;Ver archivo&amp;lt;/s:a&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ahora que está todo listo, ejecutamos nuestra aplicación e ingresamos a la siguiente dirección:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&lt;a href="http://localhost:8080/formularios/descarga/archivo.jsp"&gt;http://localhost:8080/formularios/descarga/archivo.jsp&lt;/a&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Con lo que debemos ver la siguiente página:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-ED_TkcKei9U/TqMmUU-bBSI/AAAAAAAABNk/wyOgDLB-rjQ/s1600/S3_61.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="172" src="http://2.bp.blogspot.com/-ED_TkcKei9U/TqMmUU-bBSI/AAAAAAAABNk/wyOgDLB-rjQ/s400/S3_61.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Lo único que tiene esta página es un enlace a nuestro &lt;span class="codigo"&gt;Action&lt;/span&gt;, cuando entramos en la misma deberemos ver el siguiente resultado:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-Dfs3YbLpJ04/TqMmVAxH6CI/AAAAAAAABNs/gzPHuWq0dJc/s1600/S3_62.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="298" src="http://3.bp.blogspot.com/-Dfs3YbLpJ04/TqMmVAxH6CI/AAAAAAAABNs/gzPHuWq0dJc/s400/S3_62.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Como podemos ver, el documento se ha incrustado en nuestro navegador, por lo que nuestro primer ejemplo ha funcionado de forma correcta ^_^.&lt;br /&gt;&lt;br /&gt;En el ejemplo anterior, el archivo que se envío al usuario se mostró dentro del mismo navegador. Esto nos sirve con ciertos tipos de archivos y bajo ciertas circunstancias, pero no siempre querremos que el usuario vea los archivos en su navegador, algunas veces querremos que sea forzoso que los descargue a su computadora. &lt;br /&gt;&lt;br /&gt;En nuestro segundo ejemplo veremos cómo hacer este cambio. Afortunadamente es algo muy sencillo de hacer, basta con agregar otro parámetro, "&lt;span class="codigo"&gt;contentDisposition&lt;/span&gt;", a nuestro &lt;span class="codigo"&gt;result&lt;/span&gt;. "&lt;span class="codigo"&gt;contentDisposition&lt;/span&gt;", como pueden ver en la lista anterior de parámetros, especifica cómo será enviado este archivo al cliente, si "&lt;span class="codigo"&gt;inline&lt;/span&gt;" (para mostrarse en el navegador) o "&lt;span class="codigo"&gt;attachment&lt;/span&gt;" (para que el archivo sea descargado en la máquina del cliente). Ambas opciones nos permiten indicar un "&lt;span class="codigo"&gt;filename&lt;/span&gt;" que es el nombre que tendrá el archivo al ser enviado.&lt;br /&gt;&lt;br /&gt;Como el código del &lt;span class="codigo"&gt;Action&lt;/span&gt; que se necesita para hacer este ejemplo, es muy parecido al anterior, crearé una nueva clase llamada "&lt;span class="codigo"&gt;DescargaArchivo&lt;/span&gt;" y copiaré el código anterior.&lt;br /&gt;&lt;br /&gt;Agregaremos este parámetro a nuestro &lt;span class="codigo"&gt;result&lt;/span&gt;, y como nombre del archivo colocaremos simplemente "&lt;span class="codigo"&gt;tutorial.pdf&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Namespace(value = "/descarga")&lt;br /&gt;@Action(value = "descargaArchivo", results =&lt;br /&gt;{&lt;br /&gt;    @Result(type = "stream", params =&lt;br /&gt;    {&lt;br /&gt;        "contentType", "application/pdf",    &lt;br /&gt;        "contentDisposition","attachment;filename=\"tutorial.pdf\""&lt;br /&gt;    })&lt;br /&gt;})&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Con archivos &lt;span class="codigo"&gt;XML&lt;/span&gt; quedaría de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;result type="stream"&amp;gt;&lt;br /&gt;    &amp;lt;param name="contentType"&amp;gt;application/pdf&amp;lt;/param&amp;gt;&lt;br /&gt;    &amp;lt;param name="contentDisposition"&amp;gt;attachment;filename="tutorial.pdf"&amp;lt;/param&amp;gt;&lt;br /&gt;&amp;lt;/result&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Agregamos la liga correspondiente a este nuevo &lt;span class="codigo"&gt;Action&lt;/span&gt; en la página "&lt;span class="codigo"&gt;archivo.jsp&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:a action="descargaArchivo" namespace="/descarga"&amp;gt;Descargar archivo&amp;lt;/s:a&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Con este simple cambio, al volver a ejecutar nuestra aplicación y entrar en nuestro &lt;span class="codigo"&gt;Action&lt;/span&gt;, ahora en lugar de ver el documento en pantalla veremos el cuadro de diálogo del navegador que nos pregunta qué queremos hacer con el archivo:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-fzzXjzKrCfE/TqMmVp83bxI/AAAAAAAABN0/Tccqc1jl1zw/s1600/S3_63.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="227" src="http://2.bp.blogspot.com/-fzzXjzKrCfE/TqMmVp83bxI/AAAAAAAABN0/Tccqc1jl1zw/s400/S3_63.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Podemos ver en la imagen anterior, que el nombre que tendrá el archivo es el mismo nombre que estamos regresando como el "&lt;span class="codigo"&gt;filename&lt;/span&gt;". En esta ocasión hemos puesto el nombre de forma estática, pero esta no será siempre la forma en la que querremos indicar el nombre del archivo, en la mayoría de las ocasiones este nombre deberá ser generado de forma dinámica. Para lograr esto, todas las propiedades de todos los &lt;span class="codigo"&gt;results&lt;/span&gt; de &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; permiten establecer sus valores usando expresiones, esto es colocar una marca que indique que esa propiedad deberá ser leída de algún &lt;span class="codigo"&gt;getter&lt;/span&gt; de la clase.&lt;br /&gt;&lt;br /&gt;En este caso indicaremos que el nombre del archivo deberá ser obtenido usando el método "&lt;span class="codigo"&gt;getNombreArchivo&lt;/span&gt;" de la clase:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Result(type = "stream", params =&lt;br /&gt;{&lt;br /&gt;    "contentType", "application/pdf",&lt;br /&gt;    "contentDisposition","attachment;filename=\"${nombreArchivo}\""&lt;br /&gt;})&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Podemos ver que solo colocamos "&lt;span class="codigo"&gt;nombreArchivo&lt;/span&gt;" entre los signos "&lt;span class="codigo"&gt;${&lt;/span&gt;" y "&lt;span class="codigo"&gt;}&lt;/span&gt;" (que indican que lo que esté contenido entre ambos es una expresión) y el framework automáticamente sabrá que debe buscar un &lt;span class="codigo"&gt;getter&lt;/span&gt;. &lt;br /&gt;&lt;br /&gt;Con archivos &lt;span class="codigo"&gt;XML&lt;/span&gt; queda exactamente igual:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;result type="stream"&amp;gt;&lt;br /&gt;    &amp;lt;param name="contentType"&amp;gt;application/pdf&amp;lt;/param&amp;gt;&lt;br /&gt;    &amp;lt;param name="contentDisposition"&amp;gt;attachment;filename="${nombreArchivo}"&amp;lt;/param&amp;gt;&lt;br /&gt;&amp;lt;/result&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;En este caso, nuestro método "&lt;span class="codigo"&gt;getNombreArchivo&lt;/span&gt;" regresará  una cadena estática, pero en una aplicación real esta podría ser generada de forma dinámica:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public String getNombreArchivo()&lt;br /&gt;{&lt;br /&gt;    return "documento.pdf";&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ejecutamos nuevamente la aplicación y podremos ver que ahora el nombre del archivo está siendo efectivamente leído a través del &lt;span class="codigo"&gt;getter&lt;/span&gt; correspondiente:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-V7dSII2R3CM/TqMmWRNKCtI/AAAAAAAABN8/5RTfjBaBxec/s1600/S3_64.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="227" src="http://4.bp.blogspot.com/-V7dSII2R3CM/TqMmWRNKCtI/AAAAAAAABN8/5RTfjBaBxec/s400/S3_64.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Hasta ahora nuestra descarga parece realizarse de forma correcta, pero si prestamos un poco de atención al cuadro de descarga podremos ver que hay algo que no nos agrada mucho:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-DLxV2AIkj9M/TqMmWgPdikI/AAAAAAAABOE/Oy0AU3wx5iQ/s1600/S3_65.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-DLxV2AIkj9M/TqMmWgPdikI/AAAAAAAABOE/Oy0AU3wx5iQ/s1600/S3_65.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;¿Lo han notado? Y no, no me refiero a mi velocidad de descarga (aunque a mí no me agrada mucho que digamos ^^). El cuadro de descarga nos dice que no conoce el tamaño del archivo que estamos enviando al cliente, solo sabe la cantidad de información que ya ha descargado. Esto es muy molesto para los clientes, porque no saben cuánto tiempo deberán esperar para descargar su archivo.&lt;br /&gt;&lt;br /&gt;Remediemos este pequeño error, para eso usaremos un parámetro más que nos proporciona el result "&lt;span class="codigo"&gt;stream&lt;/span&gt;", "&lt;span class="codigo"&gt;contentLength&lt;/span&gt;". Este parámetro, como su nombre lo indica, permite especificar cuál es el tamaño del archivo que estamos enviando, para que el navegador pueda colocar la barra de progreso de descarga del archivo de forma correcta. &lt;br /&gt;&lt;br /&gt;Para usar esta propiedad deberemos hacer unos pequeños cambios en nuestro código. Antes que nada debemos agregar un atributo, con su correspondiente &lt;span class="codigo"&gt;getter&lt;/span&gt;, que contenga el número de bytes que pesa nuestro archivo:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;private long bytesArchivo;&lt;br /&gt;&lt;br /&gt;public long getBytesArchivo()&lt;br /&gt;{&lt;br /&gt;    return bytesArchivo;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ahora debemos modificar el código del método "&lt;span class="codigo"&gt;execute&lt;/span&gt;" para que obtenga el dato anterior, para eso haremos uso de otro de los constructores de la clase "&lt;span class="codigo"&gt;FileInputStream&lt;/span&gt;" que hemos estado usando para leer el archivo. Este segundo constructor recibe, en vez de la ruta en la que se encuentra el archivo a leer, un objeto de tipo "&lt;span class="codigo"&gt;File&lt;/span&gt;" que representa el archivo; por lo que ahora crearemos un objeto de tipo "&lt;span class="codigo"&gt;File&lt;/span&gt;" y se lo pasaremos al constructor de "&lt;span class="codigo"&gt;FileInputStream&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Override&lt;br /&gt;public String execute() throws Exception&lt;br /&gt;{&lt;br /&gt;    String ruta = ServletActionContext.getServletContext().getRealPath("/Ingenieria de software.pdf");&lt;br /&gt;&lt;br /&gt;    File archivo = new File(ruta);&lt;br /&gt;        &lt;br /&gt;    inputStream = new FileInputStream(archivo);&lt;br /&gt;&lt;br /&gt;    return SUCCESS;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;¿Por qué hemos hecho esto? Bueno, porque la clase "&lt;span class="codigo"&gt;File&lt;/span&gt;" contiene un método que nos permite obtener justamente el tamaño del archivo, de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Override&lt;br /&gt;public String execute() throws Exception&lt;br /&gt;{&lt;br /&gt;    String ruta = ServletActionContext.getServletContext().getRealPath("/Ingenieria de software.pdf");&lt;br /&gt;&lt;br /&gt;    File archivo = new File(ruta);&lt;br /&gt;    bytesArchivo = archivo.length();&lt;br /&gt;        &lt;br /&gt;    inputStream = new FileInputStream(archivo);&lt;br /&gt;&lt;br /&gt;    return SUCCESS;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Con esto hemos terminado con las modificaciones al método "&lt;span class="codigo"&gt;execute&lt;/span&gt;" y lo único que falta es agregar el parámetro correspondiente a nuestro &lt;span class="codigo"&gt;result&lt;/span&gt;, para esto nuevamente haremos uso de una expresión:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Result(type = "stream", params =&lt;br /&gt;{&lt;br /&gt;    "contentType", "application/pdf",&lt;br /&gt;           "contentDisposition","attachment;filename=\"${nombreArchivo}\"",&lt;br /&gt;    "contentLength", "${bytesArchivo}"&lt;br /&gt;})&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Con archivos &lt;span class="codigo"&gt;XML&lt;/span&gt; queda de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;result type="stream"&amp;gt;&lt;br /&gt;    &amp;lt;param name="contentType"&amp;gt;application/pdf&amp;lt;/param&amp;gt;&lt;br /&gt;    &amp;lt;param name="contentDisposition"&amp;gt;attachment;filename="${nombreArchivo}"&amp;lt;/param&amp;gt;&lt;br /&gt;    &amp;lt;param name="contentLength"&amp;gt;${bytesArchivo}&amp;lt;/param&amp;gt;&lt;br /&gt;&amp;lt;/result&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Y esto es todo. Ahora cuando volvamos a intentar descargar nuestro archivo obtendremos el siguiente dialogo de descargar:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-C8EA0V4Y1ag/TqMmXgQ7e-I/AAAAAAAABOM/0ZeGr1gre3U/s1600/S3_66.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="227" src="http://1.bp.blogspot.com/-C8EA0V4Y1ag/TqMmXgQ7e-I/AAAAAAAABOM/0ZeGr1gre3U/s400/S3_66.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;En esta ocasión se indica el tamaño del archivo y el tiempo que hace falta para concluir con la descarga, por lo que nuestro segundo ejemplo ha funcionado correctamente ^^.&lt;br /&gt;&lt;br /&gt;Ahora pasaremos a ver el tercer y último ejemplo. En este veremos un uso aún más común del &lt;span class="codigo"&gt;result&lt;/span&gt; "&lt;span class="codigo"&gt;stream&lt;/span&gt;": &lt;span class="negritas"&gt;enviar imágenes del servidor al navegador y mostrárselas al usuario&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Para este último ejemplo del tutorial crearemos una nueva clase llamada "&lt;span class="codigo"&gt;GeneradorImagenes&lt;/span&gt;", dentro del paquete "&lt;span class="codigo"&gt;actions&lt;/span&gt;", esta clase extenderá de "&lt;span class="codigo"&gt;ActionSupport&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class GeneradorImagen extends ActionSupport&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Como regresaremos un flujo de bytes al usuario, debemos declarar una variable de tipo "&lt;span class="codigo"&gt;InputStream&lt;/span&gt;" con su correspondiente &lt;span class="codigo"&gt;getter&lt;/span&gt;. El identificador de esta variable puede ser cualquiera que queramos, en mi caso lo llamaré "&lt;span class="codigo"&gt;imagenDinamica&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;private InputStream imagenDinamica;&lt;br /&gt;&lt;br /&gt;public InputStream getImagenDinamica()&lt;br /&gt;{&lt;br /&gt;    return imagenDinamica;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ahora viene la parte interesante, generaremos la imagen de manera dinámica y la guardaremos de forma que al ser enviada al navegador este pueda entenderla para mostrarla. &lt;br /&gt;&lt;br /&gt;Sobre-escribimos el método "&lt;span class="codigo"&gt;execute&lt;/span&gt;" e indicamos cuál será el alto y el ancho de nuestra imagen:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Override&lt;br /&gt;public String execute() throws Exception&lt;br /&gt;{&lt;br /&gt;    final int ANCHO_IMAGEN = 260;&lt;br /&gt;    final int ALTO_IMAGEN = 130;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;El hecho de que las variables estén marcadas como &lt;span class="codigo"&gt;final&lt;/span&gt; es solo para asegurarme de que su valor no cambie durante la ejecución del método.&lt;br /&gt;&lt;br /&gt;Ahora crearemos un objeto que nos permita manipular de una forma sencilla imágenes generadas por nosotros mismos. Para esto haremos uso de la clase "&lt;span class="codigo"&gt;BufferedImage&lt;/span&gt;". Esta clase recibe en su constructor el ancho y alto de la imagen, además de indicar el tipo de la imagen que será creada, en nuestro caso será una sencilla imagen en &lt;span class="codigo"&gt;RGB&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;BufferedImage imagen = new BufferedImage(ANCHO, ALTO, BufferedImage.TYPE_INT_RGB);&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Existen muchas formas de establecer los colores de cada uno de los pixeles de una "&lt;span class="codigo"&gt;BufferedImage&lt;/span&gt;": podemos obtener un objeto "&lt;span class="codigo"&gt;Graphics2D&lt;/span&gt;" usando su método "&lt;span class="codigo"&gt;createGraphics()&lt;/span&gt;" y posteriormente dibujar sobre este usando el API 2D de Java. Aunque la forma más rápida para este ejemplo es usar directamente su método "&lt;span class="codigo"&gt;setRGB&lt;/span&gt;". A este método se le indica la posición del pixel que queremos establecer, en coordenadas "x,y", y el color del pixel en exadecimal, o sea "&lt;span class="codigo"&gt;0xFF0000&lt;/span&gt;" para el rojo, "&lt;span class="codigo"&gt;0x00FF00&lt;/span&gt;" para el verde, y "&lt;span class="codigo"&gt;0x0000FF&lt;/span&gt;" para el azul.&lt;br /&gt;&lt;br /&gt;Crearemos dos ciclos, uno para recorrer todos las filas de la imagen, y otro para recorrer todas sus columnas. Dentro del ciclo más anidado estableceremos el color del pixel apropiado usando una instancia de la clase "&lt;span class="codigo"&gt;Color&lt;/span&gt;" que recibe el valor correspondiente al rojo, verde, azul, y la transparencia del color. Los valores deben están dentro del un rango de &lt;span class="codigo"&gt;0&lt;/span&gt; a &lt;span class="codigo"&gt;255&lt;/span&gt;, siendo &lt;span class="codigo"&gt;0&lt;/span&gt; el tono más obscuro (negro) y &lt;span class="codigo"&gt;255&lt;/span&gt; el más claro (blanco). Si el color se sale del rango la imagen no se mostrará, por lo que usaremos el operador modulo "&lt;span class="codigo"&gt;%&lt;/span&gt;" para hacer que los valores se queden en este rango. Como el valor del pixel debe ser pasado como un entero, usaremos al final el método "&lt;span class="codigo"&gt;getRGB()&lt;/span&gt;" de "&lt;span class="codigo"&gt;Color&lt;/span&gt;" para obtener el valor correspondiente al color que estamos estableciendo:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;for(int alto = 0; alto &amp;lt; ALTO_IMAGEN; alto++)&lt;br /&gt;{&lt;br /&gt;    for(int ancho = 0; ancho &amp;lt; ANCHO_IMAGEN; ancho++)&lt;br /&gt;    {&lt;br /&gt;        imagen.setRGB(ancho, alto, new Color((ancho*alto)%255, (ancho*alto)%255, (ancho*alto)%255, 255).getRGB());&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;También pudimos haber hecho algo más sencillo como:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;imagen.setRGB(ancho, alto, ancho*alto);&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Pero no se obtiene el mismo resultado, y es un poco menos claro lo que está pasando ^_^.&lt;br /&gt;&lt;br /&gt;Nuestra imagen ya tiene color, ahora debemos transformarla a un formato que pueda ser entendido por un navegador web. Para esto haremos uso de la clase "&lt;span class="codigo"&gt;ImageIO&lt;/span&gt;", la cual tiene un método estático, "&lt;span class="codigo"&gt;write&lt;/span&gt;", que permite convertir las imágenes en formatos "&lt;span class="codigo"&gt;png&lt;/span&gt;", "&lt;span class="codigo"&gt;jpg&lt;/span&gt;", "&lt;span class="codigo"&gt;gif&lt;/span&gt;" y "&lt;span class="codigo"&gt;bmp&lt;/span&gt;". Este método recibe como parámetros la imagen que queremos dibujar, el formato en el queremos que quede la imagen, y un "&lt;span class="codigo"&gt;OutputStream&lt;/span&gt;" en donde quedarán los bytes de la imagen.&lt;br /&gt;&lt;br /&gt;Para el ultimo parámetro usaremos un tipo de "&lt;span class="codigo"&gt;OutputStream&lt;/span&gt;" que nos permita recuperar los bytes de esa imagen de una forma simple, por lo que usaramos un objeto de tipo "&lt;span class="codigo"&gt;ByteArrayOutputStream&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;ByteArrayOutputStream bytesImagen = new ByteArrayOutputStream();&lt;br /&gt;ImageIO.write(imagen, "png", bytesImagen);&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;El último paso es crear el "&lt;span class="codigo"&gt;InputStream&lt;/span&gt;" desde el cual &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; leerá nuestra imagen. La imagen ya está en un arreglo de bytes, el del objeto de tipo "&lt;span class="codigo"&gt;ByteArrayOutputStream&lt;/span&gt;", por lo que usaremos un objeto que nos permita usar este arreglo de bytes para crear un "&lt;span class="codigo"&gt;InputStream&lt;/span&gt;". Usaremos un objeto de tipo "&lt;span class="codigo"&gt;ByteArrayInputStream&lt;/span&gt;" que en su constructor recibe un arreglo de bytes, en este caso el arreglo de bytes que representa nuestra imagen:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;imagenDinamica = new ByteArrayInputStream(bytesImagen.toByteArray());&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Eso es todo. Nuestro método "&lt;span class="codigo"&gt;execute&lt;/span&gt;" queda de la siguiente forma:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public String execute() throws Exception&lt;br /&gt;{&lt;br /&gt;    final int ANCHO_IMAGEN = 260;&lt;br /&gt;    final int ALTO_IMAGEN = 130;&lt;br /&gt;        &lt;br /&gt;    BufferedImage imagen = new BufferedImage(ANCHO_IMAGEN, ALTO_IMAGEN, BufferedImage.TYPE_INT_RGB);&lt;br /&gt;        &lt;br /&gt;    for(int alto = 0; alto &amp;lt; ALTO_IMAGEN; alto++)&lt;br /&gt;    {&lt;br /&gt;        for(int ancho = 0; ancho &amp;lt; ANCHO_IMAGEN; ancho++)&lt;br /&gt;        {&lt;br /&gt;            imagen.setRGB(ancho, alto, new Color((ancho*alto)%255, (ancho*alto)%255, (ancho*alto)%255, 255).getRGB());&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;        &lt;br /&gt;    ByteArrayOutputStream bytesImagen = new ByteArrayOutputStream();&lt;br /&gt;    ImageIO.write(imagen, "png", bytesImagen);&lt;br /&gt;    &lt;br /&gt;    imagenDinamica = new ByteArrayInputStream(bytesImagen.toByteArray());&lt;br /&gt;        &lt;br /&gt;    return SUCCESS;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Como ven, es más sencillo de lo que parecía ^_^.&lt;br /&gt;&lt;br /&gt;Para terminar con nuestro &lt;span class="codigo"&gt;Action&lt;/span&gt; debemos colocar las anotaciones que indican que esta clase debe ser tratada como un &lt;span class="codigo"&gt;Action&lt;/span&gt; de &lt;span class="codigo"&gt;Struts 2&lt;/span&gt;. Casi todas ya las hemos visto hasta el cansancio, por lo que solo comentaré que nuestro &lt;span class="codigo"&gt;result&lt;/span&gt; debe ser de tipo "&lt;span class="codigo"&gt;stream&lt;/span&gt;" y que le estableceremos dos parámetros: "&lt;span class="codigo"&gt;inputName&lt;/span&gt;" que indica el nombre de la propiedad de tipo "&lt;span class="codigo"&gt;InputStream&lt;/span&gt;" que contiene los bytes que serán regresados al usuario, en nuestro caso esta es "&lt;span class="codigo"&gt;imagenDinamica&lt;/span&gt;". &lt;br /&gt;&lt;br /&gt;El otro parámetro que debemos establecer es el "&lt;span class="codigo"&gt;contentType&lt;/span&gt;" que indica el formato de nuestra imagen, en este caso "&lt;span class="codigo"&gt;image/png&lt;/span&gt;". También podríamos indicar el tamaño de la imagen usando el parámetro "&lt;span class="codigo"&gt;contentLength&lt;/span&gt;", pero esto queda como ejercicio para el lector ^_^!.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Namespace(value = "/descarga")&lt;br /&gt;@Action(value = "imagenGenerada", results =&lt;br /&gt;{&lt;br /&gt;    @Result(type = "stream", params =&lt;br /&gt;    {&lt;br /&gt;        "inputName", "imagenDinamica",&lt;br /&gt;        "contentType", "image/png"&lt;br /&gt;    })&lt;br /&gt;})&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Con archivos &lt;span class="codigo"&gt;XML&lt;/span&gt; quedaría de la siguiente forma:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;result type="stream"&amp;gt;&lt;br /&gt;    &amp;lt;param name="inputName"&amp;gt;imagenDinamica&amp;lt;/param&amp;gt;&lt;br /&gt;    &amp;lt;param name="contentType"&amp;gt;application/pdf&amp;lt;/param&amp;gt;&lt;br /&gt;&amp;lt;/result&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;La clase "&lt;span class="codigo"&gt;GeneradorImagen&lt;/span&gt;" queda finalmente de la siguiente forma:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Namespace(value = "/descarga")&lt;br /&gt;@Action(value = "imagenGenerada", results =&lt;br /&gt;{&lt;br /&gt;    @Result(type = "stream", params =&lt;br /&gt;    {&lt;br /&gt;        "inputName", "imagenDinamica",&lt;br /&gt;        "contentType", "image/png"&lt;br /&gt;    })&lt;br /&gt;})&lt;br /&gt;public class GeneradorImagen extends ActionSupport&lt;br /&gt;{&lt;br /&gt;    private InputStream imagenDinamica;&lt;br /&gt;    &lt;br /&gt;    @Override&lt;br /&gt;    public String execute() throws Exception&lt;br /&gt;    {&lt;br /&gt;        final int ANCHO_IMAGEN = 260;&lt;br /&gt;        final int ALTO_IMAGEN = 130;&lt;br /&gt;        &lt;br /&gt;        BufferedImage imagen = new BufferedImage(ANCHO_IMAGEN, ALTO_IMAGEN, BufferedImage.TYPE_INT_RGB);&lt;br /&gt;        &lt;br /&gt;        for(int alto = 0; alto &amp;lt; ALTO_IMAGEN; alto++)&lt;br /&gt;        {&lt;br /&gt;            for(int ancho = 0; ancho &amp;lt; ANCHO_IMAGEN; ancho++)&lt;br /&gt;            {&lt;br /&gt;                imagen.setRGB(ancho, alto, new Color((ancho*alto)%255, (ancho*alto)%255, (ancho*alto)%255, 255).getRGB());&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        ByteArrayOutputStream bytesImagen = new ByteArrayOutputStream();&lt;br /&gt;        ImageIO.write(imagen, "png", bytesImagen);&lt;br /&gt;    &lt;br /&gt;        imagenDinamica = new ByteArrayInputStream(bytesImagen.toByteArray());&lt;br /&gt;        &lt;br /&gt;        return SUCCESS;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public InputStream getImagenDinamica()&lt;br /&gt;    {&lt;br /&gt;        return imagenDinamica;&lt;br /&gt;    }  &lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;El último paso consiste en indicar en una &lt;span class="codigo"&gt;JSP&lt;/span&gt; que debe mostrar una imagen usando este &lt;span class="codigo"&gt;Action&lt;/span&gt;. Para eso usaremos la etiqueta "&lt;span class="codigo"&gt;&amp;lt;img&amp;gt;&lt;/span&gt;" de &lt;span class="codigo"&gt;HTML&lt;/span&gt;. Para no crear una nueva &lt;span class="codigo"&gt;JSP&lt;/span&gt; colocaremos esta etiqueta en la página "&lt;span class="codigo"&gt;archivo.jsp&lt;/span&gt;" que hemos estado usando. En esta etiqueta debemos indicar que la fuente (el source) de la imagen en nuestro &lt;span class="codigo"&gt;Action&lt;/span&gt;, de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;img src="imagenGenerada.action" alt="imagen" /&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Así de simple. Ahora si volvemos a ejecutar nuestra aplicaciones, debemos ver la siguiente salida&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-rdYVTlAHYK0/TqMmYP4x5gI/AAAAAAAABOU/W6rZKp77D8g/s1600/S3_67.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="173" src="http://1.bp.blogspot.com/-rdYVTlAHYK0/TqMmYP4x5gI/AAAAAAAABOU/W6rZKp77D8g/s400/S3_67.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;No es la mejor imagen del mundo, pero es dinámica y es nuestra ^_^&lt;br /&gt;&lt;br /&gt;Con esto damos fin a este largo tutorial en el que hemos visto todo lo que debemos saber para el trabajo de formularios con &lt;span class="codigo"&gt;Struts 2&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Cualquier duda, comentario, sugerencia, aclaración o corrección pueden dejar un comentario o enviar un correo a "&lt;span class="codigo"&gt;&lt;a href="mailto:programadorjavablog@gmail.com"&gt;programadorjavablog@gmail.com&lt;/a&gt;&lt;/span&gt;".&lt;br /&gt;&lt;br /&gt;Saludos y gracias.&lt;br /&gt;&lt;br /&gt;&lt;span class="negritas"&gt;Descarga los archivos de  este tutorial desde aquí:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://sites.google.com/site/javatutoriales/struts2/TrabajoconFormularios.zip?attredirects=0&amp;d=1"&gt;&lt;span class="ligaArchivo"&gt;Trabajo con Formularios&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="negritas"&gt;Entradas Relacionadas:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.javatutoriales.com/2011/06/struts-2-parte-1-configuracion.html"&gt;Parte 1: Configuración&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.javatutoriales.com/2011/06/struts-2-parte-2-ognl.html"&gt;Parte 2: OGNL&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2012232069289957092-3346331665909045800?l=www.javatutoriales.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.javatutoriales.com/feeds/3346331665909045800/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.javatutoriales.com/2011/10/struts-2-parte-3-trabajo-con.html#comment-form' title='4 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2012232069289957092/posts/default/3346331665909045800'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2012232069289957092/posts/default/3346331665909045800'/><link rel='alternate' type='text/html' href='http://www.javatutoriales.com/2011/10/struts-2-parte-3-trabajo-con.html' title='Struts 2 - Parte 3: Trabajo con Formularios'/><author><name>Alex</name><uri>http://www.blogger.com/profile/06974037481671868076</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-Po4hsKkqMT4/TqMlyuokLQI/AAAAAAAABGM/uvgf5oYITu4/s72-c/S3_1.png' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2012232069289957092.post-4337064050189593901</id><published>2011-06-21T21:39:00.000-07:00</published><updated>2011-10-22T14:25:10.124-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='anotaciones'/><category scheme='http://www.blogger.com/atom/ns#' term='struts2'/><category scheme='http://www.blogger.com/atom/ns#' term='ognl'/><title type='text'>Struts 2 - Parte 2: OGNL</title><content type='html'>&lt;div style="text-align: justify;"&gt;&lt;span class="codigo"&gt;OGNL&lt;/span&gt; es el acrónimo de &lt;span class="codigo"&gt;Object Graph Navigation Language&lt;/span&gt;, un lenguaje de expresiones muy poderoso que nos permite leer valores de objetos Java. Este lenguaje nos permite leer valores y ejecutar métodos (que regresen algún valor) para mostrar los valores o resultados de los mismos en nuestras páginas &lt;span class="codigo"&gt;JSP&lt;/span&gt; creadas usando las etiquetas de &lt;span class="codigo"&gt;Struts&lt;/span&gt;. Además proporciona una conversión automática de tipos que permite convertir datos desde texto &lt;span class="codigo"&gt;HTTP&lt;/span&gt; a objetos Java.&lt;br /&gt;&lt;br /&gt;En este tutorial aprenderemos a usar este sencillo pero poderoso lenguaje dentro de nuestras aplicaciones, así como los objetos implícitos que tiene y cómo acceder a ellos. Además veremos cómo obtener valores de constantes, variables, y elementos enumerados, que se encuentran en nuestras clases.&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;span class="codigo"&gt;Struts&lt;/span&gt; no funciona exactamente usando una versión estándar de &lt;span class="codigo"&gt;OGNL&lt;/span&gt;, usa una versión propia a la que agrega ciertas características interesantes.&lt;br /&gt;&lt;br /&gt;&lt;span class="codigo"&gt;OGNL&lt;/span&gt; usa un contexto estándar de nombres para evaluar las expresiones, esto quiere decir que dependiendo de qué tan "&lt;span class="negritas"&gt;profundo&lt;/span&gt;" esté nuestro objeto en el grafo, podremos hacer referencia a él de distintas formas. El objeto de más alto nivel en &lt;span class="codigo"&gt;OGNL&lt;/span&gt; es un &lt;span class="codigo"&gt;Map&lt;/span&gt;, al cual llamamos "&lt;span class="negritas"&gt;mapa de contexto&lt;/span&gt;" (&lt;span class="codigo"&gt;context map&lt;/span&gt;) o simplemente "&lt;span class="negritas"&gt;contexto&lt;/span&gt;".&lt;br /&gt;&lt;br /&gt;&lt;span class="codigo"&gt;OGNL&lt;/span&gt; maneja siempre &lt;span class="negritas"&gt;un objeto raíz&lt;/span&gt; dentro del contexto. Este objeto raíz &lt;span class="negritas"&gt;es el objeto default al que se hacen las llamadas&lt;/span&gt;, a menos que se indique lo contrario. Cuando usamos una expresión, &lt;span class="negritas"&gt;las propiedades del objeto raíz pueden ser referenciadas sin ninguna marca especial&lt;/span&gt;, esto quiere decir que si nuestro objeto tiene una propiedad llamada "&lt;span class="codigo"&gt;nombre&lt;/span&gt;", hacemos referencia a él simplemente con la expresión "&lt;span class="codigo"&gt;nombre&lt;/span&gt;". Las referencias a otros objetos son marcadas con un signo de número (&lt;span class="codigo"&gt;#&lt;/span&gt;).&lt;br /&gt;&lt;br /&gt;Para entender esto veamos un ejemplo de cómo funciona esto en el &lt;span class="codigo"&gt;OGNL&lt;/span&gt; estándar. Supongamos que hay dos objetos en el mapa de contexto de &lt;span class="codigo"&gt;OGNL&lt;/span&gt;: "&lt;span class="codigo"&gt;foo&lt;/span&gt;" y "&lt;span class="codigo"&gt;bar&lt;/span&gt;", y que el objeto "&lt;span class="codigo"&gt;foo&lt;/span&gt;" &lt;span class="negritas"&gt;es el objeto raíz&lt;/span&gt;. El siguiente código muestra cómo resuelve &lt;span class="codigo"&gt;OGNL&lt;/span&gt; los valores pedidos:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;#foo.blah   //regresa foo.getBlah()&lt;br /&gt;#bar.blah   //regresa  bar.getBlah()&lt;br /&gt;blah        //regresa foo.getBlah(), porque foo es la raíz&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Esto quiere decir que &lt;span class="codigo"&gt;OGNL&lt;/span&gt; permite que haya varios objetos en el contexto, pero solo podemos acceder a los miembros del objeto raíz directamente. También es importante mencionar aquí que cuando hacemos referencia a una propiedad como "&lt;span class="codigo"&gt;blah&lt;/span&gt;", &lt;span class="codigo"&gt;OGNL&lt;/span&gt; buscará un método "&lt;span class="codigo"&gt;getBlah()&lt;/span&gt;", que regrese algún valor y no reciba parámetros, para obtener el valor que mostrará.&lt;br /&gt;&lt;br /&gt;Cuando queremos invocar métodos usamos el nombre del método junto con paréntesis, como en una invocación normal de Java. En el caso anterior pudimos haber hecho algo como lo siguiente:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;#foo.getBlah()&lt;br /&gt;#bar.getBlah()&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;En el &lt;span class="codigo"&gt;OGNL&lt;/span&gt; estándar solo se tiene una raíz, sin embargo en el &lt;span class="codigo"&gt;OGNL&lt;/span&gt; de &lt;span class="codigo"&gt;Struts&lt;/span&gt; 2 se tiene un "&lt;span class="codigo"&gt;ValueStack&lt;/span&gt;", el cual permite simular la existencia de varias raíces. Todos los objetos que pongamos en el "&lt;span class="codigo"&gt;ValueStack&lt;/span&gt;" se comportarán como la raíz del mapa de contexto.&lt;br /&gt;&lt;br /&gt;En el caso de &lt;span class="codigo"&gt;Struts&lt;/span&gt; 2, el framework establece el contexto como un objeto de tipo "&lt;span class="codigo"&gt;ActionContext&lt;/span&gt;", que es el contexto en el cual se ejecuta un Action (cada contexto es básicamente un contenedor de objetos que un Action necesita para su ejecución, como los objetos "&lt;span class="codigo"&gt;session&lt;/span&gt;", "&lt;span class="codigo"&gt;parameters&lt;/span&gt;", "&lt;span class="codigo"&gt;locale&lt;/span&gt;", etc.), y el "&lt;span class="codigo"&gt;ValueStack&lt;/span&gt;" como el objeto raíz. El "&lt;span class="codigo"&gt;ValueStack&lt;/span&gt;" es un conjunto de muchos objetos, pero para &lt;span class="codigo"&gt;OGNL&lt;/span&gt; este aparenta ser solo uno.&lt;br /&gt;&lt;br /&gt;Debido al "&lt;span class="codigo"&gt;ValueStack&lt;/span&gt;", al que algunas veces llamamos solo "&lt;span class="codigo"&gt;stack&lt;/span&gt;", en vez de que nuestras expresiones tengan que obtener el objeto que queremos del &lt;span class="codigo"&gt;stack&lt;/span&gt; y después obtener las propiedades de él (como en el ejemplo de &lt;span class="codigo"&gt;#bar.blah&lt;/span&gt;), el &lt;span class="codigo"&gt;OGNL&lt;/span&gt; de &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; tiene un "&lt;span class="codigo"&gt;PropertyAccessor&lt;/span&gt;" especial que buscará automáticamente en todos los objetos del &lt;span class="codigo"&gt;stack&lt;/span&gt; (de arriba a abajo) hasta que encuentre un objeto con la propiedad que estamos buscando.&lt;br /&gt;&lt;br /&gt;Siempre que &lt;span class="codigo"&gt;Struts&lt;/span&gt; 2 ejecuta uno de nuestros Actions, los coloca en la cima del &lt;span class="codigo"&gt;stack&lt;/span&gt;, es por eso que en &lt;a href="http://www.javatutoriales.com/2011/06/struts-2-parte-1-configuracion.html"&gt;el tutorial anterior&lt;/a&gt; hacíamos referencia a la propiedad llamada "&lt;span class="codigo"&gt;mensaje&lt;/span&gt;", del Action correspondiente, solamente indicando el nombre de la propiedad. &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; busca en el &lt;span class="codigo"&gt;stack&lt;/span&gt; un objeto que tenga un &lt;span class="codigo"&gt;getter&lt;/span&gt; para esa propiedad, en este caso nuestro Action.&lt;br /&gt;&lt;br /&gt;Veamos otro ejemplo. Supongamos que el &lt;span class="codigo"&gt;stack&lt;/span&gt; contiene dos objetos: "&lt;span class="codigo"&gt;Animal&lt;/span&gt;" y "&lt;span class="codigo"&gt;Persona&lt;/span&gt;". Ambos objetos tienen una propiedad "&lt;span class="codigo"&gt;nombre&lt;/span&gt;", "&lt;span class="codigo"&gt;Animal&lt;/span&gt;" tiene una propiedad "&lt;span class="codigo"&gt;raza&lt;/span&gt;", y "&lt;span class="codigo"&gt;Persona&lt;/span&gt;" tiene una propiedad "&lt;span class="codigo"&gt;salario&lt;/span&gt;". "&lt;span class="codigo"&gt;Animal&lt;/span&gt;" está en la cima del &lt;span class="codigo"&gt;stack&lt;/span&gt;, y "&lt;span class="codigo"&gt;Persona&lt;/span&gt;" está debajo de él. Si hacemos llamadas simples, como las mostradas a continuación, &lt;span class="codigo"&gt;OGNL&lt;/span&gt; resuelve los valores de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;raza     //llama a animal.getRaza()&lt;br /&gt;salario  //llama a persona.getSalario()&lt;br /&gt;nombre   //llama a animal.getNombre(), porque animal está en la cima del stack&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;En el ejemplo anterior, se regresó el valor del "&lt;span class="codigo"&gt;nombre&lt;/span&gt;" del &lt;span class="codigo"&gt;Animal&lt;/span&gt;, que está en la cima del &lt;span class="codigo"&gt;stack&lt;/span&gt;. Normalmente este es el comportamiento deseado, pero algunas veces nos interesa recuperar el valor de la propiedad de un objeto que se encuentra más abajo en el &lt;span class="codigo"&gt;stack&lt;/span&gt;. Para hacer esto, &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; agrega soporte para índices en el &lt;span class="codigo"&gt;ValueStack&lt;/span&gt;. Todo lo que debemos hacer es:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;[0].nombre  //llama a animal.getNombre()&lt;br /&gt;[1].nombre  //llama a persona.getNombre()&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Con esto le indicamos a &lt;span class="codigo"&gt;OGNL&lt;/span&gt; a partir de cuál índice queremos que inicie la búsqueda (digamos que cortamos el &lt;span class="codigo"&gt;stack&lt;/span&gt; a partir del índice que le indicamos).&lt;br /&gt;&lt;br /&gt;Suficiente teoría &lt;span class="codigo"&gt;:D&lt;/span&gt;. Comencemos a ver lo anterior en código. Crearemos un nuevo proyecto web en &lt;span class="codigo"&gt;NetBeans&lt;/span&gt;. Para esto vamos al menú "&lt;span class="codigo"&gt;File -&amp;gt; New Project...&lt;/span&gt;". En la ventana que aparece seleccionamos la categoría "&lt;span class="codigo"&gt;Java Web&lt;/span&gt;" y en el tipo de proyecto "&lt;span class="codigo"&gt;Web Application&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-STpJLGVGZNM/TgFqJZAemsI/AAAAAAAAAC4/hM0EvKVJw8k/s1600/S2_1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="273" src="http://2.bp.blogspot.com/-STpJLGVGZNM/TgFqJZAemsI/AAAAAAAAAC4/hM0EvKVJw8k/s400/S2_1.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Presionamos el botón "&lt;span class="codigo"&gt;Next &amp;gt;&lt;/span&gt;" y le damos un nombre y una ubicación a nuestro proyecto; presionamos nuevamente el botón "&lt;span class="codigo"&gt;Next &amp;gt;&lt;/span&gt;" y en este punto se nos preguntará el servidor  que queremos usar. En nuestro caso usaremos el servidor "&lt;span class="codigo"&gt;Tomcat 7.0&lt;/span&gt;", con la versión 5 de JEE y presionamos el botón "&lt;span class="codigo"&gt;Finish&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-_dxbXz05qF4/TgFqKCA6M5I/AAAAAAAAAC8/aRa_MYwNXYU/s1600/S2_2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="255" src="http://3.bp.blogspot.com/-_dxbXz05qF4/TgFqKCA6M5I/AAAAAAAAAC8/aRa_MYwNXYU/s400/S2_2.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Con esto aparecerá en nuestro editor una página "&lt;span class="codigo"&gt;index.jsp&lt;/span&gt;".&lt;br /&gt;&lt;br /&gt;Ahora agregamos la librería "&lt;span class="codigo"&gt;Struts2Anotaciones&lt;/span&gt;" que creamos en &lt;a href="http://www.javatutoriales.com/2011/06/struts-2-parte-1-configuracion.html"&gt;el tutorial anterior&lt;/a&gt;. Hacemos clic derecho en el nodo "&lt;span class="codigo"&gt;Libraries&lt;/span&gt;" del panel de proyectos. En el menú que aparece seleccionamos la opción "&lt;span class="codigo"&gt;Add Library...&lt;/span&gt;". En la ventana que aparece seleccionamos la biblioteca "&lt;span class="codigo"&gt;Struts2Anotaciones&lt;/span&gt;" y presionamos "&lt;span class="codigo"&gt;Add Library&lt;/span&gt;". Con esto ya tendremos los jars de &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; en nuestro proyecto:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-75UKXHjDxIU/TgFqKrUN5OI/AAAAAAAAADA/RShugq1zahY/s1600/S2_3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="296" src="http://2.bp.blogspot.com/-75UKXHjDxIU/TgFqKrUN5OI/AAAAAAAAADA/RShugq1zahY/s320/S2_3.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Finalmente abrimos el archivo "&lt;span class="codigo"&gt;web.xml&lt;/span&gt;" y agregamos la configuración del filtro de &lt;span class="codigo"&gt;Struts 2&lt;/span&gt;, de la misma forma que lo hicimos en &lt;a href="http://www.javatutoriales.com/2011/06/struts-2-parte-1-configuracion.html"&gt;el tutorial anterior&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;filter&amp;gt;&lt;br /&gt;    &amp;lt;filter-name&amp;gt;struts2&amp;lt;/filter-name&amp;gt;&lt;br /&gt;    &amp;lt;filter-class&amp;gt;org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter&amp;lt;/filter-class&amp;gt;&lt;br /&gt;&amp;lt;/filter&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;filter-mapping&amp;gt;&lt;br /&gt;    &amp;lt;filter-name&amp;gt;struts2&amp;lt;/filter-name&amp;gt;&lt;br /&gt;    &amp;lt;url-pattern&amp;gt;/*&amp;lt;/url-pattern&amp;gt;&lt;br /&gt;&amp;lt;/filter-mapping&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ya tenemos todo listo para comenzar. Lo primero que haremos en este ejemplo es crear un paquete que contendrá nuestras clases "&lt;span class="codigo"&gt;Animal&lt;/span&gt;" y "&lt;span class="codigo"&gt;Persona&lt;/span&gt;". En mi caso el paquete se llamará "&lt;span class="codigo"&gt;com.javatutoriales.struts2.ognl.modelo&lt;/span&gt;". En el agregamos dos clases: "&lt;span class="codigo"&gt;Animal&lt;/span&gt;" y "&lt;span class="codigo"&gt;Persona&lt;/span&gt;".&lt;br /&gt;&lt;br /&gt;La clase "&lt;span class="codigo"&gt;Animal&lt;/span&gt;" tendrá, como habíamos dicho, dos atributos de tipo &lt;span class="codigo"&gt;String&lt;/span&gt;: "&lt;span class="codigo"&gt;nombre&lt;/span&gt;" y "&lt;span class="codigo"&gt;raza&lt;/span&gt;", con sus correspondientes &lt;span class="codigo"&gt;setters&lt;/span&gt; y &lt;span class="codigo"&gt;getters&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class Animal&lt;br /&gt;{&lt;br /&gt;    private String nombre;&lt;br /&gt;    private String raza;&lt;br /&gt;&lt;br /&gt;    public String getNombre()&lt;br /&gt;    {&lt;br /&gt;        return nombre;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setNombre(String nombre)&lt;br /&gt;    {&lt;br /&gt;        this.nombre = nombre;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public String getRaza()&lt;br /&gt;    {&lt;br /&gt;        return raza;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setRaza(String raza)&lt;br /&gt;    {&lt;br /&gt;        this.raza = raza;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;La clase "&lt;span class="codigo"&gt;Persona&lt;/span&gt;" también contendrá dos atributos de tipo &lt;span class="codigo"&gt;String&lt;/span&gt;: "&lt;span class="codigo"&gt;nombre&lt;/span&gt;" y "&lt;span class="codigo"&gt;salario&lt;/span&gt;", con sus correspondientes &lt;span class="codigo"&gt;setters&lt;/span&gt; y &lt;span class="codigo"&gt;getters&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class Persona&lt;br /&gt;{&lt;br /&gt;    private String nombre;&lt;br /&gt;    private String salario;&lt;br /&gt;&lt;br /&gt;    public String getNombre()&lt;br /&gt;    {&lt;br /&gt;        return nombre;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setNombre(String nombre)&lt;br /&gt;    {&lt;br /&gt;        this.nombre = nombre;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public String getSalario()&lt;br /&gt;    {&lt;br /&gt;        return salario;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setSalario(String salario)&lt;br /&gt;    {&lt;br /&gt;        this.salario = salario;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ahora crearemos el Action que se encargará de poner una instancia de cada una de estas clases en el "&lt;span class="codigo"&gt;ValueStack&lt;/span&gt;". Creamos una nueva clase llamada "&lt;span class="codigo"&gt;StackAction&lt;/span&gt;" y hacemos que esta extienda de "&lt;span class="codigo"&gt;ActionSupport&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class StackAction extends ActionSupport&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Agregamos las anotaciones correspondientes, y que explicamos en el tutorial anterior. Haremos que este Action responda al nombre de "&lt;span class="codigo"&gt;stack&lt;/span&gt;" y que nos envíe a una página llamada"&lt;span class="codigo"&gt;/stack.jsp&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Namespace(value="/")&lt;br /&gt;@Action(value="stack", results={@Result(location="/stack.jsp")})&lt;br /&gt;public class StackAction extends ActionSupport&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Lo siguiente que haremos es sobre-escribir el método "&lt;span class="codigo"&gt;execute&lt;/span&gt;" del Action para obtener una referencia al &lt;span class="codigo"&gt;ValueStack&lt;/span&gt;. La forma de hacer esto último es a través de un método estático de la clase "&lt;span class="codigo"&gt;ActionContext&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Override&lt;br /&gt;public String execute() throws Exception&lt;br /&gt;{&lt;br /&gt;    ValueStack stack = ActionContext.getContext().getValueStack();&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Una vez que tenemos esta referencia solo nos resta crear una instancia de cada una de nuestras clases, establecer los valores de sus parámetros, y agregarlos al &lt;span class="codigo"&gt;ValueStack&lt;/span&gt; usando su método "&lt;span class="codigo"&gt;push&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Override&lt;br /&gt;public String execute() throws Exception&lt;br /&gt;{&lt;br /&gt;    ValueStack stack = ActionContext.getContext().getValueStack();&lt;br /&gt;&lt;br /&gt;    Animal animal = new Animal();&lt;br /&gt;    animal.setNombre("nombre del animal");&lt;br /&gt;    animal.setRaza("perro labrador");&lt;br /&gt;&lt;br /&gt;    Persona persona = new Persona();&lt;br /&gt;    persona.setNombre("nombre de la persona");&lt;br /&gt;    persona.setSalario("realmente poco");&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    stack.push(persona);&lt;br /&gt;    stack.push(animal);&lt;br /&gt;&lt;br /&gt;    return SUCCESS;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="nota"&gt;Nota: Por lo regular no agregamos objetos al &lt;span class="codigo"&gt;stack&lt;/span&gt; de forma manual como lo estamos haciendo para este ejemplo, dejamos que sea &lt;span class="codigo"&gt;Struts&lt;/span&gt; quien agregue los objetos necesarios de forma automática. Esto solo lo hacemos en casos en los que no queda otra opción... como en este ejemplo ^_^!&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Agregamos primero la referencia de la &lt;span class="codigo"&gt;Persona&lt;/span&gt; y luego la del &lt;span class="codigo"&gt;Animal&lt;/span&gt; porque, como en toda buena pila, el último elemento que se agregue al &lt;span class="codigo"&gt;ValueStack&lt;/span&gt; será el que quede en su cima.&lt;br /&gt;&lt;br /&gt;Ahora creamos la página "&lt;span class="codigo"&gt;stack.jsp&lt;/span&gt;" en el directorio raíz de las páginas web. En esta página indicamos que se usará la biblioteca de etiquetas de &lt;span class="codigo"&gt;Struts 2&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;%@taglib uri="/struts-tags" prefix="s" %&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Usando la etiqueta "&lt;span class="codigo"&gt;&amp;lt;s:property&amp;gt;&lt;/span&gt;" mostraremos los valores de "&lt;span class="codigo"&gt;raza&lt;/span&gt;", "&lt;span class="codigo"&gt;salario&lt;/span&gt;", y "&lt;span class="codigo"&gt;nombre&lt;/span&gt;". Al colocarlos de esta forma, &lt;span class="codigo"&gt;Struts&lt;/span&gt; buscará estos valores en todos los objetos que estén en el &lt;span class="codigo"&gt;ValueStack&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;ul&amp;gt;&lt;br /&gt;    &amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;Raza: &amp;lt;/strong&amp;gt; &amp;lt;s:property value="raza" /&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;    &amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;Salario: &amp;lt;/strong&amp;gt; &amp;lt;s:property value="salario" /&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;    &amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;Nombre: &amp;lt;/strong&amp;gt; &amp;lt;s:property value="nombre" /&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;&amp;lt;/ul&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ya está todo listo para correr el ejemplo. Ejecutamos nuestra aplicación, y entramos a la siguiente dirección:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&lt;a href="http://localhost:8080/ognl/stack.action"&gt;http://localhost:8080/ognl/stack.action&lt;/a&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Deberemos ver una pantalla como la siguiente:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-b_WqRZGeTl0/TgFqLVsWICI/AAAAAAAAADE/N86-IfvBxDU/s1600/S2_4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="242" src="http://2.bp.blogspot.com/-b_WqRZGeTl0/TgFqLVsWICI/AAAAAAAAADE/N86-IfvBxDU/s400/S2_4.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Como podemos ver, la teoría es correcta ^_^. Al buscar la propiedad "&lt;span class="codigo"&gt;raza&lt;/span&gt;", la encuentra en el objeto tipo "&lt;span class="codigo"&gt;Animal&lt;/span&gt;", mostrando el valor de la misma; cuando busca la propiedad salario la encuentra en el objeto de tipo "&lt;span class="codigo"&gt;Persona&lt;/span&gt;"; y al buscar la propiedad "&lt;span class="codigo"&gt;nombre&lt;/span&gt;", que tienen ambos objetos, muestra el valor del objeto que se encuentra en la cima del &lt;span class="codigo"&gt;stack&lt;/span&gt;, o sea el de "&lt;span class="codigo"&gt;Animal&lt;/span&gt;".&lt;br /&gt;&lt;br /&gt;Ahora hagamos una segunda prueba haciendo uso de los índices del &lt;span class="codigo"&gt;ValueStack&lt;/span&gt;. Agreguemos las instrucciones que habíamos visto anteriormente: ("&lt;span class="codigo"&gt;[0].nombre&lt;/span&gt;" y "&lt;span class="codigo"&gt;[1].nombre&lt;/span&gt;") usando la etiqueta "&lt;span class="codigo"&gt;s:property&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;ul&amp;gt;&lt;br /&gt;    &amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;Animal:  &amp;lt;/strong&amp;gt;&amp;lt;s:property value="[0].nombre" /&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;    &amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;Persona: &amp;lt;/strong&amp;gt;&amp;lt;s:property value="[1].nombre" /&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;&amp;lt;/ul&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Si volvemos a ejecutar nuestra aplicación veremos la siguiente salida:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-rAiVwVl-ROA/TgFqMvx3OWI/AAAAAAAAADI/za68fN6RI70/s1600/S2_5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="242" src="http://2.bp.blogspot.com/-rAiVwVl-ROA/TgFqMvx3OWI/AAAAAAAAADI/za68fN6RI70/s400/S2_5.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Como podemos ver, efectivamente, el uso de índices permite que seleccionemos valores de objetos que se encuentran a una profundidad mayor en el &lt;span class="codigo"&gt;ValueStack&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Solo para recordar. Cuando &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; ejecuta un Action como consecuencia de una petición, este action es colocado en la cima del &lt;span class="codigo"&gt;ValueStack&lt;/span&gt;, es por esto que podemos acceder a sus atributos haciendo una llamada directa al nombre del mismo, como lo hicimos en &lt;a href="http://www.javatutoriales.com/2011/06/struts-2-parte-1-configuracion.html"&gt;el tutorial anterior&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Hagamos nuevamente una prueba para explicar un poco más en detalle lo que ocurre en ese caso. Primero crearemos una clase llamada "&lt;span class="codigo"&gt;SaludoAction&lt;/span&gt;", la cual será igual a la &lt;a href="http://www.javatutoriales.com/2011/06/struts-2-parte-1-configuracion.html"&gt;del tutorial anterior&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Namespace("/")&lt;br /&gt;@Action(value = "saludo", results ={@Result(location = "/saludo.jsp")})&lt;br /&gt;public class SaludoAction extends ActionSupport&lt;br /&gt;{&lt;br /&gt;    private String mensaje;&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    public String execute() throws Exception&lt;br /&gt;    {&lt;br /&gt;        mensaje = "Hola Mundo!!";&lt;br /&gt;&lt;br /&gt;        return SUCCESS;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public String getMensaje()&lt;br /&gt;    {&lt;br /&gt;        return mensaje;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;En este caso nuestro Action tiene un atributo "&lt;span class="codigo"&gt;mensaje&lt;/span&gt;" que en el método "&lt;span class="codigo"&gt;execute&lt;/span&gt;" será establecido con un valor. También se proporciona un &lt;span class="codigo"&gt;getter&lt;/span&gt; para este atributo.&lt;br /&gt;&lt;br /&gt;Crearemos una página &lt;span class="codigo"&gt;JSP&lt;/span&gt; llamada "&lt;span class="codigo"&gt;saludo.jsp&lt;/span&gt;", en la raíz de las páginas web de la aplicación. En esta página mostraremos el valor del atributo "&lt;span class="codigo"&gt;mensaje&lt;/span&gt;" usando la biblioteca de etiquetas de &lt;span class="codigo"&gt;Struts 2&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:property value="mensaje" /&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ejecutamos la aplicación, y al acceder a la siguiente dirección:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&lt;a href="http://localhost:8080/ognl/saludo.action"&gt;http://localhost:8080/ognl/saludo.action&lt;/a&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Debemos ver la siguiente página:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-QX_um4X8pWk/TgFqNSWSt8I/AAAAAAAAADM/qKUZpBz49xU/s1600/S2_6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="242" src="http://4.bp.blogspot.com/-QX_um4X8pWk/TgFqNSWSt8I/AAAAAAAAADM/qKUZpBz49xU/s400/S2_6.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Una vez más, solo para que quede claro. Cuando realizamos una petición para el Action, el &lt;span class="codigo"&gt;DispatcherFilter&lt;/span&gt; ejecutará el método "&lt;span class="codigo"&gt;execute&lt;/span&gt;" del Action, después colocará este Action en la cima del &lt;span class="codigo"&gt;ValueStack&lt;/span&gt; con lo cual lo tendremos disponible.&lt;br /&gt;&lt;br /&gt;Cuando hacemos la petición para el atributo "&lt;span class="codigo"&gt;mensaje&lt;/span&gt;", usando la etiqueta "&lt;span class="codigo"&gt;s:property&lt;/span&gt;", &lt;span class="codigo"&gt;Struts&lt;/span&gt; busca en el &lt;span class="codigo"&gt;ValueStack&lt;/span&gt;, de arriba a abajo, un objeto que tenga un método "&lt;span class="codigo"&gt;getMensaje()&lt;/span&gt;". Como el primer objeto que encuentra con el método "&lt;span class="codigo"&gt;getMensaje()&lt;/span&gt;" es "&lt;span class="codigo"&gt;SaludoAction&lt;/span&gt;" (de hecho es el primer objeto en el que busca)  ejecuta este método mostrando el valor correspondiente mostrando la pantalla que vimos anteriormente.&lt;br /&gt;&lt;br /&gt;Además del &lt;span class="codigo"&gt;ValueStack&lt;/span&gt;, &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; coloca otros objetos en el &lt;span class="codigo"&gt;ActionContext&lt;/span&gt;, incluyendo &lt;span class="codigo"&gt;Map&lt;/span&gt;s que representan los contextos de "&lt;span class="codigo"&gt;application&lt;/span&gt;", "&lt;span class="codigo"&gt;session&lt;/span&gt;", y "&lt;span class="codigo"&gt;request&lt;/span&gt;". Una representación de esto puede verse en la siguiente imagen:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-PF0PlW1j5vg/TgFqN-0bMWI/AAAAAAAAADQ/Jvaf1xs3dMw/s1600/S2_7.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="156" src="http://3.bp.blogspot.com/-PF0PlW1j5vg/TgFqN-0bMWI/AAAAAAAAADQ/Jvaf1xs3dMw/s640/S2_7.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Recuerden que para hacer referencia a los objetos del contexto que NO son la raíz &lt;span class="negritas"&gt;debemos preceder el nombre del objeto con el símbolo de gato (&lt;span class="codigo"&gt;#&lt;/span&gt;)&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Hablaré brevemente de estos objetos:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;"&lt;span class="codigo"&gt;application&lt;/span&gt;" representa el &lt;span class="codigo"&gt;ApplicationContext&lt;/span&gt;, o sea, el contexto completo de la aplicación.&lt;/li&gt;&lt;li&gt;"&lt;span class="codigo"&gt;session&lt;/span&gt;" representa el &lt;span class="codigo"&gt;HTTPSession&lt;/span&gt;, o sea, la sesión del usuario.&lt;/li&gt;&lt;li&gt;"&lt;span class="codigo"&gt;request&lt;/span&gt;" representa el &lt;span class="codigo"&gt;ServletRequest&lt;/span&gt;, o sea, la petición que se está sirviendo.&lt;/li&gt;&lt;li&gt;"&lt;span class="codigo"&gt;parameters&lt;/span&gt;" representa los parámetros que son enviados en la petición, ya sea por &lt;span class="codigo"&gt;GET&lt;/span&gt; o por &lt;span class="codigo"&gt;POST&lt;/span&gt;.&lt;/li&gt;&lt;li&gt;"&lt;span class="codigo"&gt;attr&lt;/span&gt;" representa los atributos de los objetos implícitos. Cuando preguntamos por un atributo, usando "&lt;span class="codigo"&gt;attr&lt;/span&gt;", este busca el atributo en los siguientes scopes: &lt;span class="codigo"&gt;page&lt;/span&gt;, &lt;span class="codigo"&gt;request&lt;/span&gt;, &lt;span class="codigo"&gt;session&lt;/span&gt;, &lt;span class="codigo"&gt;application&lt;/span&gt;. Si lo encuentra, regresa el valor del atributo y no continúa con la búsqueda, sino regresa un valor nulo.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Veamos un ejemplo de esto. No entraré en muchos detalles sobre el manejo de la sesión ya que eso lo dejaré para el próximo tutorial.&lt;br /&gt;&lt;br /&gt;Creamos una nueva clase Java llamada "&lt;span class="codigo"&gt;DatosAction&lt;/span&gt;" que extienda de "&lt;span class="codigo"&gt;ActionSupport&lt;/span&gt;". Colocaremos algunas anotaciones para la configuración de &lt;span class="codigo"&gt;Struts 2&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Namespace(value = "/")&lt;br /&gt;@Action(value = "datos", results ={@Result(location = "/datos.jsp")})&lt;br /&gt;public class DatosAction extends ActionSupport&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Sobre-escribimos el método "&lt;span class="codigo"&gt;execute&lt;/span&gt;" de esta clase para obtener el &lt;span class="codigo"&gt;ActionContext&lt;/span&gt;. Una vez teniendo este contexto podemos obtener la sesión y podemos agregar objetos a ella. En este caso agregaré una cadena solo para poder obtenerla después:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;@Override&lt;br /&gt;public String execute() throws Exception&lt;br /&gt;{&lt;br /&gt;   ActionContext.getContext().getSession().put("datoSesion", "dato en la sesion");&lt;br /&gt;&lt;br /&gt;   return SUCCESS;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ahora creamos una &lt;span class="codigo"&gt;JSP&lt;/span&gt; llamada "&lt;span class="codigo"&gt;datos.jsp&lt;/span&gt;" en el directorio raíz de las páginas web. En esta página indicaremos que usaremos la biblioteca de etiquetas de &lt;span class="codigo"&gt;Struts 2&lt;/span&gt;; y obtendremos, usando la etiqueta "&lt;span class="codigo"&gt;&amp;lt;s:property&amp;gt;&lt;/span&gt;", el valor del atributo "&lt;span class="codigo"&gt;datoSesion&lt;/span&gt;" que colocamos en la sesión del usuario.&lt;br /&gt;&lt;br /&gt;Como el objeto "&lt;span class="codigo"&gt;session&lt;/span&gt;" no es la raíz del mapa de contexto, es necesario hacer referencia a él de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;#session&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Y podemos obtener cualquiera de sus atributos mediante el nombre del atributo. Por lo que la etiqueta queda de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:property value="#session.datoSesion" /&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;También podemos hacerlo de esta otra forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:property value="#session['datoSesion']" /&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Cuando ejecutemos la aplicación debemos ver la siguiente salida:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-NYtQhrhl3rs/TgFqOkoRgoI/AAAAAAAAADU/V_bGXSH4LPg/s1600/S2_8.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="242" src="http://3.bp.blogspot.com/-NYtQhrhl3rs/TgFqOkoRgoI/AAAAAAAAADU/V_bGXSH4LPg/s400/S2_8.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Ahora, dijimos que "&lt;span class="codigo"&gt;parameters&lt;/span&gt;" representa los parámetros que se reciben, ya sea por &lt;span class="codigo"&gt;GET&lt;/span&gt; o por &lt;span class="codigo"&gt;POST&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Colocaremos una etiqueta para obtener el valor de un parámetro llamado dato:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:property value="#parameters.dato" /&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Y accedemos a la siguiente &lt;span class="codigo"&gt;URL&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&lt;a href="http://localhost:8080/ognl/datos.action?dato=Alex"&gt;http://localhost:8080/ognl/datos.action?dato=Alex&lt;/a&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;En donde estamos pasando, por &lt;span class="codigo"&gt;GET&lt;/span&gt;, un parámetro llamado "&lt;span class="codigo"&gt;dato&lt;/span&gt;" igualado al valor "&lt;span class="codigo"&gt;Alex&lt;/span&gt;". Cuando entremos en la dirección anterior veremos una pantalla como la siguiente:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-vX1ZbUnhl_U/TgFqPhJJ3fI/AAAAAAAAADY/pj20L8udt0A/s1600/S2_9.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="242" src="http://4.bp.blogspot.com/-vX1ZbUnhl_U/TgFqPhJJ3fI/AAAAAAAAADY/pj20L8udt0A/s400/S2_9.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Si ahora, usamos el objeto "&lt;span class="codigo"&gt;attr&lt;/span&gt;" para buscar el valor del atributo "&lt;span class="codigo"&gt;datoSesion&lt;/span&gt;", de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:property value="#attr.datoSesion" /&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Obtendremos la siguiente pantalla:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-PPl6o6uj3lU/TgFqQX_PFsI/AAAAAAAAADc/_ObzJeo22qc/s1600/S2_10.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="242" src="http://3.bp.blogspot.com/-PPl6o6uj3lU/TgFqQX_PFsI/AAAAAAAAADc/_ObzJeo22qc/s400/S2_10.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Con &lt;span class="codigo"&gt;OGNL&lt;/span&gt; no solo es posible acceder a los objetos dentro del &lt;span class="codigo"&gt;ActionContext&lt;/span&gt;, sino prácticamente a cualquier objeto java que sea visible. Para ilustrar esto veamos otro ejemplo.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="titulo"&gt;Obteniendo Valores de Constantes y Variables con &lt;span class="codigo"&gt;OGNL&lt;/span&gt;&lt;/h2&gt;Primero crearemos una nueva clase Java que contendrá una serie de atributos, métodos, y constantes. La clase se llamará "&lt;span class="codigo"&gt;Constantes&lt;/span&gt;" (aunque también contendrá valores variables). Esta clase tendrá una variable de instancia llamada "&lt;span class="codigo"&gt;atributo&lt;/span&gt;" (con su correspondiente &lt;span class="codigo"&gt;getter&lt;/span&gt;), una constante llamada "&lt;span class="codigo"&gt;valor&lt;/span&gt;", y una enumeración llamada "&lt;span class="codigo"&gt;Datos&lt;/span&gt;" que tendrá un método "&lt;span class="codigo"&gt;getDato()&lt;/span&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class Constantes&lt;br /&gt;{&lt;br /&gt;    private String atributo = "atributo de instancia";&lt;br /&gt;    public final static String valor = "variable estatica";&lt;br /&gt;&lt;br /&gt;    private static enum Datos {PRIMERO, SEGUNDO, TERCERO; public String getDato(){ return "dato";} };&lt;br /&gt;&lt;br /&gt;    public String getAtributo()&lt;br /&gt;    {&lt;br /&gt;        return atributo;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Sé que el atributo "&lt;span class="codigo"&gt;valor&lt;/span&gt;" no sigue la convención de las constantes de Java, pero colocarla de esta forma ayudará a hacer las explicaciones más sencillas ^_^.&lt;br /&gt;&lt;br /&gt;Ahora, para que las cosas sean un poco más interesantes, agregaremos unos cuantos métodos.&lt;br /&gt;&lt;br /&gt;Primero agregaremos un método de instancia que regrese una cadena y no reciba parámetros; y una versión sobrecargada de este método que reciba una cadena:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public String metodoDeInstancia()&lt;br /&gt;{&lt;br /&gt;    return "metodo de instancia";&lt;br /&gt;}&lt;br /&gt;    &lt;br /&gt;public String metodoDeInstancia(String mensaje)&lt;br /&gt;{&lt;br /&gt;    return mensaje;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Agregaremos también las versiones estáticas de estos métodos:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public static String metodoEstatico()&lt;br /&gt;{&lt;br /&gt;    return "metodo estatico";&lt;br /&gt;}&lt;br /&gt;    &lt;br /&gt;public static String metodoEstatico(String mensaje)&lt;br /&gt;{&lt;br /&gt;    return mensaje;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;La clase "&lt;span class="codigo"&gt;Constantes&lt;/span&gt;" completa queda de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class Constantes&lt;br /&gt;{&lt;br /&gt;    private String atributo = "atributo de instancia";&lt;br /&gt;    public final static String valor = "variable estatica";&lt;br /&gt;&lt;br /&gt;    private static enum Datos {PRIMERO, SEGUNDO, TERCERO; public String getDato(){ return "dato";} };&lt;br /&gt;    &lt;br /&gt;    public String metodoDeInstancia()&lt;br /&gt;    {&lt;br /&gt;        return "metodo de instancia";&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    public String metodoDeInstancia(String mensaje)&lt;br /&gt;    {&lt;br /&gt;        return mensaje;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    public static String metodoEstatico()&lt;br /&gt;    {&lt;br /&gt;        return "metodo estatico";&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    public static String metodoEstatico(String mensaje)&lt;br /&gt;    {&lt;br /&gt;        return mensaje;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    public String getAtributo()&lt;br /&gt;    {&lt;br /&gt;        return atributo;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Como podemos ver, esta clase no tiene nada de especial: ninguna anotación, no usa ninguna librería, ni nada por el estilo.&lt;br /&gt;&lt;br /&gt;Ahora creamos una página llamada "&lt;span class="codigo"&gt;constantes.jsp&lt;/span&gt;", en el directorio raíz de las páginas web.&lt;br /&gt;&lt;br /&gt;Para crear un objeto nuevo con &lt;span class="codigo"&gt;OGNL&lt;/span&gt; podemos usar el operador "&lt;span class="codigo"&gt;new&lt;/span&gt;" y el "fully qualified class name". Por ejemplo, para crear un nuevo objeto de la clase "&lt;span class="codigo"&gt;Constantes&lt;/span&gt;" haríamos lo siguiente:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:property value="new com.javatutoriales.struts2.ognl.Constantes()" /&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Teniendo esta instancia podemos obtener los valores de los atributos del objeto e invocar sus métodos, como lo haríamos en un objeto normal. Por ejemplo, para obtener el valor del atributo "&lt;span class="codigo"&gt;atributo&lt;/span&gt;" se puede hacer de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:property value="new com.javatutoriales.struts2.ognl.Constantes().atributo" /&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Con esto, si entramos a la siguiente dirección:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&lt;a href="http://localhost:8080/ognl/constantes.jsp"&gt;http://localhost:8080/ognl/constantes.jsp&lt;/a&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Obtenemos la siguiente pantalla:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-ou6gzFhC2ko/TgFqRN5cqNI/AAAAAAAAADg/BKjzUytyw98/s1600/S2_11.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="242" src="http://2.bp.blogspot.com/-ou6gzFhC2ko/TgFqRN5cqNI/AAAAAAAAADg/BKjzUytyw98/s400/S2_11.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Para invocar un método de instancia se hace de la misma forma (no olviden colocar los paréntesis al final):&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:property value="new com.javatutoriales.struts2.ognl.Constantes().metodoDeInstancia()" /&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Con esto, obtenemos la siguiente pantalla:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-uhc--nDRL6o/TgFqR0LsgcI/AAAAAAAAADk/JkWeCp88EqM/s1600/S2_12.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="242" src="http://4.bp.blogspot.com/-uhc--nDRL6o/TgFqR0LsgcI/AAAAAAAAADk/JkWeCp88EqM/s400/S2_12.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Podemos invocar los miembros estáticas exactamente de la misma forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:property value="new com.javatutoriales.struts2.ognl.Constantes().metodoEstatico()" /&amp;gt;&lt;br /&gt;&amp;lt;s:property value="new com.javatutoriales.struts2.ognl.Constantes().valor" /&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Con esto obtenemos la siguiente pantalla:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-d5M5SpAtFrg/TgFqSrJgKLI/AAAAAAAAADo/JaZ8iShJFYU/s1600/S2_13.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="242" src="http://3.bp.blogspot.com/-d5M5SpAtFrg/TgFqSrJgKLI/AAAAAAAAADo/JaZ8iShJFYU/s400/S2_13.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;El valor de la constante "&lt;span class="codigo"&gt;valor&lt;/span&gt;" no se muestra, porque recuerden que cuando llamamos a los atributos de esta forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:property value="new com.javatutoriales.struts2.ognl.Constantes().valor" /&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="codigo"&gt;OGNL&lt;/span&gt; busca un método llamado "&lt;span class="codigo"&gt;getValor()&lt;/span&gt;" en la clase "&lt;span class="codigo"&gt;Constantes&lt;/span&gt;", y este método no existe.&lt;br /&gt;&lt;br /&gt;Ahora bien, una de las características de los miembros estáticos es que no es necesario tener una instancia de la clase en la que existe el miembro para poder llamar a estos miembros, pero aquí estamos creando una nueva instancia de las clases para llamarlos. También es posible hacer estas llamadas sin una instancia de la clase. En este caso debemos usar una notación especial de &lt;span class="codigo"&gt;OGNL&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;En esta notación, debemos indicar el nombre completo de la clase que contiene al miembro estático, precedida por una arroba ("&lt;span class="codigo"&gt;@&lt;/span&gt;"). También se debe indicar el miembro que se quiere llamar precedido por una arroba.&lt;br /&gt;&lt;br /&gt;Por ejemplo, para usar la constante "&lt;span class="codigo"&gt;valor&lt;/span&gt;", la etiqueta debe estar colocada de esta forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:property value="@com.javatutoriales.struts2.ognl.Constantes@valor" /&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Con lo que obtenemos:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-j9lCByOQmWM/TgFqTZD3MUI/AAAAAAAAADs/lN5K-iwrllU/s1600/S2_14.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="242" src="http://1.bp.blogspot.com/-j9lCByOQmWM/TgFqTZD3MUI/AAAAAAAAADs/lN5K-iwrllU/s400/S2_14.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Y para invocar el método estático, de esta forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:property value="@com.javatutoriales.struts2.ognl.Constantes@metodoEstatico()" /&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Con esta etiqueta obtenemos la siguiente salida:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-b3fXteybMdo/TgFqUc6Xj_I/AAAAAAAAADw/xmKBsGm8Fwg/s1600/S2_15.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="242" src="http://2.bp.blogspot.com/-b3fXteybMdo/TgFqUc6Xj_I/AAAAAAAAADw/xmKBsGm8Fwg/s400/S2_15.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Bueno, en este caso parece que también ha habido un problema al invocar el método estático ^_^. En realidad lo que ocurre es que por default &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; impide la invocación de métodos estáticos desde &lt;span class="codigo"&gt;OGNL&lt;/span&gt;. &lt;br /&gt;&lt;br /&gt;¿Entonces qué podemos hacer? Pues &lt;span class="codigo"&gt;Struts&lt;/span&gt; proporciona una forma para habilitar esta opción. Podemos colocar el valor de la constante "&lt;span class="codigo"&gt;struts.ognl.allowStaticMethodAccess&lt;/span&gt;" en "&lt;span class="codigo"&gt;true&lt;/span&gt;". &lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.javatutoriales.com/2011/06/struts-2-parte-1-configuracion.html"&gt;En el tutorial anterior&lt;/a&gt; hablamos un poco de la constantes (muy poco, casi nada ^_^!), y declaramos un par de ellas en el archivo "&lt;span class="codigo"&gt;struts.xml&lt;/span&gt;". Sin embargo, ahora no tenemos un archivo "&lt;span class="codigo"&gt;struts.xml&lt;/span&gt;" ya que estamos usando anotaciones. Entonces ¿qué podemos hacer? (parece que salimos de un problema para entrar en otro, ¿no les ha pasado?).&lt;br /&gt;&lt;br /&gt;Las constantes en &lt;span class="codigo"&gt;Struts 2&lt;/span&gt; pueden ser declaradas en tres lugares:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;El archivo de configuración "&lt;span class="codigo"&gt;struts.xml&lt;/span&gt;".&lt;/li&gt;&lt;li&gt;El archivo "&lt;span class="codigo"&gt;struts.properties&lt;/span&gt;" (del que aún no hemos hablado).&lt;/li&gt;&lt;li&gt;Como un parámetro de inicio en el deployment descriptor (el archivo "&lt;span class="codigo"&gt;web.xml&lt;/span&gt;").&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Como de los tres archivos anteriores solo tenemos el archivo "&lt;span class="codigo"&gt;web.xml&lt;/span&gt;" será aquí en donde agregamos esta constante. Para esto debemos modificar la declaración del filtro de &lt;span class="codigo"&gt;Struts 2&lt;/span&gt;, dejándola de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;filter&amp;gt;&lt;br /&gt;    &amp;lt;filter-name&amp;gt;struts2&amp;lt;/filter-name&amp;gt;&lt;br /&gt;    &amp;lt;filter-class&amp;gt;org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter&amp;lt;/filter-class&amp;gt;&lt;br /&gt;    &amp;lt;init-param&amp;gt;&lt;br /&gt;        &amp;lt;param-name&amp;gt;struts.ognl.allowStaticMethodAccess&amp;lt;/param-name&amp;gt;&lt;br /&gt;        &amp;lt;param-value&amp;gt;true&amp;lt;/param-value&amp;gt;&lt;br /&gt;    &amp;lt;/init-param&amp;gt;&lt;br /&gt;&amp;lt;/filter&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ahora sí, si ejecutamos nuevamente el ejemplo debemos ver la siguiente salida:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-7cTO7k2R8ck/TgFqVY6VFHI/AAAAAAAAAD0/ww8elVv2nh0/s1600/S2_16.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="242" src="http://4.bp.blogspot.com/-7cTO7k2R8ck/TgFqVY6VFHI/AAAAAAAAAD0/ww8elVv2nh0/s400/S2_16.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Podemos ver que en este caso, se pudo obtener el valor de la variable estática de forma directa.&lt;br /&gt;&lt;br /&gt;Para invocar las versiones de los métodos que reciben un parámetro basta con pasar el parámetro que esperan recibir:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:property value="@com.javatutoriales.struts2.ognl.Constantes@metodoEstatico('Hola Amigos Estaticos')" /&amp;gt;&lt;br /&gt;&amp;lt;s:property value="new com.javatutoriales.struts2.ognl.Constantes().metodoDeInstancia('Hola Amigos')" /&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Inclusive podemos pasar como parámetro uno de los atributos obtenidos anteriormente:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;li&amp;gt;&amp;lt;s:property value="new com.javatutoriales.struts2.ognl.Constantes().metodoDeInstancia(@com.javatutoriales.struts2.ognl.Constantes@valor)" /&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Con estos cambios obtenemos la siguiente pantalla:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-InK2-XtRNRs/TgFqWBAuJkI/AAAAAAAAAD4/7Kj2WK7_xgU/s1600/S2_17.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="242" src="http://2.bp.blogspot.com/-InK2-XtRNRs/TgFqWBAuJkI/AAAAAAAAAD4/7Kj2WK7_xgU/s400/S2_17.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Otra parte interesante del uso de &lt;span class="codigo"&gt;OGNL&lt;/span&gt; viene cuando queremos obtener los valores de las constantes de una enumeración. Si recuerdan, nuestra clase "&lt;span class="codigo"&gt;Constantes&lt;/span&gt;" tiene una enumeración llamada "&lt;span class="codigo"&gt;Datos&lt;/span&gt;". Como cada uno de los valores de una enumeración es una constante (o sea una variable publica, estática, y final) obtener sus valores es igual a obtener cualquier otro valor de una variable estática. O sea que tenemos que usar la sintaxis de la doble arroba.&lt;br /&gt;&lt;br /&gt;Ahora, el secreto aquí viene dado en el sentido de que las enumeraciones son en realidad un tipo especial de clase Java. Como aquí la enumeración está dentro de otra clase, la primera se convierte en una clase interna de la segunda. El fully qualified class name de una clase interna es el nombre de la primer clase, seguida de un signo de dólar (&lt;span class="codigo"&gt;$&lt;/span&gt;) seguido del nombre de la clase interna. Por lo tanto, el fully qualified class name de la enumeración "&lt;span class="codigo"&gt;Datos&lt;/span&gt;" es "&lt;span class="codigo"&gt;com.javatutoriales.struts2.ognl.Constantes$Datos&lt;/span&gt;". Teniendo el nombre de esta enumeración, podemos obtener los valores de sus constes de la siguiente forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:property value="@com.javatutoriales.struts2.ognl.Constantes$Datos@PRIMERO" /&amp;gt;&lt;br /&gt;&amp;lt;s:property value="@com.javatutoriales.struts2.ognl.Constantes$Datos@SEGUNDO" /&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;E igual que en los casos anteriores, teniendo estos valores podemos invocar cualquier método que exista dentro de la enumeración, como en este caso el método "&lt;span class="codigo"&gt;getDato()&lt;/span&gt;" que invocamos de esta forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:property value="@com.javatutoriales.struts2.ognl.Constantes$Datos@TERCERO.dato" /&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Que también podría ser de esta forma:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;s:property value="@com.javatutoriales.struts2.ognl.Constantes$Datos@TERCERO.getDato()" /&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&
