Skip to content

Commit

Permalink
Do not ignore charset in Jaxb2XmlDecoder
Browse files Browse the repository at this point in the history
This commit makes sure that the charset, if defined in the mimetype, is
used when decoding XML to JAXB2 objects.

Closes gh-28599
  • Loading branch information
poutsma committed Jun 13, 2022
1 parent e3b2887 commit c278d8c
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 3 deletions.
@@ -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.
Expand All @@ -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;
Expand Down Expand Up @@ -189,7 +190,7 @@ public Object decode(DataBuffer dataBuffer, ResolvableType targetType,
@Nullable MimeType mimeType, @Nullable Map<String, Object> hints) throws DecodingException {

try {
Iterator eventReader = inputFactory.createXMLEventReader(dataBuffer.asInputStream());
Iterator eventReader = inputFactory.createXMLEventReader(dataBuffer.asInputStream(), encoding(mimeType));
List<XMLEvent> events = new ArrayList<>();
eventReader.forEachRemaining(event -> events.add((XMLEvent) event));
return unmarshal(events, targetType.toClass());
Expand All @@ -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<XMLEvent> events, Class<?> outputClass) {
try {
Unmarshaller unmarshaller = initUnmarshaller(outputClass);
Expand Down
@@ -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.
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -228,6 +229,28 @@ public void decodeErrorWithXmlNotWellFormed() {
assertThat(Exceptions.unwrap(ex)).isInstanceOf(DecodingException.class));
}

@Test
public void decodeNonUtf8() {
String xml = "<pojo>" +
"<foo>føø</foo>" +
"<bar>bär</bar>" +
"</pojo>";
Mono<DataBuffer> 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<Object> 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"));
Expand Down

0 comments on commit c278d8c

Please sign in to comment.