javajsonfile-access

How can I fix the issue as: "Exception in thread "main" java.nio.file.InvalidPathException: Illegal char <:> at index" reading JSON-s as a String?


What I need:

I need to get String representation of two JSON files separately or at the same time, if it possible.

To send it to the method with declaration as:

public static List<String> getAllExportsWithProductIds(String directory, List<String> productIds)

What I have:

I'm working with the following version of code as:

public class ProductIdImporter {
    public ProductIdImporter() {
        // TODO Auto-generated constructor stub
    }

    public void importJson() throws IOException {
        //List<String> stringList = Arrays.asList("0001755256", "0001694109");
        List<Path> paths = Arrays.asList(Paths.get("C:\\Users\\pc\\IdeaProjects\\jsonapi\\src\\test\\java\\resources\\json\\product_0001690510.json"),
                Paths.get("C:\\Users\\pc\\IdeaProjects\\jsonapi\\src\\test\\java\\resources\\json\\product_0001694109.json"));

        ObjectMapper jsonMapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

        List<String> productIds = paths
                .stream()
                .map(path -> {
                    try {
                        return jsonMapper
                                .readValue(Files.newInputStream(path), Product[].class);
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                }).map(Arrays::asList)
                .flatMap(List::stream)
                .map(Product::getId)
                .toList();
        productIds.forEach(System.out::println);

        try {
            String content = new String(Files.readAllBytes(Paths.get("C:\\Users\\pc\\IdeaProjects\\jsonapi\\src\\test\\java\\resources\\json\\product_0001690510.json",
                    "C:\\Users\\pc\\IdeaProjects\\jsonapi\\src\\test\\java\\resources\\json\\product_0001694109.json")), StandardCharsets.UTF_8);
            // default StandardCharsets.UTF_8
            System.out.println(getAllExportsWithProductIds(content, productIds));

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws IOException {
        ProductIdImporter importer = new ProductIdImporter();
        importer.importJson();
    }

    static class ExportList {
        public List<Product> products;

        public ExportList() {
        }

        public List<Product> getProducts() {
            return products;
        }
    }

    static class Product {
        public String productID;

        public Product() {
        }

        public String getId() {
            return productID;
        }
    }

    public static List<String> getAllExportsWithProductIds(String directory, List<String> productIds) throws IOException {
        var matchingObjects = new ArrayList<String>();
        try (var fileStream = Files.walk(Path.of(directory))) {
            for (var file : fileStream.toList()) {
                var json = Json.readString(Files.readString(file));
                var objects = JsonDecoder.array(json);

                for (var object : objects) {
                    var objectProductIDs = JsonDecoder.field(
                            object, "products",
                            JsonDecoder.array(JsonDecoder.field("productID", JsonDecoder::string))
                    );
                    for (var productId : objectProductIDs) {
                        if (productIds.contains(productId)) {
                            matchingObjects.add(Json.writeString(object));
                            break;
                        }
                    }
                }
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return matchingObjects;
    }
}

where I need to get the access specifically to the directory to read two JSON files separately to get as a parameter String representation each of them to send to the custom method for handling based on productID parameter:

  1. JSON №1
  2. JSON №2

The directory is: C:\Users\pc\IdeaProjects\jsonapi\src\test\java\resources\json

before handling list of id-s.

My project-structure of the project is as in the buttom provided:

C:.
├───.idea
│   ├───artifacts
│   ├───inspectionProfiles
│   └───libraries
├───out
│   └───artifacts
│       └───jsonapi_jar
├───src
│   ├───main
│   │   ├───java
│   │   │   └───org.example
│   │   └───resources
│   │       └───META-INF
│   └───test
│       └───java
│           └───resources
│               └───json
└───target
    ├───classes
    │   ├───META-INF
    │   └───org
    │       └───example
    └───generated-sources
        └───annotations

What I tried:

№1: I have updated my code version. I need to get the access to the directory with JSON-s correctly

№2: I have updated again with newer version, but still no luck.

№3: I have tried to use the code snippet based on this answer, but it returns me still the error while reading and parsing it as InvalidPathException.java.


While running the attached code and reading the content inside JSON-s, I'm reproducing the issue as:

Exception in thread "main" java.nio.file.InvalidPathException: Illegal char <:> at index

in one of my provided attempts.


To summarize:

As you can see, I'm passing a directory to the method instead of a file and that doesn't work.

Based on it, my question is:

How can I do each file at a time and manage them after? If it doesn't make sense to try to do two at the same time. Can I handle two files of JSON-s as one file at a time, parse to String, and send each of them to the method for handling? Is it possible, at all?

Thank you in advance for your ideas how to handle it. If you need more details, I'm ready to provide.


Solution

  • As one of ways it could be implemented as provided below:

    public class ProductIdImporter {
        record ExportList(Json undecoded, List<Product> products) {
            static ExportList fromJson(Json json) {
                return new ExportList(
                        json,
                        JsonDecoder.field(json, "products", JsonDecoder.array(Product::fromJson))
                );
            }
        }
    
        record Product(String productID) {
            static Product fromJson(Json json) {
                return new Product(JsonDecoder.field(
                        json,
                        "productID",
                        JsonDecoder::string
                ));
            }
        }
    
        public static List<ExportList> loadExports(InputStream resource) throws IOException {
            var json = Json.read(new InputStreamReader(resource));
            return JsonDecoder.array(json, ExportList::fromJson);
        }
    
        public static List<Json> getAllExportsWithProductIds(List<String> resources, List<String> productIds) throws IOException {
            var exports = new ArrayList<ExportList>();
            for (var resource : resources) {
                try (var inputStream = Objects.requireNonNull(ProductIdImporter.class.getResourceAsStream(resource))) {
                    exports.addAll(loadExports(inputStream));
                }
            }
    
            return  exports.stream()
                    .filter(export -> export.products
                            .stream()
                            .anyMatch(product -> productIds.contains(product.productID))
                    )
                    .map(ExportList::undecoded)
                    .toList();
    
        }
    
        public static void main(String[] args) throws IOException {
            var resources = List.of("/product1.json", "/product2.json");
            var productIds = List.of( "00017552897");
            System.out.println(getAllExportsWithProductIds(
                    resources,
                    productIds
            ));
        }
    }