Skip to content
This repository was archived by the owner on May 12, 2021. It is now read-only.

Commit f8e98b9

Browse files
author
tbml
committed
less memory consumption in json (de)serializer
1 parent 98b50f2 commit f8e98b9

File tree

5 files changed

+55
-82
lines changed

5 files changed

+55
-82
lines changed

core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonAdapters.java

+7-1
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,13 @@ private static class StringAdapter extends ToJsonStringAdapter<String>
135135
@Override
136136
public String deserialize( JsonValue json, BiFunction<JsonValue, ValueType, Object> deserialize )
137137
{
138-
return JavaxJson.asString( json );
138+
switch (json.getValueType()) {
139+
case NULL:
140+
return null;
141+
default:
142+
return JavaxJson.asString(json);
143+
}
144+
139145
}
140146
}
141147

core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonDeserializer.java

+36-78
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,7 @@
1717
*/
1818
package org.apache.polygene.serialization.javaxjson;
1919

20-
import java.io.BufferedReader;
21-
import java.io.IOException;
2220
import java.io.Reader;
23-
import java.io.StringReader;
24-
import java.io.UncheckedIOException;
2521
import java.lang.reflect.Array;
2622
import java.util.AbstractMap;
2723
import java.util.ArrayList;
@@ -31,17 +27,15 @@
3127
import java.util.LinkedHashSet;
3228
import java.util.List;
3329
import java.util.Map;
30+
import java.util.Scanner;
3431
import java.util.Set;
3532
import java.util.function.Function;
3633
import java.util.stream.Stream;
3734
import javax.json.JsonArray;
3835
import javax.json.JsonObject;
3936
import javax.json.JsonReader;
40-
import javax.json.JsonString;
4137
import javax.json.JsonStructure;
4238
import javax.json.JsonValue;
43-
import javax.json.stream.JsonParser;
44-
import javax.json.stream.JsonParsingException;
4539
import org.apache.polygene.api.association.AssociationDescriptor;
4640
import org.apache.polygene.api.composite.CompositeDescriptor;
4741
import org.apache.polygene.api.composite.StatefulAssociationCompositeDescriptor;
@@ -68,7 +62,6 @@
6862
import static java.util.Collections.unmodifiableList;
6963
import static java.util.Collections.unmodifiableMap;
7064
import static java.util.Collections.unmodifiableSet;
71-
import static java.util.stream.Collectors.joining;
7265
import static java.util.stream.Collectors.toCollection;
7366
import static org.apache.polygene.api.util.Collectors.toMapWithNullValues;
7467
import static org.apache.polygene.serialization.javaxjson.JavaxJson.asString;
@@ -92,88 +85,35 @@ public class JavaxJsonDeserializer extends AbstractTextDeserializer
9285
private ServiceDescriptor descriptor;
9386

9487
private JavaxJsonSettings settings;
95-
private JsonString emptyJsonString;
9688

9789
@Override
9890
public void initialize() throws Exception
9991
{
10092
settings = JavaxJsonSettings.orDefault( descriptor.metaInfo( JavaxJsonSettings.class ) );
101-
emptyJsonString = jsonFactories.builderFactory().createObjectBuilder().add( "s", "" ).build()
102-
.getJsonString( "s" );
10393
}
10494

