Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -119,34 +119,39 @@ private Object readLengthDelimitedField(
return CelByteString.of(inputStream.readByteArray());
case MESSAGE:
return mergeOrReadMessageField(
inputStream.readBytes(), fieldDescriptor.getFieldProtoTypeName(), existingValue);
inputStream.readBytes(),
fieldDescriptor.getFieldProtoTypeName(),
existingValue,
/* isView= */ true);
case STRING:
return inputStream.readStringRequireUtf8();
default:
throw new IllegalStateException("Unexpected field type: " + fieldType);
}
}

// For bytes that don't alias another message's buffer (empty or freshly serialized).
private Object readMessageField(ByteString bytes, String fieldProtoTypeName) {
return mergeOrReadMessageField(bytes, fieldProtoTypeName, /* existingValue= */ null);
return mergeOrReadMessageField(
bytes, fieldProtoTypeName, /* existingValue= */ null, /* isView= */ false);
}

private Object mergeOrReadMessageField(
ByteString bytes, String fieldProtoTypeName, @Nullable Object existingValue) {
ByteString bytes, String fieldProtoTypeName, @Nullable Object existingValue, boolean isView) {
MessageLiteDescriptor descriptor =
descriptorPool.findDescriptor(fieldProtoTypeName).orElse(null);
if (descriptor == null) {
if (existingValue instanceof RawProtoMessageLiteValue) {
bytes = ((RawProtoMessageLiteValue) existingValue).toByteString().concat(bytes);
}
return RawProtoMessageLiteValue.create(bytes, fieldProtoTypeName, this, /* isView= */ true);
return RawProtoMessageLiteValue.create(bytes, fieldProtoTypeName, this, isView);
}
WellKnownProto wellKnownProto = WellKnownProto.getByTypeName(fieldProtoTypeName).orElse(null);
if (isStructLike(wellKnownProto)) {
if (existingValue instanceof ProtoMessageLiteValue) {
bytes = ((ProtoMessageLiteValue) existingValue).toByteString().concat(bytes);
}
return ProtoMessageLiteValue.create(bytes, fieldProtoTypeName, this);
return ProtoMessageLiteValue.create(bytes, descriptor, this);
}
if (existingValue instanceof MessageLite) {
return mergeMessageLite(((MessageLite) existingValue).toBuilder(), bytes, fieldProtoTypeName);
Expand All @@ -171,29 +176,7 @@ Object getDefaultCelValue(SelectField field, FieldLiteDescriptor fieldDescriptor
: getDefaultCelValue(fieldDescriptor);
}

@Nullable FieldLiteDescriptor findFieldDescriptor(String protoTypeName, int fieldNumber) {
MessageLiteDescriptor descriptor = descriptorPool.findDescriptor(protoTypeName).orElse(null);
return descriptor == null ? null : descriptor.findByFieldNumber(fieldNumber);
}

@Nullable FieldLiteDescriptor findFieldDescriptor(String protoTypeName, String fieldName) {
MessageLiteDescriptor descriptor = descriptorPool.findDescriptor(protoTypeName).orElse(null);
return descriptor == null ? null : descriptor.findByFieldName(fieldName);
}

@Nullable MessageLiteDescriptor findDescriptorWithGetters(String protoTypeName) {
return descriptorPool
.findDescriptor(protoTypeName)
.filter(MessageLiteDescriptor::hasGetters)
.orElse(null);
}

MessageLite parseMessageLite(ByteString bytes, String protoTypeName) {
MessageLiteDescriptor descriptor = descriptorPool.getDescriptorOrThrow(protoTypeName);
return parseMessageLite(bytes, descriptor);
}

private static MessageLite parseMessageLite(ByteString bytes, MessageLiteDescriptor descriptor) {
static MessageLite parseMessageLite(ByteString bytes, MessageLiteDescriptor descriptor) {
if (bytes.isEmpty()) {
return descriptor.newMessageBuilder().getDefaultInstanceForType();
}
Expand Down Expand Up @@ -229,7 +212,7 @@ private Object toRuntimeValue(MessageLite msg, MessageLiteDescriptor descriptor)
WellKnownProto wellKnownProto =
WellKnownProto.getByTypeName(descriptor.getProtoTypeName()).orElse(null);
if (isStructLike(wellKnownProto)) {
return ProtoMessageLiteValue.create(msg, descriptor.getProtoTypeName(), this);
return ProtoMessageLiteValue.create(msg, descriptor, this);
}

return fromWellKnownProto(msg, checkNotNull(wellKnownProto));
Expand Down Expand Up @@ -425,12 +408,17 @@ Optional<Object> findByFieldNumber(ByteString bytes, String protoTypeName, Selec
return Optional.ofNullable(readField(bytes, protoTypeName, field));
}

/** Returns whether {@code field} is present in {@code bytes}. */
/** Returns whether {@code field}, unknown to its message's descriptor, is in {@code bytes}. */
boolean hasFieldByNumber(ByteString bytes, String protoTypeName, SelectField field) {
FieldLiteDescriptor fieldDescriptor = findFieldDescriptor(protoTypeName, field.fieldNumber());
if (fieldDescriptor == null) {
fieldDescriptor = newFieldDescriptor(field);
}
return hasFieldByNumber(bytes, protoTypeName, field, newFieldDescriptor(field));
}

/** Like the overload above, for a field its message's descriptor has. */
boolean hasFieldByNumber(
ByteString bytes,
String protoTypeName,
SelectField field,
FieldLiteDescriptor fieldDescriptor) {
if (fieldDescriptor.getProtoFieldType().equals(FieldLiteDescriptor.Type.GROUP)) {
throw new UnsupportedOperationException("Groups are not supported");
}
Expand Down Expand Up @@ -469,8 +457,8 @@ boolean hasFieldByNumber(ByteString bytes, String protoTypeName, SelectField fie
* wire bytes: its CEL value, or null if it's absent.
*/
@Nullable Object readFieldByGetter(
MessageLite message, MessageLiteDescriptor descriptor, FieldLiteDescriptor fieldDescriptor) {
Object value = readGetter(message, descriptor, fieldDescriptor.getFieldNumber());
ProtoMessageLiteValue message, FieldLiteDescriptor fieldDescriptor) {
Object value = readGetter(message, fieldDescriptor.getFieldNumber());
if (value == null) {
return null;
}
Expand Down Expand Up @@ -519,14 +507,14 @@ boolean hasFieldByNumber(ByteString bytes, String protoTypeName, SelectField fie
}

/** Like {@link #hasFieldByNumber}, through the field's generated getter. */
boolean hasByGetter(MessageLite message, MessageLiteDescriptor descriptor, SelectField field) {
return readGetter(message, descriptor, field.fieldNumber()) != null;
boolean hasByGetter(ProtoMessageLiteValue message, SelectField field) {
return readGetter(message, field.fieldNumber()) != null;
}

// A field's value as its getter returns it, or null if it's unset or an empty repeated or map.
private static @Nullable Object readGetter(
MessageLite message, MessageLiteDescriptor descriptor, int fieldNumber) {
Object value = descriptor.getFieldValue(message, fieldNumber);
private static @Nullable Object readGetter(ProtoMessageLiteValue message, int fieldNumber) {
Object value =
message.descriptor().getFieldValue(checkNotNull(message.rawValue()), fieldNumber);
boolean isEmpty =
(value instanceof List && ((List<?>) value).isEmpty())
|| (value instanceof Map && ((Map<?, ?>) value).isEmpty());
Expand All @@ -549,18 +537,11 @@ private Object fromGetterValue(Object value, FieldLiteDescriptor fieldDescriptor
: (long) ((EnumLite) value).getNumber();
case MESSAGE:
MessageLite message = (MessageLite) value;
String protoTypeName = fieldDescriptor.getFieldProtoTypeName();
MessageLiteDescriptor descriptor =
descriptorPool.findDescriptor(protoTypeName).orElse(null);
if (descriptor == null) {
// Without a descriptor, only this submessage is serialized, rather than its whole root.
return RawProtoMessageLiteValue.create(message.toByteString(), protoTypeName, this);
}
if (descriptorPool.findDescriptor(message).orElse(null) != descriptor) {
// The pool decodes this type into another class, such as an older version of it.
return readMessageField(message.toByteString(), protoTypeName);
}
return toRuntimeValue(message, descriptor);
MessageLiteDescriptor descriptor = descriptorPool.findDescriptor(message).orElse(null);
// Not a class the pool knows (e.g. another version of its type): read its own bytes.
return descriptor != null
? toRuntimeValue(message, descriptor)
: readMessageField(message.toByteString(), fieldDescriptor.getFieldProtoTypeName());
default:
return super.toRuntimeValue(value);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,20 +68,24 @@ abstract class ProtoMessageLiteValue extends StructValue<String, MessageLite>
// re-serializing intermediate hops; lazily parsed into a MessageLite only if value() is called.
abstract @Nullable ByteString wireBytes();

@Override
public abstract CelType celType();
abstract MessageLiteDescriptor descriptor();

abstract ProtoLiteCelValueConverter protoLiteCelValueConverter();

@Override
public CelType celType() {
// Built on demand, since one of these values is created on every hop but rarely asked its type.
return StructTypeReference.create(protoTypeName());
}

@Memoized
@Override
public MessageLite value() {
MessageLite msg = rawValue();
if (msg != null) {
return msg;
}
return protoLiteCelValueConverter()
.parseMessageLite(checkNotNull(wireBytes()), celType().name());
return ProtoLiteCelValueConverter.parseMessageLite(checkNotNull(wireBytes()), descriptor());
}

@Memoized
Expand Down Expand Up @@ -112,20 +116,26 @@ public final boolean equals(Object other) {
return false;
}
ProtoMessageLiteValue that = (ProtoMessageLiteValue) other;
return this.celType().equals(that.celType()) && this.value().equals(that.value());
return this.protoTypeName().equals(that.protoTypeName()) && this.value().equals(that.value());
}

@Override
public final int hashCode() {
return Objects.hash(value(), celType());
return Objects.hash(value(), protoTypeName());
}

@Override
public final String toString() {
// AutoValue's would print the message's contents, which may be sensitive.
return "ProtoMessageLiteValue{protoTypeName=" + protoTypeName() + "}";
}

@Override
public Object select(String field) {
FieldLiteDescriptor fd = findFieldDescriptor(field);
FieldLiteDescriptor fd = descriptor().findByFieldName(field);
if (fd == null) {
throw CelAttributeNotFoundException.of(
String.format("field '%s' is not declared in message '%s'", field, celType().name()));
String.format("field '%s' is not declared in message '%s'", field, protoTypeName()));
}
Object fieldValue = readField(fd);
return fieldValue != null ? fieldValue : protoLiteCelValueConverter().getDefaultCelValue(fd);
Expand All @@ -134,88 +144,73 @@ public Object select(String field) {
@Override
public Optional<Object> find(String field) {
// Per SelectableValue#find, a field that doesn't exist is reported as absent.
return Optional.ofNullable(findFieldDescriptor(field)).map(this::readField);
return Optional.ofNullable(descriptor().findByFieldName(field)).map(this::readField);
}

@Override
public Object selectByFieldNumber(SelectField field) {
FieldLiteDescriptor fd = findFieldDescriptor(field.fieldNumber());
FieldLiteDescriptor fd = descriptor().findByFieldNumber(field.fieldNumber());
if (fd != null) {
Object value = readField(fd);
return value != null ? value : protoLiteCelValueConverter().getDefaultCelValue(field, fd);
}
return protoLiteCelValueConverter()
.selectByFieldNumber(toByteString(), celType().name(), field);
return protoLiteCelValueConverter().selectByFieldNumber(toByteString(), protoTypeName(), field);
}

@Override
public boolean hasFieldByNumber(SelectField field) {
MessageLite message = rawValue();
if (message != null && findFieldDescriptor(field.fieldNumber()) != null) {
MessageLiteDescriptor descriptor = findDescriptorWithGetters();
if (descriptor != null) {
return protoLiteCelValueConverter().hasByGetter(message, descriptor, field);
}
FieldLiteDescriptor fd = descriptor().findByFieldNumber(field.fieldNumber());
if (fd == null) {
return protoLiteCelValueConverter().hasFieldByNumber(toByteString(), protoTypeName(), field);
}
return protoLiteCelValueConverter().hasFieldByNumber(toByteString(), celType().name(), field);
return canReadByGetter()
? protoLiteCelValueConverter().hasByGetter(this, field)
: protoLiteCelValueConverter().hasFieldByNumber(toByteString(), protoTypeName(), field, fd);
}

@Override
public Optional<Object> findByFieldNumber(SelectField field) {
FieldLiteDescriptor fd = findFieldDescriptor(field.fieldNumber());
FieldLiteDescriptor fd = descriptor().findByFieldNumber(field.fieldNumber());
if (fd != null) {
return Optional.ofNullable(readField(fd));
}
return protoLiteCelValueConverter().findByFieldNumber(toByteString(), celType().name(), field);
return protoLiteCelValueConverter().findByFieldNumber(toByteString(), protoTypeName(), field);
}

private @Nullable Object readField(FieldLiteDescriptor fd) {
MessageLite message = rawValue();
if (message != null) {
MessageLiteDescriptor descriptor = findDescriptorWithGetters();
if (descriptor != null) {
return protoLiteCelValueConverter().readFieldByGetter(message, descriptor, fd);
}
}
return protoLiteCelValueConverter().readField(toByteString(), celType().name(), fd);
return canReadByGetter()
? protoLiteCelValueConverter().readFieldByGetter(this, fd)
: protoLiteCelValueConverter().readField(toByteString(), protoTypeName(), fd);
}

private @Nullable FieldLiteDescriptor findFieldDescriptor(String fieldName) {
return protoLiteCelValueConverter().findFieldDescriptor(celType().name(), fieldName);
private boolean canReadByGetter() {
return rawValue() != null && descriptor().hasGetters();
}

private @Nullable FieldLiteDescriptor findFieldDescriptor(int fieldNumber) {
return protoLiteCelValueConverter().findFieldDescriptor(celType().name(), fieldNumber);
}

private @Nullable MessageLiteDescriptor findDescriptorWithGetters() {
return protoLiteCelValueConverter().findDescriptorWithGetters(celType().name());
private String protoTypeName() {
return descriptor().getProtoTypeName();
}

static ProtoMessageLiteValue create(
MessageLite value, String typeName, ProtoLiteCelValueConverter protoLiteCelValueConverter) {
MessageLite value,
MessageLiteDescriptor descriptor,
ProtoLiteCelValueConverter protoLiteCelValueConverter) {
checkNotNull(value);
checkNotNull(typeName);
checkNotNull(descriptor);
checkNotNull(protoLiteCelValueConverter);
return new AutoValue_ProtoMessageLiteValue(
value,
/* wireBytes= */ null,
StructTypeReference.create(typeName),
protoLiteCelValueConverter);
value, /* wireBytes= */ null, descriptor, protoLiteCelValueConverter);
}

static ProtoMessageLiteValue create(
ByteString wireBytes,
String typeName,
MessageLiteDescriptor descriptor,
ProtoLiteCelValueConverter protoLiteCelValueConverter) {
checkNotNull(wireBytes);
checkNotNull(typeName);
checkNotNull(descriptor);
checkNotNull(protoLiteCelValueConverter);
return new AutoValue_ProtoMessageLiteValue(
/* rawValue= */ null,
wireBytes,
StructTypeReference.create(typeName),
protoLiteCelValueConverter);
/* rawValue= */ null, wireBytes, descriptor, protoLiteCelValueConverter);
}

ProtoMessageLiteValue() {}
Expand Down
Loading
Loading