Use a SimpleJsonSerializer in the FileSplitter (#3262)
* Use a SimpleJsonSerializer in the FileSplitter * To avoid extra dependency for Jackson when we serialize `FileSplitter.FileMarker` to JSON, use a `SimpleJsonSerializer` instead. * Fix `SimpleJsonSerializer` to escape a `\` symbol from property values since it is used for quoting string values in the final JSON * * Document the change
This commit is contained in:
@@ -22,6 +22,7 @@ import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@@ -99,7 +100,7 @@ public final class SimpleJsonSerializer {
|
||||
return result.toString();
|
||||
}
|
||||
else {
|
||||
return "\"" + (result == null ? "null" : result.toString()) + "\"";
|
||||
return "\"" + (result == null ? "null" : Matcher.quoteReplacement(result.toString())) + "\"";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015-2019 the original author or authors.
|
||||
* Copyright 2015-2020 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.
|
||||
@@ -37,11 +37,11 @@ import java.util.NoSuchElementException;
|
||||
import org.springframework.integration.StaticMessageHeaderAccessor;
|
||||
import org.springframework.integration.file.FileHeaders;
|
||||
import org.springframework.integration.file.splitter.FileSplitter.FileMarker.Mark;
|
||||
import org.springframework.integration.json.SimpleJsonSerializer;
|
||||
import org.springframework.integration.splitter.AbstractMessageSplitter;
|
||||
import org.springframework.integration.support.AbstractIntegrationMessageBuilder;
|
||||
import org.springframework.integration.support.json.JsonObjectMapper;
|
||||
import org.springframework.integration.support.json.JsonObjectMapperProvider;
|
||||
import org.springframework.integration.util.CloseableIterator;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageHandlingException;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -75,15 +75,13 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
public class FileSplitter extends AbstractMessageSplitter {
|
||||
|
||||
private static final JsonObjectMapper<?, ?> OBJECT_MAPPER =
|
||||
JsonObjectMapperProvider.jsonAvailable() ? JsonObjectMapperProvider.newInstance() : null;
|
||||
|
||||
private final boolean returnIterator;
|
||||
|
||||
private final boolean markers;
|
||||
|
||||
private final boolean markersJson;
|
||||
|
||||
@Nullable
|
||||
private Charset charset;
|
||||
|
||||
private String firstLineHeaderName;
|
||||
@@ -129,9 +127,7 @@ public class FileSplitter extends AbstractMessageSplitter {
|
||||
* @param iterator true to return an iterator, false to return a list of lines.
|
||||
* @param markers true to emit start of file/end of file marker messages before/after
|
||||
* the data.
|
||||
* @param markersJson when true, markers are represented as JSON - requires a
|
||||
* supported JSON implementation on the classpath. See
|
||||
* {@link JsonObjectMapperProvider} for supported implementations.
|
||||
* @param markersJson when true, markers are represented as JSON.
|
||||
* @since 4.2.7
|
||||
*/
|
||||
public FileSplitter(boolean iterator, boolean markers, boolean markersJson) {
|
||||
@@ -139,9 +135,6 @@ public class FileSplitter extends AbstractMessageSplitter {
|
||||
this.markers = markers;
|
||||
if (markers) {
|
||||
setApplySequence(false);
|
||||
if (markersJson) {
|
||||
Assert.notNull(OBJECT_MAPPER, "'markersJson' requires an object mapper");
|
||||
}
|
||||
}
|
||||
this.markersJson = markersJson;
|
||||
}
|
||||
@@ -151,7 +144,7 @@ public class FileSplitter extends AbstractMessageSplitter {
|
||||
* charset is required.
|
||||
* @param charset the charset.
|
||||
*/
|
||||
public void setCharset(Charset charset) {
|
||||
public void setCharset(@Nullable Charset charset) {
|
||||
this.charset = charset;
|
||||
}
|
||||
|
||||
@@ -410,7 +403,7 @@ public class FileSplitter extends AbstractMessageSplitter {
|
||||
Object payload;
|
||||
if (FileSplitter.this.markersJson) {
|
||||
try {
|
||||
payload = OBJECT_MAPPER.toJson(fileMarker);
|
||||
payload = SimpleJsonSerializer.toJson(fileMarker);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new MessageHandlingException(this.message, "Failed to convert marker to JSON", e);
|
||||
@@ -489,7 +482,6 @@ public class FileSplitter extends AbstractMessageSplitter {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Duration;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -50,6 +51,7 @@ import org.springframework.integration.config.EnableIntegration;
|
||||
import org.springframework.integration.file.FileHeaders;
|
||||
import org.springframework.integration.file.splitter.FileSplitter.FileMarker;
|
||||
import org.springframework.integration.handler.advice.IdempotentReceiverInterceptor;
|
||||
import org.springframework.integration.json.JsonPathUtils;
|
||||
import org.springframework.integration.metadata.ConcurrentMetadataStore;
|
||||
import org.springframework.integration.metadata.SimpleMetadataStore;
|
||||
import org.springframework.integration.selector.MetadataStoreSelector;
|
||||
@@ -248,6 +250,7 @@ public class FileSplitterTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void testMarkersJson() throws Exception {
|
||||
JsonObjectMapper<?, ?> objectMapper = JsonObjectMapperProvider.newInstance();
|
||||
QueueChannel outputChannel = new QueueChannel();
|
||||
@@ -260,7 +263,8 @@ public class FileSplitterTests {
|
||||
assertThat(received.getHeaders().get(FileHeaders.MARKER)).isEqualTo("START");
|
||||
assertThat(received.getPayload()).isInstanceOf(String.class);
|
||||
String payload = (String) received.getPayload();
|
||||
assertThat(payload).contains("\"mark\":\"START\",\"lineCount\":0");
|
||||
assertThat((List<String>) JsonPathUtils.evaluate(payload, "$..mark")).hasSize(1).contains("START");
|
||||
assertThat((List<Integer>) JsonPathUtils.evaluate(payload, "$..lineCount")).hasSize(1).contains(0);
|
||||
FileMarker fileMarker = objectMapper.fromJson(payload, FileSplitter.FileMarker.class);
|
||||
assertThat(fileMarker.getMark()).isEqualTo(FileSplitter.FileMarker.Mark.START);
|
||||
assertThat(fileMarker.getFilePath()).isEqualTo(file.getAbsolutePath());
|
||||
|
||||
@@ -1016,7 +1016,7 @@ The default is `false`.
|
||||
When `true`, `apply-sequence` is `false` by default.
|
||||
See also `markers-json` (the next attribute).
|
||||
<4> When `markers` is true, set this to `true` to have the `FileMarker` objects be converted to a JSON string.
|
||||
Requires a supported JSON processor library (e.g. Jackson) on the classpath.
|
||||
(Uses a `SimpleJsonSerializer` underneath).
|
||||
<5> Set to `false` to disable the inclusion of `sequenceSize` and `sequenceNumber` headers in messages.
|
||||
The default is `true`, unless `markers` is `true`.
|
||||
When `true` and `markers` is `true`, the markers are included in the sequencing.
|
||||
@@ -1050,7 +1050,7 @@ public FileSplitter(boolean iterator, boolean markers, boolean markersJson)
|
||||
----
|
||||
====
|
||||
|
||||
When `markersJson` is true, the markers are represented as a JSON string, as long as a suitable JSON processor library (e.g Jackson) is on the classpath.
|
||||
When `markersJson` is true, the markers are represented as a JSON string (using a `SimpleJsonSerializer`).
|
||||
|
||||
Version 5.0 introduced the `firstLineAsHeader` option to specify that the first line of content is a header (such as column names in a CSV file).
|
||||
The argument passed to this property is the header name under which the first line is carried as a header in the messages emitted for the remaining lines.
|
||||
|
||||
@@ -158,3 +158,10 @@ See <<./mqtt.adoc#mqtt-events,MQTT Events>>.
|
||||
|
||||
The `FileTransferringMessageHandler` (for FTP and SFTP, for example) in addition to `File`, `byte[]`, `String` and `InputStream` now also supports an `org.springframework.core.io.Resource`.
|
||||
See <<./sftp.adoc#sftp,SFTP Support>> and <<./ftp.adoc#ftp,FTP Support>> for more information.
|
||||
|
||||
[[x5.3-file]]
|
||||
=== File Changes
|
||||
|
||||
The `FileSplitter` doesn't require a Jackson processor (or similar) dependency any more for the `markersJson` mode.
|
||||
It uses a `SimpleJsonSerializer` for a straightforward string representation of the `FileSplitter.FileMarker` instances.
|
||||
See <<./file.adoc#file-splitter,FileSplitter>> for more information.
|
||||
|
||||
Reference in New Issue
Block a user