package com.ctriposs.baiji.specific;
import com.ctriposs.baiji.exception.BaijiRuntimeException;
import com.ctriposs.baiji.generic.GenericDatumReader;
import com.ctriposs.baiji.generic.PreresolvingDatumReader;
import com.ctriposs.baiji.io.Decoder;
import com.ctriposs.baiji.schema.*;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* {@link com.ctriposs.baiji.generic.DatumReader DatumReader} for generated Java classes.
*/
public class SpecificDatumReader<T> extends PreresolvingDatumReader<T> {
public SpecificDatumReader(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 ENUM:
case STRING:
case NULL:
return false;
}
return true;
}
@Override
protected ArrayAccess getArrayAccess(ArraySchema schema) {
return new SpecificArrayAccess();
}
@Override
protected EnumAccess getEnumAccess(EnumSchema schema) {
return new SpecificEnumAccess(schema);
}
@Override
protected MapAccess getMapAccess(MapSchema schema) {
return new SpecificMapAccess();
}
@Override
protected RecordAccess getRecordAccess(RecordSchema schema) {
if (schema.getName() == null) {
return new GenericDatumReader.GenericRecordAccess(schema);
}
return new SpecificRecordAccess(schema);
}
private static class SpecificEnumAccess implements EnumAccess {
private final Method _findByValueMethod;
public SpecificEnumAccess(EnumSchema schema) {
Class clazz = ObjectCreator.INSTANCE.getClass(schema);
try {
_findByValueMethod = clazz.getMethod("findByValue", int.class);
_findByValueMethod.setAccessible(true);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
@Override
public Object createEnum(Object reuse, int ordinal) {
Object value = null;
if (_findByValueMethod != null) {
try {
value = _findByValueMethod.invoke(null, ordinal);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return value;
}
}
private static class SpecificRecordAccess implements RecordAccess {
private final Class<?> _clazz;
private Constructor<?> _ctor;
public SpecificRecordAccess(RecordSchema schema) {
_clazz = ObjectCreator.INSTANCE.getClass(schema);
try {
_ctor = _clazz != null ? _clazz.getDeclaredConstructor() : null;
} catch (NoSuchMethodException e) {
}
if (_ctor != null) {
_ctor.setAccessible(true);
}
}
@Override
public Object createRecord(Object reuse) {
try {
return reuse != null ? reuse : (_ctor != null ? _ctor.newInstance() : null);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public Object getField(Object record, String fieldName, int fieldPos) {
return ((SpecificRecord) record).get(fieldPos);
}
@Override
public void addField(Object record, String fieldName, int fieldPos, Object fieldValue) {
((SpecificRecord) record).put(fieldPos, fieldValue);
}
}
private static class SpecificArrayAccess implements ArrayAccess {
@Override
public Object create(Object reuse) {
List array;
if (reuse != null) {
if (!(reuse instanceof List)) {
throw new BaijiRuntimeException("array object does not implement non-generic List");
}
array = (List) reuse;
// retaining existing behavior where array contents aren't reused
// TODO: try to reuse contents?
array.clear();
} else {
array = new ArrayList();
}
return array;
}
@Override
public Object ensureSize(Object array, int targetSize) {
return array;
}
@Override
public Object resize(Object array, int targetSize) {
// no action needed
return array;
}
@Override
public void addElements(Object array, int elements, int index, ItemReader itemReader, Decoder decoder,
boolean reuse) throws IOException {
List list = (List) array;
for (int i = 0; i < elements; i++) {
list.add(itemReader.read(null, decoder));
}
}
}
private static class SpecificMapAccess implements MapAccess {
@Override
public Object create(Object reuse) {
Map map;
if (reuse != null) {
if (!(reuse instanceof Map)) {
throw new BaijiRuntimeException("map object does not implement non-generic IList");
}
map = (Map) reuse;
map.clear();
} else {
map = new HashMap();
}
return map;
}
@Override
public void addElements(Object mapObj, int elements, ItemReader itemReader, Decoder decoder, boolean reuse)
throws IOException {
Map map = ((Map) mapObj);
for (int i = 0; i < elements; i++) {
String key = decoder.readString();
map.put(key, itemReader.read(null, decoder));
}
}
}
}