/** Recursive helper implementing {@link #findMissingFields(Message)}. */ private static void findMissingFields( final MessageOrBuilder message, final String prefix, final List<String> results) { for (final FieldDescriptor field : message.getDescriptorForType().getFields()) { if (field.isRequired() && !message.hasField(field)) { results.add(prefix + field.getName()); } } for (final Map.Entry<FieldDescriptor, Object> entry : message.getAllFields().entrySet()) { final FieldDescriptor field = entry.getKey(); final Object value = entry.getValue(); if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { if (field.isRepeated()) { int i = 0; for (final Object element : (List) value) { findMissingFields( (MessageOrBuilder) element, subMessagePrefix(prefix, field, i++), results); } } else { if (message.hasField(field)) { findMissingFields( (MessageOrBuilder) value, subMessagePrefix(prefix, field, -1), results); } } } } }
public int getSerializedSize() { int size = memoizedSize; if (size != -1) { return size; } size = 0; final boolean isMessageSet = getDescriptorForType().getOptions().getMessageSetWireFormat(); for (final Map.Entry<FieldDescriptor, Object> entry : getAllFields().entrySet()) { final FieldDescriptor field = entry.getKey(); final Object value = entry.getValue(); if (isMessageSet && field.isExtension() && field.getType() == FieldDescriptor.Type.MESSAGE && !field.isRepeated()) { size += CodedOutputStream.computeMessageSetExtensionSize(field.getNumber(), (Message) value); } else { size += FieldSet.computeFieldSize(field, value); } } final UnknownFieldSet unknownFields = getUnknownFields(); if (isMessageSet) { size += unknownFields.getSerializedSizeAsMessageSet(); } else { size += unknownFields.getSerializedSize(); } memoizedSize = size; return size; }
@SuppressWarnings("unchecked") public boolean isInitialized() { // Check that all required fields are present. for (final FieldDescriptor field : getDescriptorForType().getFields()) { if (field.isRequired()) { if (!hasField(field)) { return false; } } } // Check that embedded messages are initialized. for (final Map.Entry<FieldDescriptor, Object> entry : getAllFields().entrySet()) { final FieldDescriptor field = entry.getKey(); if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { if (field.isRepeated()) { for (final Message element : (List<Message>) entry.getValue()) { if (!element.isInitialized()) { return false; } } } else { if (!((Message) entry.getValue()).isInitialized()) { return false; } } } } return true; }
/** * Assigns all fields in {@link JsonNode} instance to a {@link Builder}. * * @param builder the builder to be populated * @param root the JSON object * @return the original builder, populated with any fields that were discovered */ public static Builder toProto(final Builder builder, final JsonNode root) { Descriptor type = builder.getDescriptorForType(); for (final FieldDescriptor fieldDesc : type.getFields()) { final String attrName = fieldDesc.getName(); final JsonNode node = root.get(attrName); if (node == null) { continue; } if (node.isNull()) { continue; } if (fieldDesc.isRepeated()) { final Iterator<JsonNode> iter = node.getElements(); while (iter.hasNext()) { builder.addRepeatedField(fieldDesc, toJavaObj(builder, fieldDesc, iter.next())); } } else { builder.setField(fieldDesc, toJavaObj(builder, fieldDesc, node)); } } return builder; }
protected static void filterValue( boolean clearEmpty, Predicate<FieldDescriptor> filter, Message.Builder builder, Map.Entry<FieldDescriptor, Object> entry) { FieldDescriptor fd = entry.getKey(); Object value = entry.getValue(); if (fd.getType() == FieldDescriptor.Type.MESSAGE) { if (fd.isRepeated()) { for (Object obj : ((Iterable<?>) value)) { Message child = filter((Message) obj, clearEmpty, filter); if (child != null) { builder.addRepeatedField(fd, child); } } } else { Message child = filter((Message) value, clearEmpty, filter); if (child != null) { builder.setField(fd, child); } } } else { builder.setField(fd, value); } }
private void printField(final FieldDescriptor field, final Object value, final TextGenerator generator) throws IOException { if (field.isRepeated()) { // Repeated field. Print each element. for (Object element : (List<?>) value) { printSingleField(field, element, generator); } } else { printSingleField(field, value, generator); } }
public Object getField(FieldDescriptor field) { verifyContainingType(field); Object result = fields.getField(field); if (result == null) { if (field.isRepeated()) { result = Collections.emptyList(); } else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { result = getDefaultInstance(field.getMessageType()); } else { result = field.getDefaultValue(); } } return result; }
private static void getRepeatedFieldNamesInternal(Descriptor d, Map<String, Set<String>> result) { Set<String> repeatedFields = Sets.newHashSet(); for (FieldDescriptor fd : d.getFields()) { if (fd.isRepeated()) { repeatedFields.add(javaCase(fd.getName())); } if (fd.getType() == FieldDescriptor.Type.MESSAGE) { getRepeatedFieldNamesInternal(fd.getMessageType(), result); } } if (!repeatedFields.isEmpty()) { result.put(javaCase(d.getName()), repeatedFields); } }
/** * Deserializer for protobuf objects written with {@link #writeFieldNoTag(CodedOutputStream, * FieldDescriptor, Object)}. * * @param input * @param fd * @param enclosingBuilder required to create a builder when the field is a message * @throws IOException */ public static Object readFieldNoTag( CodedInputStream input, FieldDescriptor fd, Builder enclosingBuilder) throws IOException { if (!fd.isRepeated()) { return readSingleFieldNoTag(input, fd, enclosingBuilder); } // repeated field List<Object> values = Lists.newArrayList(); while (!input.isAtEnd()) { values.add(readSingleFieldNoTag(input, fd, enclosingBuilder)); } return values; }
/** * Serializes a single field. All the native fields are serialized using "NoTag" methods in {@link * CodedOutputStream} e.g. <code>writeInt32NoTag()</code>. The field index is not written. * * @param output * @param fd * @param value * @throws IOException */ public static void writeFieldNoTag(CodedOutputStream output, FieldDescriptor fd, Object value) throws IOException { if (value == null) { return; } if (fd.isRepeated()) { @SuppressWarnings("unchecked") List<Object> values = (List<Object>) value; for (Object obj : values) { writeSingleFieldNoTag(output, fd, obj); } } else { writeSingleFieldNoTag(output, fd, value); } }
/** Get a hash code for given fields and values, using the given seed. */ @SuppressWarnings("unchecked") protected int hashFields(int hash, Map<FieldDescriptor, Object> map) { for (Map.Entry<FieldDescriptor, Object> entry : map.entrySet()) { FieldDescriptor field = entry.getKey(); Object value = entry.getValue(); hash = (37 * hash) + field.getNumber(); if (field.getType() != FieldDescriptor.Type.ENUM) { hash = (53 * hash) + value.hashCode(); } else if (field.isRepeated()) { List<? extends EnumLite> list = (List<? extends EnumLite>) value; hash = (53 * hash) + hashEnumList(list); } else { hash = (53 * hash) + hashEnum((EnumLite) value); } } return hash; }
@Override public BuilderType mergeFrom(final Message other) { if (other.getDescriptorForType() != getDescriptorForType()) { throw new IllegalArgumentException( "mergeFrom(Message) can only merge messages of the same type."); } // Note: We don't attempt to verify that other's fields have valid // types. Doing so would be a losing battle. We'd have to verify // all sub-messages as well, and we'd have to make copies of all of // them to insure that they don't change after verification (since // the Message interface itself cannot enforce immutability of // implementations). // TODO(kenton): Provide a function somewhere called makeDeepCopy() // which allows people to make secure deep copies of messages. for (final Map.Entry<FieldDescriptor, Object> entry : other.getAllFields().entrySet()) { final FieldDescriptor field = entry.getKey(); if (field.isRepeated()) { for (final Object element : (List) entry.getValue()) { addRepeatedField(field, element); } } else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { final Message existingValue = (Message) getField(field); if (existingValue == existingValue.getDefaultInstanceForType()) { setField(field, entry.getValue()); } else { setField( field, existingValue .newBuilderForType() .mergeFrom(existingValue) .mergeFrom((Message) entry.getValue()) .build()); } } else { setField(field, entry.getValue()); } } mergeUnknownFields(other.getUnknownFields()); return (BuilderType) this; }
/** * Turn a Tuple into a Message with the given type. * * @param builder a builder for the Message type the tuple will be converted to * @param tuple the tuple * @return a message representing the given tuple */ public Message tupleToMessage(Builder builder, Tuple tuple) { List<FieldDescriptor> fieldDescriptors = builder.getDescriptorForType().getFields(); if (tuple == null) { return builder.build(); } for (int i = 0; i < fieldDescriptors.size() && i < tuple.size(); i++) { Object tupleField = null; FieldDescriptor fieldDescriptor = fieldDescriptors.get(i); try { tupleField = tuple.get(i); } catch (ExecException e) { LOG.warn( "Could not convert tuple field " + tupleField + " to field with descriptor " + fieldDescriptor); continue; } if (tupleField != null) { if (fieldDescriptor.isRepeated()) { // Repeated fields are set with Lists containing objects of the fields' Java type. builder.setField( fieldDescriptor, dataBagToRepeatedField(builder, fieldDescriptor, (DataBag) tupleField)); } else { if (fieldDescriptor.getType() == FieldDescriptor.Type.MESSAGE) { Builder nestedMessageBuilder = builder.newBuilderForField(fieldDescriptor); builder.setField( fieldDescriptor, tupleToMessage((Builder) nestedMessageBuilder, (Tuple) tupleField)); } else { builder.setField(fieldDescriptor, tupleFieldToSingleField(fieldDescriptor, tupleField)); } } } } return builder.build(); }
public void writeTo(final CodedOutputStream output) throws IOException { final boolean isMessageSet = getDescriptorForType().getOptions().getMessageSetWireFormat(); for (final Map.Entry<FieldDescriptor, Object> entry : getAllFields().entrySet()) { final FieldDescriptor field = entry.getKey(); final Object value = entry.getValue(); if (isMessageSet && field.isExtension() && field.getType() == FieldDescriptor.Type.MESSAGE && !field.isRepeated()) { output.writeMessageSetExtension(field.getNumber(), (Message) value); } else { FieldSet.writeField(field, value, output); } } final UnknownFieldSet unknownFields = getUnknownFields(); if (isMessageSet) { unknownFields.writeAsMessageSetTo(output); } else { unknownFields.writeTo(output); } }
/** * Like {@link #mergeFrom(CodedInputStream, ExtensionRegistryLite)}, but parses a single field. * * <p>When {@code builder} is not null, the method will parse and merge the field into {@code * builder}. Otherwise, it will try to parse the field into {@code extensions}, when it's called * by the parsing constructor in generated classes. * * <p>Package-private because it is used by GeneratedMessage.ExtendableMessage. * * @param tag The tag, which should have already been read. * @return {@code true} unless the tag is an end-group tag. */ static boolean mergeFieldFrom( CodedInputStream input, UnknownFieldSet.Builder unknownFields, ExtensionRegistryLite extensionRegistry, Descriptor type, Message.Builder builder, FieldSet<FieldDescriptor> extensions, int tag) throws IOException { if (type.getOptions().getMessageSetWireFormat() && tag == WireFormat.MESSAGE_SET_ITEM_TAG) { mergeMessageSetExtensionFromCodedStream( input, unknownFields, extensionRegistry, type, builder, extensions); return true; } final int wireType = WireFormat.getTagWireType(tag); final int fieldNumber = WireFormat.getTagFieldNumber(tag); final FieldDescriptor field; Message defaultInstance = null; if (type.isExtensionNumber(fieldNumber)) { // extensionRegistry may be either ExtensionRegistry or // ExtensionRegistryLite. Since the type we are parsing is a full // message, only a full ExtensionRegistry could possibly contain // extensions of it. Otherwise we will treat the registry as if it // were empty. if (extensionRegistry instanceof ExtensionRegistry) { final ExtensionRegistry.ExtensionInfo extension = ((ExtensionRegistry) extensionRegistry).findExtensionByNumber(type, fieldNumber); if (extension == null) { field = null; } else { field = extension.descriptor; defaultInstance = extension.defaultInstance; if (defaultInstance == null && field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { throw new IllegalStateException( "Message-typed extension lacked default instance: " + field.getFullName()); } } } else { field = null; } } else if (builder != null) { field = type.findFieldByNumber(fieldNumber); } else { field = null; } boolean unknown = false; boolean packed = false; if (field == null) { unknown = true; // Unknown field. } else if (wireType == FieldSet.getWireFormatForFieldType(field.getLiteType(), false /* isPacked */)) { packed = false; } else if (field.isPackable() && wireType == FieldSet.getWireFormatForFieldType(field.getLiteType(), true /* isPacked */)) { packed = true; } else { unknown = true; // Unknown wire type. } if (unknown) { // Unknown field or wrong wire type. Skip. return unknownFields.mergeFieldFrom(tag, input); } if (packed) { final int length = input.readRawVarint32(); final int limit = input.pushLimit(length); if (field.getLiteType() == WireFormat.FieldType.ENUM) { while (input.getBytesUntilLimit() > 0) { final int rawValue = input.readEnum(); final Object value = field.getEnumType().findValueByNumber(rawValue); if (value == null) { // If the number isn't recognized as a valid value for this // enum, drop it (don't even add it to unknownFields). return true; } addRepeatedField(builder, extensions, field, value); } } else { while (input.getBytesUntilLimit() > 0) { final Object value = FieldSet.readPrimitiveField(input, field.getLiteType()); addRepeatedField(builder, extensions, field, value); } } input.popLimit(limit); } else { final Object value; switch (field.getType()) { case GROUP: { final Message.Builder subBuilder; if (defaultInstance != null) { subBuilder = defaultInstance.newBuilderForType(); } else { subBuilder = builder.newBuilderForField(field); } if (!field.isRepeated()) { mergeOriginalMessage(builder, extensions, field, subBuilder); } input.readGroup(field.getNumber(), subBuilder, extensionRegistry); value = subBuilder.buildPartial(); break; } case MESSAGE: { final Message.Builder subBuilder; if (defaultInstance != null) { subBuilder = defaultInstance.newBuilderForType(); } else { subBuilder = builder.newBuilderForField(field); } if (!field.isRepeated()) { mergeOriginalMessage(builder, extensions, field, subBuilder); } input.readMessage(subBuilder, extensionRegistry); value = subBuilder.buildPartial(); break; } case ENUM: final int rawValue = input.readEnum(); value = field.getEnumType().findValueByNumber(rawValue); // If the number isn't recognized as a valid value for this enum, // drop it. if (value == null) { unknownFields.mergeVarintField(fieldNumber, rawValue); return true; } break; default: value = FieldSet.readPrimitiveField(input, field.getLiteType()); break; } if (field.isRepeated()) { addRepeatedField(builder, extensions, field, value); } else { setField(builder, extensions, field, value); } } return true; }
/** * Like {@link #mergeFrom(CodedInputStream, UnknownFieldSet.Builder, ExtensionRegistryLite, * Message.Builder)}, but parses a single field. Package-private because it is used by * GeneratedMessage.ExtendableMessage. * * @param tag The tag, which should have already been read. * @return {@code true} unless the tag is an end-group tag. */ @SuppressWarnings("unchecked") static boolean mergeFieldFrom( final CodedInputStream input, final UnknownFieldSet.Builder unknownFields, final ExtensionRegistryLite extensionRegistry, final Message.Builder builder, final int tag) throws IOException { final Descriptor type = builder.getDescriptorForType(); if (type.getOptions().getMessageSetWireFormat() && tag == WireFormat.MESSAGE_SET_ITEM_TAG) { mergeMessageSetExtensionFromCodedStream(input, unknownFields, extensionRegistry, builder); return true; } final int wireType = WireFormat.getTagWireType(tag); final int fieldNumber = WireFormat.getTagFieldNumber(tag); final FieldDescriptor field; Message defaultInstance = null; if (type.isExtensionNumber(fieldNumber)) { // extensionRegistry may be either ExtensionRegistry or // ExtensionRegistryLite. Since the type we are parsing is a full // message, only a full ExtensionRegistry could possibly contain // extensions of it. Otherwise we will treat the registry as if it // were empty. if (extensionRegistry instanceof ExtensionRegistry) { final ExtensionRegistry.ExtensionInfo extension = ((ExtensionRegistry) extensionRegistry).findExtensionByNumber(type, fieldNumber); if (extension == null) { field = null; } else { field = extension.descriptor; defaultInstance = extension.defaultInstance; } } else { field = null; } } else { field = type.findFieldByNumber(fieldNumber); } if (field == null || wireType != FieldSet.getWireFormatForFieldType( field.getLiteType(), field.getOptions().getPacked())) { // Unknown field or wrong wire type. Skip. return unknownFields.mergeFieldFrom(tag, input); } if (field.getOptions().getPacked()) { final int length = input.readRawVarint32(); final int limit = input.pushLimit(length); if (field.getLiteType() == WireFormat.FieldType.ENUM) { while (input.getBytesUntilLimit() > 0) { final int rawValue = input.readEnum(); final Object value = field.getEnumType().findValueByNumber(rawValue); if (value == null) { // If the number isn't recognized as a valid value for this // enum, drop it (don't even add it to unknownFields). return true; } builder.addRepeatedField(field, value); } } else { while (input.getBytesUntilLimit() > 0) { final Object value = FieldSet.readPrimitiveField(input, field.getLiteType()); builder.addRepeatedField(field, value); } } input.popLimit(limit); } else { final Object value; switch (field.getType()) { case GROUP: { final Message.Builder subBuilder; if (defaultInstance != null) { subBuilder = defaultInstance.newBuilderForType(); } else { subBuilder = builder.newBuilderForField(field); } if (!field.isRepeated()) { subBuilder.mergeFrom((Message) builder.getField(field)); } input.readGroup(field.getNumber(), subBuilder, extensionRegistry); value = subBuilder.build(); break; } case MESSAGE: { final Message.Builder subBuilder; if (defaultInstance != null) { subBuilder = defaultInstance.newBuilderForType(); } else { subBuilder = builder.newBuilderForField(field); } if (!field.isRepeated()) { subBuilder.mergeFrom((Message) builder.getField(field)); } input.readMessage(subBuilder, extensionRegistry); value = subBuilder.build(); break; } case ENUM: final int rawValue = input.readEnum(); value = field.getEnumType().findValueByNumber(rawValue); // If the number isn't recognized as a valid value for this enum, // drop it. if (value == null) { unknownFields.mergeVarintField(fieldNumber, rawValue); return true; } break; default: value = FieldSet.readPrimitiveField(input, field.getLiteType()); break; } if (field.isRepeated()) { builder.addRepeatedField(field, value); } else { builder.setField(field, value); } } return true; }