com.epam.deltix.qsrv.util.json.parser.JsonWriter Maven / Gradle / Ivy
/*
* Copyright 2024 EPAM Systems, Inc
*
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership. Licensed under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.epam.deltix.qsrv.util.json.parser;
import com.epam.deltix.dfp.Decimal64Utils;
import com.epam.deltix.qsrv.hf.pub.RawMessage;
import com.epam.deltix.qsrv.hf.pub.WritableValue;
import com.epam.deltix.qsrv.hf.pub.codec.*;
import com.epam.deltix.qsrv.hf.pub.md.*;
import com.epam.deltix.qsrv.util.json.DateFormatter;
import com.epam.deltix.util.collections.generated.ByteArrayList;
import com.epam.deltix.util.collections.generated.LongArrayList;
import com.epam.deltix.util.collections.generated.ObjectArrayList;
import com.epam.deltix.util.collections.generated.ObjectToObjectHashMap;
import com.epam.deltix.util.memory.MemoryDataOutput;
import com.epam.deltix.util.text.CharSequenceParser;
import com.epam.deltix.util.time.TimeFormatter;
import org.apache.commons.io.output.StringBuilderWriter;
import java.nio.ByteBuffer;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.ParseException;
import java.util.Collections;
import java.util.Locale;
public class JsonWriter {
private final JsonPool jsonPool;
private final String typeField;
public CodecMetaFactory factory = CompiledCodecMetaFactory.INSTANCE;
private final MemoryDataOutput output = new MemoryDataOutput();
private ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
private final DateFormatter dateFormatter = new DateFormatter();
private final ObjectToObjectHashMap encoders = new ObjectToObjectHashMap();
private DecimalFormat decimalFormat;
private String decimalSeparator;
public JsonWriter(JsonPool pool, String typeField) {
this(pool, typeField, Locale.getDefault(Locale.Category.FORMAT));
}
public JsonWriter(JsonPool pool, String typeField, Locale locale) {
this.jsonPool = pool;
this.typeField = typeField;
decimalFormat = new DecimalFormat("#.#", DecimalFormatSymbols.getInstance(locale));
updateDecimalSeparator();
}
private void updateDecimalSeparator() {
decimalSeparator = Character.toString(decimalFormat.getDecimalFormatSymbols().getDecimalSeparator());
}
public void setDecimalFormat(DecimalFormat decimalFormat) {
this.decimalFormat = decimalFormat;
updateDecimalSeparator();
}
public void writeValues(RawMessage msg, ObjectToObjectHashMap values) {
if (values == null)
return;
output.reset();
FixedUnboundEncoder encoder = getEncoder(msg.type);
encoder.beginWrite(output);
while (encoder.nextField()) {
NonStaticFieldInfo info = encoder.getField();
writeValue(encoder, info, values.get(info.getName(), null));
}
msg.copyBytes(output, 0);
}
public void writeValue(WritableValue encoder, NonStaticFieldInfo info, Object value) {
try {
if (value == null)
encoder.writeNull();
else {
final DataType type = info.getType();
if (type instanceof FloatDataType)
writeFloat((StringBuilderWriter) value, encoder, (FloatDataType) type);
else if (type instanceof IntegerDataType)
writeInteger(value, encoder, (IntegerDataType) type);
else if (type instanceof EnumDataType)
writeEnum((StringBuilderWriter) value, encoder, (EnumDataType) type);
else if (type instanceof VarcharDataType)
writeVarchar((StringBuilderWriter) value, encoder);
else if (type instanceof BooleanDataType)
encoder.writeBoolean((boolean) value);
else if (type instanceof CharDataType)
writeVarchar((StringBuilderWriter) value, encoder);
else if (type instanceof DateTimeDataType)
writeDateTime((StringBuilderWriter) value, encoder, (DateTimeDataType) type);
else if (type instanceof TimeOfDayDataType) {
if (value instanceof Number) {
encoder.writeInt(((Number) value).intValue());
} else {
writeTimeOfDay((StringBuilderWriter) value, encoder);
}
} else if (type instanceof BinaryDataType) {
writeBinary((LongArrayList) value, encoder);
} else if (type instanceof ArrayDataType) {
writeArray((ArrayDataType) type, encoder, value);
} else if (type instanceof ClassDataType) {
writeObject((ObjectToObjectHashMap) value, encoder, (ClassDataType) type);
} else {
throw new RuntimeException();
}
}
} catch (final Throwable x) {
throw new IllegalArgumentException("Can not write value to the field '" + info.getName() +
"'. Reason: " + x.getLocalizedMessage(),
x);
}
}
private void writeInteger(Object value, WritableValue encoder, IntegerDataType type) {
switch (type.getSize()) {
case 1:
encoder.writeInt(((Number) value).byteValue());
break;
case 2:
encoder.writeInt(((Number) value).shortValue());
break;
case 4:
case IntegerDataType.PACKED_UNSIGNED_INT:
case IntegerDataType.PACKED_INTERVAL:
encoder.writeInt(((Number) value).intValue());
break;
default:
encoder.writeLong(((Number) value).longValue());
break;
}
}
private void writeFloat(StringBuilderWriter writer, WritableValue encoder, FloatDataType type) {
String stringValue = writer.getBuilder().toString();
if (type.isFloat()) {
encoder.writeFloat(getNumber(stringValue).floatValue());
} else if (type.isDecimal64()) {
encoder.writeLong(Decimal64Utils.parse(stringValue, decimalSeparator));
} else {
encoder.writeDouble(getNumber(stringValue).doubleValue());
}
jsonPool.returnToPool(writer);
}
private Number getNumber(String strValue) {
try {
return decimalFormat.parse(strValue);
} catch (ParseException e) {
throw new IllegalArgumentException("Failed to convert the '" + strValue + "' to a numeric value", e);
}
}
private void writeVarchar(StringBuilderWriter writer, WritableValue encoder) {
encoder.writeString(writer.getBuilder());
jsonPool.returnToPool(writer);
}
private void writeEnum(StringBuilderWriter writer, WritableValue encoder, EnumDataType enumDataType) {
encoder.writeLong(enumDataType.getDescriptor().stringToLong(writer.getBuilder()));
jsonPool.returnToPool(writer);
}
private void writeBinary(LongArrayList bytes, WritableValue encoder) {
if (bytes.size() > byteBuffer.array().length) {
byteBuffer = ByteBuffer.allocate(bytes.size());
}
for (int i = 0; i < bytes.size(); i++) {
byteBuffer.put(i, bytes.get(i).byteValue());
}
encoder.writeBinary(byteBuffer.array(), 0, bytes.size());
jsonPool.returnToPool(bytes);
}
private void writeDateTime(StringBuilderWriter writer, WritableValue encoder, DateTimeDataType type) throws ParseException {
String value = writer.getBuilder().toString();
long timestamp = type.hasNanosecondPrecision() ? dateFormatter.nanoFromDateString(value) : dateFormatter.msFromDateString(value);
encoder.writeLong(timestamp);
jsonPool.returnToPool(writer);
}
private void writeTimeOfDay(StringBuilderWriter writer, WritableValue encoder) {
encoder.writeInt(TimeFormatter.parseTimeOfDayMillis(writer.getBuilder()));
jsonPool.returnToPool(writer);
}
private void writeObject(ObjectToObjectHashMap object, WritableValue encoder, ClassDataType type) {
RecordClassDescriptor rcd = matchObjectType(object, type.getDescriptors());
UnboundEncoder objectEncoder = encoder.getFieldEncoder(rcd);
while (objectEncoder.nextField()) {
writeValue(objectEncoder, objectEncoder.getField(), object.get(objectEncoder.getField().getName(), null));
}
jsonPool.returnToPool(object);
}
private void writeArray(ArrayDataType type, WritableValue encoder, Object value) throws ParseException {
DataType elementType = type.getElementDataType();
if (value instanceof Integer) {
writeNullsArray((int) value, encoder);
} else if (value.equals(Collections.EMPTY_LIST)) {
writeEmptyArray(encoder);
} else if (elementType instanceof IntegerDataType) {
writeLongArray((LongArrayList) value, (IntegerDataType) elementType, encoder);
} else if (elementType instanceof FloatDataType) {
writeFloatArray((ObjectArrayList
© 2015 - 2024 Weber Informatics LLC | Privacy Policy