与Jackson解组“ Json输入流必须以Json对象数组开头”

时间:2019-04-22 08:32:21

标签: json jackson spring-batch unmarshalling

当解组仅包含一个JSON对象的文件时出现错误:“ IllegalStateException:Json输入流必须以Json对象数组开头” 我找不到任何解决方法,也不知道为什么必须这样做。

@Bean
public ItemReader<JsonHar> reader(@Value("file:${json.resources.path}/*.json") Resource[] resources) {
    log.info("Processing JSON resources: {}", Arrays.toString(resources));
    JsonItemReader<JsonHar> delegate = new JsonItemReaderBuilder<JsonHar>()
            .jsonObjectReader(new JacksonJsonObjectReader<>(JsonHar.class))
            .resource(resources[0])  //FIXME had to force this, but fails anyway because the file is "{...}" and not "[...]"
            .name("jsonItemReader")
            .build();
    MultiResourceItemReader<JsonHar> reader = new MultiResourceItemReader<>();
    reader.setDelegate(delegate);
    reader.setResources(resources);
    return reader;
}

我需要一种解组单个目标文件的方法,强制数组有什么意义(在我的用例中不会有)?

3 个答案:

答案 0 :(得分:0)

  

我不明白为什么一定要这么做。

JsonItemReader被设计为读取an array of objects,因为批处理通常是关于处理包含很多项目而不是单个项目的数据源。

  

我找不到任何解决方法

JsonObjectReader是您要寻找的:您可以实现它来读取单个json对象,并将其与JsonItemReader一起使用(在构造时或使用setter)。这不是解决方法,而是为像您这样的特定用例设计的策略界面。

答案 1 :(得分:0)

这可能不理想,这是我处理情况的方式:

@Bean
public ItemReader<JsonHar> reader(@Value("file:${json.resources.path}/*.json") Resource[] resources) {
    log.info("Processing JSON resources: {}", Arrays.toString(resources));
    JsonItemReader<JsonHar> delegate = new JsonItemReaderBuilder<JsonHar>()
            .jsonObjectReader(new JacksonJsonObjectReader<>(JsonHar.class))
            .resource(resources[0]) //DEBUG had to force this because of NPE...
            .name("jsonItemReader")
            .build();
    MultiResourceItemReader<JsonHar> reader = new MultiResourceItemReader<>();
    reader.setDelegate(delegate);
    reader.setResources(Arrays.stream(resources)
            .map(WrappedResource::new) // forcing the bride to look good enough
            .toArray(Resource[]::new));
    return reader;
}
@RequiredArgsConstructor
static class WrappedResource implements Resource {
    @Delegate(excludes = InputStreamSource.class)
    private final Resource resource;
    @Override
    public InputStream getInputStream() throws IOException {
        log.info("Wrapping resource: {}", resource.getFilename());
        InputStream in = resource.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(in, UTF_8));
        String wrap = reader.lines().collect(Collectors.joining())
                .replaceAll("[^\\x00-\\xFF]", "");  // strips off all non-ASCII characters
        return new ByteArrayInputStream(("[" + wrap + "]").getBytes(UTF_8));
    }
}

答案 2 :(得分:0)

绝对不理想@thomas-escolan。正如@mahmoud-ben-hassine 所指出的,理想的做法是编写自定义阅读器。

如果一些新的 SOF 用户偶然发现了这个问题,我在这里留个 code example on how to do it