Esper version 8.2.0 handles JSON documents directly, without the need to create a class. It does so by supporting EPL create-schema for JSON, with the EPL compiler producing a suitable streaming JSON parser and a value class with fields that hold parsed JSON values. This blog post compares the performance of Gson and Jackson with the JSON parser that the EPL compiler produces.

The tests run the java-json-benchmark which we extended to test Esper. For reference, Gson is a JSON serialization/deserialization library and so is Jackson.

The JSON string contains multiple user information such as user id (guid), age, eye color, address as well as user tags and friend information. The string is ~1k bytes in size.

{
   "users": [
     {
       "_id": "45166552176594981065",
       "index": 692815193,
       "guid": "oLzFhQttjjCGmijYulZg",
       "isActive": true,
       "balance": "XtMtTkSfmQtyRHS1086c",
       "picture": "Q8YoyJ0cL1MGFwC9bpAzQXSFBEcAUQ8lGQekvJZDeJ5C5p",
       "age": 23,
       "eyeColor": "XqoN9IzOBVixZhrofJpd",
       "name": "xBavaMCv6j0eYkT6HMcB",
       "gender": "VnuP3BaA3flaA6dLGvqO",
       "company": "L9yT2IsGTjOgQc0prb4r",
       "email": "rfmlFaVxGBSZFybTIKz0",
       "phone": "vZsxzv8DlzimJauTSBre",
       "address": "fZgFDv9tX1oonnVjcNVv",
       "about": "WysqSAN1psGsJBCFSR7P",
       "registered": "Lsw4RK5gtyNWGYp9dDhy",
       "latitude": 2.6395313895198393,
       "longitude": 110.5363758848371,
       "tags": [
         "Hx6qJTHe8y",
         "23vYh8ILj6",
         "geU64sSQgH",
         "ezNI8Gx5vq"
       ],
       "friends": [
         {
           "id": "3987",
           "name": "dWwKYheGgTZejIMYdglXvvrWAzUqsk"
         },
         {
           "id": "4673",
           "name": "EqVIiZyuhSCkWXvqSxgyQihZaiwSra"
         }
       ],
       "greeting": "xfS8vUXYq4wzufBLP6CY",
       "favoriteFruit": "KT0tVAxXRawtbeQIWAot"
     },
     {
       "_id": "23504426278646846580",
       "index": 675066974,
       "guid": "MfiCc1n1WfG6d6iXcdNf",
       "isActive": true,
       "balance": "OQEwTOBvwK0b8dJYFpBU",
       "picture": "avtMGQxSrO1h86V7KVaKaWUFZ0ooZd9GmIynRomjCjP8tEN",
       "age": 33,
       "eyeColor": "Fjsm1nmwyphAw7DRnfZ7",
       "name": "NnjrrCj1TTObhT9gHMH2",
       "gender": "ISVVoyQ4cbEjQVoFy5z0",
       "company": "AfcGdkzUQMzg69yjvmL5",
       "email": "mXLtlNEJjw5heFiYykwV",
       "phone": "zXbn9iJ5ljRHForNOa79",
       "address": "XXQUcaDIX2qpyZKtw8zl",
       "about": "GBVYHdxZYgGCey6yogEi",
       "registered": "bTJynDeyvZRbsYQIW9ys",
       "latitude": 16.675958191062414,
       "longitude": 114.20858157883556,
       "tags": [],
       "friends": [],
       "greeting": "EQqKZyiGnlyHeZf9ojnl",
       "favoriteFruit": "9aUx0u6G840i0EeKFM4Z"
     }
   ]
 }

Listed below is the EPL schema for the JSON document.

create json schema Friend(id string, name string);

create json schema User(_id string,
  index int,
  guid string,
  isActive string,
  balance string,
  picture string,
  age int,
  eyeColor string,
  name string,
  gender string,
  company string,
  email string,
  phone string,
  address string,
  about string,
  registered string,
  latitude double,
  longitude double,
  tags string[],
  friends Friend[],
  greeting string,
  favoriteFruit string);

create json schema Users(users User[]);

The benchmark compiles and deploys the EPL. It obtains the event sender to parse JSON without actually processing the event. The steps for this are in the next few line.

