Skip to content

Commit cfd03f8

Browse files
authored
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
1 parent 620b9bf commit cfd03f8

File tree

5 files changed

+23
-19
lines changed

5 files changed

+23
-19
lines changed

spring-integration-core/src/main/java/org/springframework/integration/json/SimpleJsonSerializer.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import java.util.Arrays;
2323
import java.util.HashSet;
2424
import java.util.Set;
25+
import java.util.regex.Matcher;
2526

2627
import org.apache.commons.logging.Log;
2728
import org.apache.commons.logging.LogFactory;
@@ -99,7 +100,7 @@ private static String toElement(Object result) {
99100
return result.toString();
100101
}
101102
else {
102-
return "\"" + (result == null ? "null" : result.toString()) + "\"";
103+
return "\"" + (result == null ? "null" : Matcher.quoteReplacement(result.toString())) + "\"";
103104
}
104105
}
105106

spring-integration-file/src/main/java/org/springframework/integration/file/splitter/FileSplitter.java

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2015-2019 the original author or authors.
2+
* Copyright 2015-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -37,11 +37,11 @@
3737
import org.springframework.integration.StaticMessageHeaderAccessor;
3838
import org.springframework.integration.file.FileHeaders;
3939
import org.springframework.integration.file.splitter.FileSplitter.FileMarker.Mark;
40+
import org.springframework.integration.json.SimpleJsonSerializer;
4041
import org.springframework.integration.splitter.AbstractMessageSplitter;
4142
import org.springframework.integration.support.AbstractIntegrationMessageBuilder;
42-
import org.springframework.integration.support.json.JsonObjectMapper;
43-
import org.springframework.integration.support.json.JsonObjectMapperProvider;
4443
import org.springframework.integration.util.CloseableIterator;
44+
import org.springframework.lang.Nullable;
4545
import org.springframework.messaging.Message;
4646
import org.springframework.messaging.MessageHandlingException;
4747
import org.springframework.util.Assert;
@@ -75,15 +75,13 @@
7575
*/
7676
public class FileSplitter extends AbstractMessageSplitter {
7777

78-
private static final JsonObjectMapper<?, ?> OBJECT_MAPPER =
79-
JsonObjectMapperProvider.jsonAvailable() ? JsonObjectMapperProvider.newInstance() : null;
80-
8178
private final boolean returnIterator;
8279

8380
private final boolean markers;
8481

8582
private final boolean markersJson;
8683

84+
@Nullable
8785
private Charset charset;
8886

8987
private String firstLineHeaderName;
@@ -129,19 +127,14 @@ public FileSplitter(boolean iterator, boolean markers) {
129127
* @param iterator true to return an iterator, false to return a list of lines.
130128
* @param markers true to emit start of file/end of file marker messages before/after
131129
* the data.
132-
* @param markersJson when true, markers are represented as JSON - requires a
133-
* supported JSON implementation on the classpath. See
134-
* {@link JsonObjectMapperProvider} for supported implementations.
130+
* @param markersJson when true, markers are represented as JSON.
135131
* @since 4.2.7
136132
*/
137133
public FileSplitter(boolean iterator, boolean markers, boolean markersJson) {
138134
this.returnIterator = iterator;
139135
this.markers = markers;
140136
if (markers) {
141137
setApplySequence(false);
142-
if (markersJson) {
143-
Assert.notNull(OBJECT_MAPPER, "'markersJson' requires an object mapper");
144-
}
145138
}
146139
this.markersJson = markersJson;
147140
}
@@ -151,7 +144,7 @@ public FileSplitter(boolean iterator, boolean markers, boolean markersJson) {
151144
* charset is required.
152145
* @param charset the charset.
153146
*/
154-
public void setCharset(Charset charset) {
147+
public void setCharset(@Nullable Charset charset) {
155148
this.charset = charset;
156149
}
157150

@@ -410,7 +403,7 @@ private AbstractIntegrationMessageBuilder<Object> markerToReturn(FileMarker file
410403
Object payload;
411404
if (FileSplitter.this.markersJson) {
412405
try {
413-
payload = OBJECT_MAPPER.toJson(fileMarker);
406+
payload = SimpleJsonSerializer.toJson(fileMarker);
414407
}
415408
catch (Exception e) {
416409
throw new MessageHandlingException(this.message, "Failed to convert marker to JSON", e);
@@ -489,7 +482,6 @@ public String toString() {
489482
}
490483
}
491484

492-
493485
}
494486

495487
}

spring-integration-file/src/test/java/org/springframework/integration/file/splitter/FileSplitterTests.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import java.nio.charset.StandardCharsets;
3232
import java.time.Duration;
3333
import java.util.Date;
34+
import java.util.List;
3435

3536
import org.junit.jupiter.api.BeforeAll;
3637
import org.junit.jupiter.api.Test;
@@ -50,6 +51,7 @@
5051
import org.springframework.integration.file.FileHeaders;
5152
import org.springframework.integration.file.splitter.FileSplitter.FileMarker;
5253
import org.springframework.integration.handler.advice.IdempotentReceiverInterceptor;
54+
import org.springframework.integration.json.JsonPathUtils;
5355
import org.springframework.integration.metadata.ConcurrentMetadataStore;
5456
import org.springframework.integration.metadata.SimpleMetadataStore;
5557
import org.springframework.integration.selector.MetadataStoreSelector;
@@ -248,6 +250,7 @@ void testMarkersEmptyFile() throws IOException {
248250
}
249251

250252
@Test
253+
@SuppressWarnings("unchecked")
251254
void testMarkersJson() throws Exception {
252255
JsonObjectMapper<?, ?> objectMapper = JsonObjectMapperProvider.newInstance();
253256
QueueChannel outputChannel = new QueueChannel();
@@ -260,7 +263,8 @@ void testMarkersJson() throws Exception {
260263
assertThat(received.getHeaders().get(FileHeaders.MARKER)).isEqualTo("START");
261264
assertThat(received.getPayload()).isInstanceOf(String.class);
262265
String payload = (String) received.getPayload();
263-
assertThat(payload).contains("\"mark\":\"START\",\"lineCount\":0");
266+
assertThat((List<String>) JsonPathUtils.evaluate(payload, "$..mark")).hasSize(1).contains("START");
267+
assertThat((List<Integer>) JsonPathUtils.evaluate(payload, "$..lineCount")).hasSize(1).contains(0);
264268
FileMarker fileMarker = objectMapper.fromJson(payload, FileSplitter.FileMarker.class);
265269
assertThat(fileMarker.getMark()).isEqualTo(FileSplitter.FileMarker.Mark.START);
266270
assertThat(fileMarker.getFilePath()).isEqualTo(file.getAbsolutePath());

src/reference/asciidoc/file.adoc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1016,7 +1016,7 @@ The default is `false`.
10161016
When `true`, `apply-sequence` is `false` by default.
10171017
See also `markers-json` (the next attribute).
10181018
<4> When `markers` is true, set this to `true` to have the `FileMarker` objects be converted to a JSON string.
1019-
Requires a supported JSON processor library (e.g. Jackson) on the classpath.
1019+
(Uses a `SimpleJsonSerializer` underneath).
10201020
<5> Set to `false` to disable the inclusion of `sequenceSize` and `sequenceNumber` headers in messages.
10211021
The default is `true`, unless `markers` is `true`.
10221022
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)
10501050
----
10511051
====
10521052

1053-
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.
1053+
When `markersJson` is true, the markers are represented as a JSON string (using a `SimpleJsonSerializer`).
10541054

10551055
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).
10561056
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.

src/reference/asciidoc/whats-new.adoc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,3 +158,10 @@ See <<./mqtt.adoc#mqtt-events,MQTT Events>>.
158158

159159
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`.
160160
See <<./sftp.adoc#sftp,SFTP Support>> and <<./ftp.adoc#ftp,FTP Support>> for more information.
161+
162+
[[x5.3-file]]
163+
=== File Changes
164+
165+
The `FileSplitter` doesn't require a Jackson processor (or similar) dependency any more for the `markersJson` mode.
166+
It uses a `SimpleJsonSerializer` for a straightforward string representation of the `FileSplitter.FileMarker` instances.
167+
See <<./file.adoc#file-splitter,FileSplitter>> for more information.

0 commit comments

Comments
 (0)