Last active
March 19, 2021 03:58
-
-
Save StanSvec/ee5edcc04f07643d9c4a9680f44cc8e5 to your computer and use it in GitHub Desktop.
Basic JSON string reading performance benchmark of JSON-P (JSR 374) vs Jackson
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.fasterxml.jackson.annotation.JsonAutoDetect; | |
import com.fasterxml.jackson.annotation.JsonProperty; | |
import com.fasterxml.jackson.core.JsonProcessingException; | |
import com.fasterxml.jackson.databind.DeserializationFeature; | |
import com.fasterxml.jackson.databind.JsonNode; | |
import com.fasterxml.jackson.databind.ObjectMapper; | |
import org.glassfish.json.JsonUtil; | |
import javax.json.Json; | |
import javax.json.JsonObject; | |
import javax.json.JsonReader; | |
import java.io.StringReader; | |
import java.util.List; | |
import java.util.Objects; | |
import java.util.concurrent.ThreadLocalRandom; | |
import java.util.stream.Collectors; | |
import java.util.stream.IntStream; | |
import static java.util.stream.Collectors.toList; | |
/** | |
* <!-- JSR 374 Spec --> | |
* <dependency> | |
* <groupId>javax.json</groupId> | |
* <artifactId>javax.json-api</artifactId> | |
* <version>1.1</version> | |
* </dependency> | |
* <dependency> | |
* <groupId>org.glassfish</groupId> | |
* <artifactId>javax.json</artifactId> | |
* <version>1.1.4</version> | |
* </dependency> | |
* | |
* Jackson version: 2.10.5 | |
* | |
* Results: | |
* JSONP JsonUtil: 409 ms | |
* JSONP Reader: 233 ms | |
* Jackson: 73 ms | |
* Jackson To Java Type: 75 ms | |
* | |
* JSONP JsonUtil: 2417 ms | |
* JSONP Reader: 2180 ms | |
* Jackson: 345 ms | |
* Jackson To Java Type: 410 ms | |
*/ | |
public class JsonBench { | |
private static final String JSON_TEMPLATE = """ | |
{ | |
"stringField": "%s", | |
"intField": %d, | |
"doubleField": %f, | |
"booleanValue": %b, | |
"nestedObject": { | |
"f1": "%s", | |
"f2": "field2" | |
}, | |
"array1": [%s], | |
"nested": {"array2": [{"field": "value"}, {"field": "value2"}]} | |
} | |
"""; | |
public static void main(String[] args) throws JsonProcessingException { | |
List<String> jsonStrings = IntStream.range(0, 10000).mapToObj(__ -> createTestJsonStr()).collect(toList()); | |
runForJsr(jsonStrings); | |
runForJsrReader(jsonStrings); | |
runForJackson(jsonStrings); | |
runForJacksonObj(jsonStrings); | |
System.out.println("-----------------------------------------------------------"); | |
jsonStrings = IntStream.range(0, 150000).mapToObj(__ -> createTestJsonStr()).collect(toList()); | |
runForJsr(jsonStrings); | |
runForJsrReader(jsonStrings); | |
runForJackson(jsonStrings); | |
runForJacksonObj(jsonStrings); | |
} | |
public static void runForJsr(List<String> jsonStrings) { | |
System.out.println(JsonUtil.toJson(createTestJsonStr())); // Do not include potential initialization delay | |
long start = System.currentTimeMillis(); | |
for (String s : jsonStrings) { | |
JsonObject jsonObj = (JsonObject) JsonUtil.toJson(s); | |
readObj(jsonObj); | |
} | |
long stop = System.currentTimeMillis(); | |
System.out.println("JSONP JsonUtil: " + (stop - start ) + " ms"); | |
} | |
public static void runForJsrReader(List<String> jsonStrings) { | |
try (JsonReader jr = Json.createReader(new StringReader(createTestJsonStr()))) { | |
System.out.println(jr.readObject()); // Do not include potential initialization delay | |
} | |
long start = System.currentTimeMillis(); | |
for (String s : jsonStrings) { | |
try (JsonReader jr = Json.createReader(new StringReader(s))) { | |
JsonObject jsonObj = jr.readObject(); | |
readObj(jsonObj); | |
} | |
} | |
long stop = System.currentTimeMillis(); | |
System.out.println("JSONP Reader: " + (stop - start ) + " ms"); | |
} | |
private static void readObj(JsonObject obj) { | |
StringBuilder sb = new StringBuilder(); | |
sb.append(obj.getString("stringField")).append(obj.getInt("intField")).append(obj.getJsonObject("nestedObject").getString("f1")); | |
if (ThreadLocalRandom.current().nextInt() == 6) { | |
System.out.println(sb.toString()); | |
} | |
} | |
public static void runForJackson(List<String> jsonStrings) throws JsonProcessingException { | |
ObjectMapper mapper = new ObjectMapper(); | |
System.out.println(mapper.readTree(createTestJsonStr())); // Do not include potential initialization delay | |
long start = System.currentTimeMillis(); | |
for (String s : jsonStrings) { | |
JsonNode jsonObj = mapper.readTree(s); | |
readObj(jsonObj); | |
} | |
long stop = System.currentTimeMillis(); | |
System.out.println("Jackson: " + (stop - start ) + " ms"); | |
} | |
private static void readObj(JsonNode obj) { | |
StringBuilder sb = new StringBuilder(); | |
sb.append(obj.get("stringField").asText()).append(obj.get("intField").asInt()).append(obj.get("nestedObject").get("f1").asText()); | |
if (ThreadLocalRandom.current().nextInt() == 6) { | |
System.out.println(sb.toString()); | |
} | |
} | |
public static void runForJacksonObj(List<String> jsonStrings) throws JsonProcessingException { | |
ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); | |
System.out.println(mapper.readValue(createTestJsonStr(), JsonAsType.class)); // Do not include potential initialization delay | |
long start = System.currentTimeMillis(); | |
for (String s : jsonStrings) { | |
JsonAsType jsonObj = mapper.readValue(s, JsonAsType.class); | |
readObj(jsonObj); | |
} | |
long stop = System.currentTimeMillis(); | |
System.out.println("Jackson To Java Type: " + (stop - start ) + " ms"); | |
} | |
private static void readObj(JsonAsType obj) { | |
StringBuilder sb = new StringBuilder(); | |
sb.append(obj.stringField()).append(obj.intField()).append(obj.doubleField()).append(obj.nestedObject().f1()); | |
if (ThreadLocalRandom.current().nextInt() == 6) { | |
System.out.println(sb.toString()); | |
} | |
} | |
public static String createTestJsonStr() { | |
return JSON_TEMPLATE.formatted(randomStr(), (int) randomNumber(), randomNumber(), ((int)randomNumber()) % 2 == 0, randomStr(), randomSeq()); | |
} | |
public static String randomStr() { | |
return Long.toHexString(ThreadLocalRandom.current().nextLong()); | |
} | |
public static double randomNumber() { | |
return ThreadLocalRandom.current().nextDouble() * 100; | |
} | |
public static String randomSeq() { | |
int length = ThreadLocalRandom.current().nextInt(10); | |
return ThreadLocalRandom.current().ints(length).mapToObj(Objects::toString).collect(Collectors.joining(",")); | |
} | |
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY) | |
static record JsonAsType(@JsonProperty("stringField") String stringField, | |
@JsonProperty("intField") int intField, | |
@JsonProperty("doubleField") double doubleField, | |
@JsonProperty("booleanValue") boolean booleanValue, | |
@JsonProperty("nestedObject") Nested nestedObject, | |
@JsonProperty("array1") List<String> array1) {} | |
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY) | |
static record Nested(@JsonProperty("f1") String f1, @JsonProperty("f2") String f2) {} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment