From c278d8c65677814735d01472a6f19bb9360287ea Mon Sep 17 00:00:00 2001 From: Arjen Poutsma Date: Mon, 13 Jun 2022 13:47:31 +0200 Subject: [PATCH] Do not ignore charset in Jaxb2XmlDecoder This commit makes sure that the charset, if defined in the mimetype, is used when decoding XML to JAXB2 objects. Closes gh-28599 --- .../http/codec/xml/Jaxb2XmlDecoder.java | 19 ++++++++++++-- .../http/codec/xml/Jaxb2XmlDecoderTests.java | 25 ++++++++++++++++++- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/http/codec/xml/Jaxb2XmlDecoder.java b/spring-web/src/main/java/org/springframework/http/codec/xml/Jaxb2XmlDecoder.java index 2221880c49ff..9b63c105d23d 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/xml/Jaxb2XmlDecoder.java +++ b/spring-web/src/main/java/org/springframework/http/codec/xml/Jaxb2XmlDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package org.springframework.http.codec.xml; +import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -189,7 +190,7 @@ public Object decode(DataBuffer dataBuffer, ResolvableType targetType, @Nullable MimeType mimeType, @Nullable Map hints) throws DecodingException { try { - Iterator eventReader = inputFactory.createXMLEventReader(dataBuffer.asInputStream()); + Iterator eventReader = inputFactory.createXMLEventReader(dataBuffer.asInputStream(), encoding(mimeType)); List events = new ArrayList<>(); eventReader.forEachRemaining(event -> events.add((XMLEvent) event)); return unmarshal(events, targetType.toClass()); @@ -211,6 +212,20 @@ public Object decode(DataBuffer dataBuffer, ResolvableType targetType, } } + @Nullable + private static String encoding(@Nullable MimeType mimeType) { + if (mimeType == null) { + return null; + } + Charset charset = mimeType.getCharset(); + if (charset == null) { + return null; + } + else { + return charset.name(); + } + } + private Object unmarshal(List events, Class outputClass) { try { Unmarshaller unmarshaller = initUnmarshaller(outputClass); diff --git a/spring-web/src/test/java/org/springframework/http/codec/xml/Jaxb2XmlDecoderTests.java b/spring-web/src/test/java/org/springframework/http/codec/xml/Jaxb2XmlDecoderTests.java index 0f01d8c47a9f..ecb61231d4c2 100644 --- a/spring-web/src/test/java/org/springframework/http/codec/xml/Jaxb2XmlDecoderTests.java +++ b/spring-web/src/test/java/org/springframework/http/codec/xml/Jaxb2XmlDecoderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,6 +41,7 @@ import org.springframework.http.codec.xml.jaxb.XmlType; import org.springframework.http.codec.xml.jaxb.XmlTypeWithName; import org.springframework.http.codec.xml.jaxb.XmlTypeWithNameAndNamespace; +import org.springframework.util.MimeType; import org.springframework.web.testfixture.xml.Pojo; import static org.assertj.core.api.Assertions.assertThat; @@ -228,6 +229,28 @@ public void decodeErrorWithXmlNotWellFormed() { assertThat(Exceptions.unwrap(ex)).isInstanceOf(DecodingException.class)); } + @Test + public void decodeNonUtf8() { + String xml = "" + + "føø" + + "bär" + + ""; + Mono source = Mono.fromCallable(() -> { + byte[] bytes = xml.getBytes(StandardCharsets.ISO_8859_1); + DataBuffer buffer = this.bufferFactory.allocateBuffer(bytes.length); + buffer.write(bytes); + return buffer; + }); + MimeType mimeType = new MimeType(MediaType.APPLICATION_XML, StandardCharsets.ISO_8859_1); + Mono output = this.decoder.decodeToMono(source, ResolvableType.forClass(TypePojo.class), mimeType, + HINTS); + + StepVerifier.create(output) + .expectNext(new TypePojo("føø", "bär")) + .expectComplete() + .verify(); + } + @Test public void toExpectedQName() { assertThat(this.decoder.toQName(Pojo.class)).isEqualTo(new QName("pojo"));