JSON から PostgreSQL JSON演算子のパスを作る

JSONの解析として、過去、いろいろと作ってきた。
Jackson でJSON読込み key-value の BiConsumer を処理する - Oboe吹きプログラマの黙示録
Jackson でJSON読込み key-value の BiConsumer で、日付時刻も - Oboe吹きプログラマの黙示録
Jackson JSON読込み、key-value 解析を柔軟にする - Oboe吹きプログラマの黙示録
JSON の部分的な抽出 - Oboe吹きプログラマの黙示録
ここに入れてきたのだが、
github.com

PostgreSQL JSON演算子 によるパスの生成を作ることにした。
今まで作成した JsonNodeParse を継承して作成した。

package org.yipuran.json;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.JsonNodeType;
/**
 * PostgreSQL JSON演算子パス生成用 JSON Parser
 * <pre>
 * JsonNodeParse の継承クラス
 * PostgreSQL JSON演算子パスの表現、
 *    'A'->'B'->>'C'  : C の値が、 文字列、数値、null
 *    'A'->'B'->'C'   : C の値が、JSonNode
 *    'A'->'D'->>2    : 配列D インデックス=2 の値
 *    'A'->'D'->2     : 配列D インデックス=2 のJSonNode
 * 上記の表現形式の Entry<String, JsonNode> のStreamを生成する目的のクラス
 * </pre>
 */
public class JsonNodePgParse extends JsonNodeParse{

    /**
     * JsonNode Entry Stream生成.
     * <pre>
     * Entryのkeyは、PostgreSQL の JSON演算子 -> ->> とシングルクォート括りによるパス
     * value がJSONオブジェクトであれば、"->"
     * value が文字列、数値、null であれば、最後が、"->>"
     * </pre>
     * @param node JsonNode
     * @return Entry<String, JsonNode> の Stream
     */
    @Override
    public Stream<Entry<String, JsonNode>> nodeStream(JsonNode node){
        Map<String, JsonNode> map = new HashMap<>();
        nodeJsonPg(node, "", map);
        return map.entrySet().stream();
    }

    private void nodeJsonPg(JsonNode node, String path, Map<String, JsonNode> map) {
        if (node.getNodeType().equals(JsonNodeType.OBJECT)) {
            for(Iterator<Entry<String, JsonNode>> it=node.fields(); it.hasNext();) {
                Entry<String, JsonNode> entry = it.next();
                String _path = path + "->" + "'" + entry.getKey() + "'";
                map.put(_path.substring(2), node);
                nodeJsonPg(entry.getValue(), path + "->" + "'"+ entry.getKey() + "'", map);
            }
        }else if(node.getNodeType().equals(JsonNodeType.ARRAY)){
            if (node.size() > 0){
                int x=0;
                for(Iterator<JsonNode> it=node.iterator(); it.hasNext();x++){
                    nodeJsonPg(it.next(), path + "->" + x, map);
                }
            }
        }else if(node.getNodeType().equals(JsonNodeType.NULL)){
            map.put(relaceLastallow(path.substring(2)), null);
        }else{
            map.put(relaceLastallow(path.substring(2)), node);
        }
    }
    private Pattern lastallow = Pattern.compile("\\->(?<=\\->)([^\\->]+$)");
    private String relaceLastallow(String key) {
        Matcher m = lastallow.matcher(key);
        if (m.find()) {
            return key.substring(0, m.start()) + m.group().replaceFirst("\\->", "->>");
        }
        return key;
    }
}

https://github.com/yipuran/yipuran-jack の version 1.4 としてこれを追加した

使用例)

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import org.yipuran.json.JsonNodePgParse;
import com.fasterxml.jackson.databind.JsonNode;
try{
    InputStream inst = Thread.currentThread().getContextClassLoader()
    .getResourceAsStream(JsonTest.class.getPackageName().replaceAll("\\.", "/")+"/"+"sample.json");
    String json = toStringFromInputStream(inst);
    JsonNodePgParse parse = new JsonNodePgParse();
    JsonNode node = parse.readTree(json);
    
    parse.nodeStream(node).sorted((a, b)->a.getKey().compareTo(b.getKey())).forEach(e->{
        System.out.println("key="+e.getKey() +"  value="+e.getValue());
    });
    
}catch(IOException e){
    e.printStackTrace();
}