package edu.berkeley.cs.succinct.object.deserializer;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import edu.berkeley.cs.succinct.DataType;
import edu.berkeley.cs.succinct.DeserializationException;
import edu.berkeley.cs.succinct.PrimitiveDeserializer;
import edu.berkeley.cs.succinct.block.json.FieldMapping;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
public class JsonDeserializer implements ObjectDeserializer<String> {
FieldMapping fieldMapping;
ObjectMapper mapper;
public JsonDeserializer(FieldMapping fieldMapping) {
this.fieldMapping = fieldMapping;
this.mapper = new ObjectMapper();
}
@Override public String deserialize(byte[] data) throws DeserializationException {
return mapToJsonString(deserializeToMap(data));
}
public String deserialize(long id, byte[] data) throws DeserializationException {
Map<String, Object> jsonMap = deserializeToMap(data);
jsonMap.put("id", id);
return mapToJsonString(jsonMap);
}
private String mapToJsonString(Map<String, Object> jsonMap) throws DeserializationException {
String jsonString;
try {
jsonString = mapper.writeValueAsString(jsonMap);
} catch (JsonProcessingException e) {
throw new DeserializationException(e.getMessage());
}
return jsonString;
}
private Map<String, Object> deserializeToMap(byte[] data) throws DeserializationException {
Map<String, Object> jsonMap = new HashMap<String, Object>();
int curOffset = 0;
while (curOffset < data.length) {
byte curDelimiter = data[curOffset++];
String fieldKey = fieldMapping.getField(curDelimiter);
DataType fieldType = fieldMapping.getDataType(fieldKey);
byte[] fieldValueBytes = extractField(data, curOffset, curDelimiter);
Object fieldValue = PrimitiveDeserializer.deserializePrimitive(fieldValueBytes, fieldType);
add(jsonMap, fieldKey, fieldValue);
curOffset += (fieldValueBytes.length + 1); // Skip the field data, and the end delimiter
}
return jsonMap;
}
private void add(Map<String, Object> map, String key, Object value) {
if (key.contains(".")) {
String[] keySplits = key.split("\\.", 2);
if (map.containsKey(keySplits[0])) {
@SuppressWarnings("unchecked") Map<String, Object> valObj =
(Map<String, Object>) map.get(keySplits[0]);
add(valObj, keySplits[1], value);
} else {
Map<String, Object> valObj = new HashMap<String, Object>();
add(valObj, keySplits[1], value);
map.put(keySplits[0], valObj);
}
} else {
map.put(key, value);
}
}
private byte[] extractField(byte[] data, int startOffset, byte delimiter) {
int i = startOffset;
while (data[i] != delimiter) {
i++;
}
return Arrays.copyOfRange(data, startOffset, i);
}
}