2

I am trying to load a JSON file sample.json from src/main/resources directory.

I have to map that json to a Java Object. And my application is reactive, I am using Spring webflux.

I have followed Simon's Blog to come up with this:

    SimpleModule module = new SimpleModule();
    module.addDeserializer(OffsetDateTime.class, new JsonDeserializer<>() {
      @Override
      public OffsetDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        return OffsetDateTime.parse(p.getValueAsString());
      }
    });

    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.registerModule(module);


    return Flux.using(() -> Files.lines(Paths.get(ClassLoader.getSystemResource("sample.json").toURI())),
        Flux::fromStream,
        BaseStream::close
    )
        .collectList()
        .map(lines -> String.join("\n", lines))
        .map(jsonContent -> {
          try {
            return objectMapper.readValue(jsonContent, MyPojo.class);
          } catch (JsonProcessingException e) {
            e.printStackTrace();
            return null;
          }
        })
        .map(MyPojo::getValues());

This works fine in local but fails when running inside a docker container. (I am using gradle build to build the jar file and then build the docker image from it)

Part of the error stacktrace:

java.nio.file.FileSystemNotFoundException: null at jdk.zipfs/jdk.nio.zipfs.ZipFileSystemProvider.getFileSystem(ZipFileSystemProvider.java:169) ~[jdk.zipfs:na] Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:

  • Check that the wnated resource is your classpath inside the Docker container. Maybe you have to add it in your Dockerfile: https://docs.docker.com/engine/reference/builder/#add – Alberto Segura Aug 10 '20 at 09:40
  • Simon's solution is also using blocking I/O, so if you have no benefit from using Flux here, then you can just read the file in regular blocking way using inputstream and offload the work to an elastic Scheduler. – Martin Tarjányi Aug 10 '20 at 17:28
  • Does this answer your question? [Reactive way to read and parse file from resources using WebFlux?](https://stackoverflow.com/questions/61139186/reactive-way-to-read-and-parse-file-from-resources-using-webflux) – Martin Tarjányi Aug 10 '20 at 17:31

1 Answers1

1

When running the docker image, you are trying to access the file from inside a Jar. And it seems that passing a resource URI directly to Paths.get won't work.

You can refer to the following stackoverflow discussions regarding the same:

  1. This answer
  2. Answers to this question
  3. Answers to this question

I think you should take a look at this class of Spring which decodes a byte stream into JSON and convert to Object's with Jackson 2.9, leveraging non-blocking parsing.

This code should serve your needs:

First get reference to the Resource in Spring's way

  @Value("classpath:/sample.json")
  Resource sampleFile;

Then do this:

return new Jackson2JsonDecoder()
        .decodeToMono(
            DataBufferUtils.read(sampleFile, new DefaultDataBufferFactory(), 4096),
            ResolvableType.forClass(MyPojo.class),
            null,
            null)
        .map(object -> (MyPojo) object)
        .map(MyPojo::getValues)

In this way, you can read the file in a non-blocking manner using DataBufferUtils.read and also map the json to your POJO.

Abhinaba Chakraborty
  • 2,766
  • 2
  • 4
  • 26