Skip to content

Commit b467f03

Browse files
committed
[optimize] Reuse StringBuilderWriter when serializing multiple items
1 parent 32b9dd2 commit b467f03

File tree

7 files changed

+154
-53
lines changed

7 files changed

+154
-53
lines changed

exist-core/pom.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -935,6 +935,7 @@
935935
<include>src/main/java/org/exist/util/serializer/SerializerObjectFactory.java</include>
936936
<include>src/main/java/org/exist/util/serializer/json/JSONObject.java</include>
937937
<include>src/test/java/org/exist/util/serializer/json/JSONObjectTest.java</include>
938+
<include>src/main/java/org/exist/util/serializer/json/JSONSerializer.java</include>
938939
<include>src/test/java/org/exist/util/serializer/json/JSONWriterTest.java</include>
939940
<include>src/test/resources/org/exist/validation/catalog.xml</include>
940941
<include>src/test/java/org/exist/validation/CollectionConfigurationValidationModeTest.java</include>
@@ -1275,6 +1276,7 @@
12751276
<exclude>src/main/java/org/exist/util/serializer/SerializerObjectFactory.java</exclude>
12761277
<exclude>src/main/java/org/exist/util/serializer/json/JSONObject.java</exclude>
12771278
<exclude>src/test/java/org/exist/util/serializer/json/JSONObjectTest.java</exclude>
1279+
<exclude>src/main/java/org/exist/util/serializer/json/JSONSerializer.java</exclude>
12781280
<exclude>src/test/java/org/exist/util/serializer/json/JSONWriterTest.java</exclude>
12791281
<exclude>src/test/resources/org/exist/validation/catalog.xml</exclude>
12801282
<exclude>src/test/java/org/exist/validation/CollectionConfigurationValidationModeTest.java</exclude>

