|
25 | 25 | import com.google.protobuf.ByteString; |
26 | 26 | import com.google.protobuf.CodedInputStream; |
27 | 27 | import com.google.protobuf.ExtensionRegistryLite; |
| 28 | +import com.google.protobuf.Internal.EnumLite; |
28 | 29 | import com.google.protobuf.InvalidProtocolBufferException; |
29 | 30 | import com.google.protobuf.MessageLite; |
30 | 31 | import com.google.protobuf.WireFormat; |
@@ -163,16 +164,28 @@ Object getDefaultCelValue(FieldLiteDescriptor fieldDescriptor) { |
163 | 164 | return toRuntimeValue(getDefaultValue(fieldDescriptor)); |
164 | 165 | } |
165 | 166 |
|
166 | | - private Optional<FieldLiteDescriptor> findFieldDescriptor(String protoTypeName, int fieldNumber) { |
167 | | - return descriptorPool |
168 | | - .findDescriptor(protoTypeName) |
169 | | - .flatMap(desc -> desc.findByFieldNumber(fieldNumber)); |
| 167 | + // A selected field's default value: the one in the SelectField, else its type's. |
| 168 | + Object getDefaultCelValue(SelectField field, FieldLiteDescriptor fieldDescriptor) { |
| 169 | + return field.defaultValue() != null |
| 170 | + ? field.defaultValue() |
| 171 | + : getDefaultCelValue(fieldDescriptor); |
| 172 | + } |
| 173 | + |
| 174 | + @Nullable FieldLiteDescriptor findFieldDescriptor(String protoTypeName, int fieldNumber) { |
| 175 | + MessageLiteDescriptor descriptor = descriptorPool.findDescriptor(protoTypeName).orElse(null); |
| 176 | + return descriptor == null ? null : descriptor.findByFieldNumber(fieldNumber); |
170 | 177 | } |
171 | 178 |
|
172 | | - Optional<FieldLiteDescriptor> findFieldDescriptor(String protoTypeName, String fieldName) { |
| 179 | + @Nullable FieldLiteDescriptor findFieldDescriptor(String protoTypeName, String fieldName) { |
| 180 | + MessageLiteDescriptor descriptor = descriptorPool.findDescriptor(protoTypeName).orElse(null); |
| 181 | + return descriptor == null ? null : descriptor.findByFieldName(fieldName); |
| 182 | + } |
| 183 | + |
| 184 | + @Nullable MessageLiteDescriptor findDescriptorWithGetters(String protoTypeName) { |
173 | 185 | return descriptorPool |
174 | 186 | .findDescriptor(protoTypeName) |
175 | | - .flatMap(desc -> desc.findByFieldName(fieldName)); |
| 187 | + .filter(MessageLiteDescriptor::hasGetters) |
| 188 | + .orElse(null); |
176 | 189 | } |
177 | 190 |
|
178 | 191 | MessageLite parseMessageLite(ByteString bytes, String protoTypeName) { |
@@ -316,15 +329,8 @@ private Map.Entry<Object, Object> readSingleMapEntry( |
316 | 329 | return scanField(bytes, protoTypeName, fieldDescriptor, null, null); |
317 | 330 | } |
318 | 331 |
|
319 | | - /** Reads {@code field}, by its own type information if {@code fieldDescriptor} is null. */ |
320 | | - private @Nullable Object readField( |
321 | | - ByteString bytes, |
322 | | - String protoTypeName, |
323 | | - @Nullable FieldLiteDescriptor fieldDescriptor, |
324 | | - SelectField field) { |
325 | | - if (fieldDescriptor != null) { |
326 | | - return readField(bytes, protoTypeName, fieldDescriptor); |
327 | | - } |
| 332 | + /** Reads {@code field} using the type information it carries. */ |
| 333 | + private @Nullable Object readField(ByteString bytes, String protoTypeName, SelectField field) { |
328 | 334 | SelectField.MapEntrySpec mapEntrySpec = field.mapEntrySpec(); |
329 | 335 | if (mapEntrySpec == null) { |
330 | 336 | return readField(bytes, protoTypeName, newFieldDescriptor(field)); |
@@ -355,6 +361,9 @@ private Map.Entry<Object, Object> readSingleMapEntry( |
355 | 361 | FieldLiteDescriptor fieldDescriptor, |
356 | 362 | @Nullable FieldLiteDescriptor keyDescriptor, |
357 | 363 | @Nullable FieldLiteDescriptor valueDescriptor) { |
| 364 | + if (fieldDescriptor.getProtoFieldType().equals(FieldLiteDescriptor.Type.GROUP)) { |
| 365 | + throw new UnsupportedOperationException("Groups are not supported"); |
| 366 | + } |
358 | 367 | CodedInputStream inputStream = bytes.newCodedInput(); |
359 | 368 | // Submessages alias bytes; unwrapping parses or copies them, so no view outlives evaluation. |
360 | 369 | inputStream.enableAliasing(true); |
@@ -400,40 +409,31 @@ private Map.Entry<Object, Object> readSingleMapEntry( |
400 | 409 | } |
401 | 410 |
|
402 | 411 | /** |
403 | | - * Selects {@code field} from {@code bytes}, decoding it by the type information in {@code field} |
404 | | - * for fields missing from the descriptor pool. Returns the field's default value if it's absent. |
| 412 | + * Selects {@code field}, which its message's descriptor doesn't have, from {@code bytes} by the |
| 413 | + * type information it carries. Returns the field's default value if it's absent. |
405 | 414 | */ |
406 | 415 | Object selectByFieldNumber(ByteString bytes, String protoTypeName, SelectField field) { |
407 | | - FieldLiteDescriptor fieldDescriptor = |
408 | | - findFieldDescriptor(protoTypeName, field.fieldNumber()).orElse(null); |
409 | | - Object fieldValue = readField(bytes, protoTypeName, fieldDescriptor, field); |
410 | | - if (fieldValue != null) { |
411 | | - return fieldValue; |
412 | | - } |
413 | | - if (field.defaultValue() != null) { |
414 | | - return field.defaultValue(); |
415 | | - } |
416 | | - return getDefaultCelValue( |
417 | | - fieldDescriptor != null ? fieldDescriptor : newFieldDescriptor(field)); |
| 416 | + Object fieldValue = readField(bytes, protoTypeName, field); |
| 417 | + return fieldValue != null ? fieldValue : getDefaultCelValue(field, newFieldDescriptor(field)); |
418 | 418 | } |
419 | 419 |
|
420 | 420 | /** |
421 | | - * Finds {@code field} in {@code bytes}, decoding it by the type information in {@code field} for |
422 | | - * fields missing from the descriptor pool. A field without a type code is decoded as a message. |
| 421 | + * Finds {@code field}, which its message's descriptor doesn't have, in {@code bytes} by the type |
| 422 | + * information it carries. A field without a type code is decoded as a message. |
423 | 423 | */ |
424 | 424 | Optional<Object> findByFieldNumber(ByteString bytes, String protoTypeName, SelectField field) { |
425 | | - FieldLiteDescriptor fieldDescriptor = |
426 | | - findFieldDescriptor(protoTypeName, field.fieldNumber()).orElse(null); |
427 | | - return Optional.ofNullable(readField(bytes, protoTypeName, fieldDescriptor, field)); |
| 425 | + return Optional.ofNullable(readField(bytes, protoTypeName, field)); |
428 | 426 | } |
429 | 427 |
|
430 | 428 | /** Returns whether {@code field} is present in {@code bytes}. */ |
431 | 429 | boolean hasFieldByNumber(ByteString bytes, String protoTypeName, SelectField field) { |
432 | | - FieldLiteDescriptor fieldDescriptor = |
433 | | - findFieldDescriptor(protoTypeName, field.fieldNumber()).orElse(null); |
| 430 | + FieldLiteDescriptor fieldDescriptor = findFieldDescriptor(protoTypeName, field.fieldNumber()); |
434 | 431 | if (fieldDescriptor == null) { |
435 | 432 | fieldDescriptor = newFieldDescriptor(field); |
436 | 433 | } |
| 434 | + if (fieldDescriptor.getProtoFieldType().equals(FieldLiteDescriptor.Type.GROUP)) { |
| 435 | + throw new UnsupportedOperationException("Groups are not supported"); |
| 436 | + } |
437 | 437 | boolean isPackableList = |
438 | 438 | fieldDescriptor.getEncodingType().equals(EncodingType.LIST) && isPackable(fieldDescriptor); |
439 | 439 | CodedInputStream inputStream = bytes.newCodedInput(); |
@@ -464,6 +464,108 @@ boolean hasFieldByNumber(ByteString bytes, String protoTypeName, SelectField fie |
464 | 464 | return false; |
465 | 465 | } |
466 | 466 |
|
| 467 | + /** |
| 468 | + * Reads {@code fieldDescriptor} of {@code message} with its generated getter rather than from |
| 469 | + * wire bytes: its CEL value, or null if it's absent. |
| 470 | + */ |
| 471 | + @Nullable Object readFieldByGetter( |
| 472 | + MessageLite message, MessageLiteDescriptor descriptor, FieldLiteDescriptor fieldDescriptor) { |
| 473 | + Object value = readGetter(message, descriptor, fieldDescriptor.getFieldNumber()); |
| 474 | + if (value == null) { |
| 475 | + return null; |
| 476 | + } |
| 477 | + switch (fieldDescriptor.getEncodingType()) { |
| 478 | + case LIST: |
| 479 | + List<?> list = (List<?>) value; |
| 480 | + switch (fieldDescriptor.getProtoFieldType()) { |
| 481 | + case INT64: |
| 482 | + case SINT64: |
| 483 | + case SFIXED64: |
| 484 | + case DOUBLE: |
| 485 | + case BOOL: |
| 486 | + case STRING: |
| 487 | + // These elements are their own CEL values, so the immutable list needn't be copied. |
| 488 | + return CelPreAdaptedList.wrap(list); |
| 489 | + default: |
| 490 | + break; |
| 491 | + } |
| 492 | + ImmutableList.Builder<Object> listBuilder = |
| 493 | + ImmutableList.builderWithExpectedSize(list.size()); |
| 494 | + for (int i = 0; i < list.size(); i++) { |
| 495 | + listBuilder.add(fromGetterValue(list.get(i), fieldDescriptor)); |
| 496 | + } |
| 497 | + return listBuilder.build(); |
| 498 | + case MAP: |
| 499 | + Map<?, ?> map = (Map<?, ?>) value; |
| 500 | + MessageLiteDescriptor entryDescriptor = |
| 501 | + descriptorPool.getDescriptorOrThrow(fieldDescriptor.getFieldProtoTypeName()); |
| 502 | + FieldLiteDescriptor keyDescriptor = |
| 503 | + entryDescriptor.getByFieldNumberOrThrow(MAP_KEY_FIELD_NUMBER); |
| 504 | + FieldLiteDescriptor valueDescriptor = |
| 505 | + entryDescriptor.getByFieldNumberOrThrow(MAP_VALUE_FIELD_NUMBER); |
| 506 | + ImmutableMap.Builder<Object, Object> mapBuilder = |
| 507 | + ImmutableMap.builderWithExpectedSize(map.size()); |
| 508 | + for (Map.Entry<?, ?> entry : map.entrySet()) { |
| 509 | + mapBuilder.put( |
| 510 | + fromGetterValue(entry.getKey(), keyDescriptor), |
| 511 | + fromGetterValue(entry.getValue(), valueDescriptor)); |
| 512 | + } |
| 513 | + return mapBuilder.buildOrThrow(); |
| 514 | + case SINGULAR: |
| 515 | + return fromGetterValue(value, fieldDescriptor); |
| 516 | + } |
| 517 | + throw new IllegalStateException( |
| 518 | + "Unexpected encoding type: " + fieldDescriptor.getEncodingType()); |
| 519 | + } |
| 520 | + |
| 521 | + /** Like {@link #hasFieldByNumber}, through the field's generated getter. */ |
| 522 | + boolean hasByGetter(MessageLite message, MessageLiteDescriptor descriptor, SelectField field) { |
| 523 | + return readGetter(message, descriptor, field.fieldNumber()) != null; |
| 524 | + } |
| 525 | + |
| 526 | + // A field's value as its getter returns it, or null if it's unset or an empty repeated or map. |
| 527 | + private static @Nullable Object readGetter( |
| 528 | + MessageLite message, MessageLiteDescriptor descriptor, int fieldNumber) { |
| 529 | + Object value = descriptor.getFieldValue(message, fieldNumber); |
| 530 | + boolean isEmpty = |
| 531 | + (value instanceof List && ((List<?>) value).isEmpty()) |
| 532 | + || (value instanceof Map && ((Map<?, ?>) value).isEmpty()); |
| 533 | + return isEmpty ? null : value; |
| 534 | + } |
| 535 | + |
| 536 | + // Converts a field's (or element's) Java value as returned by its getter to its CEL value. |
| 537 | + private Object fromGetterValue(Object value, FieldLiteDescriptor fieldDescriptor) { |
| 538 | + switch (fieldDescriptor.getProtoFieldType()) { |
| 539 | + case UINT32: |
| 540 | + case FIXED32: |
| 541 | + return UnsignedLong.fromLongBits(Integer.toUnsignedLong((Integer) value)); |
| 542 | + case UINT64: |
| 543 | + case FIXED64: |
| 544 | + return UnsignedLong.fromLongBits((Long) value); |
| 545 | + case ENUM: |
| 546 | + // Open enums are read as their numbers; closed ones as enum constants. |
| 547 | + return value instanceof Integer |
| 548 | + ? ((Integer) value).longValue() |
| 549 | + : (long) ((EnumLite) value).getNumber(); |
| 550 | + case MESSAGE: |
| 551 | + MessageLite message = (MessageLite) value; |
| 552 | + String protoTypeName = fieldDescriptor.getFieldProtoTypeName(); |
| 553 | + MessageLiteDescriptor descriptor = |
| 554 | + descriptorPool.findDescriptor(protoTypeName).orElse(null); |
| 555 | + if (descriptor == null) { |
| 556 | + // Without a descriptor, only this submessage is serialized, rather than its whole root. |
| 557 | + return RawProtoMessageLiteValue.create(message.toByteString(), protoTypeName, this); |
| 558 | + } |
| 559 | + if (descriptorPool.findDescriptor(message).orElse(null) != descriptor) { |
| 560 | + // The pool decodes this type into another class, such as an older version of it. |
| 561 | + return readMessageField(message.toByteString(), protoTypeName); |
| 562 | + } |
| 563 | + return toRuntimeValue(message, descriptor); |
| 564 | + default: |
| 565 | + return super.toRuntimeValue(value); |
| 566 | + } |
| 567 | + } |
| 568 | + |
467 | 569 | /** Describes {@code field} by the type information it carries, built once and kept on it. */ |
468 | 570 | private static FieldLiteDescriptor newFieldDescriptor(SelectField field) { |
469 | 571 | Object cached = field.liteFieldDescriptor(); |
|
0 commit comments