com.adgear.anoa.read.ThriftReader Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of anoa-core Show documentation
Show all versions of anoa-core Show documentation
Core classes for Anoa library, which aims to be a safe, convenient and fast record
de/serialization wrapper for the Avro, Thrift and Jackson libraries, using the functional idioms
of Java 8.
The anoa-core module tries to keep upstream dependencies to a minimum.
package com.adgear.anoa.read;
import com.adgear.anoa.AnoaJacksonTypeException;
import com.adgear.anoa.AnoaReflectionUtils;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import org.apache.thrift.TBase;
import org.apache.thrift.TFieldIdEnum;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
class ThriftReader> extends AbstractReader {
final private List> fieldWrappers;
final private Map>> fieldLookUp;
final private T instance;
final private int nRequired;
ThriftReader(Class thriftClass) {
try {
this.instance = thriftClass.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new RuntimeException(e);
}
instance.clear();
this.fieldWrappers = new ArrayList<>();
AnoaReflectionUtils.getThriftMetaDataMap(thriftClass).forEach(
(k, v) -> fieldWrappers.add(new ThriftFieldWrapper<>(k, v)));
this.fieldLookUp = new HashMap<>(fieldWrappers.size());
fieldWrappers.stream().forEach(
w -> fieldLookUp.put(w.tFieldIdEnum.getFieldName(), Optional.of(w)));
this.nRequired = (int) fieldWrappers.stream().filter(w -> w.isRequired).count();
}
@Override
protected T read(JsonParser jacksonParser) throws IOException {
if (jacksonParser.getCurrentToken() == JsonToken.START_OBJECT) {
final ThriftRecordWrapper recordWrapper = newWrappedInstance();
doMap(jacksonParser, (fieldName, p) -> {
Optional> cacheValue = fieldLookUp.get(fieldName);
if (cacheValue == null) {
Optional>>> found = fieldLookUp.entrySet().stream()
.filter(e -> (0 == fieldName.compareToIgnoreCase(e.getKey())))
.findAny();
cacheValue = found.isPresent() ? found.get().getValue() : Optional.empty();
fieldLookUp.put(fieldName, cacheValue);
}
if (cacheValue.isPresent()) {
final ThriftFieldWrapper fieldWrapper = cacheValue.get();
recordWrapper.put(fieldWrapper, fieldWrapper.reader.read(p));
} else {
gobbleValue(p);
}
});
return recordWrapper.get();
} else {
gobbleValue(jacksonParser);
return null;
}
}
@Override
protected T readStrict(JsonParser jacksonParser) throws AnoaJacksonTypeException, IOException {
switch (jacksonParser.getCurrentToken()) {
case VALUE_NULL:
return null;
case START_OBJECT:
final ThriftRecordWrapper recordWrapper = newWrappedInstance();
doMap(jacksonParser, (fieldName, p) -> {
final Optional> cacheValue =
fieldLookUp.computeIfAbsent(fieldName, __ -> Optional.>empty());
if (cacheValue.isPresent()) {
final ThriftFieldWrapper fieldWrapper = cacheValue.get();
recordWrapper.put(fieldWrapper, fieldWrapper.reader.readStrict(p));
} else {
gobbleValue(p);
}
});
return recordWrapper.get();
default:
throw new AnoaJacksonTypeException("Token is not '{': " + jacksonParser.getCurrentToken());
}
}
@SuppressWarnings("unchecked")
protected ThriftRecordWrapper newWrappedInstance() {
return new ThriftRecordWrapper<>((T) instance.deepCopy(), fieldWrappers, nRequired);
}
}