105-
@Override
106-
public <T> T deserialize( ModuleDescriptor module, ValueType valueType, Reader state )
95+
@SuppressWarnings("unchecked")
96+
public <T> T deserialize(ModuleDescriptor module, ValueType valueType, Reader state)
10797
{
108-
// JSR-353 Does not allow reading "out of structure" values
109-
// See https://www.jcp.org/en/jsr/detail?id=353
110-
// And commented JsonReader#readValue() method in the javax.json API
111-
// BUT, it will be part of the JsonReader contract in the next version
112-
// See https://www.jcp.org/en/jsr/detail?id=374
113-
// Implementation by provider is optional though, so we'll always need a default implementation here.
114-
// Fortunately, JsonParser has new methods allowing to read structures while parsing so it will be easy to do.
115-
// In the meantime, a poor man's implementation reading the json into memory will do.
116-
// TODO Revisit values out of structure JSON deserialization when JSR-374 is out
117-
String stateString;
118-
try( BufferedReader buffer = new BufferedReader( state ) )
119-
{
120-
stateString = buffer.lines().collect( joining( "\n" ) );
121-
}
122-
catch( IOException ex )
123-
{
124-
throw new UncheckedIOException( ex );
125-
}
126-
// We want plain Strings, BigDecimals, BigIntegers to be deserialized even when unquoted
127-
Function<String, T> plainValueFunction = string ->
128-
{
129-
String poorMans = "{\"value\":" + string + "}";
130-
JsonObject poorMansJson = jsonFactories.readerFactory()
131-
.createReader( new StringReader( poorMans ) )
132-
.readObject();
133-
JsonValue value = poorMansJson.get( "value" );
134-
return fromJson( module, valueType, value );
135-
};
136-
Function<String, T> outOfStructureFunction = string ->
98+
Converter<Object> converter = converters.converterFor(valueType);
99+
if (converter != null)
137100
{
138-
// Is this an unquoted plain value?
139-
try
140-
{
141-
return plainValueFunction.apply( '"' + string + '"' );
142-
}
143-
catch( JsonParsingException ex )
144-
{
145-
return plainValueFunction.apply( string );
146-
}
147-
};
148-
try( JsonParser parser = jsonFactories.parserFactory().createParser( new StringReader( stateString ) ) )
149-
{
150-
if( parser.hasNext() )
151-
{
152-
JsonParser.Event e = parser.next();
153-
switch( e )
154-
{
155-
case VALUE_NULL:
156-
return null;
157-
case START_ARRAY:
158-
case START_OBJECT:
159-
// JSON Structure
160-
try( JsonReader reader = jsonFactories.readerFactory()
161-
.createReader( new StringReader( stateString ) ) )
162-
{
163-
return fromJson( module, valueType, reader.read() );
164-
}
165-
default:
166-
// JSON Value out of structure
167-
return outOfStructureFunction.apply( stateString );
168-
}
101+
String stateString = readString(state);
102+
if (isJsonNull(stateString)) {
103+
return null;
104+
} else {
105+
return (T) converter.fromString(stateString);
169106
}
170107
}
171-
catch( JsonParsingException ex )
172-
{
173-
return outOfStructureFunction.apply( stateString );
108+
109+
JavaxJsonAdapter<?> adapter = adapters.adapterFor(valueType);
110+
if (adapter != null) {
111+
return (T) adapter.deserialize(readJsonString(state), (jsonValue, type) -> doDeserialize(module, type, jsonValue));
112+
}
113+
114+
try (JsonReader reader = jsonFactories.readerFactory().createReader(state)) {
115+
return fromJson(module, valueType, reader.readValue());
174116
}
175-
// Empty state string?
176-
return fromJson( module, valueType, emptyJsonString );
177117
}
178118

179119
@Override
@@ -182,6 +122,24 @@ public <T> T fromJson( ModuleDescriptor module, ValueType valueType, JsonValue s
182122
return doDeserialize( module, valueType, state );
183123
}
184124

125+
private JsonValue readJsonString(Reader reader) {
126+
String str = readString(reader);
127+
if (isJsonNull(str)) {
128+
return JsonValue.NULL;
129+
} else {
130+
return jsonFactories.provider().createValue(str);
131+
}
132+
}
133+
134+
private boolean isJsonNull(String str) {
135+
return "null".equals(str);
136+
}
137+
138+
private String readString(Reader reader) {
139+
Scanner scanner = new Scanner(reader).useDelimiter("\\A");
140+
return scanner.hasNext() ? scanner.next() : "";
141+
}
142+
185143
@SuppressWarnings( "unchecked" )
186144
private <T> T doDeserialize( ModuleDescriptor module, ValueType valueType, JsonValue json )
187145
{

core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonFactories.java

+7-1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ public interface JavaxJsonFactories
5050

5151
JsonWriterFactory writerFactory();
5252

53+
JsonProvider provider();
5354
/**
5455
* Creates a {@link JsonString} with the {@link Object#toString()} result on the given object.
5556
*
@@ -111,14 +112,14 @@ class Mixin implements JavaxJsonFactories, Initializable
111112
private JsonGeneratorFactory generatorFactory;
112113
private JsonBuilderFactory builderFactory;
113114
private JsonWriterFactory writerFactory;
115+
private JsonProvider jsonProvider;
114116

115117
@Override
116118
public void initialize() throws Exception
117119
{
118120
JavaxJsonSettings settings = JavaxJsonSettings.orDefault( descriptor.metaInfo( JavaxJsonSettings.class ) );
119121

120122
String jsonProviderClassName = settings.getJsonProviderClassName();
121-
JsonProvider jsonProvider;
122123
if( jsonProviderClassName == null )
123124
{
124125
jsonProvider = JsonProvider.provider();
@@ -251,5 +252,10 @@ public JsonArrayBuilder cloneBuilderExclude( JsonArray jsonArray, JsonValue... v
251252
}
252253
return job;
253254
}
255+
256+
@Override
257+
public JsonProvider provider() {
258+
return jsonProvider;
259+
}
254260
}
255261
}

core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonSerializer.java

+4-1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import javax.json.JsonObjectBuilder;
3333
import javax.json.JsonString;
3434
import javax.json.JsonValue;
35+
import javax.json.JsonWriter;
3536
import org.apache.polygene.api.PolygeneAPI;
3637
import org.apache.polygene.api.association.AssociationStateHolder;
3738
import org.apache.polygene.api.common.Optional;
@@ -98,7 +99,9 @@ public void serialize( Options options, Writer writer, @Optional Object object )
9899
}
99100
else
100101
{
101-
writer.write( jsonValue.toString() );
102+
try (JsonWriter w = jsonFactories.writerFactory().createWriter(writer)) {
103+
w.write(jsonValue);
104+
}
102105
}
103106
}
104107
catch( IOException ex )

dependencies.gradle

+1-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ def jcloudsVersion = '2.0.2'
6565
def jdbmVersion = '2.4'
6666
def jedisVersion = '2.9.0'
6767
def jettyVersion = '9.2.17.v20160517' // 9.3.x Tests fail!
68-
def johnzonVersion = '1.1.1'
68+
def johnzonVersion = '1.1.7'
6969
def jooqVersion = '3.10.6'
7070
def kotlinVersion = '1.2.31'
7171
def leveldbVersion = '0.9'

0 commit comments

Comments
 (0)