All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.cefriel.template.io.json.JSONReader Maven / Gradle / Ivy

Go to download

A template-based component exploiting Apache Velocity to define declarative mappings for schema and data transformations.

There is a newer version: 2.5.2
Show newest version
/*
 * Copyright (c) 2019-2023 Cefriel.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.cefriel.template.io.json;

import com.cefriel.template.io.Reader;
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.Option;
import com.jayway.jsonpath.PathNotFoundException;
import net.minidev.json.JSONArray;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;

public class JSONReader implements Reader {

    private final Logger log = LoggerFactory.getLogger(JSONReader.class);
    Object document;

    private boolean verbose;

    public JSONReader(String json) {
        Configuration conf = Configuration.defaultConfiguration()
                .addOptions(Option.ALWAYS_RETURN_LIST);

        document = conf.jsonProvider().parse(json);
    }

    public JSONReader(File file) throws IOException {
        if (Files.exists(file.toPath())) {
            Configuration conf = Configuration.defaultConfiguration()
                    .addOptions(Option.ALWAYS_RETURN_LIST);

            document = conf.jsonProvider().parse(Files.readString(Paths.get(file.getPath())));
        } else
            throw new IllegalArgumentException("FILE: " + file.getPath() + " FOR JSONREADER DOES NOT EXIST");

    }
    @Override
    public void setQueryHeader(String header) {}

    @Override
    public void appendQueryHeader(String s) {}

    @Override
    public List> getDataframe(String query) throws Exception {
        Object queryDoc = Configuration.defaultConfiguration().jsonProvider().parse(query);
        String iterator = JsonPath.read(queryDoc, "$.iterator");
        Set keys = JsonPath.read(queryDoc, "$.paths.keys()");
        List> output = new ArrayList<>();
        // config to get results as jsonPaths
        Configuration conf = Configuration.builder().options(Option.AS_PATH_LIST).build();
        try {
            // Extract paths for each node identified by the iterator
            List results = JsonPath.using(conf).parse(document).read(iterator);
            for (int i=0; i< results.size(); i++)
                output.add(new HashMap<>());
            for(String key : keys) {
                String path = JsonPath.read(queryDoc, "$.paths." + key);
                Object objects = JsonPath.read(document, iterator + "." + path);

                // objects can either be a list of objects or a single object(string)
                // if it is a single object then in the output list i have only one item

                if (!(objects instanceof JSONArray)) {
                    String value = objects == null ? "null" : objects.toString();
                    output.get(0).put(key,value);
                }

                else {
                    JSONArray objectsList = (JSONArray) objects;
                    // CASE 1, all the nodes identified by the iterator have the key (sub field)
                    // A single query to extract all values for the key
                    if (objectsList.size() == results.size()) {
                        for (int i = 0; i < objectsList.size(); i++) {
                            String value = objectsList.get(i) == null ? "null" : objectsList.get(i).toString();
                            output.get(i).put(key, value);
                        }
                    }
                    // CASE 2, not all nodes have the key (sub field)
                    // For each node a query is executed to get the value for the key (sub field)
                    // The subquery is composed of the jsonpath for the node and the specific key (sub field)
                    else {
                        for (int i = 0; i < results.size(); i++) {
                            String topPath = results.get(i);
                            try {
                                var x = JsonPath.read(document, topPath + "." + path);
                                var value = x == null ? "null" : x.toString();
                                output.get(i).put(key, value);
                            } catch (PathNotFoundException pe) {
                                // what happens when the path is not found? i.e. the item does not have the field the jsonPath is pointing to
                                // for now we do not put the key in the map
                                if(verbose) {
                                    log.warn("PATH NOT FOUND: " + topPath + "." + path);
                                }
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            Map map = new HashMap<>();
            for(String key : keys) {
                String path = JsonPath.read(queryDoc, "$.paths." + key);
                Object object = JsonPath.read(document, iterator + "." + path);
                map.put(key, object.toString());
            }
            output.add(map);
        }
        return output;
    }

    @Override
    public List> getDataframe() throws Exception {
        return null;
    }

    @Override
    public void debugQuery(String query, String destinationPath) throws Exception {
        log.warn("Debug operation not implemented");
    }

    @Override
    public void setVerbose(boolean verbose) {
        this.verbose = verbose;
    }

    /**
     * Not implemented for JSONReader yet.
     * @param outputFormat String identifying the output format
     */
    @Override
    public void setOutputFormat(String outputFormat) { return;}

    @Override
    public void shutDown() {}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy