package com.ctriposs.baiji.generic;
import com.ctriposs.baiji.io.Decoder;
import com.ctriposs.baiji.schema.*;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
/**
* {@link DatumReader} for generic Java objects.
*/
public class GenericDatumReader<D> extends PreresolvingDatumReader<D> {
public GenericDatumReader(Schema schema) {
super(schema);
}
@Override
protected boolean isReusable(SchemaType type) {
switch (type) {
case DOUBLE:
case BOOLEAN:
case INT:
case LONG:
case FLOAT:
case BYTES:
case STRING:
case NULL:
return false;
}
return true;
}
@Override
protected ArrayAccess getArrayAccess(ArraySchema schema) {
return new GenericArrayAccess();
}
@Override
protected EnumAccess getEnumAccess(EnumSchema schema) {
return new GenericEnumAccess(schema);
}
@Override
protected MapAccess getMapAccess(MapSchema schema) {
return new GenericMapAccess();
}
@Override
protected RecordAccess getRecordAccess(RecordSchema schema) {
return new GenericRecordAccess(schema);
}
private static class GenericEnumAccess implements EnumAccess {
private final EnumSchema _schema;
public GenericEnumAccess(EnumSchema schema) {
this._schema = schema;
}
@Override
public Object createEnum(Object reuse, int ordinal) {
if (reuse instanceof GenericEnum) {
GenericEnum ge = (GenericEnum) reuse;
if (ge.getSchema().equals(_schema)) {
ge.setValue(_schema.get(ordinal));
return ge;
}
}
return new GenericEnum(_schema, _schema.get(ordinal));
}
}
public static class GenericRecordAccess implements RecordAccess {
private RecordSchema _schema;
public GenericRecordAccess(RecordSchema schema) {
_schema = schema;
}
@Override
public Object createRecord(Object reuse) {
GenericRecord ru = (!(reuse instanceof GenericRecord) || !((GenericRecord) reuse).getSchema().equals(_schema))
? new GenericRecord(_schema)
: (GenericRecord) reuse;
return ru;
}
@Override
public Object getField(Object record, String fieldName, int fieldPos) {
return ((GenericRecord) record).get(fieldName);
}
@Override
public void addField(Object record, String fieldName, int fieldPos, Object fieldValue) {
((GenericRecord) record).add(fieldName, fieldValue);
}
}
private static class GenericArrayAccess implements ArrayAccess {
@Override
public Object create(Object reuse) {
return (reuse instanceof Object[]) ? reuse : new Object[0];
}
@Override
public Object ensureSize(Object array, int targetSize) {
if (((Object[]) array).length < targetSize) {
array = sizeTo(array, targetSize);
}
return array;
}
@Override
public Object resize(Object array, int targetSize) {
return sizeTo(array, targetSize);
}
@Override
public void addElements(Object arrayObj, int elements, int index, ItemReader itemReader, Decoder decoder,
boolean reuse) throws IOException {
Object[] array = (Object[]) arrayObj;
for (int i = index; i < index + elements; i++) {
array[i] = reuse ? itemReader.read(array[i], decoder) : itemReader.read(null, decoder);
}
}
private static Object sizeTo(Object array, int targetSize) {
return Arrays.copyOf((Object[]) array, targetSize);
}
}
private static class GenericMapAccess implements MapAccess {
@Override
public Object create(Object reuse) {
if (reuse instanceof Map<?, ?>) {
Map<?, ?> result = (Map<?, ?>) reuse;
result.clear();
return result;
}
return new HashMap<String, Object>();
}
@Override
public void addElements(Object mapObj, int elements, ItemReader itemReader, Decoder decoder, boolean reuse)
throws IOException {
Map<String, Object> map = (Map<String, Object>) mapObj;
for (int i = 0; i < elements; i++) {
String key = decoder.readString();
map.put(key, itemReader.read(null, decoder));
}
}
}
}