/** * Serializes a field path in a record to a protobuf message using the specified descriptor. * * @param record Record with the field to serialize * @param field The field to serialize * @param fieldPath The field path of the specified field * @param desc Protobuf descriptor * @param messageTypeToExtensionMap Protobuf extension map * @param defaultValueMap Protobuf default field values * @return serialized message * @throws DataGeneratorException */ private static DynamicMessage sdcFieldToProtobufMsg( Record record, Field field, String fieldPath, Descriptors.Descriptor desc, Map<String, Set<Descriptors.FieldDescriptor>> messageTypeToExtensionMap, Map<String, Object> defaultValueMap) throws DataGeneratorException { if (field == null) { return null; } // compute all fields to look for including extensions DynamicMessage.Builder builder = DynamicMessage.newBuilder(desc); List<Descriptors.FieldDescriptor> fields = new ArrayList<>(); fields.addAll(desc.getFields()); if (messageTypeToExtensionMap.containsKey(desc.getFullName())) { fields.addAll(messageTypeToExtensionMap.get(desc.getFullName())); } // root field is always a Map in a record representing protobuf data Map<String, Field> valueAsMap = field.getValueAsMap(); for (Descriptors.FieldDescriptor f : fields) { Field mapField = valueAsMap.get(f.getName()); // Repeated field if (f.isMapField()) { handleMapField( record, mapField, fieldPath, messageTypeToExtensionMap, defaultValueMap, f, builder); } else if (f.isRepeated()) { handleRepeatedField( record, mapField, fieldPath, messageTypeToExtensionMap, defaultValueMap, f, builder); } else { // non repeated field handleNonRepeatedField( record, valueAsMap, fieldPath, messageTypeToExtensionMap, defaultValueMap, desc, f, builder); } } // if record has unknown fields for this field path, handle it try { handleUnknownFields(record, fieldPath, builder); } catch (IOException e) { throw new DataGeneratorException(Errors.PROTOBUF_05, e.toString(), e); } return builder.build(); }
/** * Creates an SDC Record Field from the provided protobuf message and descriptor. * * @param record record to be augmented * @param fieldPath field path in the record to insert new Field * @param fieldDescriptor descriptor for this message * @param messageTypeToExtensionMap protobuf type extensions * @param message protobuf message to decode * @return reference to the Field added to the record. * @throws DataParserException */ @SuppressWarnings("unchecked") private static Field createField( Record record, String fieldPath, Descriptors.FieldDescriptor fieldDescriptor, Map<String, Set<Descriptors.FieldDescriptor>> messageTypeToExtensionMap, Object message) throws DataParserException { Field newField; if (message == null) { // If the message does not contain required fields then builder.build() throws // UninitializedMessageException Object defaultValue = null; // get default values only for optional fields and non-message types if (fieldDescriptor.isOptional() && fieldDescriptor.getJavaType() != Descriptors.FieldDescriptor.JavaType.MESSAGE) { defaultValue = fieldDescriptor.getDefaultValue(); } newField = Field.create(getFieldType(fieldDescriptor.getJavaType()), defaultValue); } else if (fieldDescriptor.isMapField()) { // Map entry (protobuf 3 map) Map<String, Field> sdcMapFieldValues = new HashMap<>(); Collection<DynamicMessage> mapEntries = (Collection<DynamicMessage>) message; // MapEntry for (DynamicMessage dynamicMessage : mapEntries) { // MapEntry has 2 fields, key and value Map<Descriptors.FieldDescriptor, Object> kv = dynamicMessage.getAllFields(); String key = null; Object value = null; Descriptors.FieldDescriptor valueDescriptor = null; for (Map.Entry<Descriptors.FieldDescriptor, Object> entry : kv.entrySet()) { switch (entry.getKey().getName()) { case KEY: key = entry.getValue().toString(); break; case VALUE: value = entry.getValue(); valueDescriptor = entry.getKey(); break; default: throw new DataParserException(Errors.PROTOBUF_09, entry.getKey().getName()); } } if (key != null && valueDescriptor != null) { sdcMapFieldValues.put( key, createSdcField(record, fieldPath, valueDescriptor, messageTypeToExtensionMap, value)); } } newField = Field.create(sdcMapFieldValues); } else if (fieldDescriptor.isRepeated()) { // List entry (repeated) List<?> list = (List<?>) message; List<Field> listField = new ArrayList<>(); for (int i = 0; i < list.size(); i++) { if (fieldDescriptor.getJavaType() == Descriptors.FieldDescriptor.JavaType.MESSAGE) { listField.add( protobufToSdcField( record, fieldPath + "[" + i + "]", fieldDescriptor.getMessageType(), messageTypeToExtensionMap, list.get(i))); } else { listField.add( createSdcField( record, fieldPath + "[" + i + "]", fieldDescriptor, messageTypeToExtensionMap, list.get(i))); } } newField = Field.create(listField); } else { // normal entry newField = createSdcField(record, fieldPath, fieldDescriptor, messageTypeToExtensionMap, message); } return newField; }