Allow StaxEventItemReader to auto-detect the input file encoding

Before this commit, it was not possible to pass a null encoding
to the StaxEventItemReader, which prevents the XML event reader
to auto-detect the file encoding.

This commits makes the encoding setter more lenient by accepting
a null value.

Resolves #4101
This commit is contained in:
Mahmoud Ben Hassine
2023-04-27 20:52:37 +02:00
parent ec161f8429
commit 21bc4d582b
3 changed files with 49 additions and 9 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2006-2022 the original author or authors.
* Copyright 2006-2023 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.
@@ -142,10 +142,10 @@ public class StaxEventItemReader<T> extends AbstractItemCountingItemStreamItemRe
/**
* Set encoding to be used for the input file. Defaults to {@link #DEFAULT_ENCODING}.
* @param encoding the encoding to be used
* @param encoding the encoding to be used. Can be {@code null}, in which case, the
* XML event reader will attempt to auto-detect the encoding from tht input file.
*/
public void setEncoding(String encoding) {
Assert.notNull(encoding, "The encoding must not be null");
public void setEncoding(@Nullable String encoding) {
this.encoding = encoding;
}
@@ -239,7 +239,8 @@ public class StaxEventItemReader<T> extends AbstractItemCountingItemStreamItemRe
}
inputStream = resource.getInputStream();
eventReader = xmlInputFactory.createXMLEventReader(inputStream, this.encoding);
eventReader = this.encoding != null ? xmlInputFactory.createXMLEventReader(inputStream, this.encoding)
: xmlInputFactory.createXMLEventReader(inputStream);
fragmentReader = new DefaultFragmentEventReader(eventReader);
noInput = false;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2017-2020 the original author or authors.
* Copyright 2017-2023 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.
@@ -26,6 +26,7 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.batch.item.xml.StaxEventItemReader;
import org.springframework.core.io.Resource;
import org.springframework.lang.Nullable;
import org.springframework.oxm.Unmarshaller;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -194,12 +195,13 @@ public class StaxEventItemReaderBuilder<T> {
/**
* Encoding for the input file. Defaults to
* {@link StaxEventItemReader#DEFAULT_ENCODING}.
* {@link StaxEventItemReader#DEFAULT_ENCODING}. Can be {@code null}, in which case
* the XML event reader will attempt to auto-detect the encoding from tht input file.
* @param encoding String encoding algorithm
* @return the current instance of the builder
* @see StaxEventItemReader#setEncoding(String)
*/
public StaxEventItemReaderBuilder<T> encoding(String encoding) {
public StaxEventItemReaderBuilder<T> encoding(@Nullable String encoding) {
this.encoding = encoding;
return this;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2008-2022 the original author or authors.
* Copyright 2008-2023 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.
@@ -19,6 +19,7 @@ import org.hamcrest.MatcherAssert;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemCountAware;
import org.springframework.batch.item.ItemStreamException;
@@ -36,8 +37,10 @@ import org.springframework.util.xml.StaxUtils;
import javax.xml.namespace.QName;
import javax.xml.stream.FactoryConfigurationError;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.StartDocument;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import javax.xml.transform.Source;
@@ -58,6 +61,9 @@ import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* Tests for {@link StaxEventItemReader}.
@@ -159,6 +165,37 @@ class StaxEventItemReaderTests {
source.close();
}
@Test
void testNullEncoding() throws Exception {
// given
XMLEventReader eventReader = mock(XMLEventReader.class);
when(eventReader.peek()).thenReturn(mock(StartDocument.class));
Resource resource = mock(Resource.class);
InputStream inputStream = mock(InputStream.class);
when(resource.getInputStream()).thenReturn(inputStream);
when(resource.isReadable()).thenReturn(true);
when(resource.exists()).thenReturn(true);
XMLInputFactory xmlInputFactory = mock(XMLInputFactory.class);
when(xmlInputFactory.createXMLEventReader(inputStream)).thenReturn(eventReader);
StaxEventItemReader<Object> reader = new StaxEventItemReader<>();
reader.setUnmarshaller(new MockFragmentUnmarshaller());
reader.setFragmentRootElementName(FRAGMENT_ROOT_ELEMENT);
reader.setResource(resource);
reader.setEncoding(null);
reader.setStrict(false);
reader.setXmlInputFactory(xmlInputFactory);
reader.afterPropertiesSet();
// when
reader.open(new ExecutionContext());
// then
verify(xmlInputFactory).createXMLEventReader(inputStream);
reader.close();
}
@Test
void testItemCountAwareFragment() throws Exception {
StaxEventItemReader<ItemCountAwareFragment> source = createNewItemCountAwareInputSource();