Skip to content

Commit

Permalink
re-apply changes
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewparmet committed Oct 27, 2024
1 parent 5efed01 commit c8f04da
Show file tree
Hide file tree
Showing 16 changed files with 185 additions and 65 deletions.
43 changes: 43 additions & 0 deletions src/main/java/build/buf/protovalidate/MessageReflector.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright 2023-2024 Buf Technologies, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package build.buf.protovalidate;

import com.google.protobuf.Descriptors.FieldDescriptor;

/**
* {@link MessageReflector} is a wrapper around a protobuf message that provides reflective access
* to the underlying message.
*
* <p>{@link MessageReflector} is a runtime-independent interface. Any protobuf runtime that
* implements this interface can wrap its messages and, along with their {@link
* com.google.protobuf.Descriptors.Descriptor}s, protovalidate-java will be able to validate them.
*/
public interface MessageReflector {
/**
* Whether the wrapped message has the field described by the provided field descriptor.
*
* @param field The field descriptor to check for.
* @return Whether the field is present.
*/
boolean hasField(FieldDescriptor field);

/**
* Get the value described by the provided field descriptor.
*
* @param field The field descriptor for which to retrieve a value.
* @return The value corresponding to the field descriptor.
*/
Value getField(FieldDescriptor field);
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package build.buf.protovalidate.internal.evaluator;
package build.buf.protovalidate;

import com.google.protobuf.Message;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
Expand All @@ -25,22 +24,13 @@
*/
public interface Value {
/**
* Get the underlying value as a {@link Message} type.
* Get the underlying value as a {@link MessageReflector} type.
*
* @return The underlying {@link Message} value. null if the underlying value is not a {@link
* Message} type.
* @return The underlying {@link MessageReflector} value. null if the underlying value is not a
* {@link MessageReflector} type.
*/
@Nullable
Message messageValue();

/**
* Get the underlying value and cast it to the class type.
*
* @param clazz The inferred class.
* @return The value casted to the inferred class type.
* @param <T> The class type.
*/
<T> T value(Class<T> clazz);
MessageReflector messageValue();

/**
* Get the underlying value as a list.
Expand All @@ -57,4 +47,22 @@ public interface Value {
* list.
*/
Map<Value, Value> mapValue();

/**
* Get the underlying value as it should be provided to CEL.
*
* @return The underlying value as a CEL-compatible type.
*/
Object celValue();

/**
* Get the underlying value and cast it to the class type, which will be a type checkable
* internally by protovalidate-java.
*
* @param clazz The inferred class.
* @return The value cast to the inferred class type.
* @param <T> The class type.
*/
@Nullable
<T> T jvmValue(Class<T> clazz);
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@

package build.buf.protovalidate.internal.evaluator;

import build.buf.protovalidate.MessageReflector;
import build.buf.protovalidate.ValidationResult;
import build.buf.protovalidate.Value;
import build.buf.protovalidate.exceptions.ExecutionException;
import build.buf.validate.Violation;
import com.google.protobuf.Descriptors;
import com.google.protobuf.Message;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
Expand All @@ -45,12 +46,12 @@ class AnyEvaluator implements Evaluator {

@Override
public ValidationResult evaluate(Value val, boolean failFast) throws ExecutionException {
Message anyValue = val.messageValue();
MessageReflector anyValue = val.messageValue();
if (anyValue == null) {
return ValidationResult.EMPTY;
}
List<Violation> violationList = new ArrayList<>();
String typeURL = (String) anyValue.getField(typeURLDescriptor);
String typeURL = anyValue.getField(typeURLDescriptor).jvmValue(String.class);
if (!in.isEmpty() && !in.contains(typeURL)) {
Violation violation =
Violation.newBuilder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package build.buf.protovalidate.internal.evaluator;

import build.buf.protovalidate.ValidationResult;
import build.buf.protovalidate.Value;
import build.buf.protovalidate.exceptions.ExecutionException;
import build.buf.validate.Violation;
import com.google.protobuf.Descriptors;
Expand Down Expand Up @@ -62,11 +63,11 @@ public boolean tautology() {
*/
@Override
public ValidationResult evaluate(Value val, boolean failFast) throws ExecutionException {
Descriptors.EnumValueDescriptor enumValue = val.value(Descriptors.EnumValueDescriptor.class);
Integer enumValue = val.jvmValue(Integer.class);
if (enumValue == null) {
return ValidationResult.EMPTY;
}
if (!values.contains(enumValue.getNumber())) {
if (!values.contains(enumValue)) {
return new ValidationResult(
Collections.singletonList(
Violation.newBuilder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package build.buf.protovalidate.internal.evaluator;

import build.buf.protovalidate.ValidationResult;
import build.buf.protovalidate.Value;
import build.buf.protovalidate.exceptions.ExecutionException;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@

package build.buf.protovalidate.internal.evaluator;

import build.buf.protovalidate.MessageReflector;
import build.buf.protovalidate.ValidationResult;
import build.buf.protovalidate.Value;
import build.buf.protovalidate.exceptions.ExecutionException;
import build.buf.validate.Violation;
import com.google.protobuf.Descriptors.FieldDescriptor;
import com.google.protobuf.Message;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
Expand Down Expand Up @@ -68,13 +69,17 @@ public boolean tautology() {

@Override
public ValidationResult evaluate(Value val, boolean failFast) throws ExecutionException {
Message message = val.messageValue();
MessageReflector message = val.messageValue();
if (message == null) {
return ValidationResult.EMPTY;
}
boolean hasField;
if (descriptor.isRepeated()) {
hasField = message.getRepeatedFieldCount(descriptor) != 0;
if (descriptor.isMapField()) {
hasField = !message.getField(descriptor).mapValue().isEmpty();
} else {
hasField = !message.getField(descriptor).repeatedValue().isEmpty();
}
} else {
hasField = message.hasField(descriptor);
}
Expand All @@ -90,12 +95,11 @@ public ValidationResult evaluate(Value val, boolean failFast) throws ExecutionEx
if (ignoreEmpty && !hasField) {
return ValidationResult.EMPTY;
}
Object fieldValue = message.getField(descriptor);
if (ignoreDefault && Objects.equals(zero, fieldValue)) {
Value fieldValue = message.getField(descriptor);
if (ignoreDefault && Objects.equals(zero, fieldValue.jvmValue(Object.class))) {
return ValidationResult.EMPTY;
}
ValidationResult evalResult =
valueEvaluator.evaluate(new ObjectValue(descriptor, fieldValue), failFast);
ValidationResult evalResult = valueEvaluator.evaluate(fieldValue, failFast);
List<Violation> violations =
ErrorPathUtils.prefixErrorPaths(evalResult.getViolations(), "%s", descriptor.getName());
return new ValidationResult(violations);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

package build.buf.protovalidate.internal.evaluator;

import build.buf.protovalidate.MessageReflector;
import build.buf.protovalidate.Value;
import com.google.protobuf.AbstractMessage;
import com.google.protobuf.Descriptors;
import com.google.protobuf.Message;
Expand All @@ -25,11 +27,8 @@
import javax.annotation.Nullable;
import org.projectnessie.cel.common.ULong;

/**
* The {@link build.buf.protovalidate.internal.evaluator.Value} type that contains a field
* descriptor and its value.
*/
public final class ObjectValue implements Value {
/** The {@link Value} type that contains a field descriptor and its value. */
public final class FieldValue implements Value {

/**
* {@link com.google.protobuf.Descriptors.FieldDescriptor} is the field descriptor for the value.
Expand All @@ -40,27 +39,38 @@ public final class ObjectValue implements Value {
private final Object value;

/**
* Constructs a new {@link build.buf.protovalidate.internal.evaluator.ObjectValue}.
* Constructs a new {@link FieldValue}.
*
* @param fieldDescriptor The field descriptor for the value.
* @param value The value associated with the field descriptor.
*/
ObjectValue(Descriptors.FieldDescriptor fieldDescriptor, Object value) {
FieldValue(Descriptors.FieldDescriptor fieldDescriptor, Object value) {
this.fieldDescriptor = fieldDescriptor;
this.value = value;
}

@Nullable
@Override
public Message messageValue() {
if (fieldDescriptor.getJavaType() == Descriptors.FieldDescriptor.JavaType.MESSAGE) {
return (Message) value;
@Nullable
public MessageReflector messageValue() {
if (fieldDescriptor.getType() == Descriptors.FieldDescriptor.Type.MESSAGE) {
return new ProtobufMessageReflector((Message) value);
}
return null;
}

@Override
public <T> T value(Class<T> clazz) {
public <T> T jvmValue(Class<T> clazz) {
if (value instanceof Descriptors.EnumValueDescriptor) {
return clazz.cast(((Descriptors.EnumValueDescriptor) value).getNumber());
}
return clazz.cast(value);
}

@Override
public Object celValue() {
if (value instanceof Descriptors.EnumValueDescriptor) {
return ((Descriptors.EnumValueDescriptor) value).getNumber();
}
Descriptors.FieldDescriptor.Type type = fieldDescriptor.getType();
if (!fieldDescriptor.isRepeated()
&& (type == Descriptors.FieldDescriptor.Type.UINT32
Expand All @@ -74,9 +84,9 @@ public <T> T value(Class<T> clazz) {
* When using uint32/uint64 in your protobuf objects or CEL expressions in Java,
* wrap them with the org.projectnessie.cel.common.ULong type.
*/
return clazz.cast(ULong.valueOf(((Number) value).longValue()));
return ULong.valueOf(((Number) value).longValue());
}
return clazz.cast(value);
return value;
}

@Override
Expand All @@ -85,7 +95,7 @@ public List<Value> repeatedValue() {
if (fieldDescriptor.isRepeated()) {
List<?> list = (List<?>) value;
for (Object o : list) {
out.add(new build.buf.protovalidate.internal.evaluator.ObjectValue(fieldDescriptor, o));
out.add(new FieldValue(fieldDescriptor, o));
}
}
return out;
Expand All @@ -103,12 +113,10 @@ public Map<Value, Value> mapValue() {
Map<Value, Value> out = new HashMap<>(input.size());
for (AbstractMessage entry : input) {
Object keyValue = entry.getField(keyDesc);
Value keyJavaValue =
new build.buf.protovalidate.internal.evaluator.ObjectValue(keyDesc, keyValue);
Value keyJavaValue = new FieldValue(keyDesc, keyValue);

Object valValue = entry.getField(valDesc);
Value valJavaValue =
new build.buf.protovalidate.internal.evaluator.ObjectValue(valDesc, valValue);
Value valJavaValue = new FieldValue(valDesc, valValue);

out.put(keyJavaValue, valJavaValue);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package build.buf.protovalidate.internal.evaluator;

import build.buf.protovalidate.ValidationResult;
import build.buf.protovalidate.Value;
import build.buf.protovalidate.exceptions.ExecutionException;
import build.buf.validate.Violation;
import java.util.ArrayList;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package build.buf.protovalidate.internal.evaluator;

import build.buf.protovalidate.ValidationResult;
import build.buf.protovalidate.Value;
import build.buf.protovalidate.exceptions.ExecutionException;
import build.buf.validate.FieldConstraints;
import build.buf.validate.Violation;
Expand Down Expand Up @@ -100,7 +101,7 @@ private List<Violation> evalPairs(Value key, Value value, boolean failFast)
violations.addAll(keyViolations);
violations.addAll(valueViolations);

Object keyName = key.value(Object.class);
Object keyName = key.jvmValue(Object.class);
if (keyName == null) {
return Collections.emptyList();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package build.buf.protovalidate.internal.evaluator;

import build.buf.protovalidate.ValidationResult;
import build.buf.protovalidate.Value;
import build.buf.protovalidate.exceptions.ExecutionException;
import build.buf.validate.Violation;
import java.util.ArrayList;
Expand Down
Loading

0 comments on commit c8f04da

Please sign in to comment.