1818import org .openjdk .jmh .annotations .Scope ;
1919import org .openjdk .jmh .annotations .Setup ;
2020import org .openjdk .jmh .annotations .State ;
21+ import org .openjdk .jmh .runner .Runner ;
22+ import org .openjdk .jmh .runner .options .OptionsBuilder ;
23+ import org .openjdk .jmh .runner .options .TimeValue ;
2124
2225import java .io .ByteArrayInputStream ;
2326import java .io .IOException ;
2427import java .io .InputStreamReader ;
28+ import java .io .StringReader ;
29+ import java .nio .charset .Charset ;
2530import java .nio .charset .StandardCharsets ;
2631import java .util .Map ;
2732import java .util .concurrent .ThreadLocalRandom ;
@@ -51,7 +56,8 @@ <F extends JsonFactory, B extends TSFBuilder<F, B>> B apply(B factory) {
5156 <F extends JsonFactory , B extends TSFBuilder <F , B >> B apply (B factory ) {
5257 return factory .disable (JsonFactory .Feature .CANONICALIZE_FIELD_NAMES );
5358 }
54- };
59+ },
60+ ;
5561
5662 abstract <F extends JsonFactory , B extends TSFBuilder <F , B >> B apply (B factory );
5763 }
@@ -62,38 +68,79 @@ <F extends JsonFactory, B extends TSFBuilder<F, B>> B apply(B factory) {
6268 public enum InputType {
6369 INPUT_STREAM () {
6470 @ Override
65- JsonParser create (JsonFactory factory , Supplier <String > jsonSupplier ) throws IOException {
66- return factory .createParser (new ByteArrayInputStream (jsonSupplier .get (). getBytes ( StandardCharsets . UTF_8 )));
71+ JsonParser create (JsonFactory factory , Supplier <byte []> bytesSupplier ) throws IOException {
72+ return factory .createParser (new ByteArrayInputStream (bytesSupplier .get ()));
6773 }
6874 },
6975 READER () {
7076 @ Override
71- JsonParser create (JsonFactory factory , Supplier <String > jsonSupplier ) throws IOException {
72- // Instead of using 'new StringReader(jsonSupplier .get())', we construct an InputStreamReader
77+ JsonParser create (JsonFactory factory , Supplier <byte []> bytesSupplier ) throws IOException {
78+ // Instead of using 'new StringReader(bytesSupplier .get())', we construct an InputStreamReader
7379 // to more closely match overhead of INPUT_STREAM for comparison.
7480 return factory .createParser (new InputStreamReader (
75- new ByteArrayInputStream (jsonSupplier .get (). getBytes ( StandardCharsets . UTF_8 )),
81+ new ByteArrayInputStream (bytesSupplier .get ()),
7682 StandardCharsets .UTF_8 ));
7783 }
78- };
84+ },
85+ STRING_READER () {
86+ @ Override
87+ JsonParser create (JsonFactory factory , Supplier <byte []> jsonSupplier ) throws IOException {
88+ StringReader reader = new StringReader (new String (jsonSupplier .get (), Charset .forName ("UTF-8" )));
89+ return factory .createParser (reader );
90+ }
91+ },
92+ ;
7993
80- abstract JsonParser create (JsonFactory factory , Supplier <String > jsonSupplier ) throws IOException ;
94+ abstract JsonParser create (JsonFactory factory , Supplier <byte [] > jsonSupplier ) throws IOException ;
8195 }
8296
8397 public enum InputShape {
98+ KEY_MAP (
99+ new TypeReference <Map <String , Boolean >>() {
100+ },
101+ () -> "{\" key\" :true}" ),
84102 RANDOM_KEY_MAP (
85- new TypeReference <Map <String , Boolean >>() {},
103+ new TypeReference <Map <String , Boolean >>() {
104+ },
86105 () -> "{\" " + ThreadLocalRandom .current ().nextInt () + "\" :true}" ),
87106 BEAN_WITH_RANDOM_KEY_MAP (
88- new TypeReference <SimpleClass >() {},
107+ new TypeReference <SimpleClass >() {
108+ },
89109 () -> "{\" fieldWithMap\" :{\" " + ThreadLocalRandom .current ().nextInt ()
90- + "\" :true},\" stringOne\" :\" a\" ,\" stringTwo\" :\" a\" ,\" stringThree\" :\" a\" }" );
110+ + "\" :true},\" stringOne\" :\" a\" ,\" stringTwo\" :\" a\" ,\" stringThree\" :\" a\" }" ),
111+ BEAN_WITH_LARGE_KEY_MAP (
112+ new TypeReference <SimpleClass >() {
113+ },
114+ new Supplier <String >() {
115+ private final String json = generateSimpleInstanceJson (10_000 );
116+
117+ @ Override
118+ public String get () {
119+ return json ;
120+ }
121+ }
122+ ),
123+ ;
124+
125+ private static String generateSimpleInstanceJson (int n ) {
126+ StringBuilder builder = new StringBuilder ();
127+ builder .append ("{\" fieldWithMap\" :{" );
128+ for (int i = 0 ; i < n ; i ++) {
129+ builder .append ("\" " ).append (i ).append ("\" :" ).append (i % 2 == 0 );
130+ if (i < n -1 ) {
131+ builder .append (',' );
132+ }
133+ }
134+ builder .append ("},\" stringOne\" :\" a\" ,\" stringTwo\" :\" a\" ,\" stringThree\" :\" a\" }" );
135+ return builder .toString ();
136+ }
91137
92138 private final TypeReference <?> typereference ;
93- private final Supplier <String > jsonSupplier ;
139+ private final Supplier <byte []> bytesSupplier ;
140+
94141 InputShape (TypeReference <?> typereference , Supplier <String > jsonSupplier ) {
95142 this .typereference = typereference ;
96- this .jsonSupplier = jsonSupplier ;
143+ this .bytesSupplier = () -> jsonSupplier . get (). getBytes ( StandardCharsets . UTF_8 ) ;
97144 }
98145 }
99146
@@ -121,7 +168,7 @@ public void setup() {
121168
122169 @ Benchmark
123170 public Object parse () throws IOException {
124- try (JsonParser parser = type .create (factory , shape .jsonSupplier )) {
171+ try (JsonParser parser = type .create (factory , shape .bytesSupplier )) {
125172 return reader .readValue (parser );
126173 }
127174 }
@@ -140,4 +187,16 @@ public static final class SimpleClass {
140187 @ JsonProperty ("stringThree" )
141188 public String stringThree ;
142189 }
190+
191+ public static void main (String [] _args ) throws Exception {
192+ new Runner (new OptionsBuilder ()
193+ .include (JsonArbitraryFieldNameBenchmark .class .getName ())
194+ .warmupIterations (2 )
195+ .warmupTime (TimeValue .seconds (5 ))
196+ .measurementIterations (4 )
197+ .measurementTime (TimeValue .seconds (5 ))
198+ .mode (Mode .AverageTime )
199+ .forks (1 )
200+ .build ()).run ();
201+ }
143202}
0 commit comments