diff --git a/src/main/java/com/fasterxml/jackson/perf/json/JsonArbitraryFieldNameBenchmark.java b/src/main/java/com/fasterxml/jackson/perf/json/JsonArbitraryFieldNameBenchmark.java index 0ec0a38..51ff20b 100644 --- a/src/main/java/com/fasterxml/jackson/perf/json/JsonArbitraryFieldNameBenchmark.java +++ b/src/main/java/com/fasterxml/jackson/perf/json/JsonArbitraryFieldNameBenchmark.java @@ -18,10 +18,15 @@ import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.options.OptionsBuilder; +import org.openjdk.jmh.runner.options.TimeValue; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStreamReader; +import java.io.StringReader; +import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.Map; import java.util.concurrent.ThreadLocalRandom; @@ -51,7 +56,8 @@ > B apply(B factory) { > B apply(B factory) { return factory.disable(JsonFactory.Feature.CANONICALIZE_FIELD_NAMES); } - }; + }, + ; abstract > B apply(B factory); } @@ -62,38 +68,79 @@ > B apply(B factory) { public enum InputType { INPUT_STREAM() { @Override - JsonParser create(JsonFactory factory, Supplier jsonSupplier) throws IOException { - return factory.createParser(new ByteArrayInputStream(jsonSupplier.get().getBytes(StandardCharsets.UTF_8))); + JsonParser create(JsonFactory factory, Supplier bytesSupplier) throws IOException { + return factory.createParser(new ByteArrayInputStream(bytesSupplier.get())); } }, READER() { @Override - JsonParser create(JsonFactory factory, Supplier jsonSupplier) throws IOException { - // Instead of using 'new StringReader(jsonSupplier.get())', we construct an InputStreamReader + JsonParser create(JsonFactory factory, Supplier bytesSupplier) throws IOException { + // Instead of using 'new StringReader(bytesSupplier.get())', we construct an InputStreamReader // to more closely match overhead of INPUT_STREAM for comparison. return factory.createParser(new InputStreamReader( - new ByteArrayInputStream(jsonSupplier.get().getBytes(StandardCharsets.UTF_8)), + new ByteArrayInputStream(bytesSupplier.get()), StandardCharsets.UTF_8)); } - }; + }, + STRING_READER() { + @Override + JsonParser create(JsonFactory factory, Supplier jsonSupplier) throws IOException { + StringReader reader = new StringReader(new String(jsonSupplier.get(), Charset.forName("UTF-8"))); + return factory.createParser(reader); + } + }, + ; - abstract JsonParser create(JsonFactory factory, Supplier jsonSupplier) throws IOException; + abstract JsonParser create(JsonFactory factory, Supplier jsonSupplier) throws IOException; } public enum InputShape { + KEY_MAP( + new TypeReference>() { + }, + () -> "{\"key\":true}"), RANDOM_KEY_MAP( - new TypeReference>() {}, + new TypeReference>() { + }, () -> "{\"" + ThreadLocalRandom.current().nextInt() + "\":true}"), BEAN_WITH_RANDOM_KEY_MAP( - new TypeReference() {}, + new TypeReference() { + }, () -> "{\"fieldWithMap\":{\"" + ThreadLocalRandom.current().nextInt() - + "\":true},\"stringOne\":\"a\",\"stringTwo\":\"a\",\"stringThree\":\"a\"}"); + + "\":true},\"stringOne\":\"a\",\"stringTwo\":\"a\",\"stringThree\":\"a\"}"), + BEAN_WITH_LARGE_KEY_MAP( + new TypeReference() { + }, + new Supplier() { + private final String json = generateSimpleInstanceJson(10_000); + + @Override + public String get() { + return json; + } + } + ), + ; + + private static String generateSimpleInstanceJson(int n) { + StringBuilder builder = new StringBuilder(); + builder.append("{\"fieldWithMap\":{"); + for (int i = 0; i < n; i++) { + builder.append("\"").append(i).append("\":").append(i % 2 == 0); + if (i < n-1) { + builder.append(','); + } + } + builder.append("},\"stringOne\":\"a\",\"stringTwo\":\"a\",\"stringThree\":\"a\"}"); + return builder.toString(); + } private final TypeReference typereference; - private final Supplier jsonSupplier; + private final Supplier bytesSupplier; + InputShape(TypeReference typereference, Supplier jsonSupplier) { this.typereference = typereference; - this.jsonSupplier = jsonSupplier; + this.bytesSupplier = () -> jsonSupplier.get().getBytes(StandardCharsets.UTF_8); } } @@ -121,7 +168,7 @@ public void setup() { @Benchmark public Object parse() throws IOException { - try (JsonParser parser = type.create(factory, shape.jsonSupplier)) { + try (JsonParser parser = type.create(factory, shape.bytesSupplier)) { return reader.readValue(parser); } } @@ -140,4 +187,16 @@ public static final class SimpleClass { @JsonProperty("stringThree") public String stringThree; } + + public static void main(String[] _args) throws Exception { + new Runner(new OptionsBuilder() + .include(JsonArbitraryFieldNameBenchmark.class.getName()) + .warmupIterations(2) + .warmupTime(TimeValue.seconds(5)) + .measurementIterations(4) + .measurementTime(TimeValue.seconds(5)) + .mode(Mode.AverageTime) + .forks(1) + .build()).run(); + } }