├── data ├── small.json.txt ├── richard-hightower │ ├── small.json.txt │ └── large.json.txt ├── json-org │ ├── about-the-files.txt │ ├── example-2.json.txt │ ├── example-1.json.txt │ ├── example-3.json.txt │ ├── example-5.json.txt │ └── example-4.json.txt ├── medium.json.txt └── large.json.txt ├── run-benchmark.cmd ├── src-benchmark └── com │ └── jenkov │ └── parsers │ ├── JsonObject.java │ ├── FileUtil.java │ ├── IterationBenchmark.java │ ├── JsonObjectBuilder.java │ └── AllBenchmarks.java ├── src └── com │ └── jenkov │ └── parsers │ ├── core │ ├── DataCharBuffer.java │ ├── DataByteBuffer.java │ ├── ParserException.java │ └── IndexBuffer.java │ └── json │ ├── TokenTypes.java │ ├── ElementTypes.java │ ├── JsonParser.java │ ├── JsonNavigator.java │ ├── JsonTokenizer.java │ └── JsonParser2.java ├── .gitattributes ├── src-test └── com │ └── jenkov │ └── parsers │ └── json │ ├── JsonOrgExamplesTest.java │ ├── JsonTokenizerTest.java │ ├── JsonNavigatorTest.java │ ├── TestFileAssertUtil.java │ ├── JsonParser2Test.java │ └── JsonParserTest.java ├── .gitignore └── all-benchmarks.cmd /data/small.json.txt: -------------------------------------------------------------------------------- 1 | { "key" : "value", 2 | "key2" : 12345, 3 | "key3" : false } -------------------------------------------------------------------------------- /data/richard-hightower/small.json.txt: -------------------------------------------------------------------------------- 1 | { 2 | "debug": "on\toff", 3 | "num" : 1 4 | 5 | } -------------------------------------------------------------------------------- /data/json-org/about-the-files.txt: -------------------------------------------------------------------------------- 1 | The files in this directory are the example files found on json.org here: 2 | 3 | http://json.org/example -------------------------------------------------------------------------------- /run-benchmark.cmd: -------------------------------------------------------------------------------- 1 | java -cp D:\data\java\gson\google-gson-2.2.4\gson-2.2.4.jar;out\production\parsers; com.jenkov.parsers.AllBenchmarks %1 %2 %3 -------------------------------------------------------------------------------- /data/json-org/example-2.json.txt: -------------------------------------------------------------------------------- 1 | {"menu": { 2 | "id": "file", 3 | "value": "File", 4 | "popup": { 5 | "menuitem": [ 6 | {"value": "New", "onclick": "CreateNewDoc()"}, 7 | {"value": "Open", "onclick": "OpenDoc()"}, 8 | {"value": "Close", "onclick": "CloseDoc()"} 9 | ] 10 | } 11 | }} -------------------------------------------------------------------------------- /src-benchmark/com/jenkov/parsers/JsonObject.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.parsers; 2 | 3 | /** 4 | */ 5 | public class JsonObject { 6 | 7 | public String key; 8 | public int key2; 9 | public boolean key3; 10 | 11 | public String[] stringArray; 12 | public int[] numberArray; 13 | public boolean[] booleanArray; 14 | public JsonObject sub; 15 | 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/com/jenkov/parsers/core/DataCharBuffer.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.parsers.core; 2 | 3 | /** 4 | */ 5 | public class DataCharBuffer { 6 | 7 | public char[] data = null; 8 | public int length = 0; 9 | 10 | public DataCharBuffer() { 11 | } 12 | 13 | public DataCharBuffer(char[] data) { 14 | this.data = data; 15 | } 16 | 17 | public DataCharBuffer(int capacity) { 18 | this.data = new char[capacity]; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/com/jenkov/parsers/core/DataByteBuffer.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.parsers.core; 2 | 3 | /** 4 | */ 5 | public class DataByteBuffer { 6 | 7 | public byte[] data = null; 8 | public int length = 0; 9 | 10 | 11 | public DataByteBuffer() { 12 | } 13 | 14 | public DataByteBuffer(byte[] data) { 15 | this.data = data; 16 | } 17 | 18 | public DataByteBuffer(int capacity) { 19 | this.data = new byte[capacity]; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /src-benchmark/com/jenkov/parsers/FileUtil.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.parsers; 2 | 3 | import com.jenkov.parsers.core.DataCharBuffer; 4 | 5 | import java.io.FileReader; 6 | import java.io.IOException; 7 | 8 | /** 9 | */ 10 | public class FileUtil { 11 | 12 | public static DataCharBuffer readFile(String fileName) throws IOException { 13 | FileReader reader = new FileReader(fileName); 14 | DataCharBuffer dataCharBuffer = new DataCharBuffer(8192); 15 | dataCharBuffer.length = reader.read(dataCharBuffer.data); 16 | reader.close(); 17 | return dataCharBuffer; 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /data/json-org/example-1.json.txt: -------------------------------------------------------------------------------- 1 | { 2 | "glossary": { 3 | "title": "example glossary", 4 | "GlossDiv": { 5 | "title": "S", 6 | "GlossList": { 7 | "GlossEntry": { 8 | "ID": "SGML", 9 | "SortAs": "SGML", 10 | "GlossTerm": "Standard Generalized Markup Language", 11 | "Acronym": "SGML", 12 | "Abbrev": "ISO 8879:1986", 13 | "GlossDef": { 14 | "para": "A meta-markup language, used to create markup languages such as DocBook.", 15 | "GlossSeeAlso": ["GML", "XML"] 16 | }, 17 | "GlossSee": "markup" 18 | } 19 | } 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /data/json-org/example-3.json.txt: -------------------------------------------------------------------------------- 1 | {"widget": { 2 | "debug": "on", 3 | "window": { 4 | "title": "Sample Konfabulator Widget", 5 | "name": "main_window", 6 | "width": 500, 7 | "height": 500 8 | }, 9 | "image": { 10 | "src": "Images/Sun.png", 11 | "name": "sun1", 12 | "hOffset": 250, 13 | "vOffset": 250, 14 | "alignment": "center" 15 | }, 16 | "text": { 17 | "data": "Click Here", 18 | "size": 36, 19 | "style": "bold", 20 | "name": "text1", 21 | "hOffset": 250, 22 | "vOffset": 100, 23 | "alignment": "center", 24 | "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;" 25 | } 26 | }} -------------------------------------------------------------------------------- /src/com/jenkov/parsers/core/ParserException.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.parsers.core; 2 | 3 | /** 4 | */ 5 | public class ParserException extends RuntimeException { 6 | 7 | public ParserException() { 8 | } 9 | 10 | public ParserException(String message) { 11 | super(message); 12 | } 13 | 14 | public ParserException(String message, Throwable cause) { 15 | super(message, cause); 16 | } 17 | 18 | public ParserException(Throwable cause) { 19 | super(cause); 20 | } 21 | 22 | public ParserException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { 23 | super(message, cause, enableSuppression, writableStackTrace); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/com/jenkov/parsers/core/IndexBuffer.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.parsers.core; 2 | 3 | /** 4 | */ 5 | public class IndexBuffer { 6 | public int[] position = null; 7 | public int[] length = null; 8 | public byte[] type = null; /* assuming there can be max 256 different token or element types (1 byte / type) */ 9 | 10 | public int count = 0; // the number of tokens / elements in the IndexBuffer. 11 | 12 | public IndexBuffer() { } 13 | 14 | public IndexBuffer(int capacity, boolean useTypeArray) { 15 | this.position = new int[capacity]; 16 | this.length = new int[capacity]; 17 | if(useTypeArray){ 18 | this.type = new byte[capacity]; 19 | } 20 | } 21 | 22 | 23 | } 24 | -------------------------------------------------------------------------------- /data/medium.json.txt: -------------------------------------------------------------------------------- 1 | { "key" : "value", 2 | "key2" : 12345, 3 | "key3" : false, 4 | 5 | "stringArray" : [ "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"], 6 | "numberArray" : [ 12345, 12345, 12345, 12345, 12345, 12345, 12345, 12345, 12345, 12345], 7 | "booleanArray" : [ true, false, true, false, true, false, true, false, true, false], 8 | 9 | "sub" : { 10 | "key" : "value", 11 | "key2" : 12345, 12 | "key3" : false, 13 | "stringArray" : [ "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"], 14 | "numberArray" : [ 12345, 12345, 12345, 12345, 12345, 12345, 12345, 12345, 12345, 12345], 15 | "booleanArray" : [ true, false, true, false, true, false, true, false, true, false] 16 | } 17 | } -------------------------------------------------------------------------------- /src/com/jenkov/parsers/json/TokenTypes.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.parsers.json; 2 | 3 | /** 4 | */ 5 | public class TokenTypes { 6 | 7 | public static final byte JSON_CURLY_BRACKET_LEFT = 1; // { 8 | public static final byte JSON_CURLY_BRACKET_RIGHT = 2; // } 9 | public static final byte JSON_SQUARE_BRACKET_LEFT = 3; // [ 10 | public static final byte JSON_SQUARE_BRACKET_RIGHT = 4; // ] 11 | public static final byte JSON_STRING_TOKEN = 5; // 12 | public static final byte JSON_STRING_ENC_TOKEN = 6; // 13 | public static final byte JSON_NUMBER_TOKEN = 7; // 14 | public static final byte JSON_BOOLEAN_TOKEN = 8; // 15 | public static final byte JSON_NULL_TOKEN = 9; // the , between properties 16 | public static final byte JSON_COLON = 10; // : 17 | public static final byte JSON_COMMA = 11; // the , between properties 18 | 19 | 20 | } 21 | -------------------------------------------------------------------------------- /data/json-org/example-5.json.txt: -------------------------------------------------------------------------------- 1 | {"menu": { 2 | "header": "SVG Viewer", 3 | "items": [ 4 | {"id": "Open"}, 5 | {"id": "OpenNew", "label": "Open New"}, 6 | null, 7 | {"id": "ZoomIn", "label": "Zoom In"}, 8 | {"id": "ZoomOut", "label": "Zoom Out"}, 9 | {"id": "OriginalView", "label": "Original View"}, 10 | null, 11 | {"id": "Quality"}, 12 | {"id": "Pause"}, 13 | {"id": "Mute"}, 14 | null, 15 | {"id": "Find", "label": "Find..."}, 16 | {"id": "FindAgain", "label": "Find Again"}, 17 | {"id": "Copy"}, 18 | {"id": "CopyAgain", "label": "Copy Again"}, 19 | {"id": "CopySVG", "label": "Copy SVG"}, 20 | {"id": "ViewSVG", "label": "View SVG"}, 21 | {"id": "ViewSource", "label": "View Source"}, 22 | {"id": "SaveAs", "label": "Save As"}, 23 | null, 24 | {"id": "Help"}, 25 | {"id": "About", "label": "About Adobe CVG Viewer..."} 26 | ] 27 | }} -------------------------------------------------------------------------------- /src/com/jenkov/parsers/json/ElementTypes.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.parsers.json; 2 | 3 | /** 4 | */ 5 | public class ElementTypes { 6 | 7 | public static final byte JSON_OBJECT_START = 1; // 8 | public static final byte JSON_OBJECT_END = 2; // } 9 | public static final byte JSON_ARRAY_START = 3; // [ 10 | public static final byte JSON_ARRAY_VALUE_STRING = 4; // 11 | public static final byte JSON_ARRAY_VALUE_STRING_ENC = 5; // String with encoded characters, like \t or \u2345 12 | public static final byte JSON_ARRAY_VALUE_NUMBER = 6; // [ 13 | public static final byte JSON_ARRAY_VALUE_BOOLEAN = 7; // [ 14 | public static final byte JSON_ARRAY_VALUE_NULL = 8; // [ 15 | public static final byte JSON_ARRAY_END = 9; // ] 16 | public static final byte JSON_PROPERTY_NAME = 10; // 17 | public static final byte JSON_PROPERTY_VALUE_STRING = 11; // 18 | public static final byte JSON_PROPERTY_VALUE_STRING_ENC = 12; // String with encoded characters, like \t or \u2345 19 | public static final byte JSON_PROPERTY_VALUE_NUMBER = 13; // 20 | public static final byte JSON_PROPERTY_VALUE_BOOLEAN = 14; // 21 | public static final byte JSON_PROPERTY_VALUE_NULL = 15; // 22 | 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src-benchmark/com/jenkov/parsers/IterationBenchmark.java: -------------------------------------------------------------------------------- 1 | package com.jenkov.parsers; 2 | 3 | import com.jenkov.parsers.core.DataCharBuffer; 4 | 5 | import java.io.IOException; 6 | 7 | /** 8 | */ 9 | public class IterationBenchmark { 10 | 11 | public static void main(String[] args) throws IOException { 12 | String fileName = "data/small.json.txt"; 13 | if(args.length > 0) { 14 | fileName = args[0]; 15 | } 16 | System.out.println("iterating: " + fileName); 17 | 18 | DataCharBuffer dataCharBuffer = FileUtil.readFile(fileName); 19 | 20 | int iterations = 10 * 1000 * 1000; //10.000.000 iterations to warm up JIT and minimize one-off overheads etc. 21 | if(args.length > 1){ 22 | iterations = Integer.parseInt(args[1]); 23 | } 24 | System.out.println("iterations: " + iterations); 25 | 26 | long startTime = System.currentTimeMillis(); 27 | for(int i=0; i 0) { 24 | benchmark = args[0]; 25 | } 26 | String fileName = "data/medium.json.txt"; 27 | if(args.length > 1) { 28 | fileName = args[1]; 29 | } 30 | int iterations = 10 * 1000 * 1000; //10.000.000 iterations to warm up JIT and minimize one-off overheads etc. 31 | if(args.length > 2){ 32 | iterations = Integer.parseInt(args[2]); 33 | } 34 | DecimalFormat format = new DecimalFormat("###,###"); 35 | System.out.println("Benchmark : " + benchmark); 36 | System.out.println("File : " + fileName); 37 | System.out.println("Iterations: " + format.format(iterations)); 38 | 39 | DataCharBuffer buffer = FileUtil.readFile(fileName); 40 | 41 | long startTime = System.currentTimeMillis(); 42 | if("JsonParser".equals(benchmark)) { 43 | runJsonParserBenchmark(buffer, iterations); 44 | } else if("JsonParser2".equals(benchmark)) { 45 | runJsonParser2Benchmark(buffer, iterations); 46 | } else if("JsonParserBuilder".equals(benchmark)) { 47 | runJsonParserBuilderBenchmark(buffer, iterations); 48 | } else if("JsonParser2Builder".equals(benchmark)) { 49 | runJsonParser2BuilderBenchmark(buffer, iterations); 50 | } else if("GsonStream".equals(benchmark)) { 51 | runGsonStreamBenchmark(buffer, iterations); 52 | } else if("GsonStreamBuilder".equals(benchmark)) { 53 | runGsonStreamBuilderBenchmark(buffer, iterations); 54 | } else if("GsonMap".equals(benchmark)) { 55 | runGsonMapBenchmark(buffer, iterations); 56 | } else if("GsonReflection".equals(benchmark)) { 57 | runGsonReflectionBenchmark(buffer, iterations); 58 | } else { 59 | System.out.println("Benchmark not recognized: " + benchmark); 60 | return; 61 | } 62 | long endTime = System.currentTimeMillis(); 63 | long totalTime = endTime - startTime; 64 | System.out.println("time : " + format.format(totalTime)); 65 | 66 | 67 | } 68 | 69 | 70 | private static void runJsonParserBenchmark(DataCharBuffer buffer, int iterations) { 71 | IndexBuffer jsonTokens = new IndexBuffer(8192, true); 72 | IndexBuffer jsonElements = new IndexBuffer(8192, true); 73 | 74 | JsonParser jsonParser = new JsonParser(jsonTokens, jsonElements); 75 | 76 | for(int i=0; i elements = new ArrayList(); 191 | reader.beginArray(); 192 | while(reader.hasNext()){ 193 | elements.add(reader.nextString()); 194 | } 195 | reader.endArray(); 196 | jsonObject.stringArray = elements.toArray(new String[elements.size()]); 197 | } else if("numberArray".equals(name)) { 198 | List elements = new ArrayList(); 199 | reader.beginArray(); 200 | while(reader.hasNext()){ 201 | elements.add(reader.nextInt()); 202 | } 203 | reader.endArray(); 204 | int[] ints = new int[elements.size()]; 205 | for(int i=0; i elements = new ArrayList(); 211 | reader.beginArray(); 212 | while(reader.hasNext()){ 213 | elements.add(reader.nextBoolean()); 214 | } 215 | reader.endArray(); 216 | boolean[] booleans = new boolean[elements.size()]; 217 | for(int i=0; i map = (Map) gson.fromJson ( 235 | new CharArrayReader( buffer.data, 0, buffer.length ), Map.class ); 236 | 237 | } 238 | 239 | } 240 | 241 | private static void runGsonReflectionBenchmark(DataCharBuffer buffer, int iterations) { 242 | Gson gson = new Gson(); 243 | 244 | for(int i=0; i