Skip to content

Commit 523331e

Browse files
jabolinawburns
authored andcommitted
Added benchmark for JSON escaping
1 parent 46f5770 commit 523331e

File tree

5 files changed

+545
-0
lines changed

5 files changed

+545
-0
lines changed

json/pom.xml

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<groupId>org.infinispan</groupId>
8+
<artifactId>json</artifactId>
9+
<version>1.0</version>
10+
<packaging>jar</packaging>
11+
12+
<name>JMH benchmark Infinispan JSON</name>
13+
14+
<properties>
15+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
16+
17+
<jmh.version>1.35</jmh.version>
18+
19+
<javac.target>11</javac.target>
20+
21+
<uberjar.name>benchmarks</uberjar.name>
22+
<infinispan.version>15.0.0-SNAPSHOT</infinispan.version>
23+
</properties>
24+
25+
<dependencies>
26+
<dependency>
27+
<groupId>org.openjdk.jmh</groupId>
28+
<artifactId>jmh-core</artifactId>
29+
<version>${jmh.version}</version>
30+
</dependency>
31+
<dependency>
32+
<groupId>org.openjdk.jmh</groupId>
33+
<artifactId>jmh-generator-annprocess</artifactId>
34+
<version>${jmh.version}</version>
35+
<scope>provided</scope>
36+
</dependency>
37+
<dependency>
38+
<groupId>org.infinispan</groupId>
39+
<artifactId>infinispan-core</artifactId>
40+
<version>${infinispan.version}</version>
41+
</dependency>
42+
<dependency>
43+
<groupId>org.infinispan</groupId>
44+
<artifactId>infinispan-core</artifactId>
45+
<version>${infinispan.version}</version>
46+
<type>test-jar</type>
47+
</dependency>
48+
</dependencies>
49+
50+
51+
<build>
52+
<plugins>
53+
<plugin>
54+
<groupId>org.apache.maven.plugins</groupId>
55+
<artifactId>maven-compiler-plugin</artifactId>
56+
<version>3.8.0</version>
57+
<configuration>
58+
<compilerVersion>${javac.target}</compilerVersion>
59+
<source>${javac.target}</source>
60+
<target>${javac.target}</target>
61+
</configuration>
62+
</plugin>
63+
<plugin>
64+
<groupId>org.apache.maven.plugins</groupId>
65+
<artifactId>maven-shade-plugin</artifactId>
66+
<version>3.2.1</version>
67+
<executions>
68+
<execution>
69+
<phase>package</phase>
70+
<goals>
71+
<goal>shade</goal>
72+
</goals>
73+
<configuration>
74+
<finalName>${uberjar.name}</finalName>
75+
<transformers>
76+
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
77+
<mainClass>org.openjdk.jmh.Main</mainClass>
78+
</transformer>
79+
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
80+
</transformers>
81+
<filters>
82+
<filter>
83+
<!--
84+
Shading signed JARs will fail without this.
85+
http://stackoverflow.com/questions/999489/invalid-signature-file-when-attempting-to-run-a-jar
86+
-->
87+
<artifact>*:*</artifact>
88+
<excludes>
89+
<exclude>META-INF/*.SF</exclude>
90+
<exclude>META-INF/*.DSA</exclude>
91+
<exclude>META-INF/*.RSA</exclude>
92+
</excludes>
93+
</filter>
94+
</filters>
95+
</configuration>
96+
</execution>
97+
</executions>
98+
</plugin>
99+
</plugins>
100+
<pluginManagement>
101+
<plugins>
102+
<plugin>
103+
<artifactId>maven-clean-plugin</artifactId>
104+
<version>2.5</version>
105+
</plugin>
106+
<plugin>
107+
<artifactId>maven-deploy-plugin</artifactId>
108+
<version>2.8.1</version>
109+
</plugin>
110+
<plugin>
111+
<artifactId>maven-install-plugin</artifactId>
112+
<version>2.5.1</version>
113+
</plugin>
114+
<plugin>
115+
<artifactId>maven-jar-plugin</artifactId>
116+
<version>2.4</version>
117+
</plugin>
118+
<plugin>
119+
<artifactId>maven-javadoc-plugin</artifactId>
120+
<version>2.9.1</version>
121+
</plugin>
122+
<plugin>
123+
<artifactId>maven-resources-plugin</artifactId>
124+
<version>2.6</version>
125+
</plugin>
126+
<plugin>
127+
<artifactId>maven-site-plugin</artifactId>
128+
<version>3.3</version>
129+
</plugin>
130+
<plugin>
131+
<artifactId>maven-source-plugin</artifactId>
132+
<version>2.2.1</version>
133+
</plugin>
134+
<plugin>
135+
<artifactId>maven-surefire-plugin</artifactId>
136+
<version>2.17</version>
137+
</plugin>
138+
</plugins>
139+
</pluginManagement>
140+
</build>
141+
</project>
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
package org.infinispan.json;
2+
3+
import java.io.IOException;
4+
import java.util.Collections;
5+
import java.util.HashSet;
6+
import java.util.Set;
7+
8+
public class EscapeMain {
9+
10+
/**
11+
* <p>
12+
* Exposes some internal methods that are useful for {@link JsonMain.Factory} implementations or other extension/layers
13+
* of the library.
14+
* </p>
15+
*
16+
* @author Borislav Iordanov
17+
*/
18+
public static class help {
19+
/**
20+
* <p>
21+
* Perform JSON escaping so that ", <, >, etc. characters are properly encoded in the JSON string representation
22+
* before returning to the client code. This is useful when serializing property names or string values.
23+
* </p>
24+
*/
25+
public static String escape(String string) {
26+
return escaper.escapeJsonString(string);
27+
}
28+
}
29+
30+
// ------------------------------------------------------------------------
31+
// Extra utilities, taken from around the internet:
32+
// ------------------------------------------------------------------------
33+
34+
/*
35+
* Copyright (C) 2008 Google Inc.
36+
*
37+
* Licensed under the Apache License, Version 2.0 (the "License");
38+
* you may not use this file except in compliance with the License.
39+
* You may obtain a copy of the License at
40+
*
41+
* http://www.apache.org/licenses/LICENSE-2.0
42+
*
43+
* Unless required by applicable law or agreed to in writing, software
44+
* distributed under the License is distributed on an "AS IS" BASIS,
45+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
46+
* See the License for the specific language governing permissions and
47+
* limitations under the License.
48+
*/
49+
50+
/**
51+
* A utility class that is used to perform JSON escaping so that ", <, >, etc. characters are properly encoded in the
52+
* JSON string representation before returning to the client code.
53+
*
54+
* <p>This class contains a single method to escape a passed in string value:
55+
* <pre>
56+
* String jsonStringValue = "beforeQuote\"afterQuote";
57+
* String escapedValue = Escaper.escapeJsonString(jsonStringValue);
58+
* </pre></p>
59+
*
60+
* @author Inderjeet Singh
61+
* @author Joel Leitch
62+
*/
63+
static Escaper escaper = new Escaper(false);
64+
65+
final static class Escaper {
66+
67+
private static final char[] HEX_CHARS = {
68+
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
69+
};
70+
71+
private static final Set<Character> JS_ESCAPE_CHARS;
72+
private static final Set<Character> HTML_ESCAPE_CHARS;
73+
74+
static {
75+
Set<Character> mandatoryEscapeSet = new HashSet<Character>();
76+
mandatoryEscapeSet.add('"');
77+
mandatoryEscapeSet.add('\\');
78+
JS_ESCAPE_CHARS = Collections.unmodifiableSet(mandatoryEscapeSet);
79+
80+
Set<Character> htmlEscapeSet = new HashSet<Character>();
81+
htmlEscapeSet.add('<');
82+
htmlEscapeSet.add('>');
83+
htmlEscapeSet.add('&');
84+
htmlEscapeSet.add('=');
85+
htmlEscapeSet.add('\'');
86+
HTML_ESCAPE_CHARS = Collections.unmodifiableSet(htmlEscapeSet);
87+
}
88+
89+
private final boolean escapeHtmlCharacters;
90+
91+
Escaper(boolean escapeHtmlCharacters) {
92+
this.escapeHtmlCharacters = escapeHtmlCharacters;
93+
}
94+
95+
public String escapeJsonString(CharSequence plainText) {
96+
StringBuilder escapedString = new StringBuilder(plainText.length() + 20);
97+
try {
98+
escapeJsonString(plainText, escapedString);
99+
} catch (IOException e) {
100+
throw new RuntimeException(e);
101+
}
102+
return escapedString.toString();
103+
}
104+
105+
private void escapeJsonString(CharSequence plainText, Appendable out) throws IOException {
106+
int pos = 0; // Index just past the last char in plainText written to out.
107+
int len = plainText.length();
108+
109+
for (int charCount, i = 0; i < len; i += charCount) {
110+
int codePoint = Character.codePointAt(plainText, i);
111+
charCount = Character.charCount(codePoint);
112+
113+
if (!isControlCharacter(codePoint) && !mustEscapeCharInJsString(codePoint)) {
114+
continue;
115+
}
116+
117+
out.append(plainText, pos, i);
118+
pos = i + charCount;
119+
switch (codePoint) {
120+
case '\b':
121+
out.append("\\b");
122+
break;
123+
case '\t':
124+
out.append("\\t");
125+
break;
126+
case '\n':
127+
out.append("\\n");
128+
break;
129+
case '\f':
130+
out.append("\\f");
131+
break;
132+
case '\r':
133+
out.append("\\r");
134+
break;
135+
case '\\':
136+
out.append("\\\\");
137+
break;
138+
case '/':
139+
out.append("\\/");
140+
break;
141+
case '"':
142+
out.append("\\\"");
143+
break;
144+
default:
145+
appendHexJavaScriptRepresentation(codePoint, out);
146+
break;
147+
}
148+
}
149+
out.append(plainText, pos, len);
150+
}
151+
152+
private boolean mustEscapeCharInJsString(int codepoint) {
153+
if (!Character.isSupplementaryCodePoint(codepoint)) {
154+
char c = (char) codepoint;
155+
return JS_ESCAPE_CHARS.contains(c)
156+
|| (escapeHtmlCharacters && HTML_ESCAPE_CHARS.contains(c));
157+
}
158+
return false;
159+
}
160+
161+
private static boolean isControlCharacter(int codePoint) {
162+
// JSON spec defines these code points as control characters, so they must be escaped
163+
return codePoint < 0x20
164+
|| codePoint == 0x2028 // Line separator
165+
|| codePoint == 0x2029 // Paragraph separator
166+
|| (codePoint >= 0x7f && codePoint <= 0x9f);
167+
}
168+
169+
private static void appendHexJavaScriptRepresentation(int codePoint, Appendable out)
170+
throws IOException {
171+
if (Character.isSupplementaryCodePoint(codePoint)) {
172+
// Handle supplementary unicode values which are not representable in
173+
// javascript. We deal with these by escaping them as two 4B sequences
174+
// so that they will round-trip properly when sent from java to javascript
175+
// and back.
176+
char[] surrogates = Character.toChars(codePoint);
177+
appendHexJavaScriptRepresentation(surrogates[0], out);
178+
appendHexJavaScriptRepresentation(surrogates[1], out);
179+
return;
180+
}
181+
out.append("\\u")
182+
.append(HEX_CHARS[(codePoint >>> 12) & 0xf])
183+
.append(HEX_CHARS[(codePoint >>> 8) & 0xf])
184+
.append(HEX_CHARS[(codePoint >>> 4) & 0xf])
185+
.append(HEX_CHARS[codePoint & 0xf]);
186+
}
187+
}
188+
}

0 commit comments

Comments
 (0)