JSONパーサーslowjson ANTLR戦闘

最近の原則を学んでコンパイルされている、そしてantlr4この強力なツールを学び、ANTLRは、(言語認識のための別のツール)スタンドのJavaで書かれたものの、形態や構文を解析するための非常に強力なツールですが、それコードc ++、行く......と他の言語を生成することができます。その主な役割は、あなたが使用できるということであるBNFを構文規則を記述するために、それはあなたが対応するパーサを生成するのに役立ちます。
練習は、学習するための最良の方法である速い深くANTLRの操作を理解するために、関連のインターフェイスが実践手の事を見つける必要がありますことを私たちは皆知っています。私はJSONパーサについて準備ができてがたつきてるので、継続的なセキュリティの脆弱性は、昨年のfastjsonを報告したことを思い出してください。我々は行う他の方法ながら、我々は戦いの正に勝つません速くfastjson以上書くことはできません、バグ少なく、より安全なJSONパーサ、またバグより、遅く、安全性の低いパーサに書き込むことができますライン。
アリのベンチマークfastjsonに、私はそれを命名あげるslowjsonを、ソースコードがされているgithubのslowjsonの歓迎の星。slowjsonを促進するために、私は良い広告の言葉が欲しいです。

推進と賃金は、あなたがやりたい上がりますか?
あなたは、年末の賞にそれを取るしたいですか?
あなたは小さなアーティストたちのパフォーマンスを最適化するために、同僚の目になりたいですか?
今日slowjsonで、交換fastjsonでエンドのパフォーマンスの最適化を行い、10倍のパフォーマンスが夢ではない、それは準プロモーションや賃金上昇になることができます。

解析JSON文字列

あまりにも多くのトピックに、JSONパーサーはどのように書くには?あなたが実際に歌詞を自分のパーサ、パーサ......、今日のヒーローANTLRはあなたが唯一のJSON BNF構文規則に必要な、生成ライン上で明確に説明するのに役立ちますを記述する必要はありません、あなたはこれを記述することができます直接はjson.org我々はそこにコードのANTLRのgithubのリポジトリで見つかった、両方の外観がわずかに異なるルールは、公式ウェブサイトにいくつかの詳細をJSON。ここで私は、提供直接使用ルールANTLRを記述する。

grammar JSON;

json
   : value
   ;

obj
   : '{' pair (',' pair)* '}'
   | '{' '}'
   ;

pair
   : STRING ':' value
   ;

array
   : '[' value (',' value)* ']'
   | '[' ']'
   ;

value
   : STRING
   | NUMBER
   | obj
   | array
   | 'true'
   | 'false'
   | 'null'
   ;


STRING
   : '"' (ESC | SAFECODEPOINT)* '"'
   ;


fragment ESC
   : '\\' (["\\/bfnrt] | UNICODE)
   ;
fragment UNICODE
   : 'u' HEX HEX HEX HEX
   ;
fragment HEX
   : [0-9a-fA-F]
   ;
fragment SAFECODEPOINT
   : ~ ["\\\u0000-\u001F]
   ;


NUMBER
   : '-'? INT ('.' [0-9] +)? EXP?
   ;


fragment INT
   : '0' | [1-9] [0-9]*
   ;

// no leading zeros

fragment EXP
   : [Ee] [+\-]? INT
   ;

// \- since - means "range" inside [...]

WS
   : [ \t\n\r] + -> skip
   ;

このファイル保存JSON.g4、次のコマンドを実行し、もちろん、あなたが適切antlr4がインストールされていることを提供します。

antlr4 JSON.g4  -no-listener -package xyz.xindoo.slowjson

この時間ANTLRを使用すると、JSONパーサーと字句解析JSONLexer.java JSONParser.javaを生成するのに役立ちます。

    private static String jsonStr = "{\"key1\":\"value1\",\"sub\":{\"subkey\":\"subvalue1\"}}"; 
    public static JSONParser.ObjContext parse() {
        JSONLexer lexer = new JSONLexer(CharStreams.fromString(jsonStr));
        CommonTokenStream tokens = new CommonTokenStream(lexer);  //生成token 
        JSONParser parser = new JSONParser(tokens);
        JSONParser.ObjContext objCtx = parser.obj(); // 将token转化为抽象语法树(AST) 
        return new objCtx;
    }

実際には、あなただけの、あなたは、解決するにはjsonStrを完了することができますので、多くのコードの先頭に記述する必要があるが、この決議の結果は、我々はASTが出て解析された視覚化することができますプラグインANTLRのアイデアを使用して、パッケージ抽象構文木の内部ANTLRです、 "{" KEY1 ":" 値1 "は、" サブ ":{" サブキー ":" subvalue1 "}}" 構文木の長さに従います。
ここに画像を挿入説明

JSONObjectにJSON文字

それは、JSON完了しているが、文字列を解析することができますが、fastjsonの使用と思われる場合、あなたはJSONObjectの変換の構文木のノードを完了する必要があります。ANTLR文法規則に従って、自動的に各ノードタイプの生成を助けるされているが、実際には、あなただけの各ノードは、それのためにJSONObjectまたはKVを変換して、ツリー全体をトラバースする必要があります。

package xyz.xindoo.slowjson;

import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

public class JSONObject {

    private Map<String, Object> map;

    public JSONObject() {
        this.map = new HashMap<>();
    }

    protected JSONObject(JSONParser.ObjContext objCtx) {
        this.map = new HashMap<>();
        for (JSONParser.PairContext pairCtx: objCtx.pair()) {
            String key = pairCtx.STRING().getText();
            map.put(key.substring(1, key.length()-1), pairCtx.value());
        }
    }

    public JSONObject getJSONObject(String key) {
        JSONParser.ValueContext value = (JSONParser.ValueContext)map.get(key);
        if (value == null) {
            return null;
        }
        return new JSONObject(value.obj());
    }

    public String getString(String key) {
        Object value = map.get(key);
        if (value == null) {
            return null;
        }
        if (JSONParser.ValueContext.class.isInstance(value)) {
            JSONParser.ValueContext ctx = (JSONParser.ValueContext)value;
            String newValue = ctx.STRING().getText();
            map.put(key, newValue.substring(1, newValue.length()-1));
        }
        return (String)map.get(key);
    }

    public int getInt(String key) {
        String value = getString(key);
        if (value == null || "".equals(value)) {
            return 0;
        }
        return Integer.parseInt(value);
    }

    public long getLong(String key) {
        String value = getString(key);
        if (value == null || "".equals(value)) {
            return 0L;
        }
        return Long.parseLong(value);
    }

    public double getDouble(String key) {
        String value = getString(key);
        if (value == null || "".equals(value)) {
            return 0.0;
        }
        return Double.parseDouble(value);
    }
    
    public JSONArray getJSONArray(String key) {
        JSONParser.ValueContext value = (JSONParser.ValueContext)map.get(key);
        if (value == null) {
            return null;
        }
        return new JSONArray(value.array());
    }

    public void put(String key, Object object) {
        map.put(key, object);
    }

    public static JSONObject parseObject(String text) {
        JSONLexer lexer = new JSONLexer(CharStreams.fromString(text));
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        JSONParser parser = new JSONParser(tokens);
        JSONParser.ObjContext objCtx = parser.obj();
        return new JSONObject(objCtx);
    }

    public static JSONArray parseArray(String text) {
        if (text == null) {
            return null;
        }
        JSONArray array = JSONArray.parseArray(text);
        return array;
    }
}

私は、全体のASTをトラバースし、JSONObjectに変換するためのコードを持っていますが、より便利に達成するために、必要なサブになるまで待ってはいけません。多くのAPIとfastjsonのslowjsonのように発見していないここを参照してください!はい、私はちょうどfastjsonコピーされますが、私は、全体をコピーしていません。

性能試験

非常にカジュアルなパフォーマンステストされる次は、私は簡単にJSON文字列を発見し、いくつかの主要な競合他社のslowjsonに引っ張られ、次のようにfastjson、ジャクソン、gson、テスト結果は以下のとおりです。

Benchmark       Mode  Cnt       Score   Error  Units
Test.fastjson  thrpt    2  235628.511          ops/s
Test.gson      thrpt    2  237975.534          ops/s
Test.jackson   thrpt    2  212453.073          ops/s
Test.slowjson  thrpt    2   29905.109          ops/s

大きさのひとつ順位をPerformance're、私はとても遅いこれを期待していなかった...... OK、それに加えて、ランダムスピン......

    private static void randomSpin() {
        Random random = new Random();
        int nCPU = Runtime.getRuntime().availableProcessors();
        int spins = (random.nextInt()%8 + nCPU) * SPIN_UNIT;
        while (spins > 0) {
            spins--;
            float a = random.nextFloat();
        }
    }

その後、すべての方法は、ランダムなスピンで最初の呼び出しを取得し、CPUを消費していました。テストのパフォーマンスを、是非。

Benchmark       Mode  Cnt       Score   Error  Units
Test.fastjson  thrpt    2  349994.543          ops/s
Test.gson      thrpt    2  318087.884          ops/s
Test.jackson   thrpt    2  244393.573          ops/s
Test.slowjson  thrpt    2    2681.164          ops/s

マグニチュード差、およびIの二桁がパフォーマンス標準的な生産環境に到達した〜ああ、それはライン上に存在することができます......

JSON文字列にJSONObject

待機待機袋ブリッジは現在、JSON文字列からの変換を達成するためにJSON文字列JSONObjectなしJSONObjectに変換達成される、機能が完全にああではありません。しかし、これは、我々は再帰的toSting、次のコードを実行し、レベルのオブジェクトに合わせて、またJSONObject簡単です。

    @Override
    public String toString() {
        return toJSONString();
    }

    public String toJSONString() {
        StringBuilder sb = new StringBuilder();
        List<String> list = new ArrayList<>(map.size());
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            String key = entry.getKey();
            Object object = entry.getValue();
            String value = null;
            if (String.class.isInstance(object)) {
                value = "\"" + object.toString() + "\"";
            } else if (JSONObject.class.isInstance(object)) {
                value = object.toString();
            } else if (JSONArray.class.isInstance(object)) {
                value = object.toString();
            } else {
                value = ((JSONParser.ValueContext)object).getText();
            }
            list.add("\"" + key + "\":" + value);
        }
        sb.append("{");
        sb.append(String.join(",", list));
        sb.append("}");
        return sb.toString();
    }

JSONArray

JSONArrayが、実際には、上記のJSONArray JSONの重要な部分を言及したことはありません、次のようにアイデアやJSONArray JSONObjectの実現は、私のパッケージは非常に似ていますが、単純であるためである理由については言及しませんでした。

package xyz.xindoo.slowjson;

import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class JSONArray {
    private final List<JSONObject> list;

    public JSONArray() {
        this.list = new ArrayList<>();
    }
    public JSONArray(List<JSONObject> list) {
        this.list = new ArrayList<>(list.size());
        this.list.addAll(list);
    }

    protected JSONArray(JSONParser.ArrayContext arrayCtx) {
        this.list = arrayCtx.value()
                            .stream()
                            .map(valueContext -> new JSONObject(valueContext.obj()))
                            .collect(Collectors.toList());
    }

    public static JSONArray parseArray(String text) {
        JSONLexer lexer = new JSONLexer(CharStreams.fromString(text));
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        JSONParser parser = new JSONParser(tokens);
        JSONParser.ArrayContext arrayCtx = parser.array();
        return new JSONArray(arrayCtx);
    }

    public JSONObject getJSONObject(int index) {
        return list.get(index);
    }

    public void add(JSONObject jsonObject) {
        list.add(jsonObject);
    }

    @Override
    public String toString() {
        return toJSONString();
    }

    public String toJSONString() {
        StringBuilder sb = new StringBuilder();
        sb.append("[");
        List<String> strList = list.stream().map(JSONObject::toString).collect(Collectors.toList());
        sb.append(String.join(",", strList));
        sb.append("]");
        return sb.toString();
    }
}

全て

  1. Mavenはちょっとちょっとちょっと、赤KPIを容易にするために、中央の倉庫にアップロード。
  2. パーフェクトAPI、fastjsonのAPIのコピーは、それが全体をコピーしませんが。
  3. 完璧なタイプは、実際の支援はnull、ブール、数値型でJSON規範は、私は、String型のこの簡単な図を使用していました。
  4. 、例外スローANTLRを投げている存在すればパーフェクトExcptionは、ユーザーが誤解を招くだろう。
  5. ランダムスピン制御API、ユーザーへの相互の制御の性能を向上させます。

実際には藤堂の欄には、プロジェクトのようなslowjsonの外観は、すべての後、完璧ではないslowjsonの最大の特徴である、レヴェルへとそれをしないようにすることです。

最後に、ソースコードのすべてがのGitHubにアップロードされたslowjson、スターを歓迎しました。

公開された237元の記事 ウォンの賞賛574 ビュー510 000 +

おすすめ

転載: blog.csdn.net/xindoo/article/details/104735750