exist-core/src/main/java/org/exist/http/RESTServer.java

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2236,7 +2236,7 @@ private void writeResultJSON(final HttpServletResponse response,
22362236
outputProperties.setProperty(Serializer.GENERATE_DOC_EVENTS, "false");
22372237
try {
22382238
serializer.setProperties(outputProperties);
2239-
try (Writer writer = new OutputStreamWriter(response.getOutputStream(), getEncoding(outputProperties))) {
2239+
try (final Writer writer = new OutputStreamWriter(response.getOutputStream(), getEncoding(outputProperties))) {
22402240
final JSONObject root = new JSONObject();
22412241
root.addObject(new JSONSimpleProperty("start", Integer.toString(start), true));
22422242
root.addObject(new JSONSimpleProperty("count", Integer.toString(howmany), true));
@@ -2251,24 +2251,29 @@ private void writeResultJSON(final HttpServletResponse response,
22512251
final JSONObject data = new JSONObject("data");
22522252
root.addObject(data);
22532253

2254-
Item item;
2255-
for (int i = --start; i < start + howmany; i++) {
2256-
item = results.itemAt(i);
2257-
if (Type.subTypeOf(item.getType(), Type.NODE)) {
2258-
final NodeValue value = (NodeValue) item;
2259-
JSONValue json;
2260-
if ("json".equals(outputProperties.getProperty("method", "xml"))) {
2261-
json = new JSONValue(serializer.serialize(value), false);
2262-
json.setSerializationDataType(JSONNode.SerializationDataType.AS_LITERAL);
2254+
try (final StringBuilderWriter sbWriter = new StringBuilderWriter()) {
2255+
for (int i = --start; i < start + howmany; i++) {
2256+
final Item item = results.itemAt(i);
2257+
if (Type.subTypeOf(item.getType(), Type.NODE)) {
2258+
final NodeValue value = (NodeValue) item;
2259+
sbWriter.getBuilder().setLength(0);
2260+
serializer.serialize(value, sbWriter);
2261+
2262+
final JSONValue json;
2263+
if ("json".equals(outputProperties.getProperty("method", "xml"))) {
2264+
json = new JSONValue(sbWriter.toString(), false);
2265+
json.setSerializationDataType(JSONNode.SerializationDataType.AS_LITERAL);
2266+
} else {
2267+
json = new JSONValue(sbWriter.toString());
2268+
json.setSerializationType(JSONNode.SerializationType.AS_ARRAY);
2269+
}
2270+
2271+
data.addObject(json);
22632272
} else {
2264-
json = new JSONValue(serializer.serialize(value));
2273+
final JSONValue json = new JSONValue(item.getStringValue());
22652274
json.setSerializationType(JSONNode.SerializationType.AS_ARRAY);
2275+
data.addObject(json);
22662276
}
2267-
data.addObject(json);
2268-
} else {
2269-
final JSONValue json = new JSONValue(item.getStringValue());
2270-
json.setSerializationType(JSONNode.SerializationType.AS_ARRAY);
2271-
data.addObject(json);
22722277
}
22732278
}
22742279

exist-core/src/main/java/org/exist/util/serializer/json/JSONSerializer.java

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,28 @@
11
/*
2+
* Elemental
3+
* Copyright (C) 2024, Evolved Binary Ltd
4+
*
5+
6+
* https://www.evolvedbinary.com | https://www.elemental.xyz
7+
*
8+
* This library is free software; you can redistribute it and/or
9+
* modify it under the terms of the GNU Lesser General Public
10+
* License as published by the Free Software Foundation; version 2.1.
11+
*
12+
* This library is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15+
* Lesser General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU Lesser General Public
18+
* License along with this library; if not, write to the Free Software
19+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20+
*
21+
* NOTE: Parts of this file contain code from 'The eXist-db Authors'.
22+
* The original license header is included below.
23+
*
24+
* =====================================================================
25+
*
226
* eXist-db Open Source Native XML Database
327
* Copyright (C) 2001 The eXist-db Authors
428
*
@@ -24,6 +48,7 @@
2448
import com.fasterxml.jackson.core.JsonFactory;
2549
import com.fasterxml.jackson.core.JsonGenerator;
2650
import io.lacuna.bifurcan.IEntry;
51+
import org.apache.commons.io.output.StringBuilderWriter;
2752
import org.exist.storage.DBBroker;
2853
import org.exist.storage.serializers.EXistOutputKeys;
2954
import org.exist.storage.serializers.Serializer;
@@ -69,7 +94,11 @@ public void serialize(Sequence sequence, Writer writer) throws SAXException {
6994
} else {
7095
generator.disable(JsonGenerator.Feature.STRICT_DUPLICATE_DETECTION);
7196
}
72-
serializeSequence(sequence, generator);
97+
98+
try (final StringBuilderWriter sbWriter = new StringBuilderWriter()) {
99+
serializeSequence(sequence, generator, sbWriter);
100+
}
101+
73102
if ("yes".equals(outputProperties.getProperty(EXistOutputKeys.INSERT_FINAL_NEWLINE, "no"))) {
74103
generator.writeRaw('\n');
75104
}
@@ -79,25 +108,25 @@ public void serialize(Sequence sequence, Writer writer) throws SAXException {
79108
}
80109
}
81110

82-
private void serializeSequence(Sequence sequence, JsonGenerator generator) throws IOException, XPathException, SAXException {
111+
private void serializeSequence(final Sequence sequence, final JsonGenerator generator, final StringBuilderWriter sbWriter) throws IOException, XPathException, SAXException {
83112
if (sequence.isEmpty()) {
84113
generator.writeNull();
85114
} else if (sequence.hasOne() && "no".equals(outputProperties.getProperty(EXistOutputKeys.JSON_ARRAY_OUTPUT, "no"))) {
86-
serializeItem(sequence.itemAt(0), generator);
115+
serializeItem(sequence.itemAt(0), generator, sbWriter);
87116
} else {
88117
generator.writeStartArray();
89-
for (SequenceIterator i = sequence.iterate(); i.hasNext(); ) {
90-
serializeItem(i.nextItem(), generator);
118+
for (final SequenceIterator i = sequence.iterate(); i.hasNext(); ) {
119+
serializeItem(i.nextItem(), generator, sbWriter);
91120
}
92121
generator.writeEndArray();
93122
}
94123
}
95124

96-
private void serializeItem(Item item, JsonGenerator generator) throws IOException, XPathException, SAXException {
125+
private void serializeItem(final Item item, final JsonGenerator generator, final StringBuilderWriter sbWriter) throws IOException, XPathException, SAXException {
97126
if (item.getType() == Type.ARRAY_ITEM) {
98-
serializeArray((ArrayType) item, generator);
127+
serializeArray((ArrayType) item, generator, sbWriter);
99128
} else if (item.getType() == Type.MAP_ITEM) {
100-
serializeMap((MapType) item, generator);
129+
serializeMap((MapType) item, generator, sbWriter);
101130
} else if (Type.subTypeOf(item.getType(), Type.ANY_ATOMIC_TYPE)) {
102131
if (Type.subTypeOfUnion(item.getType(), Type.NUMERIC)) {
103132
generator.writeNumber(item.getStringValue());
@@ -112,40 +141,42 @@ private void serializeItem(Item item, JsonGenerator generator) throws IOExceptio
112141
}
113142
}
114143
} else if (Type.subTypeOf(item.getType(), Type.NODE)) {
115-
serializeNode(item, generator);
144+
serializeNode(item, generator, sbWriter);
116145
}
117146
}
118147

119-
private void serializeNode(Item item, JsonGenerator generator) throws SAXException {
148+
private void serializeNode(final Item item, final JsonGenerator generator, final StringBuilderWriter sbWriter) throws SAXException {
120149
final Serializer serializer = broker.borrowSerializer();
121150
final Properties xmlOutput = new Properties();
122151
xmlOutput.setProperty(OutputKeys.METHOD, outputProperties.getProperty(EXistOutputKeys.JSON_NODE_OUTPUT_METHOD, "xml"));
123152
xmlOutput.setProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
124153
xmlOutput.setProperty(OutputKeys.INDENT, outputProperties.getProperty(OutputKeys.INDENT, "no"));
125154
try {
126155
serializer.setProperties(xmlOutput);
127-
generator.writeString(serializer.serialize((NodeValue)item));
156+
sbWriter.getBuilder().setLength(0);
157+
serializer.serialize((NodeValue) item, sbWriter);
158+
generator.writeString(sbWriter.toString());
128159
} catch (IOException e) {
129160
throw new SAXException(e.getMessage(), e);
130161
} finally {
131162
broker.returnSerializer(serializer);
132163
}
133164
}
134165

135-
private void serializeArray(ArrayType array, JsonGenerator generator) throws IOException, XPathException, SAXException {
166+
private void serializeArray(final ArrayType array, final JsonGenerator generator, final StringBuilderWriter sbWriter) throws IOException, XPathException, SAXException {
136167
generator.writeStartArray();
137168
for (int i = 0; i < array.getSize(); i++) {
138169
final Sequence member = array.get(i);
139-
serializeSequence(member, generator);
170+
serializeSequence(member, generator, sbWriter);
140171
}
141172
generator.writeEndArray();
142173
}
143174

144-
private void serializeMap(MapType map, JsonGenerator generator) throws IOException, XPathException, SAXException {
175+
private void serializeMap(final MapType map, final JsonGenerator generator, final StringBuilderWriter sbWriter) throws IOException, XPathException, SAXException {
145176
generator.writeStartObject();
146177
for (final IEntry<AtomicValue, Sequence> entry: map) {
147178
generator.writeFieldName(entry.key().getStringValue());
148-
serializeSequence(entry.value(), generator);
179+
serializeSequence(entry.value(), generator, sbWriter);
149180
}
150181
generator.writeEndObject();
151182
}

extensions/modules/cache/pom.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@
144144
</multi>
145145
<includes>
146146
<include>pom.xml</include>
147+
<include>src/main/java/org/exist/xquery/modules/cache/CacheFunctions.java</include>
147148
<include>src/test/java/org/exist/xquery/modules/cache/LazyCacheTest.java</include>
148149
<include>src/test/java/org/exist/xquery/modules/cache/NonLazyCacheTest.java</include>
149150
<include>src/test/resources-filtered/conf.xml</include>
@@ -160,6 +161,7 @@
160161
<header>${project.parent.relativePath}/../../exist-parent/existdb-LGPL-21-license.template.txt</header>
161162
<excludes>
162163
<exclude>pom.xml</exclude>
164+
<exclude>src/main/java/org/exist/xquery/modules/cache/CacheFunctions.java</exclude>
163165
<exclude>src/test/java/org/exist/xquery/modules/cache/LazyCacheTest.java</exclude>
164166
<exclude>src/test/java/org/exist/xquery/modules/cache/NonLazyCacheTest.java</exclude>
165167
<exclude>src/test/resources-filtered/conf.xml</exclude>

extensions/modules/cache/src/main/java/org/exist/xquery/modules/cache/CacheFunctions.java

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,28 @@
11
/*
2+
* Elemental
3+
* Copyright (C) 2024, Evolved Binary Ltd
4+
*
5+
6+
* https://www.evolvedbinary.com | https://www.elemental.xyz
7+
*
8+
* This library is free software; you can redistribute it and/or
9+
* modify it under the terms of the GNU Lesser General Public
10+
* License as published by the Free Software Foundation; version 2.1.
11+
*
12+
* This library is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15+
* Lesser General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU Lesser General Public
18+
* License along with this library; if not, write to the Free Software
19+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20+
*
21+
* NOTE: Parts of this file contain code from 'The eXist-db Authors'.
22+
* The original license header is included below.
23+
*
24+
* =====================================================================
25+
*
226
* eXist-db Open Source Native XML Database
327
* Copyright (C) 2001 The eXist-db Authors
428
*
@@ -21,6 +45,7 @@
2145
*/
2246
package org.exist.xquery.modules.cache;
2347

48+
import org.apache.commons.io.output.StringBuilderWriter;
2449
import org.exist.storage.serializers.Serializer;
2550
import org.exist.xquery.BasicFunction;
2651
import org.exist.xquery.FunctionSignature;
@@ -467,14 +492,16 @@ private String[] toMapKeys(final Sequence keys) throws XPathException {
467492
final String[] mapKeys = new String[keys.getItemCount()];
468493

469494
final Serializer serializer = context.getBroker().borrowSerializer();
470-
try {
495+
try (final StringBuilderWriter sbWriter = new StringBuilderWriter()) {
471496
serializer.setProperties(OUTPUT_PROPERTIES);
472497
int i = 0;
473498
for (final SequenceIterator it = keys.iterate(); it.hasNext(); ) {
474499
final Item item = it.nextItem();
475500
try {
476501
final NodeValue node = (NodeValue) item;
477-
mapKeys[i] = serializer.serialize(node);
502+
sbWriter.getBuilder().setLength(0);
503+
serializer.serialize(node, sbWriter);
504+
mapKeys[i] = sbWriter.toString();
478505
} catch (final ClassCastException e) {
479506
mapKeys[i] = item.getStringValue();
480507
}
@@ -490,20 +517,19 @@ private String[] toMapKeys(final Sequence keys) throws XPathException {
490517
}
491518

492519
private String serializeKey(final Sequence key) throws XPathException {
493-
final StringBuilder builder = new StringBuilder();
494520
final Serializer serializer = context.getBroker().borrowSerializer();
495-
try {
521+
try (final StringBuilderWriter sbWriter = new StringBuilderWriter()) {
496522
serializer.setProperties(OUTPUT_PROPERTIES);
497523
for (final SequenceIterator i = key.iterate(); i.hasNext(); ) {
498524
final Item item = i.nextItem();
499525
try {
500526
final NodeValue node = (NodeValue) item;
501-
builder.append(serializer.serialize(node));
527+
serializer.serialize(node, sbWriter);
502528
} catch (final ClassCastException e) {
503-
builder.append(item.getStringValue());
529+
sbWriter.getBuilder().append(item.getStringValue());
504530
}
505531
}
506-
return builder.toString();
532+
return sbWriter.toString();
507533
} catch (final SAXException e) {
508534
throw new XPathException(this, KEY_SERIALIZATION, e);
509535
} finally {

extensions/modules/compression/pom.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@
162162
<include>pom.xml</include>
163163
<include>src/test/resources-filtered/conf.xml</include>
164164
<include>src/test/resources/log4j2.xml</include>
165+
<include>src/main/java/org/exist/xquery/modules/compression/AbstractCompressFunction.java</include>
165166
<include>src/main/java/org/exist/xquery/modules/compression/EntryFunctions.java</include>
166167
</includes>
167168
</licenseSet>
@@ -175,6 +176,7 @@
175176
<exclude>pom.xml</exclude>
176177
<exclude>src/test/resources-filtered/conf.xml</exclude>
177178
<exclude>src/test/resources/log4j2.xml</exclude>
179+
<exclude>src/main/java/org/exist/xquery/modules/compression/AbstractCompressFunction.java</exclude>
178180
<exclude>src/main/java/org/exist/xquery/modules/compression/EntryFunctions.java</exclude>
179181
</excludes>
180182
</licenseSet>

0 commit comments

Comments
 (0)