La entrada Unicode recuperada a través de los componentes de entrada de PrimeFaces se corrompe

Cuando todavía estaba usando PrimeFaces v2.2.1, pude escribir entradas Unicode como chino con un componente de entrada PrimeFaces como

y

, y recuperar la entrada en buen estado en el método de bean administrado .

Sin embargo, después de actualizar a PrimeFaces v3.1.1, todos esos personajes se convierten en Mojibake o signos de interrogación. Solo la entrada en latín viene bien, son los caracteres chinos, árabes, hebreos, cirílicos, etc. que se deforman.

¿Cómo es esto causado y cómo puedo resolverlo?

Introducción

Normalmente, JSF / Facelets establecerá la encoding de caracteres del parámetro de solicitud en UTF-8 de forma predeterminada cuando se crea / restaura la vista. Pero si se solicita algún parámetro de solicitud antes de crear / restaurar la vista, entonces es demasiado tarde para establecer la encoding de caracteres adecuada. Los parámetros de solicitud se analizarán solo una vez.

La encoding PrimeFaces falla

Que falló en PrimeFaces 3.x después de la actualización de 2.x es causado por la nueva isAjaxRequest() en PrimePartialViewContext PrimeFaces que verifica un parámetro de solicitud:

 @Override public boolean isAjaxRequest() { return getWrapped().isAjaxRequest() || FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().containsKey("javax.faces.partial.ajax"); } 

Por defecto, isAjaxRequest() (el de Mojarra / MyFaces, como el código PrimeFaces anterior obtenido por getWrapped() ) comprueba el encabezado de solicitud de la siguiente manera que no afecta la encoding del parámetro de solicitud ya que los parámetros de solicitud no se analizarán cuando se obtiene un encabezado de solicitud:

  if (ajaxRequest == null) { ajaxRequest = "partial/ajax".equals(ctx. getExternalContext().getRequestHeaderMap().get("Faces-Request")); } 

Sin embargo, isAjaxRequest() puede ser llamado por cualquier oyente de fase o detector de eventos del sistema o alguna fábrica de aplicaciones antes de que la vista sea creada / restaurada. Por lo tanto, cuando utilice PrimeFaces 3.x, los parámetros de la solicitud se analizarán antes de que se establezca la encoding de caracteres adecuada y, por lo tanto, usará la encoding predeterminada del servidor, que generalmente es ISO-8859-1. Esto arruinará todo.

Soluciones

Hay varias formas de solucionarlo:

  1. Utilice un filtro de servlet que establezca ServletRequest#setCharacterEncoding() con UTF-8. Establecer la encoding de respuesta por ServletResponse#setCharacterEncoding() es, por cierto, innecesario, ya que no se verá afectado por este problema.

     @WebFilter("/*") public class CharacterEncodingFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); chain.doFilter(request, response); } // ... } 

    Solo necesita tener en cuenta que HttpServletRequest#setCharacterEncoding() solo establece la encoding para los parámetros de solicitud POST, no para los parámetros de solicitud GET. Para los parámetros de solicitud GET, aún deberá configurarlo en el nivel del servidor.

    Si usa la biblioteca de utilidades JSF OmniFaces , dicho filtro ya está provisto en la caja, el CharacterEncodingFilter . Simplemente instálelo de la siguiente manera en web.xml como primera entrada de filtro:

      characterEncodingFilter org.omnifaces.filter.CharacterEncodingFilter   characterEncodingFilter /*  

  2. Vuelva a configurar el servidor para usar UTF-8 en lugar de ISO-8859-1 como encoding predeterminada. En el caso de Glassfish, eso sería una cuestión de agregar la siguiente entrada a del archivo /WEB-INF/glassfish-web.xml :

      

    Tomcat no lo admite. Tiene el atributo URIEncoding en la entrada , pero esto se aplica solo a las solicitudes GET, no a las solicitudes POST.


  3. Informar como un error a PrimeFaces. ¿Existe realmente alguna razón legítima para verificar que la solicitud HTTP sea una solicitud de Ajax al verificar un parámetro de solicitud en lugar de un encabezado de solicitud como lo haría con JSF estándar y, por ejemplo, jQuery? El JavaScript core.js PrimeFaces está haciendo eso. Sería mejor si lo hubiera establecido como un encabezado de solicitud de XMLHttpRequest .


Soluciones que NO funcionan

Quizás te encuentres con las “soluciones” a continuación en algún lugar de Internet mientras investigas este problema. Esas soluciones no funcionarán en este caso específico. La explicación sigue.

  • Configuración de prólogo XML:

     < ?xml version='1.0' encoding='UTF-8' ?> 

    Esto solo le dice al analizador XML que use UTF-8 para decodificar el origen XML antes de construir el árbol XML a su alrededor. El analizador XML que Facelts realmente usa es SAX durante el tiempo de comstackción de la vista JSF. Esta parte no tiene nada que ver con la encoding de solicitud / respuesta HTTP.

  • Configuración de metaetiqueta HTML:

      

    La metaetiqueta HTML se ignora cuando la página se sirve a través de HTTP a través de http(s):// URI. Solo se ha usado cuando la página está guardada por el cliente como un archivo HTML en el sistema de disco local y luego se vuelve a abrir mediante un file:// URI en el navegador.

  • La configuración del formulario HTML acepta el atributo charset:

      

    Los navegadores modernos ignoran esto. Esto solo tiene efecto en el navegador Microsoft Internet Explorer. Incluso entonces lo está haciendo mal. Nunca lo use Todos los navegadores web reales usarán el atributo de conjunto de caracteres especificado en el encabezado Content-Type de la respuesta. Incluso MSIE lo hará de la manera correcta, siempre y cuando no especifique el atributo accept-charset .

  • Estableciendo el argumento JVM:

     -Dfile.encoding=UTF-8 

    Esto solo lo utiliza Oracle (!) JVM para leer y analizar los archivos fuente de Java.