mirror of
https://github.com/valitydev/geck.git
synced 2024-11-06 09:45:24 +00:00
Ft/bj 76/json writer (#3)
* BJ-76: Add json writer * BJ-76: Add stack changes * BJ-76: Add check in endKey * BJ-76: Change name method interaction * BJ-76: Change ids names in stack * BJ-76: Add enum, check nulls and more
This commit is contained in:
parent
ebbc8bacfd
commit
a0a4fd0dba
@ -1,14 +1,26 @@
|
||||
package com.rbkmoney.kebab;
|
||||
|
||||
import com.rbkmoney.kebab.serializer.TBaseSerializer;
|
||||
import com.rbkmoney.kebab.writer.JsonStructWriter;
|
||||
import org.apache.thrift.TBase;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
|
||||
/**
|
||||
* Created by tolkonepiu on 24/01/2017.
|
||||
*/
|
||||
public class Kebab<T extends TBase> {
|
||||
|
||||
public String toJson(T src) {
|
||||
throw new UnsupportedOperationException("under contruction");
|
||||
StringWriter writer = new StringWriter();
|
||||
Serializer serializer = new TBaseSerializer();
|
||||
try {
|
||||
serializer.write(new JsonStructWriter(writer), src);
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
return writer.toString();
|
||||
}
|
||||
|
||||
public byte[] toMsgPack(T src) {
|
||||
|
@ -9,6 +9,7 @@ import java.util.Arrays;
|
||||
*/
|
||||
public enum ThriftType {
|
||||
|
||||
NULL(-1),
|
||||
BOOLEAN(TType.BOOL),
|
||||
BYTE(TType.BYTE),
|
||||
DOUBLE(TType.DOUBLE),
|
||||
@ -20,7 +21,8 @@ public enum ThriftType {
|
||||
LIST(TType.LIST),
|
||||
SET(TType.SET),
|
||||
MAP(TType.MAP),
|
||||
STRUCT(TType.STRUCT);
|
||||
STRUCT(TType.STRUCT),
|
||||
BINARY(21);
|
||||
|
||||
int code;
|
||||
|
||||
|
@ -5,6 +5,7 @@ import com.rbkmoney.kebab.StructWriter;
|
||||
import com.rbkmoney.kebab.ThriftType;
|
||||
import org.apache.thrift.TBase;
|
||||
import org.apache.thrift.TFieldIdEnum;
|
||||
import org.apache.thrift.TFieldRequirementType;
|
||||
import org.apache.thrift.meta_data.*;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -19,26 +20,38 @@ public class TBaseSerializer implements Serializer<TBase> {
|
||||
|
||||
@Override
|
||||
public void write(StructWriter out, TBase value) throws IOException {
|
||||
out.beginStruct();
|
||||
|
||||
if (value == null) {
|
||||
out.nullValue();
|
||||
return;
|
||||
}
|
||||
|
||||
writeStruct(out, value);
|
||||
}
|
||||
|
||||
private void writeStruct(StructWriter out, TBase value) throws IOException {
|
||||
out.beginStruct();
|
||||
|
||||
TFieldIdEnum[] tFieldIdEnums = value.getFields();
|
||||
Map<TFieldIdEnum, FieldMetaData> fieldMetaDataMap = value.getFieldMetaData();
|
||||
|
||||
for (TFieldIdEnum tFieldIdEnum : tFieldIdEnums) {
|
||||
FieldMetaData fieldMetaData = fieldMetaDataMap.get(tFieldIdEnum);
|
||||
if (value.isSet(tFieldIdEnum)) {
|
||||
out.name(tFieldIdEnum.getFieldName());
|
||||
FieldMetaData fieldMetaData = fieldMetaDataMap.get(tFieldIdEnum);
|
||||
write(out, value.getFieldValue(tFieldIdEnum), fieldMetaData.valueMetaData);
|
||||
} else if (fieldMetaData.requirementType == TFieldRequirementType.REQUIRED) {
|
||||
throw new IllegalStateException(String.format("Field '%s' is required and must not be null", tFieldIdEnum.getFieldName()));
|
||||
}
|
||||
}
|
||||
out.endStruct();
|
||||
}
|
||||
|
||||
private void write(StructWriter out, Object object, FieldValueMetaData fieldValueMetaData) throws IOException {
|
||||
if (object == null) {
|
||||
out.nullValue();
|
||||
return;
|
||||
}
|
||||
|
||||
ThriftType type = ThriftType.findByCode(fieldValueMetaData.getType());
|
||||
boolean isBinary = fieldValueMetaData.isBinary();
|
||||
|
||||
@ -67,17 +80,20 @@ public class TBaseSerializer implements Serializer<TBase> {
|
||||
case DOUBLE:
|
||||
out.value((double) object);
|
||||
break;
|
||||
case ENUM:
|
||||
out.value(object.toString());
|
||||
break;
|
||||
case LIST:
|
||||
write(out, (List) object, (ListMetaData) fieldValueMetaData);
|
||||
writeList(out, (List) object, (ListMetaData) fieldValueMetaData);
|
||||
break;
|
||||
case SET:
|
||||
write(out, (Set) object, (SetMetaData) fieldValueMetaData);
|
||||
writeSet(out, (Set) object, (SetMetaData) fieldValueMetaData);
|
||||
break;
|
||||
case MAP:
|
||||
write(out, (Map) object, (MapMetaData) fieldValueMetaData);
|
||||
writeMap(out, (Map) object, (MapMetaData) fieldValueMetaData);
|
||||
break;
|
||||
case STRUCT:
|
||||
write(out, (TBase) object);
|
||||
writeStruct(out, (TBase) object);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException(String.format("Type '%s' not found", type));
|
||||
@ -85,7 +101,7 @@ public class TBaseSerializer implements Serializer<TBase> {
|
||||
}
|
||||
}
|
||||
|
||||
private void write(StructWriter out, Set objectSet, SetMetaData metaData) throws IOException {
|
||||
private void writeSet(StructWriter out, Set objectSet, SetMetaData metaData) throws IOException {
|
||||
out.beginList(objectSet.size());
|
||||
for (Object object : objectSet) {
|
||||
write(out, object, metaData.getElementMetaData());
|
||||
@ -93,7 +109,7 @@ public class TBaseSerializer implements Serializer<TBase> {
|
||||
out.endList();
|
||||
}
|
||||
|
||||
private void write(StructWriter out, List objectList, ListMetaData metaData) throws IOException {
|
||||
private void writeList(StructWriter out, List objectList, ListMetaData metaData) throws IOException {
|
||||
out.beginList(objectList.size());
|
||||
for (Object object : objectList) {
|
||||
write(out, object, metaData.getElementMetaData());
|
||||
@ -102,7 +118,7 @@ public class TBaseSerializer implements Serializer<TBase> {
|
||||
}
|
||||
|
||||
|
||||
private void write(StructWriter out, Map objectMap, MapMetaData metaData) throws IOException {
|
||||
private void writeMap(StructWriter out, Map objectMap, MapMetaData metaData) throws IOException {
|
||||
out.beginMap(objectMap.size());
|
||||
for (Map.Entry entry : (Set<Map.Entry>) objectMap.entrySet()) {
|
||||
out.beginKey();
|
||||
|
@ -1,116 +1,263 @@
|
||||
package com.rbkmoney.kebab.writer;
|
||||
|
||||
import com.rbkmoney.kebab.ByteStack;
|
||||
import com.rbkmoney.kebab.StructWriter;
|
||||
import com.rbkmoney.kebab.ThriftType;
|
||||
import com.rbkmoney.kebab.exception.BadFormatException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.Base64;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Created by tolkonepiu on 27/01/2017.
|
||||
*/
|
||||
public class JsonStructWriter implements StructWriter {
|
||||
|
||||
static final byte EMPTY_STRUCT = 1;
|
||||
|
||||
static final byte NONEMPTY_STRUCT = 2;
|
||||
|
||||
static final byte EMPTY_LIST = 3;
|
||||
|
||||
static final byte NONEMPTY_LIST = 4;
|
||||
|
||||
static final byte EMPTY_MAP = 5;
|
||||
|
||||
static final byte NONEMPTY_MAP = 6;
|
||||
|
||||
static final byte JSON_NAME = 7;
|
||||
|
||||
static final byte EMPTY_DOCUMENT = 8;
|
||||
|
||||
static final byte NONEMPTY_DOCUMENT = 9;
|
||||
|
||||
private final Writer out;
|
||||
|
||||
private ByteStack stack = new ByteStack();
|
||||
|
||||
{
|
||||
stack.push(EMPTY_DOCUMENT);
|
||||
}
|
||||
|
||||
public JsonStructWriter(Writer out) {
|
||||
Objects.requireNonNull(out);
|
||||
this.out = out;
|
||||
}
|
||||
|
||||
private void writeBeforeValue(ThriftType type) throws IOException {
|
||||
writeBegin(EMPTY_STRUCT, '{');
|
||||
name("type");
|
||||
beforeValue();
|
||||
writeString(type.toString());
|
||||
name("value");
|
||||
|
||||
}
|
||||
|
||||
private void writeAfterValue() throws IOException {
|
||||
writeEnd(EMPTY_STRUCT, NONEMPTY_STRUCT, '}');
|
||||
}
|
||||
|
||||
private void newline() throws IOException {
|
||||
out.write("\n");
|
||||
for (int i = 0; i < stack.size(); i++) {
|
||||
out.write(' ');
|
||||
}
|
||||
}
|
||||
|
||||
private void beforeValue() throws IOException {
|
||||
switch (stack.peek()) {
|
||||
case EMPTY_LIST:
|
||||
stack.pop();
|
||||
stack.push(NONEMPTY_LIST);
|
||||
newline();
|
||||
break;
|
||||
case EMPTY_MAP:
|
||||
stack.pop();
|
||||
stack.push(NONEMPTY_MAP);
|
||||
newline();
|
||||
break;
|
||||
case NONEMPTY_LIST:
|
||||
out.append(',');
|
||||
newline();
|
||||
break;
|
||||
case NONEMPTY_MAP:
|
||||
out.append(',');
|
||||
newline();
|
||||
break;
|
||||
case EMPTY_DOCUMENT:
|
||||
stack.pop();
|
||||
stack.push(NONEMPTY_DOCUMENT);
|
||||
break;
|
||||
case JSON_NAME:
|
||||
out.append(':');
|
||||
stack.pop();
|
||||
stack.push(NONEMPTY_STRUCT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void writeString(String value) throws IOException {
|
||||
out.write('"');
|
||||
out.write(value);
|
||||
out.write('"');
|
||||
}
|
||||
|
||||
private void writeBegin(byte empty, char symbol) throws IOException {
|
||||
beforeValue();
|
||||
stack.push(empty);
|
||||
out.write(symbol);
|
||||
}
|
||||
|
||||
private void writeEnd(byte empty, byte nonEmpty, char symbol) throws IOException {
|
||||
byte element = stack.peek();
|
||||
if (element != empty && element != nonEmpty) {
|
||||
throw new BadFormatException();
|
||||
}
|
||||
|
||||
if (element == nonEmpty) {
|
||||
newline();
|
||||
}
|
||||
stack.pop();
|
||||
out.write(symbol);
|
||||
}
|
||||
|
||||
private void writeValue(String value, ThriftType type) throws IOException {
|
||||
writeBeforeValue(type);
|
||||
beforeValue();
|
||||
if (type == ThriftType.BINARY || type == ThriftType.STRING) {
|
||||
writeString(value);
|
||||
} else {
|
||||
out.write(value);
|
||||
}
|
||||
writeAfterValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginStruct() throws IOException {
|
||||
|
||||
writeBeforeValue(ThriftType.STRUCT);
|
||||
writeBegin(EMPTY_STRUCT, '{');
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endStruct() throws IOException {
|
||||
|
||||
writeEnd(EMPTY_STRUCT, NONEMPTY_STRUCT, '}');
|
||||
writeAfterValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginList(int size) throws IOException {
|
||||
|
||||
writeBeforeValue(ThriftType.LIST);
|
||||
writeBegin(EMPTY_LIST, '[');
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endList() throws IOException {
|
||||
|
||||
writeEnd(EMPTY_LIST, NONEMPTY_LIST, ']');
|
||||
writeAfterValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginMap(int size) throws IOException {
|
||||
|
||||
writeBeforeValue(ThriftType.MAP);
|
||||
writeBegin(EMPTY_MAP, '[');
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endMap() throws IOException {
|
||||
|
||||
writeEnd(EMPTY_MAP, NONEMPTY_MAP, ']');
|
||||
writeAfterValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginKey() throws IOException {
|
||||
|
||||
writeBegin(EMPTY_STRUCT, '{');
|
||||
name("key");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endKey() throws IOException {
|
||||
|
||||
if (stack.peek() == JSON_NAME) {
|
||||
throw new BadFormatException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginValue() throws IOException {
|
||||
|
||||
name("value");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endValue() throws IOException {
|
||||
|
||||
writeEnd(EMPTY_STRUCT, NONEMPTY_STRUCT, '}');
|
||||
}
|
||||
|
||||
@Override
|
||||
public void name(String name) throws IOException {
|
||||
Objects.requireNonNull(name);
|
||||
|
||||
if (stack.peek() == NONEMPTY_STRUCT) {
|
||||
out.write(',');
|
||||
}
|
||||
newline();
|
||||
stack.pop();
|
||||
stack.push(JSON_NAME);
|
||||
|
||||
writeString(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void value(boolean value) throws IOException {
|
||||
|
||||
writeValue(value ? "true" : "false", ThriftType.BOOLEAN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void value(String value) throws IOException {
|
||||
|
||||
writeValue(value, ThriftType.STRING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void value(byte value) throws IOException {
|
||||
|
||||
writeValue(Byte.toString(value), ThriftType.BYTE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void value(short value) throws IOException {
|
||||
|
||||
writeValue(Short.toString(value), ThriftType.SHORT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void value(int value) throws IOException {
|
||||
|
||||
writeValue(Integer.toString(value), ThriftType.INTEGER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void value(double value) throws IOException {
|
||||
|
||||
writeValue(Double.toString(value), ThriftType.DOUBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void value(long value) throws IOException {
|
||||
|
||||
writeValue(Long.toString(value), ThriftType.LONG);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void value(byte[] value) throws IOException {
|
||||
|
||||
writeValue(Base64.getEncoder().encodeToString(value), ThriftType.BINARY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nullValue() throws IOException {
|
||||
|
||||
writeValue("null", ThriftType.NULL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
out.close();
|
||||
|
||||
if (stack.size() > 1 || stack.size() == 1 && stack.peek() == NONEMPTY_DOCUMENT) {
|
||||
throw new BadFormatException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -36,19 +36,17 @@ public class KebabTest {
|
||||
testObject.setFuck(Arrays.asList(suk, suk, suk));
|
||||
|
||||
Fail fail = new Fail();
|
||||
|
||||
fail.setReasons(new HashSet<>(Arrays.asList("kek1", "kek2")));
|
||||
|
||||
testObject.setStatus(Status.fail(new Fail(fail)));
|
||||
Map<String, Integer> map = new HashMap<>();
|
||||
map.put("kek1", 455);
|
||||
map.put("kek2", 564);
|
||||
map.put("kek3", 565);
|
||||
map.put(null, null);
|
||||
testObject.setMaps(map);
|
||||
|
||||
testObject.setStatus(Status.fail(new Fail(fail)));
|
||||
|
||||
Kebab kebab = new Kebab();
|
||||
kebab.toJson(testObject);
|
||||
System.out.println(kebab.toJson(testObject));
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user