MockMvc ya no maneja caracteres UTF-8 con Spring Boot 2.2.0.


14

Después de actualizar a la 2.2.0.RELEASEversión recién lanzada de Spring Boot, algunas de mis pruebas fallaron. Parece que MediaType.APPLICATION_JSON_UTF8ha quedado en desuso y ya no se devuelve como tipo de contenido predeterminado de los métodos del controlador que no especifican explícitamente el tipo de contenido.

Código de prueba como

String content = mockMvc.perform(get("/some-api")
            .contentType(MediaType.APPLICATION_JSON))
            .andExpect(status().isOk())
            .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
            .andReturn()
            .getResponse()
            .getContentAsString();

de repente ya no funcionó ya que el tipo de contenido no coincidía como se muestra a continuación

java.lang.AssertionError: Content type 
Expected :application/json;charset=UTF-8
Actual   :application/json

Cambiando el código para .andExpect(content().contentType(MediaType.APPLICATION_JSON))resolver el problema por ahora.

Pero ahora, cuando se compara contentcon el objeto serializado esperado, todavía hay una falta de coincidencia si hay caracteres especiales en el objeto. Parece que el .getContentAsString()método no utiliza la codificación de caracteres UTF-8 de forma predeterminada (más).

java.lang.AssertionError: Response content expected:<[{"description":"Er hörte leise Schritte hinter sich."}]> but was:<[{"description":"Er hörte leise Schritte hinter sich."}]>
Expected :[{"description":"Er hörte leise Schritte hinter sich."}]
Actual   :[{"description":"Er hörte leise Schritte hinter sich."}]

¿Cómo puedo obtener la contentcodificación UTF-8?

Respuestas:


7

Si. Este es un problema de 2.2.0 spring-boot. Establecen la obsolescencia para la codificación de juego de caracteres predeterminada.

.getContentAsString(StandardCharsets.UTF_8) - bueno pero en cualquier respuesta se rellenaría ISO 8859-1 por defecto.

En mi proyecto actualicé el convertidor creado actual:

@Configuration
public class SpringConfig implements WebMvcConfigurer {

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.stream()
            .filter(converter -> converter instanceof MappingJackson2HttpMessageConverter)
            .findFirst()
            .ifPresent(converter -> ((MappingJackson2HttpMessageConverter) converter).setDefaultCharset(UTF_8));
    }
...

¡Esta fue la solución más fácil recomendada aquí!
Veces del

¡Salvaste mi día!
Filomat


2

El carácter de codificación predeterminado ya no es UTF-8 desde la versión 5.2.0 de spring.

Para continuar usando UTF-8, debe configurarlo en ServletResponse del resultado de MockMvc. Para establecer la codificación de caracteres predeterminada en UTF-8, haga algo como esto en su método de configuración:

@Before
public void setUp() {
   mockMvc = webAppContextSetup(wac).addFilter(((request, response, chain) -> {
                response.setCharacterEncoding("UTF-8");
                chain.doFilter(request, response);
            })).build();
}

Luego puede usar la instancia de mockMvc para realizar su solicitud.

Espero que esto ayude.


Con esta solución, tendría que configurar el mockMvc en cada clase de prueba. ¡Esto puede ser bastante tedioso para muchas clases de prueba!
Veces del

0

De acuerdo con esta solicitud de extracción de los desarrolladores de Spring, el encabezado UTF-8 ya no es necesario y, por lo tanto, está en desuso. Si está utilizando el encabezado UTF-8 en su aplicación, puede considerar eliminarlo de su aplicación en lugar de intentar arreglar su prueba. Solo asegúrate de estar usando el tipo de contenido: encabezado de aplicación / json y estarás bien.


Creo que no entiendes el problema. Le sugiero que lea toda la pregunta y luego vuelva a evaluar, si su respuesta ofrece algún valor. Mi aplicación funciona perfectamente bien, el problema está relacionado con las pruebas.
Horarios del

Leí toda la pregunta nuevamente y reevalué mi respuesta, la respuesta sigue siendo la misma. En su pregunta no explica por qué el encabezado está en desuso, enriquecí su pregunta con mi publicación. Le sugiero que lea el PR al que me vinculé, para que entienda por qué el encabezado está en desuso. Si comprende el por qué, es posible que desee considerar cambiar su prueba ya que su prueba está probando el comportamiento predeterminado en Spring 2.1.X, pero no prueba el comportamiento en Spring 2.2.X correctamente. El comportamiento de Spring cambió, su prueba debería cambiar en consecuencia si acepta el nuevo comportamiento de Spring.
scre_www

No estás siendo muy consistente aquí. En tu respuesta dices "[...] en lugar de intentar arreglar tu prueba". En su comentario dice "su [...] prueba debería cambiar en consecuencia si acepta el nuevo comportamiento de Spring".
Veces del

Cada programador enfrenta valores obsoletos de vez en cuando. Cuando algo está en desuso, puede solucionarlo de alguna manera sin investigar por qué se dejó de usar en primer lugar. Este enfoque parece ser la forma en que maneja este problema. Ahora le sugiero que busque más e investigue por qué quedó en desuso. Si comprende eso, puede tomar una mejor decisión sobre qué hacer a continuación. En su pregunta no hay nada acerca de por qué solo nos dice que su prueba está fallando debido a un valor obsoleto que es una investigación deficiente. Enriquecí la pregunta con algunas investigaciones que no hiciste Y elevé la Q.
scre_www

0

Estoy usando Spring Boot 1.5.15.RELEASE y enfrenté el mismo problema al escribir pruebas.

La primera solución que me ayudó fue agregar .characterEncoding ("UTF-8")) así:

String content = mockMvc.perform(get("/some-api")
            .contentType(MediaType.APPLICATION_JSON)
            .characterEncoding("UTF-8"))
            .andExpect(status().isOk())
            .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
            .andReturn()
            .getResponse()
            .getContentAsString();

Estoy usando un StandaloneMockMvcBuilder en mi clase de prueba, por lo que la segunda solución que me ayudó fue crear un filtro, por ejemplo:

private static class Utf8Filter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
        throws ServletException, IOException {
        response.setCharacterEncoding(StandardCharsets.UTF_8.toString());
        filterChain.doFilter(request, response);
    }
}

y luego lo agrego al método standaloneSetup en mi clase de prueba de esta manera:

@Before
public void setup() {
    MockitoAnnotations.initMocks(this);
    final SomeResource someResource = new SomeResource(someService);
    this.restLankMockMvc = MockMvcBuilders.standaloneSetup(someResource)
        .setCustomArgumentResolvers(pageableArgumentResolver)
        .setControllerAdvice(exceptionTranslator)
        .setConversionService(createFormattingConversionService())
        .setMessageConverters(jacksonMessageConverter)
        .addFilter(new Utf8Filter())
        .build();
}

0

Ajuste adicional a MockMvc, .accept(MediaType.APPLICATION_JSON_UTF8_VALUE):

    String content = mockMvc.perform(get("/some-api")
        .contentType(MediaType.APPLICATION_JSON)
        .accept(MediaType.APPLICATION_JSON_UTF8_VALUE))
        .andExpect(status().isOk())
        .andExpect(content().contentType(MediaType.APPLICATION_JSON))
        .andReturn()
        .getResponse()
        .getContentAsString();

Este problema no es Spring Boot, sino uno específico de MockMvc, supongo. Por lo tanto, una solución debe aplicarse solo a MockMvc. ( JSON debe estar codificado con UTF-8 ).

problema relacionado: manejo UTF-8 incorrecto en MockMvc para respuesta JSON · Problema # 23622 · spring-projects / spring-framework

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.