compileDeploy(runtime, schema); // compile and deploy schema (see doc)
EventSenderJson sender = (EventSenderJson)      
       runtime.getEventService().getEventSender("Users");
sender.parse(json); // json string as above

We extended the java-json-benchmark project to run Esper. The java-json-benchmark uses JMH and can run the different libraries. The results of the run is below.

.\run.ps1 deser --apis databind --libs "esper,gson,jackson"

Benchmark                  Mode  Cnt       Score        Error  Units
 Deserialization.gson      thrpt   20  380355.156 ± 102952.861  ops/s
 Deserialization.esper     thrpt   20  625104.578 ± 124892.697  ops/s
 Deserialization.jackson   thrpt   20  703692.069 ± 166341.185  ops/s

It is not clear why Gson performance looks low. The complete output is below.

Run progress: 0.00% complete, ETA 00:01:10
 Fork: 1 of 2
 Warmup Iteration   1: SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
 SLF4J: Defaulting to no-operation (NOP) logger implementation
 SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
 Using SEED=355928074 as seed for Random
 356831.878 ops/s
 Warmup Iteration   2: 486136.353 ops/s
 Warmup Iteration   3: 515357.952 ops/s
 Warmup Iteration   4: 509446.072 ops/s
 Warmup Iteration   5: 518303.540 ops/s
 Iteration   1: 517984.589 ops/s
 Iteration   2: 518057.298 ops/s
 Iteration   3: 517874.770 ops/s
 Iteration   4: 520368.313 ops/s
 Iteration   5: 504031.483 ops/s
 Iteration   6: 259520.276 ops/s
 Iteration   7: 141100.628 ops/s
 Iteration   8: 196268.361 ops/s
 Iteration   9: 228216.651 ops/s
 Iteration  10: 260322.078 ops/s
 Run progress: 50.00% complete, ETA 00:00:39
 Fork: 2 of 2
 Warmup Iteration   1: SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
 SLF4J: Defaulting to no-operation (NOP) logger implementation
 SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
 Using SEED=355928074 as seed for Random
 193367.787 ops/s
 Warmup Iteration   2: 280659.932 ops/s
 Warmup Iteration   3: 302554.536 ops/s
 Warmup Iteration   4: 322162.441 ops/s
 Warmup Iteration   5: 329478.408 ops/s
 Iteration   1: 341587.662 ops/s
 Iteration   2: 353809.794 ops/s
 Iteration   3: 364638.181 ops/s
 Iteration   4: 384033.414 ops/s
 Iteration   5: 402530.792 ops/s
 Iteration   6: 412963.221 ops/s
 Iteration   7: 423726.426 ops/s
 Iteration   8: 431531.785 ops/s
 Iteration   9: 440825.460 ops/s
 Iteration  10: 448492.988 ops/s
 Result "com.github.fabienrenaud.jjb.databind.Deserialization.gson":
   383394.208 ±(99.9%) 99933.179 ops/s [Average]
   (min, avg, max) = (141100.628, 383394.208, 520368.313), stdev = 115083.198
   CI (99.9%): [283461.029, 483327.387] (assumes normal distribution)
 Run complete. Total time: 00:01:19
 Benchmark              Mode  Cnt       Score       Error  Units
 Deserialization.gson  thrpt   20  383394.208 ± 99933.179  ops/s
 java -server -XX:+AggressiveOpts -Xms2g -Xmx2g -jar build\libs\app.jar deser --apis databind --libs esper,gson,jackson
 JMH version: 1.20
 VM version: JDK 1.8.0_192, VM 25.192-b12
 VM invoker: C:\Java\jdk1.8.0_192\jre\bin\java.exe
 VM options: 
 Warmup: 5 iterations, 1 s each
 Measurement: 10 iterations, 3 s each
 Timeout: 10 min per iteration
 Threads: 16 threads, will synchronize iterations
 Benchmark mode: Throughput, ops/time
 Benchmark: com.github.fabienrenaud.jjb.databind.Deserialization.gson
 Run progress: 0.00% complete, ETA 00:03:30
 Fork: 1 of 2
 Warmup Iteration   1: SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
 SLF4J: Defaulting to no-operation (NOP) logger implementation
 SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
 Using SEED=355928074 as seed for Random
 288279.935 ops/s
 Warmup Iteration   2: 489983.172 ops/s
 Warmup Iteration   3: 520986.946 ops/s
 Warmup Iteration   4: 524690.847 ops/s
 Warmup Iteration   5: 524284.236 ops/s
 Iteration   1: 526489.947 ops/s
 Iteration   2: 525270.990 ops/s
 Iteration   3: 526443.131 ops/s
 Iteration   4: 513476.515 ops/s
 Iteration   5: 153916.529 ops/s
 Iteration   6: 168760.049 ops/s
 Iteration   7: 210875.579 ops/s
 Iteration   8: 237990.523 ops/s
 Iteration   9: 273769.762 ops/s
 Iteration  10: 298343.511 ops/s
 Run progress: 16.67% complete, ETA 00:03:15
 Fork: 2 of 2
 Warmup Iteration   1: SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
 SLF4J: Defaulting to no-operation (NOP) logger implementation
 SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
 Using SEED=355928074 as seed for Random
 197768.475 ops/s
 Warmup Iteration   2: 306685.739 ops/s
 Warmup Iteration   3: 337464.437 ops/s
 Warmup Iteration   4: 347067.561 ops/s
 Warmup Iteration   5: 350076.319 ops/s
 Iteration   1: 364416.146 ops/s
 Iteration   2: 381411.513 ops/s
 Iteration   3: 396296.144 ops/s
 Iteration   4: 406238.196 ops/s
 Iteration   5: 408165.895 ops/s
 Iteration   6: 422488.775 ops/s
 Iteration   7: 433276.809 ops/s
 Iteration   8: 445738.057 ops/s
 Iteration   9: 453633.056 ops/s
 Iteration  10: 460101.988 ops/s
 Result "com.github.fabienrenaud.jjb.databind.Deserialization.gson":
   380355.156 ±(99.9%) 102952.861 ops/s [Average]
   (min, avg, max) = (153916.529, 380355.156, 526489.947), stdev = 118560.668
   CI (99.9%): [277402.295, 483308.017] (assumes normal distribution)
 JMH version: 1.20
 VM version: JDK 1.8.0_192, VM 25.192-b12
 VM invoker: C:\Java\jdk1.8.0_192\jre\bin\java.exe
 VM options: 
 Warmup: 5 iterations, 1 s each
 Measurement: 10 iterations, 3 s each
 Timeout: 10 min per iteration
 Threads: 16 threads, will synchronize iterations
 Benchmark mode: Throughput, ops/time
 Benchmark: com.github.fabienrenaud.jjb.databind.Deserialization.jackson
 Run progress: 33.33% complete, ETA 00:02:37
 Fork: 1 of 2
 Warmup Iteration   1: SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
 SLF4J: Defaulting to no-operation (NOP) logger implementation
 SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
 Using SEED=355928074 as seed for Random
 474878.945 ops/s
 Warmup Iteration   2: 802966.481 ops/s
 Warmup Iteration   3: 712858.027 ops/s
 Warmup Iteration   4: 740797.359 ops/s
 Warmup Iteration   5: 763551.499 ops/s
 Iteration   1: 782842.724 ops/s
 Iteration   2: 886217.925 ops/s
 Iteration   3: 897024.236 ops/s
 Iteration   4: 906403.846 ops/s
 Iteration   5: 922395.550 ops/s
 Iteration   6: 885245.860 ops/s
 Iteration   7: 826431.459 ops/s
 Iteration   8: 844156.887 ops/s
 Iteration   9: 854776.515 ops/s
 Iteration  10: 870187.841 ops/s
 Run progress: 50.00% complete, ETA 00:01:57
 Fork: 2 of 2
 Warmup Iteration   1: SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
 SLF4J: Defaulting to no-operation (NOP) logger implementation
 SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
 Using SEED=355928074 as seed for Random
 546879.887 ops/s
 Warmup Iteration   2: 849142.467 ops/s
 Warmup Iteration   3: 335546.405 ops/s
 Warmup Iteration   4: 232004.319 ops/s
 Warmup Iteration   5: 236806.194 ops/s
 Iteration   1: 304245.449 ops/s
 Iteration   2: 398422.848 ops/s
 Iteration   3: 448193.203 ops/s
 Iteration   4: 503593.337 ops/s
 Iteration   5: 539268.939 ops/s
 Iteration   6: 581295.972 ops/s
 Iteration   7: 616766.077 ops/s
 Iteration   8: 640036.098 ops/s
 Iteration   9: 667639.232 ops/s
 Iteration  10: 698697.385 ops/s
 Result "com.github.fabienrenaud.jjb.databind.Deserialization.jackson":
   703692.069 ±(99.9%) 166341.185 ops/s [Average]
   (min, avg, max) = (304245.449, 703692.069, 922395.550), stdev = 191558.755
   CI (99.9%): [537350.885, 870033.254] (assumes normal distribution)
 JMH version: 1.20
 VM version: JDK 1.8.0_192, VM 25.192-b12
 VM invoker: C:\Java\jdk1.8.0_192\jre\bin\java.exe
 VM options: 
 Warmup: 5 iterations, 1 s each
 Measurement: 10 iterations, 3 s each
 Timeout: 10 min per iteration
 Threads: 16 threads, will synchronize iterations
 Benchmark mode: Throughput, ops/time
 Benchmark: com.github.fabienrenaud.jjb.databind.Deserialization.jackson_afterburner
 Run progress: 66.67% complete, ETA 00:01:18
 Fork: 1 of 2
 Warmup Iteration   1: SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
 SLF4J: Defaulting to no-operation (NOP) logger implementation
 SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
 Using SEED=355928074 as seed for Random
 577052.249 ops/s
 Warmup Iteration   2: 837639.921 ops/s
 Warmup Iteration   3: 851474.733 ops/s
 Warmup Iteration   4: 873343.762 ops/s
 Warmup Iteration   5: 873135.520 ops/s
 Iteration   1: 889379.290 ops/s
 Iteration   2: 914258.396 ops/s
 Iteration   3: 928132.585 ops/s
 Iteration   4: 953161.613 ops/s
 Iteration   5: 952915.538 ops/s
 Iteration   6: 958374.194 ops/s
 Iteration   7: 977448.096 ops/s
 Iteration   8: 1009370.292 ops/s
 Iteration   9: 1025722.026 ops/s
 Iteration  10: 1037452.536 ops/s
 Run progress: 83.33% complete, ETA 00:00:39
 Fork: 2 of 2
 Warmup Iteration   1: SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
 SLF4J: Defaulting to no-operation (NOP) logger implementation
 SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
 Using SEED=355928074 as seed for Random
 712829.114 ops/s
 Warmup Iteration   2: 1070309.076 ops/s
 Warmup Iteration   3: 1027631.655 ops/s
 Warmup Iteration   4: 905102.951 ops/s
 Warmup Iteration   5: 923147.446 ops/s
 Iteration   1: 942076.760 ops/s
 Iteration   2: 945732.126 ops/s
 Iteration   3: 955351.526 ops/s
 Iteration   4: 973549.500 ops/s
 Iteration   5: 999500.944 ops/s
 Iteration   6: 1020378.209 ops/s
 Iteration   7: 1024975.429 ops/s
 Iteration   8: 1030572.193 ops/s
 Iteration   9: 1052722.004 ops/s
 Iteration  10: 996312.536 ops/s
 Result "com.github.fabienrenaud.jjb.databind.Deserialization.jackson_afterburner":
   979369.290 ±(99.9%) 39243.509 ops/s [Average]
   (min, avg, max) = (889379.290, 979369.290, 1052722.004), stdev = 45192.883
   CI (99.9%): [940125.781, 1018612.799] (assumes normal distribution)
 Run complete. Total time: 00:03:55
 Benchmark                             Mode  Cnt       Score        Error  Units
 Deserialization.gson                 thrpt   20  380355.156 ± 102952.861  ops/s
 Deserialization.esper               thrpt   20  625104.578 ± 124892.697  ops/s
 Deserialization.jackson              thrpt   20  703692.069 ± 166341.185  ops/s
 Deserialization.jackson_afterburner  thrpt   20  979369.290 ±  39243.509  ops/s