src/main/java/com/gojek/beast/protomapping/Parser.java
package com.gojek.beast.protomapping;
import com.gojek.beast.exception.ProtoNotFoundException;
import com.gojek.beast.models.ProtoField;
import com.gojek.beast.stats.Stats;
import com.google.protobuf.Descriptors;
import java.util.Map;
public class Parser {
private final Stats statsClient = Stats.client();
private final DescriptorCache descriptorCache = new DescriptorCache();
/**
* Bigquery supports a maximum of 15 level nested structures.
* Thus for nested data type of more than 15 level or for recursive data type,
* we limit the fields to only contain schema upto 15 levels deep
*/
private static final int MAX_BIGQUERY_NESTED_SCHEMA_LEVEL = 15;
public ProtoField parseFields(ProtoField protoField, String protoSchema, Map<String, Descriptors.Descriptor> allDescriptors,
Map<String, String> typeNameToPackageNameMap) {
return parseFields(protoField, protoSchema, allDescriptors, typeNameToPackageNameMap, 1);
}
private ProtoField parseFields(ProtoField protoField, String protoSchema, Map<String, Descriptors.Descriptor> allDescriptors,
Map<String, String> typeNameToPackageNameMap, int level) {
Descriptors.Descriptor currentProto = descriptorCache.fetch(allDescriptors, typeNameToPackageNameMap, protoSchema);
if (currentProto == null) {
statsClient.increment(String.format("proto.notfound.errors,proto=%s", protoSchema));
throw new ProtoNotFoundException("No Proto found for class " + protoSchema);
}
for (Descriptors.FieldDescriptor field : currentProto.getFields()) {
ProtoField fieldModel = new ProtoField(field.toProto());
if (fieldModel.isNested()) {
if (protoSchema.substring(1).equals(currentProto.getFullName())) {
if (level >= MAX_BIGQUERY_NESTED_SCHEMA_LEVEL) {
continue;
}
}
fieldModel = parseFields(fieldModel, field.toProto().getTypeName(), allDescriptors, typeNameToPackageNameMap, level + 1);
}
protoField.addField(fieldModel);
}
return protoField;
}
}