rwzdk opened a new pull request, #13020:
URL: https://github.com/apache/seatunnel/pull/13020
## Symptom
The HTTP source fails the whole job with an `IndexOutOfBoundsException` on
perfectly valid JSON, whenever the configured `json_field` paths match a
different number of elements and `json_filed_missed_return_null` is enabled.
Minimal reproduction — two paths over an array of different lengths:
```json
{"a":[1],"b":[10,20]}
```
```hocon
source {
Http {
url = "http://..."
json_field_missed_return_null = true
json_field = {
a = "$.a[*]"
b = "$.b[*]"
}
}
}
```
→ `java.lang.IndexOutOfBoundsException: Index 1 out of bounds for length 1`
## Root cause
`seatunnel-connectors-v2/connector-http/connector-http-base/src/main/java/org/apache/seatunnel/connectors/seatunnel/http/util/JsonPathProcessorImpl.java:108`
```java
protected List<List<String>> dataFlip(List<List<String>> results) {
List<List<String>> datas = new ArrayList<>();
for (int i = 0; i < results.size(); i++) {
List<String> result = results.get(i);
if (i == 0) {
// rows are created from the FIRST path's result size
for (Object o : result) { ... datas.add(row); }
} else {
for (int j = 0; j < result.size(); j++) {
...
List<String> row = datas.get(j); // <-- no bound check
row.add(val);
}
}
}
```
`dataFlip` assumes every per-path list has the same length as the first one.
It builds exactly `results.get(0).size()` rows, then indexes `datas.get(j)`
with `j` running up to a *later* path's size.
That assumption holds when consistency is validated — but `processJsonData`
deliberately **skips** that validation when `json_filed_missed_return_null` is
enabled:
```java
// Only validate consistency if jsonFiledMissedReturnNull is false
boolean shouldValidate = !isJsonFiledMissedReturnNull();
if (shouldValidate) {
validateResultsConsistency(results, paths);
}
return dataFlip(results);
```
So the exact configuration that is *supposed* to tolerate missing/short
fields is the one that crashes.
## Fix
Build one row per element of the **longest** path, and pad shorter paths
with `null`, preserving index alignment:
```java
int rowCount = 0;
for (List<String> result : results) {
if (result != null && result.size() > rowCount) {
rowCount = result.size();
}
}
for (int i = 0; i < rowCount; i++) {
datas.add(new ArrayList<>(results.size()));
}
for (int pathIndex = 0; pathIndex < results.size(); pathIndex++) {
List<String> result = results.get(pathIndex);
int size = result == null ? 0 : result.size();
for (int rowIndex = 0; rowIndex < rowCount; rowIndex++) {
Object o = rowIndex < size ? result.get(rowIndex) : null;
String val = o == null ? null : o.toString();
datas.get(rowIndex).add(val);
}
}
```
Note this keeps the existing behaviour for the equal-length case (the only
case reachable when validation is on), so no regression there.
## Test
New `JsonPathProcessorDataFlipTest` (4 cases):
1. `$.a[*]`=1, `$.b[*]`=2 — shorter **first** path (crashed before);
2. `$.a[*]`=2, `$.b[*]`=1 — shorter **later** path (crashed before);
3. equal cardinality — rows still aligned (`[[1,10],[2,20]]`);
4. a path matching **nothing** — padded with `null`, first column order
preserved.
**Before (real output)**
```
[ERROR] Tests run: 4, Failures: 1, Errors: 1, Skipped: 0 <<< FAILURE!
[ERROR]
JsonPathProcessorDataFlipTest.shorterFirstPathMustNotThrowIndexOutOfBounds:65
Unequal path cardinality must not crash the reader
==> Unexpected exception thrown: java.lang.IndexOutOfBoundsException:
Index 1 out of bounds for length 1
[ERROR]
JsonPathProcessorDataFlipTest.missingFieldPadsWithNullInsteadOfShifting:120 »
IndexOutOfBounds
```
**After (real output)**
```
[INFO] Tests run: 4, Failures: 0, Errors: 0, Skipped: 0 -- in
...util.JsonPathProcessorDataFlipTest
```
**Full `connector-http-base` module suite (no regressions)**
```
[INFO] Tests run: 6 -- HttpClientProviderTest
[INFO] Tests run: 5 -- HttpParameterCredentialSchemeTest
[INFO] Tests run: 13 -- HttpFactoryTest
[INFO] Tests run: 3 -- HttpSourceReaderInternalPollNextTest
[INFO] Tests run: 17 -- HttpSourceReaderUpdateRequestParamTest
[INFO] Tests run: 1 -- JsonFieldMissedReturnNullComplexTest
[INFO] Tests run: 1 -- JsonFieldMissedReturnNullTest
[INFO] Tests run: 1 -- JsonFieldMissedReturnNullTreeFeatureTest
[INFO] Tests run: 5 -- HttpSinkBatchWriterTest
[INFO] Tests run: 5 -- BinaryResponseCollectorTest
[INFO] Tests run: 11 -- FilenameExtractorTest
[INFO] Tests run: 4 -- JsonPathProcessorDataFlipTest
[INFO] Tests run: 72, Failures: 0, Errors: 0, Skipped: 0
[INFO] BUILD SUCCESS
```
Commands run:
```shell
export JAVA_HOME=/path/to/jdk17
# compile the module and its upstream deps (offline, using the local ~/.m2
cache)
mvn -o -q -pl seatunnel-connectors-v2/connector-http/connector-http-base -am
\
-DskipTests -Dspotless.check.skip=true install
# the new regression test
mvn -o -pl seatunnel-connectors-v2/connector-http/connector-http-base \
-Dspotless.check.skip=true -Dcheckstyle.skip=true \
-Dtest=JsonPathProcessorDataFlipTest -DfailIfNoTests=false test
# full module suite
mvn -o -pl seatunnel-connectors-v2/connector-http/connector-http-base \
-Dspotless.check.skip=true -Dcheckstyle.skip=true test
# formatting (Apache spotless / AOSP style)
mvn -o -pl seatunnel-connectors-v2/connector-http/connector-http-base
spotless:apply
```
**What was not run (stated plainly):** only `connector-http-base` was built
and tested, not the full reactor — the repo is huge and most other modules need
network/DB/Docker services. There is no end-to-end HTTP-source job run against
a live endpoint; the proof is at the unit level (the exact `dataFlip` contract
plus the full module suite). `spotless:apply` was run so the new files match
the project's formatter.
## Notes
- The `ArrayJsonPathProcessor` subclass always pre-sizes its rows, so it
cannot hit this path; the fix is in the shared base class `dataFlip` that it
also inherits.
- Configuration that previously crashed now yields rows padded with `null`,
matching the documented intent of `json_field_missed_return_null`.
Prepared with an AI coding agent.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]