diff --git a/conformance/src/main/java/build/buf/validate/conformance/cases/custom_constraints/CustomConstraintsProto.java b/conformance/src/main/java/build/buf/validate/conformance/cases/custom_constraints/CustomConstraintsProto.java index 0f5414b5..fe29345f 100644 --- a/conformance/src/main/java/build/buf/validate/conformance/cases/custom_constraints/CustomConstraintsProto.java +++ b/conformance/src/main/java/build/buf/validate/conformance/cases/custom_constraints/CustomConstraintsProto.java @@ -110,7 +110,7 @@ public static void registerAllExtensions( ".a < this.b\032?\n\027message_expression_enum\022\022" + "c must not equal d\032\020this.c != this.d\032D\n\030" + "message_expression_embed\022\022e.a must equal" + - " f.a\032\024this.e.a == this.f.a\"\366\003\n\020FieldExpr" + + " f.a\032\024this.e.a == this.f.a\"\252\005\n\020FieldExpr" + "essions\022Z\n\001a\030\001 \001(\005BL\272HI\272\001F\n\027field_expres" + "sion_scalar\032+this > 42 ? \'\': \'a must be " + "greater than 42\'R\001a\022\177\n\001b\030\002 \001(\01627.buf.val" + @@ -120,29 +120,34 @@ public static void registerAllExtensions( "2J.buf.validate.conformance.cases.custom" + "_constraints.FieldExpressions.NestedBL\272H" + "I\272\001F\n\026field_expression_embed\022\033c.a must b" + - "e a multiple of 4\032\017this.a % 4 == 0R\001c\032\\\n" + - "\006Nested\022R\n\001a\030\001 \001(\005BD\272HA\272\001>\n\027field_expres" + - "sion_nested\032#this > 0 ? \'\': \'a must be p" + - "ositive\'R\001a\"R\n\014MissingField\022\014\n\001a\030\001 \001(\005R\001" + - "a:4\272H1\032/\n\rmissing_field\022\022b must be posit" + - "ive\032\nthis.b > 0\"g\n\rIncorrectType\022\014\n\001a\030\001 " + - "\001(\005R\001a:H\272HE\032C\n\016incorrect_type\022\027a must st" + - "art with \'foo\'\032\030this.a.startsWith(\'foo\')" + - "\"}\n\017DynRuntimeError\022\014\n\001a\030\001 \001(\005R\001a:\\\272HY\032W" + - "\n\017dyn_runtime_err\022.dynamic type tries to" + - " use a non-existent field\032\024dyn(this).b =" + - "= \'foo\'\"\\\n\014NowEqualsNow:L\272HI\032G\n\016now_equa" + - "ls_now\022)now should equal now within an e" + - "xpression\032\nnow == now**\n\004Enum\022\024\n\020ENUM_UN" + - "SPECIFIED\020\000\022\014\n\010ENUM_ONE\020\001B\267\002\n7build.buf." + - "validate.conformance.cases.custom_constr" + - "aintsB\026CustomConstraintsProtoP\001\242\002\005BVCCC\252" + - "\0020Buf.Validate.Conformance.Cases.CustomC" + - "onstraints\312\0020Buf\\Validate\\Conformance\\Ca" + - "ses\\CustomConstraints\342\002\n\027field_expression_nested\032#this > " + + "0 ? \'\': \'a must be positive\'R\001a\"R\n\014Missi" + + "ngField\022\014\n\001a\030\001 \001(\005R\001a:4\272H1\032/\n\rmissing_fi" + + "eld\022\022b must be positive\032\nthis.b > 0\"g\n\rI" + + "ncorrectType\022\014\n\001a\030\001 \001(\005R\001a:H\272HE\032C\n\016incor" + + "rect_type\022\027a must start with \'foo\'\032\030this" + + ".a.startsWith(\'foo\')\"}\n\017DynRuntimeError\022" + + "\014\n\001a\030\001 \001(\005R\001a:\\\272HY\032W\n\017dyn_runtime_err\022.d" + + "ynamic type tries to use a non-existent " + + "field\032\024dyn(this).b == \'foo\'\"\\\n\014NowEquals" + + "Now:L\272HI\032G\n\016now_equals_now\022)now should e" + + "qual now within an expression\032\nnow == no" + + "w**\n\004Enum\022\024\n\020ENUM_UNSPECIFIED\020\000\022\014\n\010ENUM_" + + "ONE\020\001B\267\002\n7build.buf.validate.conformance" + + ".cases.custom_constraintsB\026CustomConstra" + + "intsProtoP\001\242\002\005BVCCC\252\0020Buf.Validate.Confo" + + "rmance.Cases.CustomConstraints\312\0020Buf\\Val" + + "idate\\Conformance\\Cases\\CustomConstraint" + + "s\342\002int32 d = 4 [json_name = "d", (.buf.validate.field) = { ... } + * @return The d. + */ + @java.lang.Override + public int getD() { + return d_; + } + private byte memoizedIsInitialized = -1; @java.lang.Override public final boolean isInitialized() { @@ -556,6 +567,9 @@ public void writeTo(com.google.protobuf.CodedOutputStream output) if (((bitField0_ & 0x00000001) != 0)) { output.writeMessage(3, getC()); } + if (d_ != 0) { + output.writeInt32(4, d_); + } getUnknownFields().writeTo(output); } @@ -577,6 +591,10 @@ public int getSerializedSize() { size += com.google.protobuf.CodedOutputStream .computeMessageSize(3, getC()); } + if (d_ != 0) { + size += com.google.protobuf.CodedOutputStream + .computeInt32Size(4, d_); + } size += getUnknownFields().getSerializedSize(); memoizedSize = size; return size; @@ -600,6 +618,8 @@ public boolean equals(final java.lang.Object obj) { if (!getC() .equals(other.getC())) return false; } + if (getD() + != other.getD()) return false; if (!getUnknownFields().equals(other.getUnknownFields())) return false; return true; } @@ -619,6 +639,8 @@ public int hashCode() { hash = (37 * hash) + C_FIELD_NUMBER; hash = (53 * hash) + getC().hashCode(); } + hash = (37 * hash) + D_FIELD_NUMBER; + hash = (53 * hash) + getD(); hash = (29 * hash) + getUnknownFields().hashCode(); memoizedHashCode = hash; return hash; @@ -763,6 +785,7 @@ public Builder clear() { cBuilder_.dispose(); cBuilder_ = null; } + d_ = 0; return this; } @@ -809,6 +832,9 @@ private void buildPartial0(build.buf.validate.conformance.cases.custom_constrain : cBuilder_.build(); to_bitField0_ |= 0x00000001; } + if (((from_bitField0_ & 0x00000008) != 0)) { + result.d_ = d_; + } result.bitField0_ |= to_bitField0_; } @@ -833,6 +859,9 @@ public Builder mergeFrom(build.buf.validate.conformance.cases.custom_constraints if (other.hasC()) { mergeC(other.getC()); } + if (other.getD() != 0) { + setD(other.getD()); + } this.mergeUnknownFields(other.getUnknownFields()); onChanged(); return this; @@ -876,6 +905,11 @@ public Builder mergeFrom( bitField0_ |= 0x00000004; break; } // case 26 + case 32: { + d_ = input.readInt32(); + bitField0_ |= 0x00000008; + break; + } // case 32 default: { if (!super.parseUnknownField(input, extensionRegistry, tag)) { done = true; // was an endgroup tag @@ -1099,6 +1133,38 @@ public build.buf.validate.conformance.cases.custom_constraints.FieldExpressions. return cBuilder_; } + private int d_ ; + /** + * int32 d = 4 [json_name = "d", (.buf.validate.field) = { ... } + * @return The d. + */ + @java.lang.Override + public int getD() { + return d_; + } + /** + * int32 d = 4 [json_name = "d", (.buf.validate.field) = { ... } + * @param value The d to set. + * @return This builder for chaining. + */ + public Builder setD(int value) { + + d_ = value; + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + /** + * int32 d = 4 [json_name = "d", (.buf.validate.field) = { ... } + * @return This builder for chaining. + */ + public Builder clearD() { + bitField0_ = (bitField0_ & ~0x00000008); + d_ = 0; + onChanged(); + return this; + } + // @@protoc_insertion_point(builder_scope:buf.validate.conformance.cases.custom_constraints.FieldExpressions) } diff --git a/conformance/src/main/java/build/buf/validate/conformance/cases/custom_constraints/FieldExpressionsOrBuilder.java b/conformance/src/main/java/build/buf/validate/conformance/cases/custom_constraints/FieldExpressionsOrBuilder.java index 46f5e949..d212e97a 100644 --- a/conformance/src/main/java/build/buf/validate/conformance/cases/custom_constraints/FieldExpressionsOrBuilder.java +++ b/conformance/src/main/java/build/buf/validate/conformance/cases/custom_constraints/FieldExpressionsOrBuilder.java @@ -40,4 +40,10 @@ public interface FieldExpressionsOrBuilder extends * .buf.validate.conformance.cases.custom_constraints.FieldExpressions.Nested c = 3 [json_name = "c", (.buf.validate.field) = { ... } */ build.buf.validate.conformance.cases.custom_constraints.FieldExpressions.NestedOrBuilder getCOrBuilder(); + + /** + * int32 d = 4 [json_name = "d", (.buf.validate.field) = { ... } + * @return The d. + */ + int getD(); } diff --git a/gradle.properties b/gradle.properties index 9e884fbc..3e31ce65 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ # Version of buf.build/bufbuild/protovalidate to use. -protovalidate.version = v0.8.2 +protovalidate.version = v0.9.0 # Arguments to the protovalidate-conformance CLI protovalidate.conformance.args = --strict --strict_message --strict_error diff --git a/src/main/java/build/buf/protovalidate/Validator.java b/src/main/java/build/buf/protovalidate/Validator.java index 61d43adb..3cdb051b 100644 --- a/src/main/java/build/buf/protovalidate/Validator.java +++ b/src/main/java/build/buf/protovalidate/Validator.java @@ -17,6 +17,7 @@ import build.buf.protovalidate.exceptions.CompilationException; import build.buf.protovalidate.exceptions.ValidationException; import build.buf.protovalidate.internal.celext.ValidateLibrary; +import build.buf.protovalidate.internal.errors.FieldPathUtils; import build.buf.protovalidate.internal.evaluator.Evaluator; import build.buf.protovalidate.internal.evaluator.EvaluatorBuilder; import build.buf.protovalidate.internal.evaluator.MessageValue; @@ -74,7 +75,11 @@ public ValidationResult validate(Message msg) throws ValidationException { } Descriptor descriptor = msg.getDescriptorForType(); Evaluator evaluator = evaluatorBuilder.load(descriptor); - return evaluator.evaluate(new MessageValue(msg), failFast); + ValidationResult result = evaluator.evaluate(new MessageValue(msg), failFast); + if (result.isSuccess()) { + return result; + } + return new ValidationResult(FieldPathUtils.calculateFieldPathStrings(result.getViolations())); } /** diff --git a/src/main/java/build/buf/protovalidate/internal/constraints/ConstraintCache.java b/src/main/java/build/buf/protovalidate/internal/constraints/ConstraintCache.java index 207aed4d..a290f99d 100644 --- a/src/main/java/build/buf/protovalidate/internal/constraints/ConstraintCache.java +++ b/src/main/java/build/buf/protovalidate/internal/constraints/ConstraintCache.java @@ -16,11 +16,13 @@ import build.buf.protovalidate.Config; import build.buf.protovalidate.exceptions.CompilationException; +import build.buf.protovalidate.internal.errors.FieldPathUtils; import build.buf.protovalidate.internal.expression.AstExpression; import build.buf.protovalidate.internal.expression.CompiledProgram; import build.buf.protovalidate.internal.expression.Expression; import build.buf.protovalidate.internal.expression.Variable; import build.buf.validate.FieldConstraints; +import build.buf.validate.FieldPath; import build.buf.validate.ValidateProto; import com.google.protobuf.DescriptorProtos; import com.google.protobuf.Descriptors; @@ -52,10 +54,12 @@ public class ConstraintCache { private static class CelRule { public final AstExpression astExpression; public final FieldDescriptor field; + public final FieldPath rulePath; - public CelRule(AstExpression astExpression, FieldDescriptor field) { + public CelRule(AstExpression astExpression, FieldDescriptor field, FieldPath rulePath) { this.astExpression = astExpression; this.field = field; + this.rulePath = rulePath; } } @@ -119,16 +123,17 @@ public ConstraintCache(Env env, Config config) { public List compile( FieldDescriptor fieldDescriptor, FieldConstraints fieldConstraints, boolean forItems) throws CompilationException { - Message message = resolveConstraints(fieldDescriptor, fieldConstraints, forItems); - if (message == null) { + ResolvedConstraint resolved = resolveConstraints(fieldDescriptor, fieldConstraints, forItems); + if (resolved == null) { // Message null means there were no constraints resolved. return Collections.emptyList(); } + Message message = resolved.message; List completeProgramList = new ArrayList<>(); for (Map.Entry entry : message.getAllFields().entrySet()) { FieldDescriptor constraintFieldDesc = entry.getKey(); List programList = - compileRule(fieldDescriptor, forItems, constraintFieldDesc, message); + compileRule(fieldDescriptor, forItems, resolved.setOneof, constraintFieldDesc, message); if (programList == null) continue; completeProgramList.addAll(programList); } @@ -152,11 +157,14 @@ public List compile( } Ast residual = ruleEnv.residualAst(rule.astExpression.ast, evalResult.getEvalDetails()); programs.add( - new CompiledProgram(ruleEnv.program(residual, globals), rule.astExpression.source)); + new CompiledProgram( + ruleEnv.program(residual, globals), rule.astExpression.source, rule.rulePath)); } catch (Exception e) { programs.add( new CompiledProgram( - ruleEnv.program(rule.astExpression.ast, globals), rule.astExpression.source)); + ruleEnv.program(rule.astExpression.ast, globals), + rule.astExpression.source, + rule.rulePath)); } } return Collections.unmodifiableList(programs); @@ -165,6 +173,7 @@ public List compile( private @Nullable List compileRule( FieldDescriptor fieldDescriptor, boolean forItems, + FieldDescriptor setOneof, FieldDescriptor constraintFieldDesc, Message message) throws CompilationException { @@ -178,8 +187,14 @@ public List compile( celRules = new ArrayList<>(expressions.size()); Env ruleEnv = getRuleEnv(fieldDescriptor, message, constraintFieldDesc, forItems); for (Expression expression : expressions) { + FieldPath rulePath = + FieldPath.newBuilder() + .addElements(FieldPathUtils.fieldPathElement(setOneof)) + .addElements(FieldPathUtils.fieldPathElement(constraintFieldDesc)) + .build(); celRules.add( - new CelRule(AstExpression.newAstExpression(ruleEnv, expression), constraintFieldDesc)); + new CelRule( + AstExpression.newAstExpression(ruleEnv, expression), constraintFieldDesc, rulePath)); } descriptorMap.put(constraintFieldDesc, celRules); return celRules; @@ -246,13 +261,23 @@ private Env getRuleEnv( Variable.RULE_NAME, DescriptorMappings.getCELType(constraintFieldDesc, false)))); } + private static class ResolvedConstraint { + final Message message; + final FieldDescriptor setOneof; + + ResolvedConstraint(Message message, FieldDescriptor setOneof) { + this.message = message; + this.setOneof = setOneof; + } + } + /** * Extracts the standard constraints for the specified field. An exception is thrown if the wrong * constraints are applied to a field (typically if there is a type-mismatch). Null is returned if * there are no standard constraints to apply to this field. */ @Nullable - private Message resolveConstraints( + private ResolvedConstraint resolveConstraints( FieldDescriptor fieldDescriptor, FieldConstraints fieldConstraints, boolean forItems) throws CompilationException { // Get the oneof field descriptor from the field constraints. @@ -313,6 +338,6 @@ private Message resolveConstraints( if (!allowUnknownFields && !typeConstraints.getUnknownFields().isEmpty()) { throw new CompilationException("unrecognized field constraints"); } - return typeConstraints; + return new ResolvedConstraint(typeConstraints, oneofFieldDescriptor); } } diff --git a/src/main/java/build/buf/protovalidate/internal/errors/FieldPathUtils.java b/src/main/java/build/buf/protovalidate/internal/errors/FieldPathUtils.java new file mode 100644 index 00000000..79837df1 --- /dev/null +++ b/src/main/java/build/buf/protovalidate/internal/errors/FieldPathUtils.java @@ -0,0 +1,171 @@ +// 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.internal.errors; + +import build.buf.validate.FieldPath; +import build.buf.validate.FieldPathElement; +import build.buf.validate.Violation; +import com.google.protobuf.Descriptors; +import java.util.ArrayList; +import java.util.List; + +/** Utility class for manipulating error paths in violations. */ +public final class FieldPathUtils { + private FieldPathUtils() {} + + /** + * Prepends the field paths of the given violations with the provided element. + * + * @param violations The list of violations to operate on. + * @param element The element to prefix to each field path. + * @param skipSubscript Skips prepending a field path if the first element has a subscript. + * @return The modified violations with prepended field paths. + */ + public static List prependFieldPaths( + List violations, FieldPathElement element, boolean skipSubscript) { + List result = new ArrayList<>(); + for (Violation violation : violations) { + // Special case: Here we skip prepending if the first element has a subscript. This is a weird + // special case that makes it significantly simpler to handle reverse-constructing paths with + // maps and repeated fields. + if (skipSubscript + && violation.getField().getElementsCount() > 0 + && violation.getField().getElements(0).getSubscriptCase() + != FieldPathElement.SubscriptCase.SUBSCRIPT_NOT_SET) { + result.add(violation); + continue; + } + result.add( + violation.toBuilder() + .setField( + FieldPath.newBuilder() + .addElements(element) + .addAllElements(violation.getField().getElementsList()) + .build()) + .build()); + } + return result; + } + + /** + * Prepends the rule paths of the given violations with the provided elements. + * + * @param violations The list of violations to operate on. + * @param elements The elements to prefix to each rule path. + * @return The modified violations with prepended rule paths. + */ + public static List prependRulePaths( + List violations, Iterable elements) { + List result = new ArrayList<>(); + for (Violation violation : violations) { + result.add( + violation.toBuilder() + .setRule( + FieldPath.newBuilder() + .addAllElements(elements) + .addAllElements(violation.getRule().getElementsList()) + .build()) + .build()); + } + return result; + } + + /** + * Calculates the field path strings for each violation. + * + * @param violations The list of violations to operate on. + * @return The modified violations with field path strings. + */ + public static List calculateFieldPathStrings(List violations) { + List result = new ArrayList<>(); + for (Violation violation : violations) { + if (violation.getField().getElementsCount() > 0) { + result.add( + violation.toBuilder().setFieldPath(fieldPathString(violation.getField())).build()); + } else { + result.add(violation); + } + } + return result; + } + + /** + * Converts the provided field path to a string. + * + * @param fieldPath A field path to convert to a string. + * @return The string representation of the provided field path. + */ + static String fieldPathString(FieldPath fieldPath) { + StringBuilder builder = new StringBuilder(); + for (FieldPathElement element : fieldPath.getElementsList()) { + if (builder.length() > 0) { + builder.append("."); + } + builder.append(element.getFieldName()); + switch (element.getSubscriptCase()) { + case INDEX: + builder.append("["); + builder.append(element.getIndex()); + builder.append("]"); + break; + case BOOL_KEY: + if (element.getBoolKey()) { + builder.append("[true]"); + } else { + builder.append("[false]"); + } + break; + case INT_KEY: + builder.append("["); + builder.append(element.getIntKey()); + builder.append("]"); + break; + case UINT_KEY: + builder.append("["); + builder.append(element.getUintKey()); + builder.append("]"); + break; + case STRING_KEY: + builder.append("[\""); + builder.append(element.getStringKey().replace("\\", "\\\\").replace("\"", "\\\"")); + builder.append("\"]"); + break; + case SUBSCRIPT_NOT_SET: + break; + } + } + return builder.toString(); + } + + /** + * Returns the field path element that refers to the provided field descriptor. + * + * @param fieldDescriptor The field descriptor to generate a field path element for. + * @return The field path element that corresponds to the provided field descriptor. + */ + public static FieldPathElement.Builder fieldPathElement( + Descriptors.FieldDescriptor fieldDescriptor) { + String name; + if (fieldDescriptor.isExtension()) { + name = "[" + fieldDescriptor.getFullName() + "]"; + } else { + name = fieldDescriptor.getName(); + } + return FieldPathElement.newBuilder() + .setFieldNumber(fieldDescriptor.getNumber()) + .setFieldName(name) + .setFieldType(fieldDescriptor.getType().toProto()); + } +} diff --git a/src/main/java/build/buf/protovalidate/internal/evaluator/AnyEvaluator.java b/src/main/java/build/buf/protovalidate/internal/evaluator/AnyEvaluator.java index c1a8c8e5..16658a34 100644 --- a/src/main/java/build/buf/protovalidate/internal/evaluator/AnyEvaluator.java +++ b/src/main/java/build/buf/protovalidate/internal/evaluator/AnyEvaluator.java @@ -16,6 +16,10 @@ import build.buf.protovalidate.ValidationResult; import build.buf.protovalidate.exceptions.ExecutionException; +import build.buf.protovalidate.internal.errors.FieldPathUtils; +import build.buf.validate.AnyRules; +import build.buf.validate.FieldConstraints; +import build.buf.validate.FieldPath; import build.buf.validate.Violation; import com.google.protobuf.Descriptors; import com.google.protobuf.Message; @@ -36,6 +40,28 @@ class AnyEvaluator implements Evaluator { private final Set in; private final Set notIn; + private static final FieldPath IN_RULE_PATH = + FieldPath.newBuilder() + .addElements( + FieldPathUtils.fieldPathElement( + FieldConstraints.getDescriptor() + .findFieldByNumber(FieldConstraints.ANY_FIELD_NUMBER))) + .addElements( + FieldPathUtils.fieldPathElement( + AnyRules.getDescriptor().findFieldByNumber(AnyRules.IN_FIELD_NUMBER))) + .build(); + + private static final FieldPath NOT_IN_RULE_PATH = + FieldPath.newBuilder() + .addElements( + FieldPathUtils.fieldPathElement( + FieldConstraints.getDescriptor() + .findFieldByNumber(FieldConstraints.ANY_FIELD_NUMBER))) + .addElements( + FieldPathUtils.fieldPathElement( + AnyRules.getDescriptor().findFieldByNumber(AnyRules.NOT_IN_FIELD_NUMBER))) + .build(); + /** Constructs a new evaluator for {@link build.buf.validate.AnyRules} messages. */ AnyEvaluator(Descriptors.FieldDescriptor typeURLDescriptor, List in, List notIn) { this.typeURLDescriptor = typeURLDescriptor; @@ -54,6 +80,7 @@ public ValidationResult evaluate(Value val, boolean failFast) throws ExecutionEx if (!in.isEmpty() && !in.contains(typeURL)) { Violation violation = Violation.newBuilder() + .setRule(IN_RULE_PATH) .setConstraintId("any.in") .setMessage("type URL must be in the allow list") .build(); @@ -65,6 +92,7 @@ public ValidationResult evaluate(Value val, boolean failFast) throws ExecutionEx if (!notIn.isEmpty() && notIn.contains(typeURL)) { Violation violation = Violation.newBuilder() + .setRule(NOT_IN_RULE_PATH) .setConstraintId("any.not_in") .setMessage("type URL must not be in the block list") .build(); diff --git a/src/main/java/build/buf/protovalidate/internal/evaluator/EnumEvaluator.java b/src/main/java/build/buf/protovalidate/internal/evaluator/EnumEvaluator.java index 7f2b17da..1ea95797 100644 --- a/src/main/java/build/buf/protovalidate/internal/evaluator/EnumEvaluator.java +++ b/src/main/java/build/buf/protovalidate/internal/evaluator/EnumEvaluator.java @@ -16,6 +16,10 @@ import build.buf.protovalidate.ValidationResult; import build.buf.protovalidate.exceptions.ExecutionException; +import build.buf.protovalidate.internal.errors.FieldPathUtils; +import build.buf.validate.EnumRules; +import build.buf.validate.FieldConstraints; +import build.buf.validate.FieldPath; import build.buf.validate.Violation; import com.google.protobuf.Descriptors; import java.util.Collections; @@ -31,6 +35,17 @@ class EnumEvaluator implements Evaluator { /** Captures all the defined values for this enum */ private final Set values; + private static final FieldPath DEFINED_ONLY_RULE_PATH = + FieldPath.newBuilder() + .addElements( + FieldPathUtils.fieldPathElement( + FieldConstraints.getDescriptor() + .findFieldByNumber(FieldConstraints.ENUM_FIELD_NUMBER))) + .addElements( + FieldPathUtils.fieldPathElement( + EnumRules.getDescriptor().findFieldByNumber(EnumRules.DEFINED_ONLY_FIELD_NUMBER))) + .build(); + /** * Constructs a new evaluator for enum values. * @@ -70,6 +85,7 @@ public ValidationResult evaluate(Value val, boolean failFast) throws ExecutionEx return new ValidationResult( Collections.singletonList( Violation.newBuilder() + .setRule(DEFINED_ONLY_RULE_PATH) .setConstraintId("enum.defined_only") .setMessage("value must be one of the defined enum values") .build())); diff --git a/src/main/java/build/buf/protovalidate/internal/evaluator/ErrorPathUtils.java b/src/main/java/build/buf/protovalidate/internal/evaluator/ErrorPathUtils.java deleted file mode 100644 index 8367ffaf..00000000 --- a/src/main/java/build/buf/protovalidate/internal/evaluator/ErrorPathUtils.java +++ /dev/null @@ -1,56 +0,0 @@ -// 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.internal.evaluator; - -import build.buf.validate.Violation; -import com.google.common.base.Strings; -import com.google.errorprone.annotations.FormatMethod; -import com.google.errorprone.annotations.FormatString; -import java.util.List; -import java.util.stream.Collectors; - -/** Utility class for manipulating error paths in violations. */ -final class ErrorPathUtils { - private ErrorPathUtils() {} - - /** - * Prefixes the error paths of the given violations with a format string and its arguments. - * - * @param violations The list of violations to modify. - * @param format The format string to use as the prefix. - * @param args The arguments to apply to the format string. - * @return The modified list of violations with prefixed error paths. - */ - @FormatMethod - static List prefixErrorPaths( - List violations, @FormatString String format, Object... args) { - String prefix = String.format(format, args); - return violations.stream() - .map( - violation -> { - String fieldPath = violation.getFieldPath(); - String prefixedFieldPath; - if (fieldPath.isEmpty()) { - prefixedFieldPath = prefix; - } else if (fieldPath.charAt(0) == '[') { - prefixedFieldPath = prefix + fieldPath; - } else { - prefixedFieldPath = Strings.lenientFormat("%s.%s", prefix, fieldPath); - } - return violation.toBuilder().setFieldPath(prefixedFieldPath).build(); - }) - .collect(Collectors.toList()); - } -} diff --git a/src/main/java/build/buf/protovalidate/internal/evaluator/EvaluatorBuilder.java b/src/main/java/build/buf/protovalidate/internal/evaluator/EvaluatorBuilder.java index 9cc74185..f2e4a2e4 100644 --- a/src/main/java/build/buf/protovalidate/internal/evaluator/EvaluatorBuilder.java +++ b/src/main/java/build/buf/protovalidate/internal/evaluator/EvaluatorBuilder.java @@ -18,6 +18,7 @@ import build.buf.protovalidate.exceptions.CompilationException; import build.buf.protovalidate.internal.constraints.ConstraintCache; import build.buf.protovalidate.internal.constraints.DescriptorMappings; +import build.buf.protovalidate.internal.errors.FieldPathUtils; import build.buf.protovalidate.internal.expression.AstExpression; import build.buf.protovalidate.internal.expression.CelPrograms; import build.buf.protovalidate.internal.expression.CompiledProgram; @@ -25,6 +26,8 @@ import build.buf.protovalidate.internal.expression.Variable; import build.buf.validate.Constraint; import build.buf.validate.FieldConstraints; +import build.buf.validate.FieldPath; +import build.buf.validate.FieldPathElement; import build.buf.validate.Ignore; import build.buf.validate.MessageConstraints; import build.buf.validate.OneofConstraints; @@ -42,12 +45,18 @@ import java.util.HashMap; import java.util.List; import java.util.Objects; +import javax.annotation.Nullable; import org.projectnessie.cel.Env; import org.projectnessie.cel.EnvOption; import org.projectnessie.cel.checker.Decls; /** A build-through cache of message evaluators keyed off the provided descriptor. */ public class EvaluatorBuilder { + private static final FieldPathElement CEL_FIELD_PATH_ELEMENT = + FieldPathUtils.fieldPathElement( + FieldConstraints.getDescriptor().findFieldByNumber(FieldConstraints.CEL_FIELD_NUMBER)) + .build(); + private volatile ImmutableMap evaluatorCache = ImmutableMap.of(); private final Env env; @@ -184,7 +193,7 @@ private void processMessageExpressions( EnvOption.types(message), EnvOption.declarations( Decls.newVar(Variable.THIS_NAME, Decls.newObjectType(desc.getFullName())))); - List compiledPrograms = compileConstraints(celList, finalEnv); + List compiledPrograms = compileConstraints(celList, finalEnv, false); if (compiledPrograms.isEmpty()) { throw new CompilationException("compile returned null"); } @@ -231,7 +240,7 @@ private FieldEvaluator buildField( fieldDescriptor.hasPresence() || shouldIgnoreEmpty(fieldConstraints), fieldDescriptor.hasPresence() && shouldIgnoreDefault(fieldConstraints), zero); - buildValue(fieldDescriptor, fieldConstraints, false, fieldEvaluator.valueEvaluator); + buildValue(fieldDescriptor, fieldConstraints, null, fieldEvaluator.valueEvaluator); return fieldEvaluator; } @@ -254,27 +263,27 @@ private static boolean shouldIgnoreDefault(FieldConstraints constraints) { private void buildValue( FieldDescriptor fieldDescriptor, FieldConstraints fieldConstraints, - boolean forItems, + @Nullable EvaluatorWrapper itemsWrapper, ValueEvaluator valueEvaluator) throws CompilationException { - processIgnoreEmpty(fieldDescriptor, fieldConstraints, forItems, valueEvaluator); + processIgnoreEmpty(fieldDescriptor, fieldConstraints, itemsWrapper, valueEvaluator); processFieldExpressions(fieldDescriptor, fieldConstraints, valueEvaluator); - processEmbeddedMessage(fieldDescriptor, fieldConstraints, forItems, valueEvaluator); - processWrapperConstraints(fieldDescriptor, fieldConstraints, forItems, valueEvaluator); - processStandardConstraints(fieldDescriptor, fieldConstraints, forItems, valueEvaluator); - processAnyConstraints(fieldDescriptor, fieldConstraints, forItems, valueEvaluator); - processEnumConstraints(fieldDescriptor, fieldConstraints, valueEvaluator); - processMapConstraints(fieldDescriptor, fieldConstraints, valueEvaluator); - processRepeatedConstraints(fieldDescriptor, fieldConstraints, forItems, valueEvaluator); + processEmbeddedMessage(fieldDescriptor, fieldConstraints, itemsWrapper, valueEvaluator); + processWrapperConstraints(fieldDescriptor, fieldConstraints, itemsWrapper, valueEvaluator); + processStandardConstraints(fieldDescriptor, fieldConstraints, itemsWrapper, valueEvaluator); + processAnyConstraints(fieldDescriptor, fieldConstraints, itemsWrapper, valueEvaluator); + processEnumConstraints(fieldDescriptor, fieldConstraints, itemsWrapper, valueEvaluator); + processMapConstraints(fieldDescriptor, fieldConstraints, itemsWrapper, valueEvaluator); + processRepeatedConstraints(fieldDescriptor, fieldConstraints, itemsWrapper, valueEvaluator); } private void processIgnoreEmpty( FieldDescriptor fieldDescriptor, FieldConstraints fieldConstraints, - boolean forItems, + @Nullable EvaluatorWrapper itemsWrapper, ValueEvaluator valueEvaluatorEval) throws CompilationException { - if (forItems && shouldIgnoreEmpty(fieldConstraints)) { + if (itemsWrapper != null && shouldIgnoreEmpty(fieldConstraints)) { valueEvaluatorEval.setIgnoreEmpty(zeroValue(fieldDescriptor, true)); } } @@ -365,7 +374,8 @@ private void processFieldExpressions( DescriptorMappings.protoKindToCELType(fieldDescriptor.getType())))); } Env finalEnv = env.extend(opts.toArray(new EnvOption[0])); - List compiledPrograms = compileConstraints(constraintsCelList, finalEnv); + List compiledPrograms = + compileConstraints(constraintsCelList, finalEnv, true); if (!compiledPrograms.isEmpty()) { valueEvaluatorEval.append(new CelPrograms(compiledPrograms)); } @@ -374,13 +384,13 @@ private void processFieldExpressions( private void processEmbeddedMessage( FieldDescriptor fieldDescriptor, FieldConstraints fieldConstraints, - boolean forItems, + @Nullable EvaluatorWrapper itemsWrapper, ValueEvaluator valueEvaluatorEval) throws CompilationException { if (fieldDescriptor.getJavaType() != FieldDescriptor.JavaType.MESSAGE || shouldSkip(fieldConstraints) || fieldDescriptor.isMapField() - || (fieldDescriptor.isRepeated() && !forItems)) { + || (fieldDescriptor.isRepeated() && itemsWrapper == null)) { return; } Evaluator embedEval = createMessageEvaluator(fieldDescriptor.getMessageType()); @@ -390,13 +400,13 @@ private void processEmbeddedMessage( private void processWrapperConstraints( FieldDescriptor fieldDescriptor, FieldConstraints fieldConstraints, - boolean forItems, + @Nullable EvaluatorWrapper itemsWrapper, ValueEvaluator valueEvaluatorEval) throws CompilationException { if (fieldDescriptor.getJavaType() != FieldDescriptor.JavaType.MESSAGE || shouldSkip(fieldConstraints) || fieldDescriptor.isMapField() - || (fieldDescriptor.isRepeated() && !forItems)) { + || (fieldDescriptor.isRepeated() && itemsWrapper == null)) { return; } FieldDescriptor expectedWrapperDescriptor = @@ -410,7 +420,7 @@ private void processWrapperConstraints( buildValue( fieldDescriptor.getMessageType().findFieldByName("value"), fieldConstraints, - true, + itemsWrapper, unwrapped); valueEvaluatorEval.append(unwrapped); } @@ -418,23 +428,23 @@ private void processWrapperConstraints( private void processStandardConstraints( FieldDescriptor fieldDescriptor, FieldConstraints fieldConstraints, - boolean forItems, + @Nullable EvaluatorWrapper itemsWrapper, ValueEvaluator valueEvaluatorEval) throws CompilationException { List compile = - constraintCache.compile(fieldDescriptor, fieldConstraints, forItems); + constraintCache.compile(fieldDescriptor, fieldConstraints, itemsWrapper != null); if (compile.isEmpty()) { return; } - valueEvaluatorEval.append(new CelPrograms(compile)); + appendEvaluator(valueEvaluatorEval, new CelPrograms(compile), itemsWrapper); } private void processAnyConstraints( FieldDescriptor fieldDescriptor, FieldConstraints fieldConstraints, - boolean forItems, + @Nullable EvaluatorWrapper itemsWrapper, ValueEvaluator valueEvaluatorEval) { - if ((fieldDescriptor.isRepeated() && !forItems) + if ((fieldDescriptor.isRepeated() && itemsWrapper == null) || fieldDescriptor.getJavaType() != FieldDescriptor.JavaType.MESSAGE || !fieldDescriptor.getMessageType().getFullName().equals("google.protobuf.Any")) { return; @@ -445,72 +455,91 @@ private void processAnyConstraints( typeURLDesc, fieldConstraints.getAny().getInList(), fieldConstraints.getAny().getNotInList()); - valueEvaluatorEval.append(anyEvaluatorEval); + appendEvaluator(valueEvaluatorEval, anyEvaluatorEval, itemsWrapper); } private void processEnumConstraints( FieldDescriptor fieldDescriptor, FieldConstraints fieldConstraints, + @Nullable EvaluatorWrapper itemsWrapper, ValueEvaluator valueEvaluatorEval) { if (fieldDescriptor.getJavaType() != FieldDescriptor.JavaType.ENUM) { return; } if (fieldConstraints.getEnum().getDefinedOnly()) { Descriptors.EnumDescriptor enumDescriptor = fieldDescriptor.getEnumType(); - valueEvaluatorEval.append(new EnumEvaluator(enumDescriptor.getValues())); + appendEvaluator( + valueEvaluatorEval, new EnumEvaluator(enumDescriptor.getValues()), itemsWrapper); } } private void processMapConstraints( FieldDescriptor fieldDescriptor, FieldConstraints fieldConstraints, + @Nullable EvaluatorWrapper itemsWrapper, ValueEvaluator valueEvaluatorEval) throws CompilationException { if (!fieldDescriptor.isMapField()) { return; } - MapEvaluator mapEval = new MapEvaluator(fieldConstraints, fieldDescriptor); + MapEvaluator mapEval = new MapEvaluator(fieldDescriptor); buildValue( fieldDescriptor.getMessageType().findFieldByNumber(1), fieldConstraints.getMap().getKeys(), - true, + MapEvaluator.KEYS_WRAPPER, mapEval.getKeyEvaluator()); buildValue( fieldDescriptor.getMessageType().findFieldByNumber(2), fieldConstraints.getMap().getValues(), - true, + MapEvaluator.VALUES_WRAPPER, mapEval.getValueEvaluator()); - valueEvaluatorEval.append(mapEval); + appendEvaluator(valueEvaluatorEval, mapEval, itemsWrapper); } private void processRepeatedConstraints( FieldDescriptor fieldDescriptor, FieldConstraints fieldConstraints, - boolean forItems, + @Nullable EvaluatorWrapper itemsWrapper, ValueEvaluator valueEvaluatorEval) throws CompilationException { - if (fieldDescriptor.isMapField() || !fieldDescriptor.isRepeated() || forItems) { + if (fieldDescriptor.isMapField() || !fieldDescriptor.isRepeated() || itemsWrapper != null) { return; } - ListEvaluator listEval = new ListEvaluator(); + ListEvaluator listEval = new ListEvaluator(fieldDescriptor); buildValue( fieldDescriptor, fieldConstraints.getRepeated().getItems(), - true, + ListEvaluator.ITEMS_WRAPPER, listEval.itemConstraints); - valueEvaluatorEval.append(listEval); + appendEvaluator(valueEvaluatorEval, listEval, itemsWrapper); } - private static List compileConstraints(List constraints, Env env) - throws CompilationException { + private static List compileConstraints( + List constraints, Env env, boolean isField) throws CompilationException { List expressions = Expression.fromConstraints(constraints); List compiledPrograms = new ArrayList<>(); - for (Expression expression : expressions) { + for (int i = 0; i < expressions.size(); i++) { + Expression expression = expressions.get(i); AstExpression astExpression = AstExpression.newAstExpression(env, expression); + @Nullable FieldPath rulePath = null; + if (isField) { + rulePath = + FieldPath.newBuilder() + .addElements(CEL_FIELD_PATH_ELEMENT.toBuilder().setIndex(i)) + .build(); + } compiledPrograms.add( - new CompiledProgram(env.program(astExpression.ast), astExpression.source)); + new CompiledProgram(env.program(astExpression.ast), astExpression.source, rulePath)); } return compiledPrograms; } } + + private static void appendEvaluator( + ValueEvaluator valueEvaluatorEval, Evaluator embedEval, @Nullable EvaluatorWrapper wrapper) { + if (wrapper != null) { + embedEval = wrapper.wrap(embedEval); + } + valueEvaluatorEval.append(embedEval); + } } diff --git a/src/main/java/build/buf/protovalidate/internal/evaluator/EvaluatorWrapper.java b/src/main/java/build/buf/protovalidate/internal/evaluator/EvaluatorWrapper.java new file mode 100644 index 00000000..03c3cd5f --- /dev/null +++ b/src/main/java/build/buf/protovalidate/internal/evaluator/EvaluatorWrapper.java @@ -0,0 +1,26 @@ +// 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.internal.evaluator; + +/** Wrappers are used to special-case certain aspects of handling nested rules. */ +interface EvaluatorWrapper { + /** + * Returns a wrapped evaluator for a given kind of nested rule. + * + * @param evaluator Evaluator to wrap inside a nested evaluator wrapper. + * @return A wrapped Evaluator that proxies the provided evaluator. + */ + Evaluator wrap(Evaluator evaluator); +} diff --git a/src/main/java/build/buf/protovalidate/internal/evaluator/FieldEvaluator.java b/src/main/java/build/buf/protovalidate/internal/evaluator/FieldEvaluator.java index e4043680..0120197a 100644 --- a/src/main/java/build/buf/protovalidate/internal/evaluator/FieldEvaluator.java +++ b/src/main/java/build/buf/protovalidate/internal/evaluator/FieldEvaluator.java @@ -16,6 +16,9 @@ import build.buf.protovalidate.ValidationResult; import build.buf.protovalidate.exceptions.ExecutionException; +import build.buf.protovalidate.internal.errors.FieldPathUtils; +import build.buf.validate.FieldConstraints; +import build.buf.validate.FieldPath; import build.buf.validate.Violation; import com.google.protobuf.Descriptors.FieldDescriptor; import com.google.protobuf.Message; @@ -26,6 +29,14 @@ /** Performs validation on a single message field, defined by its descriptor. */ class FieldEvaluator implements Evaluator { + private static final FieldPath requiredFieldRulePath = + FieldPath.newBuilder() + .addElements( + FieldPathUtils.fieldPathElement( + FieldConstraints.getDescriptor() + .findFieldByNumber(FieldConstraints.REQUIRED_FIELD_NUMBER))) + .build(); + /** The {@link ValueEvaluator} to apply to the field's value */ public final ValueEvaluator valueEvaluator; @@ -82,7 +93,11 @@ public ValidationResult evaluate(Value val, boolean failFast) throws ExecutionEx return new ValidationResult( Collections.singletonList( Violation.newBuilder() - .setFieldPath(descriptor.getName()) + .setField( + FieldPath.newBuilder() + .addElements(FieldPathUtils.fieldPathElement(descriptor)) + .build()) + .setRule(requiredFieldRulePath) .setConstraintId("required") .setMessage("value is required") .build())); @@ -97,7 +112,10 @@ public ValidationResult evaluate(Value val, boolean failFast) throws ExecutionEx ValidationResult evalResult = valueEvaluator.evaluate(new ObjectValue(descriptor, fieldValue), failFast); List violations = - ErrorPathUtils.prefixErrorPaths(evalResult.getViolations(), "%s", descriptor.getName()); + FieldPathUtils.prependFieldPaths( + evalResult.getViolations(), + FieldPathUtils.fieldPathElement(descriptor).build(), + descriptor.isRepeated()); return new ValidationResult(violations); } } diff --git a/src/main/java/build/buf/protovalidate/internal/evaluator/ListEvaluator.java b/src/main/java/build/buf/protovalidate/internal/evaluator/ListEvaluator.java index b55c671f..65a5d384 100644 --- a/src/main/java/build/buf/protovalidate/internal/evaluator/ListEvaluator.java +++ b/src/main/java/build/buf/protovalidate/internal/evaluator/ListEvaluator.java @@ -16,19 +16,75 @@ import build.buf.protovalidate.ValidationResult; import build.buf.protovalidate.exceptions.ExecutionException; +import build.buf.protovalidate.internal.errors.FieldPathUtils; +import build.buf.validate.FieldConstraints; +import build.buf.validate.FieldPath; +import build.buf.validate.FieldPathElement; +import build.buf.validate.RepeatedRules; import build.buf.validate.Violation; +import com.google.protobuf.Descriptors; import java.util.ArrayList; import java.util.List; /** Performs validation on the elements of a repeated field. */ class ListEvaluator implements Evaluator { + /** Rule path to repeated items rules */ + private static final List REPEATED_ITEMS_RULE_PATH = + FieldPath.newBuilder() + .addElements( + FieldPathUtils.fieldPathElement( + FieldConstraints.getDescriptor() + .findFieldByNumber(FieldConstraints.REPEATED_FIELD_NUMBER))) + .addElements( + FieldPathUtils.fieldPathElement( + RepeatedRules.getDescriptor() + .findFieldByNumber(RepeatedRules.ITEMS_FIELD_NUMBER))) + .build() + .getElementsList(); + + public static final EvaluatorWrapper ITEMS_WRAPPER = new ItemsWrapper(); + + private static class ItemsEvaluator implements Evaluator { + /** Evaluator to wrap */ + private final Evaluator evaluator; + + public ItemsEvaluator(Evaluator evaluator) { + this.evaluator = evaluator; + } + + @Override + public boolean tautology() { + return this.evaluator.tautology(); + } + + @Override + public ValidationResult evaluate(Value val, boolean failFast) throws ExecutionException { + ValidationResult result = evaluator.evaluate(val, failFast); + if (result.isSuccess()) { + return result; + } + return new ValidationResult( + FieldPathUtils.prependRulePaths(result.getViolations(), REPEATED_ITEMS_RULE_PATH)); + } + } + + private static class ItemsWrapper implements EvaluatorWrapper { + @Override + public Evaluator wrap(Evaluator evaluator) { + return new ItemsEvaluator(evaluator); + } + } /** Constraints are checked on every item of the list. */ final ValueEvaluator itemConstraints; + /** Field descriptor of the list field. */ + final Descriptors.FieldDescriptor fieldDescriptor; + /** Constructs a {@link ListEvaluator}. */ - ListEvaluator() { + ListEvaluator(Descriptors.FieldDescriptor fieldDescriptor) { this.itemConstraints = new ValueEvaluator(); + this.fieldDescriptor = fieldDescriptor; } @Override @@ -46,7 +102,10 @@ public ValidationResult evaluate(Value val, boolean failFast) throws ExecutionEx continue; } List violations = - ErrorPathUtils.prefixErrorPaths(evalResult.getViolations(), "[%d]", i); + FieldPathUtils.prependFieldPaths( + evalResult.getViolations(), + FieldPathUtils.fieldPathElement(fieldDescriptor).setIndex(i).build(), + false); if (failFast && !violations.isEmpty()) { return evalResult; } diff --git a/src/main/java/build/buf/protovalidate/internal/evaluator/MapEvaluator.java b/src/main/java/build/buf/protovalidate/internal/evaluator/MapEvaluator.java index 3110d390..79f0ffe8 100644 --- a/src/main/java/build/buf/protovalidate/internal/evaluator/MapEvaluator.java +++ b/src/main/java/build/buf/protovalidate/internal/evaluator/MapEvaluator.java @@ -16,7 +16,11 @@ import build.buf.protovalidate.ValidationResult; import build.buf.protovalidate.exceptions.ExecutionException; +import build.buf.protovalidate.internal.errors.FieldPathUtils; import build.buf.validate.FieldConstraints; +import build.buf.validate.FieldPath; +import build.buf.validate.FieldPathElement; +import build.buf.validate.MapRules; import build.buf.validate.Violation; import com.google.protobuf.Descriptors; import java.util.ArrayList; @@ -27,21 +31,124 @@ /** Performs validation on a map field's key-value pairs. */ class MapEvaluator implements Evaluator { + /** Rule path to map key rules */ + private static final List MAP_KEYS_RULE_PATH = + FieldPath.newBuilder() + .addElements( + FieldPathUtils.fieldPathElement( + FieldConstraints.getDescriptor() + .findFieldByNumber(FieldConstraints.MAP_FIELD_NUMBER))) + .addElements( + FieldPathUtils.fieldPathElement( + MapRules.getDescriptor().findFieldByNumber(MapRules.KEYS_FIELD_NUMBER))) + .build() + .getElementsList(); + + /** Rule path to map value rules */ + private static final List MAP_VALUES_RULE_PATH = + FieldPath.newBuilder() + .addElements( + FieldPathUtils.fieldPathElement( + FieldConstraints.getDescriptor() + .findFieldByNumber(FieldConstraints.MAP_FIELD_NUMBER))) + .addElements( + FieldPathUtils.fieldPathElement( + MapRules.getDescriptor().findFieldByNumber(MapRules.VALUES_FIELD_NUMBER))) + .build() + .getElementsList(); + + public static final EvaluatorWrapper KEYS_WRAPPER = new KeysWrapper(); + + public static final EvaluatorWrapper VALUES_WRAPPER = new ValuesWrapper(); + + private static class KeysEvaluator implements Evaluator { + /** Evaluator to wrap */ + private final Evaluator evaluator; + + public KeysEvaluator(Evaluator evaluator) { + this.evaluator = evaluator; + } + + @Override + public boolean tautology() { + return this.evaluator.tautology(); + } + + @Override + public ValidationResult evaluate(Value val, boolean failFast) throws ExecutionException { + ValidationResult result = evaluator.evaluate(val, failFast); + if (result.isSuccess()) { + return result; + } + return new ValidationResult( + FieldPathUtils.prependRulePaths(result.getViolations(), MAP_KEYS_RULE_PATH)); + } + } + + private static class KeysWrapper implements EvaluatorWrapper { + @Override + public Evaluator wrap(Evaluator evaluator) { + return new KeysEvaluator(evaluator); + } + } + + private static class ValuesEvaluator implements Evaluator { + /** Evaluator to wrap */ + private final Evaluator evaluator; + + public ValuesEvaluator(Evaluator evaluator) { + this.evaluator = evaluator; + } + + @Override + public boolean tautology() { + return this.evaluator.tautology(); + } + + @Override + public ValidationResult evaluate(Value val, boolean failFast) throws ExecutionException { + ValidationResult result = evaluator.evaluate(val, failFast); + if (result.isSuccess()) { + return result; + } + return new ValidationResult( + FieldPathUtils.prependRulePaths(result.getViolations(), MAP_VALUES_RULE_PATH)); + } + } + + private static class ValuesWrapper implements EvaluatorWrapper { + @Override + public Evaluator wrap(Evaluator evaluator) { + return new ValuesEvaluator(evaluator); + } + } + /** Constraint for checking the map keys */ private final ValueEvaluator keyEvaluator; /** Constraint for checking the map values */ private final ValueEvaluator valueEvaluator; + /** Field descriptor of the map field */ + final Descriptors.FieldDescriptor fieldDescriptor; + + /** Field descriptor of the map key field */ + final Descriptors.FieldDescriptor keyFieldDescriptor; + + /** Field descriptor of the map value field */ + final Descriptors.FieldDescriptor valueFieldDescriptor; + /** * Constructs a {@link MapEvaluator}. * - * @param fieldConstraints The field constraints to apply to the map. * @param fieldDescriptor The descriptor of the map field being evaluated. */ - MapEvaluator(FieldConstraints fieldConstraints, Descriptors.FieldDescriptor fieldDescriptor) { + MapEvaluator(Descriptors.FieldDescriptor fieldDescriptor) { this.keyEvaluator = new ValueEvaluator(); this.valueEvaluator = new ValueEvaluator(); + this.fieldDescriptor = fieldDescriptor; + this.keyFieldDescriptor = fieldDescriptor.getMessageType().findFieldByNumber(1); + this.valueFieldDescriptor = fieldDescriptor.getMessageType().findFieldByNumber(2); } /** @@ -104,16 +211,33 @@ private List evalPairs(Value key, Value value, boolean failFast) violations.addAll(keyViolations); violations.addAll(valueViolations); - Object keyName = key.value(Object.class); - if (keyName == null) { - return Collections.emptyList(); - } - List prefixedViolations; - if (keyName instanceof Number) { - prefixedViolations = ErrorPathUtils.prefixErrorPaths(violations, "[%s]", keyName); - } else { - prefixedViolations = ErrorPathUtils.prefixErrorPaths(violations, "[\"%s\"]", keyName); + FieldPathElement.Builder fieldPathElement = FieldPathUtils.fieldPathElement(fieldDescriptor); + fieldPathElement.setKeyType(keyFieldDescriptor.getType().toProto()); + fieldPathElement.setValueType(valueFieldDescriptor.getType().toProto()); + switch (keyFieldDescriptor.getType().toProto()) { + case TYPE_INT64: + case TYPE_INT32: + case TYPE_SINT32: + case TYPE_SINT64: + case TYPE_SFIXED32: + case TYPE_SFIXED64: + fieldPathElement.setIntKey(key.value(Number.class).longValue()); + break; + case TYPE_UINT32: + case TYPE_UINT64: + case TYPE_FIXED32: + case TYPE_FIXED64: + fieldPathElement.setUintKey(key.value(Number.class).longValue()); + break; + case TYPE_BOOL: + fieldPathElement.setBoolKey(key.value(Boolean.class)); + break; + case TYPE_STRING: + fieldPathElement.setStringKey(key.value(String.class)); + break; + default: + throw new ExecutionException("Unexpected map key type"); } - return prefixedViolations; + return FieldPathUtils.prependFieldPaths(violations, fieldPathElement.build(), false); } } diff --git a/src/main/java/build/buf/protovalidate/internal/evaluator/OneofEvaluator.java b/src/main/java/build/buf/protovalidate/internal/evaluator/OneofEvaluator.java index d5a4fa21..19beb5c8 100644 --- a/src/main/java/build/buf/protovalidate/internal/evaluator/OneofEvaluator.java +++ b/src/main/java/build/buf/protovalidate/internal/evaluator/OneofEvaluator.java @@ -16,6 +16,8 @@ import build.buf.protovalidate.ValidationResult; import build.buf.protovalidate.exceptions.ExecutionException; +import build.buf.validate.FieldPath; +import build.buf.validate.FieldPathElement; import build.buf.validate.Violation; import com.google.protobuf.Descriptors.OneofDescriptor; import com.google.protobuf.Message; @@ -55,7 +57,10 @@ public ValidationResult evaluate(Value val, boolean failFast) throws ExecutionEx return new ValidationResult( Collections.singletonList( Violation.newBuilder() - .setFieldPath(descriptor.getName()) + .setField( + FieldPath.newBuilder() + .addElements( + FieldPathElement.newBuilder().setFieldName(descriptor.getName()))) .setConstraintId("required") .setMessage("exactly one field is required in oneof") .build())); diff --git a/src/main/java/build/buf/protovalidate/internal/expression/CompiledProgram.java b/src/main/java/build/buf/protovalidate/internal/expression/CompiledProgram.java index 17154f16..d3576534 100644 --- a/src/main/java/build/buf/protovalidate/internal/expression/CompiledProgram.java +++ b/src/main/java/build/buf/protovalidate/internal/expression/CompiledProgram.java @@ -15,6 +15,7 @@ package build.buf.protovalidate.internal.expression; import build.buf.protovalidate.exceptions.ExecutionException; +import build.buf.validate.FieldPath; import build.buf.validate.Violation; import javax.annotation.Nullable; import org.projectnessie.cel.Program; @@ -32,15 +33,20 @@ public class CompiledProgram { /** The original expression that was compiled into the program from the proto file. */ private final Expression source; + /** The field path from FieldConstraints to the constraint rule value. */ + @Nullable private final FieldPath rulePath; + /** * Constructs a new {@link CompiledProgram}. * * @param program The compiled CEL program. * @param source The original expression that was compiled into the program. + * @param rulePath The field path from the FieldConstraints to the rule value. */ - public CompiledProgram(Program program, Expression source) { + public CompiledProgram(Program program, Expression source, @Nullable FieldPath rulePath) { this.program = program; this.source = source; + this.rulePath = rulePath; } /** @@ -63,18 +69,22 @@ public Violation eval(Variable bindings) throws ExecutionException { if ("".equals(value)) { return null; } - return Violation.newBuilder() - .setConstraintId(this.source.id) - .setMessage(value.toString()) - .build(); + Violation.Builder violation = + Violation.newBuilder().setConstraintId(this.source.id).setMessage(value.toString()); + if (rulePath != null) { + violation.setRule(rulePath); + } + return violation.build(); } else if (value instanceof Boolean) { if (val.booleanValue()) { return null; } - return Violation.newBuilder() - .setConstraintId(this.source.id) - .setMessage(this.source.message) - .build(); + Violation.Builder violation = + Violation.newBuilder().setConstraintId(this.source.id).setMessage(this.source.message); + if (rulePath != null) { + violation.setRule(rulePath); + } + return violation.build(); } else { throw new ExecutionException(String.format("resolved to an unexpected type %s", val)); } diff --git a/src/main/java/build/buf/validate/FieldPath.java b/src/main/java/build/buf/validate/FieldPath.java new file mode 100644 index 00000000..ec6fc118 --- /dev/null +++ b/src/main/java/build/buf/validate/FieldPath.java @@ -0,0 +1,825 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: buf/validate/validate.proto +// Protobuf Java Version: 4.28.3 + +package build.buf.validate; + +/** + *
+ * `FieldPath` provides a path to a nested protobuf field.
+ *
+ * This message provides enough information to render a dotted field path even without protobuf descriptors.
+ * It also provides enough information to resolve a nested field through unknown wire data.
+ * 
+ * + * Protobuf type {@code buf.validate.FieldPath} + */ +public final class FieldPath extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:buf.validate.FieldPath) + FieldPathOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 28, + /* patch= */ 3, + /* suffix= */ "", + FieldPath.class.getName()); + } + // Use FieldPath.newBuilder() to construct. + private FieldPath(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private FieldPath() { + elements_ = java.util.Collections.emptyList(); + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return build.buf.validate.ValidateProto.internal_static_buf_validate_FieldPath_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return build.buf.validate.ValidateProto.internal_static_buf_validate_FieldPath_fieldAccessorTable + .ensureFieldAccessorsInitialized( + build.buf.validate.FieldPath.class, build.buf.validate.FieldPath.Builder.class); + } + + public static final int ELEMENTS_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private java.util.List elements_; + /** + *
+   * `elements` contains each element of the path, starting from the root and recursing downward.
+   * 
+ * + * repeated .buf.validate.FieldPathElement elements = 1 [json_name = "elements"]; + */ + @java.lang.Override + public java.util.List getElementsList() { + return elements_; + } + /** + *
+   * `elements` contains each element of the path, starting from the root and recursing downward.
+   * 
+ * + * repeated .buf.validate.FieldPathElement elements = 1 [json_name = "elements"]; + */ + @java.lang.Override + public java.util.List + getElementsOrBuilderList() { + return elements_; + } + /** + *
+   * `elements` contains each element of the path, starting from the root and recursing downward.
+   * 
+ * + * repeated .buf.validate.FieldPathElement elements = 1 [json_name = "elements"]; + */ + @java.lang.Override + public int getElementsCount() { + return elements_.size(); + } + /** + *
+   * `elements` contains each element of the path, starting from the root and recursing downward.
+   * 
+ * + * repeated .buf.validate.FieldPathElement elements = 1 [json_name = "elements"]; + */ + @java.lang.Override + public build.buf.validate.FieldPathElement getElements(int index) { + return elements_.get(index); + } + /** + *
+   * `elements` contains each element of the path, starting from the root and recursing downward.
+   * 
+ * + * repeated .buf.validate.FieldPathElement elements = 1 [json_name = "elements"]; + */ + @java.lang.Override + public build.buf.validate.FieldPathElementOrBuilder getElementsOrBuilder( + int index) { + return elements_.get(index); + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + for (int i = 0; i < elements_.size(); i++) { + output.writeMessage(1, elements_.get(i)); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + for (int i = 0; i < elements_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(1, elements_.get(i)); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof build.buf.validate.FieldPath)) { + return super.equals(obj); + } + build.buf.validate.FieldPath other = (build.buf.validate.FieldPath) obj; + + if (!getElementsList() + .equals(other.getElementsList())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + if (getElementsCount() > 0) { + hash = (37 * hash) + ELEMENTS_FIELD_NUMBER; + hash = (53 * hash) + getElementsList().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static build.buf.validate.FieldPath parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static build.buf.validate.FieldPath parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static build.buf.validate.FieldPath parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static build.buf.validate.FieldPath parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static build.buf.validate.FieldPath parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static build.buf.validate.FieldPath parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static build.buf.validate.FieldPath parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static build.buf.validate.FieldPath parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static build.buf.validate.FieldPath parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static build.buf.validate.FieldPath parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static build.buf.validate.FieldPath parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static build.buf.validate.FieldPath parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(build.buf.validate.FieldPath prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * `FieldPath` provides a path to a nested protobuf field.
+   *
+   * This message provides enough information to render a dotted field path even without protobuf descriptors.
+   * It also provides enough information to resolve a nested field through unknown wire data.
+   * 
+ * + * Protobuf type {@code buf.validate.FieldPath} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:buf.validate.FieldPath) + build.buf.validate.FieldPathOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return build.buf.validate.ValidateProto.internal_static_buf_validate_FieldPath_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return build.buf.validate.ValidateProto.internal_static_buf_validate_FieldPath_fieldAccessorTable + .ensureFieldAccessorsInitialized( + build.buf.validate.FieldPath.class, build.buf.validate.FieldPath.Builder.class); + } + + // Construct using build.buf.validate.FieldPath.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + if (elementsBuilder_ == null) { + elements_ = java.util.Collections.emptyList(); + } else { + elements_ = null; + elementsBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000001); + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return build.buf.validate.ValidateProto.internal_static_buf_validate_FieldPath_descriptor; + } + + @java.lang.Override + public build.buf.validate.FieldPath getDefaultInstanceForType() { + return build.buf.validate.FieldPath.getDefaultInstance(); + } + + @java.lang.Override + public build.buf.validate.FieldPath build() { + build.buf.validate.FieldPath result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public build.buf.validate.FieldPath buildPartial() { + build.buf.validate.FieldPath result = new build.buf.validate.FieldPath(this); + buildPartialRepeatedFields(result); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartialRepeatedFields(build.buf.validate.FieldPath result) { + if (elementsBuilder_ == null) { + if (((bitField0_ & 0x00000001) != 0)) { + elements_ = java.util.Collections.unmodifiableList(elements_); + bitField0_ = (bitField0_ & ~0x00000001); + } + result.elements_ = elements_; + } else { + result.elements_ = elementsBuilder_.build(); + } + } + + private void buildPartial0(build.buf.validate.FieldPath result) { + int from_bitField0_ = bitField0_; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof build.buf.validate.FieldPath) { + return mergeFrom((build.buf.validate.FieldPath)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(build.buf.validate.FieldPath other) { + if (other == build.buf.validate.FieldPath.getDefaultInstance()) return this; + if (elementsBuilder_ == null) { + if (!other.elements_.isEmpty()) { + if (elements_.isEmpty()) { + elements_ = other.elements_; + bitField0_ = (bitField0_ & ~0x00000001); + } else { + ensureElementsIsMutable(); + elements_.addAll(other.elements_); + } + onChanged(); + } + } else { + if (!other.elements_.isEmpty()) { + if (elementsBuilder_.isEmpty()) { + elementsBuilder_.dispose(); + elementsBuilder_ = null; + elements_ = other.elements_; + bitField0_ = (bitField0_ & ~0x00000001); + elementsBuilder_ = + com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? + getElementsFieldBuilder() : null; + } else { + elementsBuilder_.addAllMessages(other.elements_); + } + } + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + build.buf.validate.FieldPathElement m = + input.readMessage( + build.buf.validate.FieldPathElement.parser(), + extensionRegistry); + if (elementsBuilder_ == null) { + ensureElementsIsMutable(); + elements_.add(m); + } else { + elementsBuilder_.addMessage(m); + } + break; + } // case 10 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.util.List elements_ = + java.util.Collections.emptyList(); + private void ensureElementsIsMutable() { + if (!((bitField0_ & 0x00000001) != 0)) { + elements_ = new java.util.ArrayList(elements_); + bitField0_ |= 0x00000001; + } + } + + private com.google.protobuf.RepeatedFieldBuilder< + build.buf.validate.FieldPathElement, build.buf.validate.FieldPathElement.Builder, build.buf.validate.FieldPathElementOrBuilder> elementsBuilder_; + + /** + *
+     * `elements` contains each element of the path, starting from the root and recursing downward.
+     * 
+ * + * repeated .buf.validate.FieldPathElement elements = 1 [json_name = "elements"]; + */ + public java.util.List getElementsList() { + if (elementsBuilder_ == null) { + return java.util.Collections.unmodifiableList(elements_); + } else { + return elementsBuilder_.getMessageList(); + } + } + /** + *
+     * `elements` contains each element of the path, starting from the root and recursing downward.
+     * 
+ * + * repeated .buf.validate.FieldPathElement elements = 1 [json_name = "elements"]; + */ + public int getElementsCount() { + if (elementsBuilder_ == null) { + return elements_.size(); + } else { + return elementsBuilder_.getCount(); + } + } + /** + *
+     * `elements` contains each element of the path, starting from the root and recursing downward.
+     * 
+ * + * repeated .buf.validate.FieldPathElement elements = 1 [json_name = "elements"]; + */ + public build.buf.validate.FieldPathElement getElements(int index) { + if (elementsBuilder_ == null) { + return elements_.get(index); + } else { + return elementsBuilder_.getMessage(index); + } + } + /** + *
+     * `elements` contains each element of the path, starting from the root and recursing downward.
+     * 
+ * + * repeated .buf.validate.FieldPathElement elements = 1 [json_name = "elements"]; + */ + public Builder setElements( + int index, build.buf.validate.FieldPathElement value) { + if (elementsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureElementsIsMutable(); + elements_.set(index, value); + onChanged(); + } else { + elementsBuilder_.setMessage(index, value); + } + return this; + } + /** + *
+     * `elements` contains each element of the path, starting from the root and recursing downward.
+     * 
+ * + * repeated .buf.validate.FieldPathElement elements = 1 [json_name = "elements"]; + */ + public Builder setElements( + int index, build.buf.validate.FieldPathElement.Builder builderForValue) { + if (elementsBuilder_ == null) { + ensureElementsIsMutable(); + elements_.set(index, builderForValue.build()); + onChanged(); + } else { + elementsBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * `elements` contains each element of the path, starting from the root and recursing downward.
+     * 
+ * + * repeated .buf.validate.FieldPathElement elements = 1 [json_name = "elements"]; + */ + public Builder addElements(build.buf.validate.FieldPathElement value) { + if (elementsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureElementsIsMutable(); + elements_.add(value); + onChanged(); + } else { + elementsBuilder_.addMessage(value); + } + return this; + } + /** + *
+     * `elements` contains each element of the path, starting from the root and recursing downward.
+     * 
+ * + * repeated .buf.validate.FieldPathElement elements = 1 [json_name = "elements"]; + */ + public Builder addElements( + int index, build.buf.validate.FieldPathElement value) { + if (elementsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureElementsIsMutable(); + elements_.add(index, value); + onChanged(); + } else { + elementsBuilder_.addMessage(index, value); + } + return this; + } + /** + *
+     * `elements` contains each element of the path, starting from the root and recursing downward.
+     * 
+ * + * repeated .buf.validate.FieldPathElement elements = 1 [json_name = "elements"]; + */ + public Builder addElements( + build.buf.validate.FieldPathElement.Builder builderForValue) { + if (elementsBuilder_ == null) { + ensureElementsIsMutable(); + elements_.add(builderForValue.build()); + onChanged(); + } else { + elementsBuilder_.addMessage(builderForValue.build()); + } + return this; + } + /** + *
+     * `elements` contains each element of the path, starting from the root and recursing downward.
+     * 
+ * + * repeated .buf.validate.FieldPathElement elements = 1 [json_name = "elements"]; + */ + public Builder addElements( + int index, build.buf.validate.FieldPathElement.Builder builderForValue) { + if (elementsBuilder_ == null) { + ensureElementsIsMutable(); + elements_.add(index, builderForValue.build()); + onChanged(); + } else { + elementsBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + /** + *
+     * `elements` contains each element of the path, starting from the root and recursing downward.
+     * 
+ * + * repeated .buf.validate.FieldPathElement elements = 1 [json_name = "elements"]; + */ + public Builder addAllElements( + java.lang.Iterable values) { + if (elementsBuilder_ == null) { + ensureElementsIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, elements_); + onChanged(); + } else { + elementsBuilder_.addAllMessages(values); + } + return this; + } + /** + *
+     * `elements` contains each element of the path, starting from the root and recursing downward.
+     * 
+ * + * repeated .buf.validate.FieldPathElement elements = 1 [json_name = "elements"]; + */ + public Builder clearElements() { + if (elementsBuilder_ == null) { + elements_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + } else { + elementsBuilder_.clear(); + } + return this; + } + /** + *
+     * `elements` contains each element of the path, starting from the root and recursing downward.
+     * 
+ * + * repeated .buf.validate.FieldPathElement elements = 1 [json_name = "elements"]; + */ + public Builder removeElements(int index) { + if (elementsBuilder_ == null) { + ensureElementsIsMutable(); + elements_.remove(index); + onChanged(); + } else { + elementsBuilder_.remove(index); + } + return this; + } + /** + *
+     * `elements` contains each element of the path, starting from the root and recursing downward.
+     * 
+ * + * repeated .buf.validate.FieldPathElement elements = 1 [json_name = "elements"]; + */ + public build.buf.validate.FieldPathElement.Builder getElementsBuilder( + int index) { + return getElementsFieldBuilder().getBuilder(index); + } + /** + *
+     * `elements` contains each element of the path, starting from the root and recursing downward.
+     * 
+ * + * repeated .buf.validate.FieldPathElement elements = 1 [json_name = "elements"]; + */ + public build.buf.validate.FieldPathElementOrBuilder getElementsOrBuilder( + int index) { + if (elementsBuilder_ == null) { + return elements_.get(index); } else { + return elementsBuilder_.getMessageOrBuilder(index); + } + } + /** + *
+     * `elements` contains each element of the path, starting from the root and recursing downward.
+     * 
+ * + * repeated .buf.validate.FieldPathElement elements = 1 [json_name = "elements"]; + */ + public java.util.List + getElementsOrBuilderList() { + if (elementsBuilder_ != null) { + return elementsBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(elements_); + } + } + /** + *
+     * `elements` contains each element of the path, starting from the root and recursing downward.
+     * 
+ * + * repeated .buf.validate.FieldPathElement elements = 1 [json_name = "elements"]; + */ + public build.buf.validate.FieldPathElement.Builder addElementsBuilder() { + return getElementsFieldBuilder().addBuilder( + build.buf.validate.FieldPathElement.getDefaultInstance()); + } + /** + *
+     * `elements` contains each element of the path, starting from the root and recursing downward.
+     * 
+ * + * repeated .buf.validate.FieldPathElement elements = 1 [json_name = "elements"]; + */ + public build.buf.validate.FieldPathElement.Builder addElementsBuilder( + int index) { + return getElementsFieldBuilder().addBuilder( + index, build.buf.validate.FieldPathElement.getDefaultInstance()); + } + /** + *
+     * `elements` contains each element of the path, starting from the root and recursing downward.
+     * 
+ * + * repeated .buf.validate.FieldPathElement elements = 1 [json_name = "elements"]; + */ + public java.util.List + getElementsBuilderList() { + return getElementsFieldBuilder().getBuilderList(); + } + private com.google.protobuf.RepeatedFieldBuilder< + build.buf.validate.FieldPathElement, build.buf.validate.FieldPathElement.Builder, build.buf.validate.FieldPathElementOrBuilder> + getElementsFieldBuilder() { + if (elementsBuilder_ == null) { + elementsBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< + build.buf.validate.FieldPathElement, build.buf.validate.FieldPathElement.Builder, build.buf.validate.FieldPathElementOrBuilder>( + elements_, + ((bitField0_ & 0x00000001) != 0), + getParentForChildren(), + isClean()); + elements_ = null; + } + return elementsBuilder_; + } + + // @@protoc_insertion_point(builder_scope:buf.validate.FieldPath) + } + + // @@protoc_insertion_point(class_scope:buf.validate.FieldPath) + private static final build.buf.validate.FieldPath DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new build.buf.validate.FieldPath(); + } + + public static build.buf.validate.FieldPath getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public FieldPath parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public build.buf.validate.FieldPath getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/src/main/java/build/buf/validate/FieldPathElement.java b/src/main/java/build/buf/validate/FieldPathElement.java new file mode 100644 index 00000000..cc0ea796 --- /dev/null +++ b/src/main/java/build/buf/validate/FieldPathElement.java @@ -0,0 +1,1882 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: buf/validate/validate.proto +// Protobuf Java Version: 4.28.3 + +package build.buf.validate; + +/** + *
+ * `FieldPathElement` provides enough information to nest through a single protobuf field.
+ *
+ * If the selected field is a map or repeated field, the `subscript` value selects a specific element from it.
+ * A path that refers to a value nested under a map key or repeated field index will have a `subscript` value.
+ * The `field_type` field allows unambiguous resolution of a field even if descriptors are not available.
+ * 
+ * + * Protobuf type {@code buf.validate.FieldPathElement} + */ +public final class FieldPathElement extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:buf.validate.FieldPathElement) + FieldPathElementOrBuilder { +private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 28, + /* patch= */ 3, + /* suffix= */ "", + FieldPathElement.class.getName()); + } + // Use FieldPathElement.newBuilder() to construct. + private FieldPathElement(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private FieldPathElement() { + fieldName_ = ""; + fieldType_ = 1; + keyType_ = 1; + valueType_ = 1; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return build.buf.validate.ValidateProto.internal_static_buf_validate_FieldPathElement_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return build.buf.validate.ValidateProto.internal_static_buf_validate_FieldPathElement_fieldAccessorTable + .ensureFieldAccessorsInitialized( + build.buf.validate.FieldPathElement.class, build.buf.validate.FieldPathElement.Builder.class); + } + + private int bitField0_; + private int subscriptCase_ = 0; + @SuppressWarnings("serial") + private java.lang.Object subscript_; + public enum SubscriptCase + implements com.google.protobuf.Internal.EnumLite, + com.google.protobuf.AbstractMessage.InternalOneOfEnum { + INDEX(6), + BOOL_KEY(7), + INT_KEY(8), + UINT_KEY(9), + STRING_KEY(10), + SUBSCRIPT_NOT_SET(0); + private final int value; + private SubscriptCase(int value) { + this.value = value; + } + /** + * @param value The number of the enum to look for. + * @return The enum associated with the given number. + * @deprecated Use {@link #forNumber(int)} instead. + */ + @java.lang.Deprecated + public static SubscriptCase valueOf(int value) { + return forNumber(value); + } + + public static SubscriptCase forNumber(int value) { + switch (value) { + case 6: return INDEX; + case 7: return BOOL_KEY; + case 8: return INT_KEY; + case 9: return UINT_KEY; + case 10: return STRING_KEY; + case 0: return SUBSCRIPT_NOT_SET; + default: return null; + } + } + public int getNumber() { + return this.value; + } + }; + + public SubscriptCase + getSubscriptCase() { + return SubscriptCase.forNumber( + subscriptCase_); + } + + public static final int FIELD_NUMBER_FIELD_NUMBER = 1; + private int fieldNumber_ = 0; + /** + *
+   * `field_number` is the field number this path element refers to.
+   * 
+ * + * optional int32 field_number = 1 [json_name = "fieldNumber"]; + * @return Whether the fieldNumber field is set. + */ + @java.lang.Override + public boolean hasFieldNumber() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + *
+   * `field_number` is the field number this path element refers to.
+   * 
+ * + * optional int32 field_number = 1 [json_name = "fieldNumber"]; + * @return The fieldNumber. + */ + @java.lang.Override + public int getFieldNumber() { + return fieldNumber_; + } + + public static final int FIELD_NAME_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object fieldName_ = ""; + /** + *
+   * `field_name` contains the field name this path element refers to.
+   * This can be used to display a human-readable path even if the field number is unknown.
+   * 
+ * + * optional string field_name = 2 [json_name = "fieldName"]; + * @return Whether the fieldName field is set. + */ + @java.lang.Override + public boolean hasFieldName() { + return ((bitField0_ & 0x00000002) != 0); + } + /** + *
+   * `field_name` contains the field name this path element refers to.
+   * This can be used to display a human-readable path even if the field number is unknown.
+   * 
+ * + * optional string field_name = 2 [json_name = "fieldName"]; + * @return The fieldName. + */ + @java.lang.Override + public java.lang.String getFieldName() { + java.lang.Object ref = fieldName_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + fieldName_ = s; + } + return s; + } + } + /** + *
+   * `field_name` contains the field name this path element refers to.
+   * This can be used to display a human-readable path even if the field number is unknown.
+   * 
+ * + * optional string field_name = 2 [json_name = "fieldName"]; + * @return The bytes for fieldName. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getFieldNameBytes() { + java.lang.Object ref = fieldName_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + fieldName_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int FIELD_TYPE_FIELD_NUMBER = 3; + private int fieldType_ = 1; + /** + *
+   * `field_type` specifies the type of this field. When using reflection, this value is not needed.
+   *
+   * This value is provided to make it possible to traverse unknown fields through wire data.
+   * When traversing wire data, be mindful of both packed[1] and delimited[2] encoding schemes.
+   *
+   * [1]: https://protobuf.dev/programming-guides/encoding/#packed
+   * [2]: https://protobuf.dev/programming-guides/encoding/#groups
+   *
+   * N.B.: Although groups are deprecated, the corresponding delimited encoding scheme is not, and
+   * can be explicitly used in Protocol Buffers 2023 Edition.
+   * 
+ * + * optional .google.protobuf.FieldDescriptorProto.Type field_type = 3 [json_name = "fieldType"]; + * @return Whether the fieldType field is set. + */ + @java.lang.Override public boolean hasFieldType() { + return ((bitField0_ & 0x00000004) != 0); + } + /** + *
+   * `field_type` specifies the type of this field. When using reflection, this value is not needed.
+   *
+   * This value is provided to make it possible to traverse unknown fields through wire data.
+   * When traversing wire data, be mindful of both packed[1] and delimited[2] encoding schemes.
+   *
+   * [1]: https://protobuf.dev/programming-guides/encoding/#packed
+   * [2]: https://protobuf.dev/programming-guides/encoding/#groups
+   *
+   * N.B.: Although groups are deprecated, the corresponding delimited encoding scheme is not, and
+   * can be explicitly used in Protocol Buffers 2023 Edition.
+   * 
+ * + * optional .google.protobuf.FieldDescriptorProto.Type field_type = 3 [json_name = "fieldType"]; + * @return The fieldType. + */ + @java.lang.Override public com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type getFieldType() { + com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type result = com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type.forNumber(fieldType_); + return result == null ? com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type.TYPE_DOUBLE : result; + } + + public static final int KEY_TYPE_FIELD_NUMBER = 4; + private int keyType_ = 1; + /** + *
+   * `key_type` specifies the map key type of this field. This value is useful when traversing
+   * unknown fields through wire data: specifically, it allows handling the differences between
+   * different integer encodings.
+   * 
+ * + * optional .google.protobuf.FieldDescriptorProto.Type key_type = 4 [json_name = "keyType"]; + * @return Whether the keyType field is set. + */ + @java.lang.Override public boolean hasKeyType() { + return ((bitField0_ & 0x00000008) != 0); + } + /** + *
+   * `key_type` specifies the map key type of this field. This value is useful when traversing
+   * unknown fields through wire data: specifically, it allows handling the differences between
+   * different integer encodings.
+   * 
+ * + * optional .google.protobuf.FieldDescriptorProto.Type key_type = 4 [json_name = "keyType"]; + * @return The keyType. + */ + @java.lang.Override public com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type getKeyType() { + com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type result = com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type.forNumber(keyType_); + return result == null ? com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type.TYPE_DOUBLE : result; + } + + public static final int VALUE_TYPE_FIELD_NUMBER = 5; + private int valueType_ = 1; + /** + *
+   * `value_type` specifies map value type of this field. This is useful if you want to display a
+   * value inside unknown fields through wire data.
+   * 
+ * + * optional .google.protobuf.FieldDescriptorProto.Type value_type = 5 [json_name = "valueType"]; + * @return Whether the valueType field is set. + */ + @java.lang.Override public boolean hasValueType() { + return ((bitField0_ & 0x00000010) != 0); + } + /** + *
+   * `value_type` specifies map value type of this field. This is useful if you want to display a
+   * value inside unknown fields through wire data.
+   * 
+ * + * optional .google.protobuf.FieldDescriptorProto.Type value_type = 5 [json_name = "valueType"]; + * @return The valueType. + */ + @java.lang.Override public com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type getValueType() { + com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type result = com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type.forNumber(valueType_); + return result == null ? com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type.TYPE_DOUBLE : result; + } + + public static final int INDEX_FIELD_NUMBER = 6; + /** + *
+   * `index` specifies a 0-based index into a repeated field.
+   * 
+ * + * uint64 index = 6 [json_name = "index"]; + * @return Whether the index field is set. + */ + @java.lang.Override + public boolean hasIndex() { + return subscriptCase_ == 6; + } + /** + *
+   * `index` specifies a 0-based index into a repeated field.
+   * 
+ * + * uint64 index = 6 [json_name = "index"]; + * @return The index. + */ + @java.lang.Override + public long getIndex() { + if (subscriptCase_ == 6) { + return (java.lang.Long) subscript_; + } + return 0L; + } + + public static final int BOOL_KEY_FIELD_NUMBER = 7; + /** + *
+   * `bool_key` specifies a map key of type bool.
+   * 
+ * + * bool bool_key = 7 [json_name = "boolKey"]; + * @return Whether the boolKey field is set. + */ + @java.lang.Override + public boolean hasBoolKey() { + return subscriptCase_ == 7; + } + /** + *
+   * `bool_key` specifies a map key of type bool.
+   * 
+ * + * bool bool_key = 7 [json_name = "boolKey"]; + * @return The boolKey. + */ + @java.lang.Override + public boolean getBoolKey() { + if (subscriptCase_ == 7) { + return (java.lang.Boolean) subscript_; + } + return false; + } + + public static final int INT_KEY_FIELD_NUMBER = 8; + /** + *
+   * `int_key` specifies a map key of type int32, int64, sint32, sint64, sfixed32 or sfixed64.
+   * 
+ * + * int64 int_key = 8 [json_name = "intKey"]; + * @return Whether the intKey field is set. + */ + @java.lang.Override + public boolean hasIntKey() { + return subscriptCase_ == 8; + } + /** + *
+   * `int_key` specifies a map key of type int32, int64, sint32, sint64, sfixed32 or sfixed64.
+   * 
+ * + * int64 int_key = 8 [json_name = "intKey"]; + * @return The intKey. + */ + @java.lang.Override + public long getIntKey() { + if (subscriptCase_ == 8) { + return (java.lang.Long) subscript_; + } + return 0L; + } + + public static final int UINT_KEY_FIELD_NUMBER = 9; + /** + *
+   * `uint_key` specifies a map key of type uint32, uint64, fixed32 or fixed64.
+   * 
+ * + * uint64 uint_key = 9 [json_name = "uintKey"]; + * @return Whether the uintKey field is set. + */ + @java.lang.Override + public boolean hasUintKey() { + return subscriptCase_ == 9; + } + /** + *
+   * `uint_key` specifies a map key of type uint32, uint64, fixed32 or fixed64.
+   * 
+ * + * uint64 uint_key = 9 [json_name = "uintKey"]; + * @return The uintKey. + */ + @java.lang.Override + public long getUintKey() { + if (subscriptCase_ == 9) { + return (java.lang.Long) subscript_; + } + return 0L; + } + + public static final int STRING_KEY_FIELD_NUMBER = 10; + /** + *
+   * `string_key` specifies a map key of type string.
+   * 
+ * + * string string_key = 10 [json_name = "stringKey"]; + * @return Whether the stringKey field is set. + */ + public boolean hasStringKey() { + return subscriptCase_ == 10; + } + /** + *
+   * `string_key` specifies a map key of type string.
+   * 
+ * + * string string_key = 10 [json_name = "stringKey"]; + * @return The stringKey. + */ + public java.lang.String getStringKey() { + java.lang.Object ref = ""; + if (subscriptCase_ == 10) { + ref = subscript_; + } + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8() && (subscriptCase_ == 10)) { + subscript_ = s; + } + return s; + } + } + /** + *
+   * `string_key` specifies a map key of type string.
+   * 
+ * + * string string_key = 10 [json_name = "stringKey"]; + * @return The bytes for stringKey. + */ + public com.google.protobuf.ByteString + getStringKeyBytes() { + java.lang.Object ref = ""; + if (subscriptCase_ == 10) { + ref = subscript_; + } + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + if (subscriptCase_ == 10) { + subscript_ = b; + } + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (((bitField0_ & 0x00000001) != 0)) { + output.writeInt32(1, fieldNumber_); + } + if (((bitField0_ & 0x00000002) != 0)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, fieldName_); + } + if (((bitField0_ & 0x00000004) != 0)) { + output.writeEnum(3, fieldType_); + } + if (((bitField0_ & 0x00000008) != 0)) { + output.writeEnum(4, keyType_); + } + if (((bitField0_ & 0x00000010) != 0)) { + output.writeEnum(5, valueType_); + } + if (subscriptCase_ == 6) { + output.writeUInt64( + 6, (long)((java.lang.Long) subscript_)); + } + if (subscriptCase_ == 7) { + output.writeBool( + 7, (boolean)((java.lang.Boolean) subscript_)); + } + if (subscriptCase_ == 8) { + output.writeInt64( + 8, (long)((java.lang.Long) subscript_)); + } + if (subscriptCase_ == 9) { + output.writeUInt64( + 9, (long)((java.lang.Long) subscript_)); + } + if (subscriptCase_ == 10) { + com.google.protobuf.GeneratedMessage.writeString(output, 10, subscript_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeInt32Size(1, fieldNumber_); + } + if (((bitField0_ & 0x00000002) != 0)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, fieldName_); + } + if (((bitField0_ & 0x00000004) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(3, fieldType_); + } + if (((bitField0_ & 0x00000008) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(4, keyType_); + } + if (((bitField0_ & 0x00000010) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(5, valueType_); + } + if (subscriptCase_ == 6) { + size += com.google.protobuf.CodedOutputStream + .computeUInt64Size( + 6, (long)((java.lang.Long) subscript_)); + } + if (subscriptCase_ == 7) { + size += com.google.protobuf.CodedOutputStream + .computeBoolSize( + 7, (boolean)((java.lang.Boolean) subscript_)); + } + if (subscriptCase_ == 8) { + size += com.google.protobuf.CodedOutputStream + .computeInt64Size( + 8, (long)((java.lang.Long) subscript_)); + } + if (subscriptCase_ == 9) { + size += com.google.protobuf.CodedOutputStream + .computeUInt64Size( + 9, (long)((java.lang.Long) subscript_)); + } + if (subscriptCase_ == 10) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(10, subscript_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof build.buf.validate.FieldPathElement)) { + return super.equals(obj); + } + build.buf.validate.FieldPathElement other = (build.buf.validate.FieldPathElement) obj; + + if (hasFieldNumber() != other.hasFieldNumber()) return false; + if (hasFieldNumber()) { + if (getFieldNumber() + != other.getFieldNumber()) return false; + } + if (hasFieldName() != other.hasFieldName()) return false; + if (hasFieldName()) { + if (!getFieldName() + .equals(other.getFieldName())) return false; + } + if (hasFieldType() != other.hasFieldType()) return false; + if (hasFieldType()) { + if (fieldType_ != other.fieldType_) return false; + } + if (hasKeyType() != other.hasKeyType()) return false; + if (hasKeyType()) { + if (keyType_ != other.keyType_) return false; + } + if (hasValueType() != other.hasValueType()) return false; + if (hasValueType()) { + if (valueType_ != other.valueType_) return false; + } + if (!getSubscriptCase().equals(other.getSubscriptCase())) return false; + switch (subscriptCase_) { + case 6: + if (getIndex() + != other.getIndex()) return false; + break; + case 7: + if (getBoolKey() + != other.getBoolKey()) return false; + break; + case 8: + if (getIntKey() + != other.getIntKey()) return false; + break; + case 9: + if (getUintKey() + != other.getUintKey()) return false; + break; + case 10: + if (!getStringKey() + .equals(other.getStringKey())) return false; + break; + case 0: + default: + } + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + if (hasFieldNumber()) { + hash = (37 * hash) + FIELD_NUMBER_FIELD_NUMBER; + hash = (53 * hash) + getFieldNumber(); + } + if (hasFieldName()) { + hash = (37 * hash) + FIELD_NAME_FIELD_NUMBER; + hash = (53 * hash) + getFieldName().hashCode(); + } + if (hasFieldType()) { + hash = (37 * hash) + FIELD_TYPE_FIELD_NUMBER; + hash = (53 * hash) + fieldType_; + } + if (hasKeyType()) { + hash = (37 * hash) + KEY_TYPE_FIELD_NUMBER; + hash = (53 * hash) + keyType_; + } + if (hasValueType()) { + hash = (37 * hash) + VALUE_TYPE_FIELD_NUMBER; + hash = (53 * hash) + valueType_; + } + switch (subscriptCase_) { + case 6: + hash = (37 * hash) + INDEX_FIELD_NUMBER; + hash = (53 * hash) + com.google.protobuf.Internal.hashLong( + getIndex()); + break; + case 7: + hash = (37 * hash) + BOOL_KEY_FIELD_NUMBER; + hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean( + getBoolKey()); + break; + case 8: + hash = (37 * hash) + INT_KEY_FIELD_NUMBER; + hash = (53 * hash) + com.google.protobuf.Internal.hashLong( + getIntKey()); + break; + case 9: + hash = (37 * hash) + UINT_KEY_FIELD_NUMBER; + hash = (53 * hash) + com.google.protobuf.Internal.hashLong( + getUintKey()); + break; + case 10: + hash = (37 * hash) + STRING_KEY_FIELD_NUMBER; + hash = (53 * hash) + getStringKey().hashCode(); + break; + case 0: + default: + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static build.buf.validate.FieldPathElement parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static build.buf.validate.FieldPathElement parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static build.buf.validate.FieldPathElement parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static build.buf.validate.FieldPathElement parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static build.buf.validate.FieldPathElement parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static build.buf.validate.FieldPathElement parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static build.buf.validate.FieldPathElement parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static build.buf.validate.FieldPathElement parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static build.buf.validate.FieldPathElement parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static build.buf.validate.FieldPathElement parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static build.buf.validate.FieldPathElement parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static build.buf.validate.FieldPathElement parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(build.buf.validate.FieldPathElement prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * `FieldPathElement` provides enough information to nest through a single protobuf field.
+   *
+   * If the selected field is a map or repeated field, the `subscript` value selects a specific element from it.
+   * A path that refers to a value nested under a map key or repeated field index will have a `subscript` value.
+   * The `field_type` field allows unambiguous resolution of a field even if descriptors are not available.
+   * 
+ * + * Protobuf type {@code buf.validate.FieldPathElement} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:buf.validate.FieldPathElement) + build.buf.validate.FieldPathElementOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return build.buf.validate.ValidateProto.internal_static_buf_validate_FieldPathElement_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return build.buf.validate.ValidateProto.internal_static_buf_validate_FieldPathElement_fieldAccessorTable + .ensureFieldAccessorsInitialized( + build.buf.validate.FieldPathElement.class, build.buf.validate.FieldPathElement.Builder.class); + } + + // Construct using build.buf.validate.FieldPathElement.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + fieldNumber_ = 0; + fieldName_ = ""; + fieldType_ = 1; + keyType_ = 1; + valueType_ = 1; + subscriptCase_ = 0; + subscript_ = null; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return build.buf.validate.ValidateProto.internal_static_buf_validate_FieldPathElement_descriptor; + } + + @java.lang.Override + public build.buf.validate.FieldPathElement getDefaultInstanceForType() { + return build.buf.validate.FieldPathElement.getDefaultInstance(); + } + + @java.lang.Override + public build.buf.validate.FieldPathElement build() { + build.buf.validate.FieldPathElement result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public build.buf.validate.FieldPathElement buildPartial() { + build.buf.validate.FieldPathElement result = new build.buf.validate.FieldPathElement(this); + if (bitField0_ != 0) { buildPartial0(result); } + buildPartialOneofs(result); + onBuilt(); + return result; + } + + private void buildPartial0(build.buf.validate.FieldPathElement result) { + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.fieldNumber_ = fieldNumber_; + to_bitField0_ |= 0x00000001; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.fieldName_ = fieldName_; + to_bitField0_ |= 0x00000002; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.fieldType_ = fieldType_; + to_bitField0_ |= 0x00000004; + } + if (((from_bitField0_ & 0x00000008) != 0)) { + result.keyType_ = keyType_; + to_bitField0_ |= 0x00000008; + } + if (((from_bitField0_ & 0x00000010) != 0)) { + result.valueType_ = valueType_; + to_bitField0_ |= 0x00000010; + } + result.bitField0_ |= to_bitField0_; + } + + private void buildPartialOneofs(build.buf.validate.FieldPathElement result) { + result.subscriptCase_ = subscriptCase_; + result.subscript_ = this.subscript_; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof build.buf.validate.FieldPathElement) { + return mergeFrom((build.buf.validate.FieldPathElement)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(build.buf.validate.FieldPathElement other) { + if (other == build.buf.validate.FieldPathElement.getDefaultInstance()) return this; + if (other.hasFieldNumber()) { + setFieldNumber(other.getFieldNumber()); + } + if (other.hasFieldName()) { + fieldName_ = other.fieldName_; + bitField0_ |= 0x00000002; + onChanged(); + } + if (other.hasFieldType()) { + setFieldType(other.getFieldType()); + } + if (other.hasKeyType()) { + setKeyType(other.getKeyType()); + } + if (other.hasValueType()) { + setValueType(other.getValueType()); + } + switch (other.getSubscriptCase()) { + case INDEX: { + setIndex(other.getIndex()); + break; + } + case BOOL_KEY: { + setBoolKey(other.getBoolKey()); + break; + } + case INT_KEY: { + setIntKey(other.getIntKey()); + break; + } + case UINT_KEY: { + setUintKey(other.getUintKey()); + break; + } + case STRING_KEY: { + subscriptCase_ = 10; + subscript_ = other.subscript_; + onChanged(); + break; + } + case SUBSCRIPT_NOT_SET: { + break; + } + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 8: { + fieldNumber_ = input.readInt32(); + bitField0_ |= 0x00000001; + break; + } // case 8 + case 18: { + fieldName_ = input.readBytes(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 24: { + int tmpRaw = input.readEnum(); + com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type tmpValue = + com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type.forNumber(tmpRaw); + if (tmpValue == null) { + mergeUnknownVarintField(3, tmpRaw); + } else { + fieldType_ = tmpRaw; + bitField0_ |= 0x00000004; + } + break; + } // case 24 + case 32: { + int tmpRaw = input.readEnum(); + com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type tmpValue = + com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type.forNumber(tmpRaw); + if (tmpValue == null) { + mergeUnknownVarintField(4, tmpRaw); + } else { + keyType_ = tmpRaw; + bitField0_ |= 0x00000008; + } + break; + } // case 32 + case 40: { + int tmpRaw = input.readEnum(); + com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type tmpValue = + com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type.forNumber(tmpRaw); + if (tmpValue == null) { + mergeUnknownVarintField(5, tmpRaw); + } else { + valueType_ = tmpRaw; + bitField0_ |= 0x00000010; + } + break; + } // case 40 + case 48: { + subscript_ = input.readUInt64(); + subscriptCase_ = 6; + break; + } // case 48 + case 56: { + subscript_ = input.readBool(); + subscriptCase_ = 7; + break; + } // case 56 + case 64: { + subscript_ = input.readInt64(); + subscriptCase_ = 8; + break; + } // case 64 + case 72: { + subscript_ = input.readUInt64(); + subscriptCase_ = 9; + break; + } // case 72 + case 82: { + com.google.protobuf.ByteString bs = input.readBytes(); + subscriptCase_ = 10; + subscript_ = bs; + break; + } // case 82 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int subscriptCase_ = 0; + private java.lang.Object subscript_; + public SubscriptCase + getSubscriptCase() { + return SubscriptCase.forNumber( + subscriptCase_); + } + + public Builder clearSubscript() { + subscriptCase_ = 0; + subscript_ = null; + onChanged(); + return this; + } + + private int bitField0_; + + private int fieldNumber_ ; + /** + *
+     * `field_number` is the field number this path element refers to.
+     * 
+ * + * optional int32 field_number = 1 [json_name = "fieldNumber"]; + * @return Whether the fieldNumber field is set. + */ + @java.lang.Override + public boolean hasFieldNumber() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + *
+     * `field_number` is the field number this path element refers to.
+     * 
+ * + * optional int32 field_number = 1 [json_name = "fieldNumber"]; + * @return The fieldNumber. + */ + @java.lang.Override + public int getFieldNumber() { + return fieldNumber_; + } + /** + *
+     * `field_number` is the field number this path element refers to.
+     * 
+ * + * optional int32 field_number = 1 [json_name = "fieldNumber"]; + * @param value The fieldNumber to set. + * @return This builder for chaining. + */ + public Builder setFieldNumber(int value) { + + fieldNumber_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * `field_number` is the field number this path element refers to.
+     * 
+ * + * optional int32 field_number = 1 [json_name = "fieldNumber"]; + * @return This builder for chaining. + */ + public Builder clearFieldNumber() { + bitField0_ = (bitField0_ & ~0x00000001); + fieldNumber_ = 0; + onChanged(); + return this; + } + + private java.lang.Object fieldName_ = ""; + /** + *
+     * `field_name` contains the field name this path element refers to.
+     * This can be used to display a human-readable path even if the field number is unknown.
+     * 
+ * + * optional string field_name = 2 [json_name = "fieldName"]; + * @return Whether the fieldName field is set. + */ + public boolean hasFieldName() { + return ((bitField0_ & 0x00000002) != 0); + } + /** + *
+     * `field_name` contains the field name this path element refers to.
+     * This can be used to display a human-readable path even if the field number is unknown.
+     * 
+ * + * optional string field_name = 2 [json_name = "fieldName"]; + * @return The fieldName. + */ + public java.lang.String getFieldName() { + java.lang.Object ref = fieldName_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + fieldName_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * `field_name` contains the field name this path element refers to.
+     * This can be used to display a human-readable path even if the field number is unknown.
+     * 
+ * + * optional string field_name = 2 [json_name = "fieldName"]; + * @return The bytes for fieldName. + */ + public com.google.protobuf.ByteString + getFieldNameBytes() { + java.lang.Object ref = fieldName_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + fieldName_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * `field_name` contains the field name this path element refers to.
+     * This can be used to display a human-readable path even if the field number is unknown.
+     * 
+ * + * optional string field_name = 2 [json_name = "fieldName"]; + * @param value The fieldName to set. + * @return This builder for chaining. + */ + public Builder setFieldName( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + fieldName_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * `field_name` contains the field name this path element refers to.
+     * This can be used to display a human-readable path even if the field number is unknown.
+     * 
+ * + * optional string field_name = 2 [json_name = "fieldName"]; + * @return This builder for chaining. + */ + public Builder clearFieldName() { + fieldName_ = getDefaultInstance().getFieldName(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + *
+     * `field_name` contains the field name this path element refers to.
+     * This can be used to display a human-readable path even if the field number is unknown.
+     * 
+ * + * optional string field_name = 2 [json_name = "fieldName"]; + * @param value The bytes for fieldName to set. + * @return This builder for chaining. + */ + public Builder setFieldNameBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + fieldName_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private int fieldType_ = 1; + /** + *
+     * `field_type` specifies the type of this field. When using reflection, this value is not needed.
+     *
+     * This value is provided to make it possible to traverse unknown fields through wire data.
+     * When traversing wire data, be mindful of both packed[1] and delimited[2] encoding schemes.
+     *
+     * [1]: https://protobuf.dev/programming-guides/encoding/#packed
+     * [2]: https://protobuf.dev/programming-guides/encoding/#groups
+     *
+     * N.B.: Although groups are deprecated, the corresponding delimited encoding scheme is not, and
+     * can be explicitly used in Protocol Buffers 2023 Edition.
+     * 
+ * + * optional .google.protobuf.FieldDescriptorProto.Type field_type = 3 [json_name = "fieldType"]; + * @return Whether the fieldType field is set. + */ + @java.lang.Override public boolean hasFieldType() { + return ((bitField0_ & 0x00000004) != 0); + } + /** + *
+     * `field_type` specifies the type of this field. When using reflection, this value is not needed.
+     *
+     * This value is provided to make it possible to traverse unknown fields through wire data.
+     * When traversing wire data, be mindful of both packed[1] and delimited[2] encoding schemes.
+     *
+     * [1]: https://protobuf.dev/programming-guides/encoding/#packed
+     * [2]: https://protobuf.dev/programming-guides/encoding/#groups
+     *
+     * N.B.: Although groups are deprecated, the corresponding delimited encoding scheme is not, and
+     * can be explicitly used in Protocol Buffers 2023 Edition.
+     * 
+ * + * optional .google.protobuf.FieldDescriptorProto.Type field_type = 3 [json_name = "fieldType"]; + * @return The fieldType. + */ + @java.lang.Override + public com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type getFieldType() { + com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type result = com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type.forNumber(fieldType_); + return result == null ? com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type.TYPE_DOUBLE : result; + } + /** + *
+     * `field_type` specifies the type of this field. When using reflection, this value is not needed.
+     *
+     * This value is provided to make it possible to traverse unknown fields through wire data.
+     * When traversing wire data, be mindful of both packed[1] and delimited[2] encoding schemes.
+     *
+     * [1]: https://protobuf.dev/programming-guides/encoding/#packed
+     * [2]: https://protobuf.dev/programming-guides/encoding/#groups
+     *
+     * N.B.: Although groups are deprecated, the corresponding delimited encoding scheme is not, and
+     * can be explicitly used in Protocol Buffers 2023 Edition.
+     * 
+ * + * optional .google.protobuf.FieldDescriptorProto.Type field_type = 3 [json_name = "fieldType"]; + * @param value The fieldType to set. + * @return This builder for chaining. + */ + public Builder setFieldType(com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + fieldType_ = value.getNumber(); + onChanged(); + return this; + } + /** + *
+     * `field_type` specifies the type of this field. When using reflection, this value is not needed.
+     *
+     * This value is provided to make it possible to traverse unknown fields through wire data.
+     * When traversing wire data, be mindful of both packed[1] and delimited[2] encoding schemes.
+     *
+     * [1]: https://protobuf.dev/programming-guides/encoding/#packed
+     * [2]: https://protobuf.dev/programming-guides/encoding/#groups
+     *
+     * N.B.: Although groups are deprecated, the corresponding delimited encoding scheme is not, and
+     * can be explicitly used in Protocol Buffers 2023 Edition.
+     * 
+ * + * optional .google.protobuf.FieldDescriptorProto.Type field_type = 3 [json_name = "fieldType"]; + * @return This builder for chaining. + */ + public Builder clearFieldType() { + bitField0_ = (bitField0_ & ~0x00000004); + fieldType_ = 1; + onChanged(); + return this; + } + + private int keyType_ = 1; + /** + *
+     * `key_type` specifies the map key type of this field. This value is useful when traversing
+     * unknown fields through wire data: specifically, it allows handling the differences between
+     * different integer encodings.
+     * 
+ * + * optional .google.protobuf.FieldDescriptorProto.Type key_type = 4 [json_name = "keyType"]; + * @return Whether the keyType field is set. + */ + @java.lang.Override public boolean hasKeyType() { + return ((bitField0_ & 0x00000008) != 0); + } + /** + *
+     * `key_type` specifies the map key type of this field. This value is useful when traversing
+     * unknown fields through wire data: specifically, it allows handling the differences between
+     * different integer encodings.
+     * 
+ * + * optional .google.protobuf.FieldDescriptorProto.Type key_type = 4 [json_name = "keyType"]; + * @return The keyType. + */ + @java.lang.Override + public com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type getKeyType() { + com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type result = com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type.forNumber(keyType_); + return result == null ? com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type.TYPE_DOUBLE : result; + } + /** + *
+     * `key_type` specifies the map key type of this field. This value is useful when traversing
+     * unknown fields through wire data: specifically, it allows handling the differences between
+     * different integer encodings.
+     * 
+ * + * optional .google.protobuf.FieldDescriptorProto.Type key_type = 4 [json_name = "keyType"]; + * @param value The keyType to set. + * @return This builder for chaining. + */ + public Builder setKeyType(com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000008; + keyType_ = value.getNumber(); + onChanged(); + return this; + } + /** + *
+     * `key_type` specifies the map key type of this field. This value is useful when traversing
+     * unknown fields through wire data: specifically, it allows handling the differences between
+     * different integer encodings.
+     * 
+ * + * optional .google.protobuf.FieldDescriptorProto.Type key_type = 4 [json_name = "keyType"]; + * @return This builder for chaining. + */ + public Builder clearKeyType() { + bitField0_ = (bitField0_ & ~0x00000008); + keyType_ = 1; + onChanged(); + return this; + } + + private int valueType_ = 1; + /** + *
+     * `value_type` specifies map value type of this field. This is useful if you want to display a
+     * value inside unknown fields through wire data.
+     * 
+ * + * optional .google.protobuf.FieldDescriptorProto.Type value_type = 5 [json_name = "valueType"]; + * @return Whether the valueType field is set. + */ + @java.lang.Override public boolean hasValueType() { + return ((bitField0_ & 0x00000010) != 0); + } + /** + *
+     * `value_type` specifies map value type of this field. This is useful if you want to display a
+     * value inside unknown fields through wire data.
+     * 
+ * + * optional .google.protobuf.FieldDescriptorProto.Type value_type = 5 [json_name = "valueType"]; + * @return The valueType. + */ + @java.lang.Override + public com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type getValueType() { + com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type result = com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type.forNumber(valueType_); + return result == null ? com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type.TYPE_DOUBLE : result; + } + /** + *
+     * `value_type` specifies map value type of this field. This is useful if you want to display a
+     * value inside unknown fields through wire data.
+     * 
+ * + * optional .google.protobuf.FieldDescriptorProto.Type value_type = 5 [json_name = "valueType"]; + * @param value The valueType to set. + * @return This builder for chaining. + */ + public Builder setValueType(com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000010; + valueType_ = value.getNumber(); + onChanged(); + return this; + } + /** + *
+     * `value_type` specifies map value type of this field. This is useful if you want to display a
+     * value inside unknown fields through wire data.
+     * 
+ * + * optional .google.protobuf.FieldDescriptorProto.Type value_type = 5 [json_name = "valueType"]; + * @return This builder for chaining. + */ + public Builder clearValueType() { + bitField0_ = (bitField0_ & ~0x00000010); + valueType_ = 1; + onChanged(); + return this; + } + + /** + *
+     * `index` specifies a 0-based index into a repeated field.
+     * 
+ * + * uint64 index = 6 [json_name = "index"]; + * @return Whether the index field is set. + */ + public boolean hasIndex() { + return subscriptCase_ == 6; + } + /** + *
+     * `index` specifies a 0-based index into a repeated field.
+     * 
+ * + * uint64 index = 6 [json_name = "index"]; + * @return The index. + */ + public long getIndex() { + if (subscriptCase_ == 6) { + return (java.lang.Long) subscript_; + } + return 0L; + } + /** + *
+     * `index` specifies a 0-based index into a repeated field.
+     * 
+ * + * uint64 index = 6 [json_name = "index"]; + * @param value The index to set. + * @return This builder for chaining. + */ + public Builder setIndex(long value) { + + subscriptCase_ = 6; + subscript_ = value; + onChanged(); + return this; + } + /** + *
+     * `index` specifies a 0-based index into a repeated field.
+     * 
+ * + * uint64 index = 6 [json_name = "index"]; + * @return This builder for chaining. + */ + public Builder clearIndex() { + if (subscriptCase_ == 6) { + subscriptCase_ = 0; + subscript_ = null; + onChanged(); + } + return this; + } + + /** + *
+     * `bool_key` specifies a map key of type bool.
+     * 
+ * + * bool bool_key = 7 [json_name = "boolKey"]; + * @return Whether the boolKey field is set. + */ + public boolean hasBoolKey() { + return subscriptCase_ == 7; + } + /** + *
+     * `bool_key` specifies a map key of type bool.
+     * 
+ * + * bool bool_key = 7 [json_name = "boolKey"]; + * @return The boolKey. + */ + public boolean getBoolKey() { + if (subscriptCase_ == 7) { + return (java.lang.Boolean) subscript_; + } + return false; + } + /** + *
+     * `bool_key` specifies a map key of type bool.
+     * 
+ * + * bool bool_key = 7 [json_name = "boolKey"]; + * @param value The boolKey to set. + * @return This builder for chaining. + */ + public Builder setBoolKey(boolean value) { + + subscriptCase_ = 7; + subscript_ = value; + onChanged(); + return this; + } + /** + *
+     * `bool_key` specifies a map key of type bool.
+     * 
+ * + * bool bool_key = 7 [json_name = "boolKey"]; + * @return This builder for chaining. + */ + public Builder clearBoolKey() { + if (subscriptCase_ == 7) { + subscriptCase_ = 0; + subscript_ = null; + onChanged(); + } + return this; + } + + /** + *
+     * `int_key` specifies a map key of type int32, int64, sint32, sint64, sfixed32 or sfixed64.
+     * 
+ * + * int64 int_key = 8 [json_name = "intKey"]; + * @return Whether the intKey field is set. + */ + public boolean hasIntKey() { + return subscriptCase_ == 8; + } + /** + *
+     * `int_key` specifies a map key of type int32, int64, sint32, sint64, sfixed32 or sfixed64.
+     * 
+ * + * int64 int_key = 8 [json_name = "intKey"]; + * @return The intKey. + */ + public long getIntKey() { + if (subscriptCase_ == 8) { + return (java.lang.Long) subscript_; + } + return 0L; + } + /** + *
+     * `int_key` specifies a map key of type int32, int64, sint32, sint64, sfixed32 or sfixed64.
+     * 
+ * + * int64 int_key = 8 [json_name = "intKey"]; + * @param value The intKey to set. + * @return This builder for chaining. + */ + public Builder setIntKey(long value) { + + subscriptCase_ = 8; + subscript_ = value; + onChanged(); + return this; + } + /** + *
+     * `int_key` specifies a map key of type int32, int64, sint32, sint64, sfixed32 or sfixed64.
+     * 
+ * + * int64 int_key = 8 [json_name = "intKey"]; + * @return This builder for chaining. + */ + public Builder clearIntKey() { + if (subscriptCase_ == 8) { + subscriptCase_ = 0; + subscript_ = null; + onChanged(); + } + return this; + } + + /** + *
+     * `uint_key` specifies a map key of type uint32, uint64, fixed32 or fixed64.
+     * 
+ * + * uint64 uint_key = 9 [json_name = "uintKey"]; + * @return Whether the uintKey field is set. + */ + public boolean hasUintKey() { + return subscriptCase_ == 9; + } + /** + *
+     * `uint_key` specifies a map key of type uint32, uint64, fixed32 or fixed64.
+     * 
+ * + * uint64 uint_key = 9 [json_name = "uintKey"]; + * @return The uintKey. + */ + public long getUintKey() { + if (subscriptCase_ == 9) { + return (java.lang.Long) subscript_; + } + return 0L; + } + /** + *
+     * `uint_key` specifies a map key of type uint32, uint64, fixed32 or fixed64.
+     * 
+ * + * uint64 uint_key = 9 [json_name = "uintKey"]; + * @param value The uintKey to set. + * @return This builder for chaining. + */ + public Builder setUintKey(long value) { + + subscriptCase_ = 9; + subscript_ = value; + onChanged(); + return this; + } + /** + *
+     * `uint_key` specifies a map key of type uint32, uint64, fixed32 or fixed64.
+     * 
+ * + * uint64 uint_key = 9 [json_name = "uintKey"]; + * @return This builder for chaining. + */ + public Builder clearUintKey() { + if (subscriptCase_ == 9) { + subscriptCase_ = 0; + subscript_ = null; + onChanged(); + } + return this; + } + + /** + *
+     * `string_key` specifies a map key of type string.
+     * 
+ * + * string string_key = 10 [json_name = "stringKey"]; + * @return Whether the stringKey field is set. + */ + @java.lang.Override + public boolean hasStringKey() { + return subscriptCase_ == 10; + } + /** + *
+     * `string_key` specifies a map key of type string.
+     * 
+ * + * string string_key = 10 [json_name = "stringKey"]; + * @return The stringKey. + */ + @java.lang.Override + public java.lang.String getStringKey() { + java.lang.Object ref = ""; + if (subscriptCase_ == 10) { + ref = subscript_; + } + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (subscriptCase_ == 10) { + if (bs.isValidUtf8()) { + subscript_ = s; + } + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * `string_key` specifies a map key of type string.
+     * 
+ * + * string string_key = 10 [json_name = "stringKey"]; + * @return The bytes for stringKey. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getStringKeyBytes() { + java.lang.Object ref = ""; + if (subscriptCase_ == 10) { + ref = subscript_; + } + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + if (subscriptCase_ == 10) { + subscript_ = b; + } + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * `string_key` specifies a map key of type string.
+     * 
+ * + * string string_key = 10 [json_name = "stringKey"]; + * @param value The stringKey to set. + * @return This builder for chaining. + */ + public Builder setStringKey( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + subscriptCase_ = 10; + subscript_ = value; + onChanged(); + return this; + } + /** + *
+     * `string_key` specifies a map key of type string.
+     * 
+ * + * string string_key = 10 [json_name = "stringKey"]; + * @return This builder for chaining. + */ + public Builder clearStringKey() { + if (subscriptCase_ == 10) { + subscriptCase_ = 0; + subscript_ = null; + onChanged(); + } + return this; + } + /** + *
+     * `string_key` specifies a map key of type string.
+     * 
+ * + * string string_key = 10 [json_name = "stringKey"]; + * @param value The bytes for stringKey to set. + * @return This builder for chaining. + */ + public Builder setStringKeyBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + subscriptCase_ = 10; + subscript_ = value; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:buf.validate.FieldPathElement) + } + + // @@protoc_insertion_point(class_scope:buf.validate.FieldPathElement) + private static final build.buf.validate.FieldPathElement DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new build.buf.validate.FieldPathElement(); + } + + public static build.buf.validate.FieldPathElement getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public FieldPathElement parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public build.buf.validate.FieldPathElement getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/src/main/java/build/buf/validate/FieldPathElementOrBuilder.java b/src/main/java/build/buf/validate/FieldPathElementOrBuilder.java new file mode 100644 index 00000000..f66621e6 --- /dev/null +++ b/src/main/java/build/buf/validate/FieldPathElementOrBuilder.java @@ -0,0 +1,250 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: buf/validate/validate.proto +// Protobuf Java Version: 4.28.3 + +package build.buf.validate; + +public interface FieldPathElementOrBuilder extends + // @@protoc_insertion_point(interface_extends:buf.validate.FieldPathElement) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * `field_number` is the field number this path element refers to.
+   * 
+ * + * optional int32 field_number = 1 [json_name = "fieldNumber"]; + * @return Whether the fieldNumber field is set. + */ + boolean hasFieldNumber(); + /** + *
+   * `field_number` is the field number this path element refers to.
+   * 
+ * + * optional int32 field_number = 1 [json_name = "fieldNumber"]; + * @return The fieldNumber. + */ + int getFieldNumber(); + + /** + *
+   * `field_name` contains the field name this path element refers to.
+   * This can be used to display a human-readable path even if the field number is unknown.
+   * 
+ * + * optional string field_name = 2 [json_name = "fieldName"]; + * @return Whether the fieldName field is set. + */ + boolean hasFieldName(); + /** + *
+   * `field_name` contains the field name this path element refers to.
+   * This can be used to display a human-readable path even if the field number is unknown.
+   * 
+ * + * optional string field_name = 2 [json_name = "fieldName"]; + * @return The fieldName. + */ + java.lang.String getFieldName(); + /** + *
+   * `field_name` contains the field name this path element refers to.
+   * This can be used to display a human-readable path even if the field number is unknown.
+   * 
+ * + * optional string field_name = 2 [json_name = "fieldName"]; + * @return The bytes for fieldName. + */ + com.google.protobuf.ByteString + getFieldNameBytes(); + + /** + *
+   * `field_type` specifies the type of this field. When using reflection, this value is not needed.
+   *
+   * This value is provided to make it possible to traverse unknown fields through wire data.
+   * When traversing wire data, be mindful of both packed[1] and delimited[2] encoding schemes.
+   *
+   * [1]: https://protobuf.dev/programming-guides/encoding/#packed
+   * [2]: https://protobuf.dev/programming-guides/encoding/#groups
+   *
+   * N.B.: Although groups are deprecated, the corresponding delimited encoding scheme is not, and
+   * can be explicitly used in Protocol Buffers 2023 Edition.
+   * 
+ * + * optional .google.protobuf.FieldDescriptorProto.Type field_type = 3 [json_name = "fieldType"]; + * @return Whether the fieldType field is set. + */ + boolean hasFieldType(); + /** + *
+   * `field_type` specifies the type of this field. When using reflection, this value is not needed.
+   *
+   * This value is provided to make it possible to traverse unknown fields through wire data.
+   * When traversing wire data, be mindful of both packed[1] and delimited[2] encoding schemes.
+   *
+   * [1]: https://protobuf.dev/programming-guides/encoding/#packed
+   * [2]: https://protobuf.dev/programming-guides/encoding/#groups
+   *
+   * N.B.: Although groups are deprecated, the corresponding delimited encoding scheme is not, and
+   * can be explicitly used in Protocol Buffers 2023 Edition.
+   * 
+ * + * optional .google.protobuf.FieldDescriptorProto.Type field_type = 3 [json_name = "fieldType"]; + * @return The fieldType. + */ + com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type getFieldType(); + + /** + *
+   * `key_type` specifies the map key type of this field. This value is useful when traversing
+   * unknown fields through wire data: specifically, it allows handling the differences between
+   * different integer encodings.
+   * 
+ * + * optional .google.protobuf.FieldDescriptorProto.Type key_type = 4 [json_name = "keyType"]; + * @return Whether the keyType field is set. + */ + boolean hasKeyType(); + /** + *
+   * `key_type` specifies the map key type of this field. This value is useful when traversing
+   * unknown fields through wire data: specifically, it allows handling the differences between
+   * different integer encodings.
+   * 
+ * + * optional .google.protobuf.FieldDescriptorProto.Type key_type = 4 [json_name = "keyType"]; + * @return The keyType. + */ + com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type getKeyType(); + + /** + *
+   * `value_type` specifies map value type of this field. This is useful if you want to display a
+   * value inside unknown fields through wire data.
+   * 
+ * + * optional .google.protobuf.FieldDescriptorProto.Type value_type = 5 [json_name = "valueType"]; + * @return Whether the valueType field is set. + */ + boolean hasValueType(); + /** + *
+   * `value_type` specifies map value type of this field. This is useful if you want to display a
+   * value inside unknown fields through wire data.
+   * 
+ * + * optional .google.protobuf.FieldDescriptorProto.Type value_type = 5 [json_name = "valueType"]; + * @return The valueType. + */ + com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type getValueType(); + + /** + *
+   * `index` specifies a 0-based index into a repeated field.
+   * 
+ * + * uint64 index = 6 [json_name = "index"]; + * @return Whether the index field is set. + */ + boolean hasIndex(); + /** + *
+   * `index` specifies a 0-based index into a repeated field.
+   * 
+ * + * uint64 index = 6 [json_name = "index"]; + * @return The index. + */ + long getIndex(); + + /** + *
+   * `bool_key` specifies a map key of type bool.
+   * 
+ * + * bool bool_key = 7 [json_name = "boolKey"]; + * @return Whether the boolKey field is set. + */ + boolean hasBoolKey(); + /** + *
+   * `bool_key` specifies a map key of type bool.
+   * 
+ * + * bool bool_key = 7 [json_name = "boolKey"]; + * @return The boolKey. + */ + boolean getBoolKey(); + + /** + *
+   * `int_key` specifies a map key of type int32, int64, sint32, sint64, sfixed32 or sfixed64.
+   * 
+ * + * int64 int_key = 8 [json_name = "intKey"]; + * @return Whether the intKey field is set. + */ + boolean hasIntKey(); + /** + *
+   * `int_key` specifies a map key of type int32, int64, sint32, sint64, sfixed32 or sfixed64.
+   * 
+ * + * int64 int_key = 8 [json_name = "intKey"]; + * @return The intKey. + */ + long getIntKey(); + + /** + *
+   * `uint_key` specifies a map key of type uint32, uint64, fixed32 or fixed64.
+   * 
+ * + * uint64 uint_key = 9 [json_name = "uintKey"]; + * @return Whether the uintKey field is set. + */ + boolean hasUintKey(); + /** + *
+   * `uint_key` specifies a map key of type uint32, uint64, fixed32 or fixed64.
+   * 
+ * + * uint64 uint_key = 9 [json_name = "uintKey"]; + * @return The uintKey. + */ + long getUintKey(); + + /** + *
+   * `string_key` specifies a map key of type string.
+   * 
+ * + * string string_key = 10 [json_name = "stringKey"]; + * @return Whether the stringKey field is set. + */ + boolean hasStringKey(); + /** + *
+   * `string_key` specifies a map key of type string.
+   * 
+ * + * string string_key = 10 [json_name = "stringKey"]; + * @return The stringKey. + */ + java.lang.String getStringKey(); + /** + *
+   * `string_key` specifies a map key of type string.
+   * 
+ * + * string string_key = 10 [json_name = "stringKey"]; + * @return The bytes for stringKey. + */ + com.google.protobuf.ByteString + getStringKeyBytes(); + + build.buf.validate.FieldPathElement.SubscriptCase getSubscriptCase(); +} diff --git a/src/main/java/build/buf/validate/FieldPathOrBuilder.java b/src/main/java/build/buf/validate/FieldPathOrBuilder.java new file mode 100644 index 00000000..cdeb91a8 --- /dev/null +++ b/src/main/java/build/buf/validate/FieldPathOrBuilder.java @@ -0,0 +1,55 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: buf/validate/validate.proto +// Protobuf Java Version: 4.28.3 + +package build.buf.validate; + +public interface FieldPathOrBuilder extends + // @@protoc_insertion_point(interface_extends:buf.validate.FieldPath) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * `elements` contains each element of the path, starting from the root and recursing downward.
+   * 
+ * + * repeated .buf.validate.FieldPathElement elements = 1 [json_name = "elements"]; + */ + java.util.List + getElementsList(); + /** + *
+   * `elements` contains each element of the path, starting from the root and recursing downward.
+   * 
+ * + * repeated .buf.validate.FieldPathElement elements = 1 [json_name = "elements"]; + */ + build.buf.validate.FieldPathElement getElements(int index); + /** + *
+   * `elements` contains each element of the path, starting from the root and recursing downward.
+   * 
+ * + * repeated .buf.validate.FieldPathElement elements = 1 [json_name = "elements"]; + */ + int getElementsCount(); + /** + *
+   * `elements` contains each element of the path, starting from the root and recursing downward.
+   * 
+ * + * repeated .buf.validate.FieldPathElement elements = 1 [json_name = "elements"]; + */ + java.util.List + getElementsOrBuilderList(); + /** + *
+   * `elements` contains each element of the path, starting from the root and recursing downward.
+   * 
+ * + * repeated .buf.validate.FieldPathElement elements = 1 [json_name = "elements"]; + */ + build.buf.validate.FieldPathElementOrBuilder getElementsOrBuilder( + int index); +} diff --git a/src/main/java/build/buf/validate/StringRules.java b/src/main/java/build/buf/validate/StringRules.java index 9b772f04..e573ced6 100644 --- a/src/main/java/build/buf/validate/StringRules.java +++ b/src/main/java/build/buf/validate/StringRules.java @@ -2056,8 +2056,8 @@ public boolean getStrict() { * ```proto * message MyString { * string value = 1 [ - * (buf.validate.field).string.example = 1, - * (buf.validate.field).string.example = 2 + * (buf.validate.field).string.example = "hello", + * (buf.validate.field).string.example = "world" * ]; * } * ``` @@ -2079,8 +2079,8 @@ public boolean getStrict() { * ```proto * message MyString { * string value = 1 [ - * (buf.validate.field).string.example = 1, - * (buf.validate.field).string.example = 2 + * (buf.validate.field).string.example = "hello", + * (buf.validate.field).string.example = "world" * ]; * } * ``` @@ -2101,8 +2101,8 @@ public int getExampleCount() { * ```proto * message MyString { * string value = 1 [ - * (buf.validate.field).string.example = 1, - * (buf.validate.field).string.example = 2 + * (buf.validate.field).string.example = "hello", + * (buf.validate.field).string.example = "world" * ]; * } * ``` @@ -2124,8 +2124,8 @@ public java.lang.String getExample(int index) { * ```proto * message MyString { * string value = 1 [ - * (buf.validate.field).string.example = 1, - * (buf.validate.field).string.example = 2 + * (buf.validate.field).string.example = "hello", + * (buf.validate.field).string.example = "world" * ]; * } * ``` @@ -7319,8 +7319,8 @@ private void ensureExampleIsMutable() { * ```proto * message MyString { * string value = 1 [ - * (buf.validate.field).string.example = 1, - * (buf.validate.field).string.example = 2 + * (buf.validate.field).string.example = "hello", + * (buf.validate.field).string.example = "world" * ]; * } * ``` @@ -7343,8 +7343,8 @@ private void ensureExampleIsMutable() { * ```proto * message MyString { * string value = 1 [ - * (buf.validate.field).string.example = 1, - * (buf.validate.field).string.example = 2 + * (buf.validate.field).string.example = "hello", + * (buf.validate.field).string.example = "world" * ]; * } * ``` @@ -7365,8 +7365,8 @@ public int getExampleCount() { * ```proto * message MyString { * string value = 1 [ - * (buf.validate.field).string.example = 1, - * (buf.validate.field).string.example = 2 + * (buf.validate.field).string.example = "hello", + * (buf.validate.field).string.example = "world" * ]; * } * ``` @@ -7388,8 +7388,8 @@ public java.lang.String getExample(int index) { * ```proto * message MyString { * string value = 1 [ - * (buf.validate.field).string.example = 1, - * (buf.validate.field).string.example = 2 + * (buf.validate.field).string.example = "hello", + * (buf.validate.field).string.example = "world" * ]; * } * ``` @@ -7412,8 +7412,8 @@ public java.lang.String getExample(int index) { * ```proto * message MyString { * string value = 1 [ - * (buf.validate.field).string.example = 1, - * (buf.validate.field).string.example = 2 + * (buf.validate.field).string.example = "hello", + * (buf.validate.field).string.example = "world" * ]; * } * ``` @@ -7442,8 +7442,8 @@ public Builder setExample( * ```proto * message MyString { * string value = 1 [ - * (buf.validate.field).string.example = 1, - * (buf.validate.field).string.example = 2 + * (buf.validate.field).string.example = "hello", + * (buf.validate.field).string.example = "world" * ]; * } * ``` @@ -7471,8 +7471,8 @@ public Builder addExample( * ```proto * message MyString { * string value = 1 [ - * (buf.validate.field).string.example = 1, - * (buf.validate.field).string.example = 2 + * (buf.validate.field).string.example = "hello", + * (buf.validate.field).string.example = "world" * ]; * } * ``` @@ -7500,8 +7500,8 @@ public Builder addAllExample( * ```proto * message MyString { * string value = 1 [ - * (buf.validate.field).string.example = 1, - * (buf.validate.field).string.example = 2 + * (buf.validate.field).string.example = "hello", + * (buf.validate.field).string.example = "world" * ]; * } * ``` @@ -7526,8 +7526,8 @@ public Builder clearExample() { * ```proto * message MyString { * string value = 1 [ - * (buf.validate.field).string.example = 1, - * (buf.validate.field).string.example = 2 + * (buf.validate.field).string.example = "hello", + * (buf.validate.field).string.example = "world" * ]; * } * ``` diff --git a/src/main/java/build/buf/validate/StringRulesOrBuilder.java b/src/main/java/build/buf/validate/StringRulesOrBuilder.java index 45c7b9db..427fe1a6 100644 --- a/src/main/java/build/buf/validate/StringRulesOrBuilder.java +++ b/src/main/java/build/buf/validate/StringRulesOrBuilder.java @@ -1475,8 +1475,8 @@ public interface StringRulesOrBuilder extends * ```proto * message MyString { * string value = 1 [ - * (buf.validate.field).string.example = 1, - * (buf.validate.field).string.example = 2 + * (buf.validate.field).string.example = "hello", + * (buf.validate.field).string.example = "world" * ]; * } * ``` @@ -1496,8 +1496,8 @@ public interface StringRulesOrBuilder extends * ```proto * message MyString { * string value = 1 [ - * (buf.validate.field).string.example = 1, - * (buf.validate.field).string.example = 2 + * (buf.validate.field).string.example = "hello", + * (buf.validate.field).string.example = "world" * ]; * } * ``` @@ -1516,8 +1516,8 @@ public interface StringRulesOrBuilder extends * ```proto * message MyString { * string value = 1 [ - * (buf.validate.field).string.example = 1, - * (buf.validate.field).string.example = 2 + * (buf.validate.field).string.example = "hello", + * (buf.validate.field).string.example = "world" * ]; * } * ``` @@ -1537,8 +1537,8 @@ public interface StringRulesOrBuilder extends * ```proto * message MyString { * string value = 1 [ - * (buf.validate.field).string.example = 1, - * (buf.validate.field).string.example = 2 + * (buf.validate.field).string.example = "hello", + * (buf.validate.field).string.example = "world" * ]; * } * ``` diff --git a/src/main/java/build/buf/validate/ValidateProto.java b/src/main/java/build/buf/validate/ValidateProto.java index d7130493..85dfeac8 100644 --- a/src/main/java/build/buf/validate/ValidateProto.java +++ b/src/main/java/build/buf/validate/ValidateProto.java @@ -247,6 +247,16 @@ public static void registerAllExtensions( static final com.google.protobuf.GeneratedMessage.FieldAccessorTable internal_static_buf_validate_Violation_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_buf_validate_FieldPath_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_buf_validate_FieldPath_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_buf_validate_FieldPathElement_descriptor; + static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_buf_validate_FieldPathElement_fieldAccessorTable; public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { @@ -1572,29 +1582,45 @@ public static void registerAllExtensions( "B\036\302H\033\n\031\n\021timestamp.example\032\004trueR\007exampl" + "e*\t\010\350\007\020\200\200\200\200\002B\013\n\tless_thanB\016\n\014greater_tha" + "n\"E\n\nViolations\0227\n\nviolations\030\001 \003(\0132\027.bu" + - "f.validate.ViolationR\nviolations\"\202\001\n\tVio" + - "lation\022\035\n\nfield_path\030\001 \001(\tR\tfieldPath\022#\n" + - "\rconstraint_id\030\002 \001(\tR\014constraintId\022\030\n\007me" + - "ssage\030\003 \001(\tR\007message\022\027\n\007for_key\030\004 \001(\010R\006f" + - "orKey*\235\001\n\006Ignore\022\026\n\022IGNORE_UNSPECIFIED\020\000" + - "\022\031\n\025IGNORE_IF_UNPOPULATED\020\001\022\033\n\027IGNORE_IF" + - "_DEFAULT_VALUE\020\002\022\021\n\rIGNORE_ALWAYS\020\003\022\024\n\014I" + - "GNORE_EMPTY\020\001\032\002\010\001\022\026\n\016IGNORE_DEFAULT\020\002\032\002\010" + - "\001\032\002\020\001*n\n\nKnownRegex\022\033\n\027KNOWN_REGEX_UNSPE" + - "CIFIED\020\000\022 \n\034KNOWN_REGEX_HTTP_HEADER_NAME" + - "\020\001\022!\n\035KNOWN_REGEX_HTTP_HEADER_VALUE\020\002:\\\n" + - "\007message\022\037.google.protobuf.MessageOption" + - "s\030\207\t \001(\0132 .buf.validate.MessageConstrain" + - "tsR\007message:T\n\005oneof\022\035.google.protobuf.O" + - "neofOptions\030\207\t \001(\0132\036.buf.validate.OneofC" + - "onstraintsR\005oneof:T\n\005field\022\035.google.prot" + - "obuf.FieldOptions\030\207\t \001(\0132\036.buf.validate." + - "FieldConstraintsR\005field:c\n\npredefined\022\035." + - "google.protobuf.FieldOptions\030\210\t \001(\0132#.bu" + - "f.validate.PredefinedConstraintsR\npredef" + - "inedBn\n\022build.buf.validateB\rValidateProt" + - "oP\001ZGbuf.build/gen/go/bufbuild/protovali" + - "date/protocolbuffers/go/buf/validate" + "f.validate.ViolationR\nviolations\"\342\001\n\tVio" + + "lation\022-\n\005field\030\005 \001(\0132\027.buf.validate.Fie" + + "ldPathR\005field\022+\n\004rule\030\006 \001(\0132\027.buf.valida" + + "te.FieldPathR\004rule\022!\n\nfield_path\030\001 \001(\tB\002" + + "\030\001R\tfieldPath\022#\n\rconstraint_id\030\002 \001(\tR\014co" + + "nstraintId\022\030\n\007message\030\003 \001(\tR\007message\022\027\n\007" + + "for_key\030\004 \001(\010R\006forKey\"G\n\tFieldPath\022:\n\010el" + + "ements\030\001 \003(\0132\036.buf.validate.FieldPathEle" + + "mentR\010elements\"\314\003\n\020FieldPathElement\022!\n\014f" + + "ield_number\030\001 \001(\005R\013fieldNumber\022\035\n\nfield_" + + "name\030\002 \001(\tR\tfieldName\022I\n\nfield_type\030\003 \001(" + + "\0162*.google.protobuf.FieldDescriptorProto" + + ".TypeR\tfieldType\022E\n\010key_type\030\004 \001(\0162*.goo" + + "gle.protobuf.FieldDescriptorProto.TypeR\007" + + "keyType\022I\n\nvalue_type\030\005 \001(\0162*.google.pro" + + "tobuf.FieldDescriptorProto.TypeR\tvalueTy" + + "pe\022\026\n\005index\030\006 \001(\004H\000R\005index\022\033\n\010bool_key\030\007" + + " \001(\010H\000R\007boolKey\022\031\n\007int_key\030\010 \001(\003H\000R\006intK" + + "ey\022\033\n\010uint_key\030\t \001(\004H\000R\007uintKey\022\037\n\nstrin" + + "g_key\030\n \001(\tH\000R\tstringKeyB\013\n\tsubscript*\235\001" + + "\n\006Ignore\022\026\n\022IGNORE_UNSPECIFIED\020\000\022\031\n\025IGNO" + + "RE_IF_UNPOPULATED\020\001\022\033\n\027IGNORE_IF_DEFAULT" + + "_VALUE\020\002\022\021\n\rIGNORE_ALWAYS\020\003\022\024\n\014IGNORE_EM" + + "PTY\020\001\032\002\010\001\022\026\n\016IGNORE_DEFAULT\020\002\032\002\010\001\032\002\020\001*n\n" + + "\nKnownRegex\022\033\n\027KNOWN_REGEX_UNSPECIFIED\020\000" + + "\022 \n\034KNOWN_REGEX_HTTP_HEADER_NAME\020\001\022!\n\035KN" + + "OWN_REGEX_HTTP_HEADER_VALUE\020\002:\\\n\007message" + + "\022\037.google.protobuf.MessageOptions\030\207\t \001(\013" + + "2 .buf.validate.MessageConstraintsR\007mess" + + "age:T\n\005oneof\022\035.google.protobuf.OneofOpti" + + "ons\030\207\t \001(\0132\036.buf.validate.OneofConstrain" + + "tsR\005oneof:T\n\005field\022\035.google.protobuf.Fie" + + "ldOptions\030\207\t \001(\0132\036.buf.validate.FieldCon" + + "straintsR\005field:c\n\npredefined\022\035.google.p" + + "rotobuf.FieldOptions\030\210\t \001(\0132#.buf.valida" + + "te.PredefinedConstraintsR\npredefinedBn\n\022" + + "build.buf.validateB\rValidateProtoP\001ZGbuf" + + ".build/gen/go/bufbuild/protovalidate/pro" + + "tocolbuffers/go/buf/validate" }; descriptor = com.google.protobuf.Descriptors.FileDescriptor .internalBuildGeneratedFileFrom(descriptorData, @@ -1770,7 +1796,19 @@ public static void registerAllExtensions( internal_static_buf_validate_Violation_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_buf_validate_Violation_descriptor, - new java.lang.String[] { "FieldPath", "ConstraintId", "Message", "ForKey", }); + new java.lang.String[] { "Field", "Rule", "FieldPath", "ConstraintId", "Message", "ForKey", }); + internal_static_buf_validate_FieldPath_descriptor = + getDescriptor().getMessageTypes().get(28); + internal_static_buf_validate_FieldPath_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_buf_validate_FieldPath_descriptor, + new java.lang.String[] { "Elements", }); + internal_static_buf_validate_FieldPathElement_descriptor = + getDescriptor().getMessageTypes().get(29); + internal_static_buf_validate_FieldPathElement_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_buf_validate_FieldPathElement_descriptor, + new java.lang.String[] { "FieldNumber", "FieldName", "FieldType", "KeyType", "ValueType", "Index", "BoolKey", "IntKey", "UintKey", "StringKey", "Subscript", }); message.internalInit(descriptor.getExtensions().get(0)); oneof.internalInit(descriptor.getExtensions().get(1)); field.internalInit(descriptor.getExtensions().get(2)); diff --git a/src/main/java/build/buf/validate/Violation.java b/src/main/java/build/buf/validate/Violation.java index c1df7ed9..02b45e59 100644 --- a/src/main/java/build/buf/validate/Violation.java +++ b/src/main/java/build/buf/validate/Violation.java @@ -61,33 +61,252 @@ private Violation() { } private int bitField0_; + public static final int FIELD_FIELD_NUMBER = 5; + private build.buf.validate.FieldPath field_; + /** + *
+   * `field` is a machine-readable path to the field that failed validation.
+   * This could be a nested field, in which case the path will include all the parent fields leading to the actual field that caused the violation.
+   *
+   * For example, consider the following message:
+   *
+   * ```proto
+   * message Message {
+   * bool a = 1 [(buf.validate.field).required = true];
+   * }
+   * ```
+   *
+   * It could produce the following violation:
+   *
+   * ```textproto
+   * violation {
+   * field { element { field_number: 1, field_name: "a", field_type: 8 } }
+   * ...
+   * }
+   * ```
+   * 
+ * + * optional .buf.validate.FieldPath field = 5 [json_name = "field"]; + * @return Whether the field field is set. + */ + @java.lang.Override + public boolean hasField() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + *
+   * `field` is a machine-readable path to the field that failed validation.
+   * This could be a nested field, in which case the path will include all the parent fields leading to the actual field that caused the violation.
+   *
+   * For example, consider the following message:
+   *
+   * ```proto
+   * message Message {
+   * bool a = 1 [(buf.validate.field).required = true];
+   * }
+   * ```
+   *
+   * It could produce the following violation:
+   *
+   * ```textproto
+   * violation {
+   * field { element { field_number: 1, field_name: "a", field_type: 8 } }
+   * ...
+   * }
+   * ```
+   * 
+ * + * optional .buf.validate.FieldPath field = 5 [json_name = "field"]; + * @return The field. + */ + @java.lang.Override + public build.buf.validate.FieldPath getField() { + return field_ == null ? build.buf.validate.FieldPath.getDefaultInstance() : field_; + } + /** + *
+   * `field` is a machine-readable path to the field that failed validation.
+   * This could be a nested field, in which case the path will include all the parent fields leading to the actual field that caused the violation.
+   *
+   * For example, consider the following message:
+   *
+   * ```proto
+   * message Message {
+   * bool a = 1 [(buf.validate.field).required = true];
+   * }
+   * ```
+   *
+   * It could produce the following violation:
+   *
+   * ```textproto
+   * violation {
+   * field { element { field_number: 1, field_name: "a", field_type: 8 } }
+   * ...
+   * }
+   * ```
+   * 
+ * + * optional .buf.validate.FieldPath field = 5 [json_name = "field"]; + */ + @java.lang.Override + public build.buf.validate.FieldPathOrBuilder getFieldOrBuilder() { + return field_ == null ? build.buf.validate.FieldPath.getDefaultInstance() : field_; + } + + public static final int RULE_FIELD_NUMBER = 6; + private build.buf.validate.FieldPath rule_; + /** + *
+   * `rule` is a machine-readable path that points to the specific constraint rule that failed validation.
+   * This will be a nested field starting from the FieldConstraints of the field that failed validation.
+   * For custom constraints, this will provide the path of the constraint, e.g. `cel[0]`.
+   *
+   * For example, consider the following message:
+   *
+   * ```proto
+   * message Message {
+   * bool a = 1 [(buf.validate.field).required = true];
+   * bool b = 2 [(buf.validate.field).cel = {
+   * id: "custom_constraint",
+   * expression: "!this ? 'b must be true': ''"
+   * }]
+   * }
+   * ```
+   *
+   * It could produce the following violations:
+   *
+   * ```textproto
+   * violation {
+   * rule { element { field_number: 25, field_name: "required", field_type: 8 } }
+   * ...
+   * }
+   * violation {
+   * rule { element { field_number: 23, field_name: "cel", field_type: 11, index: 0 } }
+   * ...
+   * }
+   * ```
+   * 
+ * + * optional .buf.validate.FieldPath rule = 6 [json_name = "rule"]; + * @return Whether the rule field is set. + */ + @java.lang.Override + public boolean hasRule() { + return ((bitField0_ & 0x00000002) != 0); + } + /** + *
+   * `rule` is a machine-readable path that points to the specific constraint rule that failed validation.
+   * This will be a nested field starting from the FieldConstraints of the field that failed validation.
+   * For custom constraints, this will provide the path of the constraint, e.g. `cel[0]`.
+   *
+   * For example, consider the following message:
+   *
+   * ```proto
+   * message Message {
+   * bool a = 1 [(buf.validate.field).required = true];
+   * bool b = 2 [(buf.validate.field).cel = {
+   * id: "custom_constraint",
+   * expression: "!this ? 'b must be true': ''"
+   * }]
+   * }
+   * ```
+   *
+   * It could produce the following violations:
+   *
+   * ```textproto
+   * violation {
+   * rule { element { field_number: 25, field_name: "required", field_type: 8 } }
+   * ...
+   * }
+   * violation {
+   * rule { element { field_number: 23, field_name: "cel", field_type: 11, index: 0 } }
+   * ...
+   * }
+   * ```
+   * 
+ * + * optional .buf.validate.FieldPath rule = 6 [json_name = "rule"]; + * @return The rule. + */ + @java.lang.Override + public build.buf.validate.FieldPath getRule() { + return rule_ == null ? build.buf.validate.FieldPath.getDefaultInstance() : rule_; + } + /** + *
+   * `rule` is a machine-readable path that points to the specific constraint rule that failed validation.
+   * This will be a nested field starting from the FieldConstraints of the field that failed validation.
+   * For custom constraints, this will provide the path of the constraint, e.g. `cel[0]`.
+   *
+   * For example, consider the following message:
+   *
+   * ```proto
+   * message Message {
+   * bool a = 1 [(buf.validate.field).required = true];
+   * bool b = 2 [(buf.validate.field).cel = {
+   * id: "custom_constraint",
+   * expression: "!this ? 'b must be true': ''"
+   * }]
+   * }
+   * ```
+   *
+   * It could produce the following violations:
+   *
+   * ```textproto
+   * violation {
+   * rule { element { field_number: 25, field_name: "required", field_type: 8 } }
+   * ...
+   * }
+   * violation {
+   * rule { element { field_number: 23, field_name: "cel", field_type: 11, index: 0 } }
+   * ...
+   * }
+   * ```
+   * 
+ * + * optional .buf.validate.FieldPath rule = 6 [json_name = "rule"]; + */ + @java.lang.Override + public build.buf.validate.FieldPathOrBuilder getRuleOrBuilder() { + return rule_ == null ? build.buf.validate.FieldPath.getDefaultInstance() : rule_; + } + public static final int FIELD_PATH_FIELD_NUMBER = 1; @SuppressWarnings("serial") private volatile java.lang.Object fieldPath_ = ""; /** *
-   * `field_path` is a machine-readable identifier that points to the specific field that failed the validation.
+   * `field_path` is a human-readable identifier that points to the specific field that failed the validation.
    * This could be a nested field, in which case the path will include all the parent fields leading to the actual field that caused the violation.
+   *
+   * Deprecated: use the `field` instead.
    * 
* - * optional string field_path = 1 [json_name = "fieldPath"]; + * optional string field_path = 1 [json_name = "fieldPath", deprecated = true]; + * @deprecated buf.validate.Violation.field_path is deprecated. + * See buf/validate/validate.proto;l=4827 * @return Whether the fieldPath field is set. */ @java.lang.Override - public boolean hasFieldPath() { - return ((bitField0_ & 0x00000001) != 0); + @java.lang.Deprecated public boolean hasFieldPath() { + return ((bitField0_ & 0x00000004) != 0); } /** *
-   * `field_path` is a machine-readable identifier that points to the specific field that failed the validation.
+   * `field_path` is a human-readable identifier that points to the specific field that failed the validation.
    * This could be a nested field, in which case the path will include all the parent fields leading to the actual field that caused the violation.
+   *
+   * Deprecated: use the `field` instead.
    * 
* - * optional string field_path = 1 [json_name = "fieldPath"]; + * optional string field_path = 1 [json_name = "fieldPath", deprecated = true]; + * @deprecated buf.validate.Violation.field_path is deprecated. + * See buf/validate/validate.proto;l=4827 * @return The fieldPath. */ @java.lang.Override - public java.lang.String getFieldPath() { + @java.lang.Deprecated public java.lang.String getFieldPath() { java.lang.Object ref = fieldPath_; if (ref instanceof java.lang.String) { return (java.lang.String) ref; @@ -103,15 +322,19 @@ public java.lang.String getFieldPath() { } /** *
-   * `field_path` is a machine-readable identifier that points to the specific field that failed the validation.
+   * `field_path` is a human-readable identifier that points to the specific field that failed the validation.
    * This could be a nested field, in which case the path will include all the parent fields leading to the actual field that caused the violation.
+   *
+   * Deprecated: use the `field` instead.
    * 
* - * optional string field_path = 1 [json_name = "fieldPath"]; + * optional string field_path = 1 [json_name = "fieldPath", deprecated = true]; + * @deprecated buf.validate.Violation.field_path is deprecated. + * See buf/validate/validate.proto;l=4827 * @return The bytes for fieldPath. */ @java.lang.Override - public com.google.protobuf.ByteString + @java.lang.Deprecated public com.google.protobuf.ByteString getFieldPathBytes() { java.lang.Object ref = fieldPath_; if (ref instanceof java.lang.String) { @@ -139,7 +362,7 @@ public java.lang.String getFieldPath() { */ @java.lang.Override public boolean hasConstraintId() { - return ((bitField0_ & 0x00000002) != 0); + return ((bitField0_ & 0x00000008) != 0); } /** *
@@ -203,7 +426,7 @@ public java.lang.String getConstraintId() {
    */
   @java.lang.Override
   public boolean hasMessage() {
-    return ((bitField0_ & 0x00000004) != 0);
+    return ((bitField0_ & 0x00000010) != 0);
   }
   /**
    * 
@@ -265,7 +488,7 @@ public java.lang.String getMessage() {
    */
   @java.lang.Override
   public boolean hasForKey() {
-    return ((bitField0_ & 0x00000008) != 0);
+    return ((bitField0_ & 0x00000020) != 0);
   }
   /**
    * 
@@ -294,18 +517,24 @@ public final boolean isInitialized() {
   @java.lang.Override
   public void writeTo(com.google.protobuf.CodedOutputStream output)
                       throws java.io.IOException {
-    if (((bitField0_ & 0x00000001) != 0)) {
+    if (((bitField0_ & 0x00000004) != 0)) {
       com.google.protobuf.GeneratedMessage.writeString(output, 1, fieldPath_);
     }
-    if (((bitField0_ & 0x00000002) != 0)) {
+    if (((bitField0_ & 0x00000008) != 0)) {
       com.google.protobuf.GeneratedMessage.writeString(output, 2, constraintId_);
     }
-    if (((bitField0_ & 0x00000004) != 0)) {
+    if (((bitField0_ & 0x00000010) != 0)) {
       com.google.protobuf.GeneratedMessage.writeString(output, 3, message_);
     }
-    if (((bitField0_ & 0x00000008) != 0)) {
+    if (((bitField0_ & 0x00000020) != 0)) {
       output.writeBool(4, forKey_);
     }
+    if (((bitField0_ & 0x00000001) != 0)) {
+      output.writeMessage(5, getField());
+    }
+    if (((bitField0_ & 0x00000002) != 0)) {
+      output.writeMessage(6, getRule());
+    }
     getUnknownFields().writeTo(output);
   }
 
@@ -315,19 +544,27 @@ public int getSerializedSize() {
     if (size != -1) return size;
 
     size = 0;
-    if (((bitField0_ & 0x00000001) != 0)) {
+    if (((bitField0_ & 0x00000004) != 0)) {
       size += com.google.protobuf.GeneratedMessage.computeStringSize(1, fieldPath_);
     }
-    if (((bitField0_ & 0x00000002) != 0)) {
+    if (((bitField0_ & 0x00000008) != 0)) {
       size += com.google.protobuf.GeneratedMessage.computeStringSize(2, constraintId_);
     }
-    if (((bitField0_ & 0x00000004) != 0)) {
+    if (((bitField0_ & 0x00000010) != 0)) {
       size += com.google.protobuf.GeneratedMessage.computeStringSize(3, message_);
     }
-    if (((bitField0_ & 0x00000008) != 0)) {
+    if (((bitField0_ & 0x00000020) != 0)) {
       size += com.google.protobuf.CodedOutputStream
         .computeBoolSize(4, forKey_);
     }
+    if (((bitField0_ & 0x00000001) != 0)) {
+      size += com.google.protobuf.CodedOutputStream
+        .computeMessageSize(5, getField());
+    }
+    if (((bitField0_ & 0x00000002) != 0)) {
+      size += com.google.protobuf.CodedOutputStream
+        .computeMessageSize(6, getRule());
+    }
     size += getUnknownFields().getSerializedSize();
     memoizedSize = size;
     return size;
@@ -343,6 +580,16 @@ public boolean equals(final java.lang.Object obj) {
     }
     build.buf.validate.Violation other = (build.buf.validate.Violation) obj;
 
+    if (hasField() != other.hasField()) return false;
+    if (hasField()) {
+      if (!getField()
+          .equals(other.getField())) return false;
+    }
+    if (hasRule() != other.hasRule()) return false;
+    if (hasRule()) {
+      if (!getRule()
+          .equals(other.getRule())) return false;
+    }
     if (hasFieldPath() != other.hasFieldPath()) return false;
     if (hasFieldPath()) {
       if (!getFieldPath()
@@ -374,6 +621,14 @@ public int hashCode() {
     }
     int hash = 41;
     hash = (19 * hash) + getDescriptor().hashCode();
+    if (hasField()) {
+      hash = (37 * hash) + FIELD_FIELD_NUMBER;
+      hash = (53 * hash) + getField().hashCode();
+    }
+    if (hasRule()) {
+      hash = (37 * hash) + RULE_FIELD_NUMBER;
+      hash = (53 * hash) + getRule().hashCode();
+    }
     if (hasFieldPath()) {
       hash = (37 * hash) + FIELD_PATH_FIELD_NUMBER;
       hash = (53 * hash) + getFieldPath().hashCode();
@@ -525,18 +780,35 @@ public static final class Builder extends
 
     // Construct using build.buf.validate.Violation.newBuilder()
     private Builder() {
-
+      maybeForceBuilderInitialization();
     }
 
     private Builder(
         com.google.protobuf.GeneratedMessage.BuilderParent parent) {
       super(parent);
-
+      maybeForceBuilderInitialization();
+    }
+    private void maybeForceBuilderInitialization() {
+      if (com.google.protobuf.GeneratedMessage
+              .alwaysUseFieldBuilders) {
+        getFieldFieldBuilder();
+        getRuleFieldBuilder();
+      }
     }
     @java.lang.Override
     public Builder clear() {
       super.clear();
       bitField0_ = 0;
+      field_ = null;
+      if (fieldBuilder_ != null) {
+        fieldBuilder_.dispose();
+        fieldBuilder_ = null;
+      }
+      rule_ = null;
+      if (ruleBuilder_ != null) {
+        ruleBuilder_.dispose();
+        ruleBuilder_ = null;
+      }
       fieldPath_ = "";
       constraintId_ = "";
       message_ = "";
@@ -576,21 +848,33 @@ private void buildPartial0(build.buf.validate.Violation result) {
       int from_bitField0_ = bitField0_;
       int to_bitField0_ = 0;
       if (((from_bitField0_ & 0x00000001) != 0)) {
-        result.fieldPath_ = fieldPath_;
+        result.field_ = fieldBuilder_ == null
+            ? field_
+            : fieldBuilder_.build();
         to_bitField0_ |= 0x00000001;
       }
       if (((from_bitField0_ & 0x00000002) != 0)) {
-        result.constraintId_ = constraintId_;
+        result.rule_ = ruleBuilder_ == null
+            ? rule_
+            : ruleBuilder_.build();
         to_bitField0_ |= 0x00000002;
       }
       if (((from_bitField0_ & 0x00000004) != 0)) {
-        result.message_ = message_;
+        result.fieldPath_ = fieldPath_;
         to_bitField0_ |= 0x00000004;
       }
       if (((from_bitField0_ & 0x00000008) != 0)) {
-        result.forKey_ = forKey_;
+        result.constraintId_ = constraintId_;
         to_bitField0_ |= 0x00000008;
       }
+      if (((from_bitField0_ & 0x00000010) != 0)) {
+        result.message_ = message_;
+        to_bitField0_ |= 0x00000010;
+      }
+      if (((from_bitField0_ & 0x00000020) != 0)) {
+        result.forKey_ = forKey_;
+        to_bitField0_ |= 0x00000020;
+      }
       result.bitField0_ |= to_bitField0_;
     }
 
@@ -606,19 +890,25 @@ public Builder mergeFrom(com.google.protobuf.Message other) {
 
     public Builder mergeFrom(build.buf.validate.Violation other) {
       if (other == build.buf.validate.Violation.getDefaultInstance()) return this;
+      if (other.hasField()) {
+        mergeField(other.getField());
+      }
+      if (other.hasRule()) {
+        mergeRule(other.getRule());
+      }
       if (other.hasFieldPath()) {
         fieldPath_ = other.fieldPath_;
-        bitField0_ |= 0x00000001;
+        bitField0_ |= 0x00000004;
         onChanged();
       }
       if (other.hasConstraintId()) {
         constraintId_ = other.constraintId_;
-        bitField0_ |= 0x00000002;
+        bitField0_ |= 0x00000008;
         onChanged();
       }
       if (other.hasMessage()) {
         message_ = other.message_;
-        bitField0_ |= 0x00000004;
+        bitField0_ |= 0x00000010;
         onChanged();
       }
       if (other.hasForKey()) {
@@ -652,24 +942,38 @@ public Builder mergeFrom(
               break;
             case 10: {
               fieldPath_ = input.readBytes();
-              bitField0_ |= 0x00000001;
+              bitField0_ |= 0x00000004;
               break;
             } // case 10
             case 18: {
               constraintId_ = input.readBytes();
-              bitField0_ |= 0x00000002;
+              bitField0_ |= 0x00000008;
               break;
             } // case 18
             case 26: {
               message_ = input.readBytes();
-              bitField0_ |= 0x00000004;
+              bitField0_ |= 0x00000010;
               break;
             } // case 26
             case 32: {
               forKey_ = input.readBool();
-              bitField0_ |= 0x00000008;
+              bitField0_ |= 0x00000020;
               break;
             } // case 32
+            case 42: {
+              input.readMessage(
+                  getFieldFieldBuilder().getBuilder(),
+                  extensionRegistry);
+              bitField0_ |= 0x00000001;
+              break;
+            } // case 42
+            case 50: {
+              input.readMessage(
+                  getRuleFieldBuilder().getBuilder(),
+                  extensionRegistry);
+              bitField0_ |= 0x00000002;
+              break;
+            } // case 50
             default: {
               if (!super.parseUnknownField(input, extensionRegistry, tag)) {
                 done = true; // was an endgroup tag
@@ -687,29 +991,756 @@ public Builder mergeFrom(
     }
     private int bitField0_;
 
+    private build.buf.validate.FieldPath field_;
+    private com.google.protobuf.SingleFieldBuilder<
+        build.buf.validate.FieldPath, build.buf.validate.FieldPath.Builder, build.buf.validate.FieldPathOrBuilder> fieldBuilder_;
+    /**
+     * 
+     * `field` is a machine-readable path to the field that failed validation.
+     * This could be a nested field, in which case the path will include all the parent fields leading to the actual field that caused the violation.
+     *
+     * For example, consider the following message:
+     *
+     * ```proto
+     * message Message {
+     * bool a = 1 [(buf.validate.field).required = true];
+     * }
+     * ```
+     *
+     * It could produce the following violation:
+     *
+     * ```textproto
+     * violation {
+     * field { element { field_number: 1, field_name: "a", field_type: 8 } }
+     * ...
+     * }
+     * ```
+     * 
+ * + * optional .buf.validate.FieldPath field = 5 [json_name = "field"]; + * @return Whether the field field is set. + */ + public boolean hasField() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + *
+     * `field` is a machine-readable path to the field that failed validation.
+     * This could be a nested field, in which case the path will include all the parent fields leading to the actual field that caused the violation.
+     *
+     * For example, consider the following message:
+     *
+     * ```proto
+     * message Message {
+     * bool a = 1 [(buf.validate.field).required = true];
+     * }
+     * ```
+     *
+     * It could produce the following violation:
+     *
+     * ```textproto
+     * violation {
+     * field { element { field_number: 1, field_name: "a", field_type: 8 } }
+     * ...
+     * }
+     * ```
+     * 
+ * + * optional .buf.validate.FieldPath field = 5 [json_name = "field"]; + * @return The field. + */ + public build.buf.validate.FieldPath getField() { + if (fieldBuilder_ == null) { + return field_ == null ? build.buf.validate.FieldPath.getDefaultInstance() : field_; + } else { + return fieldBuilder_.getMessage(); + } + } + /** + *
+     * `field` is a machine-readable path to the field that failed validation.
+     * This could be a nested field, in which case the path will include all the parent fields leading to the actual field that caused the violation.
+     *
+     * For example, consider the following message:
+     *
+     * ```proto
+     * message Message {
+     * bool a = 1 [(buf.validate.field).required = true];
+     * }
+     * ```
+     *
+     * It could produce the following violation:
+     *
+     * ```textproto
+     * violation {
+     * field { element { field_number: 1, field_name: "a", field_type: 8 } }
+     * ...
+     * }
+     * ```
+     * 
+ * + * optional .buf.validate.FieldPath field = 5 [json_name = "field"]; + */ + public Builder setField(build.buf.validate.FieldPath value) { + if (fieldBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + field_ = value; + } else { + fieldBuilder_.setMessage(value); + } + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * `field` is a machine-readable path to the field that failed validation.
+     * This could be a nested field, in which case the path will include all the parent fields leading to the actual field that caused the violation.
+     *
+     * For example, consider the following message:
+     *
+     * ```proto
+     * message Message {
+     * bool a = 1 [(buf.validate.field).required = true];
+     * }
+     * ```
+     *
+     * It could produce the following violation:
+     *
+     * ```textproto
+     * violation {
+     * field { element { field_number: 1, field_name: "a", field_type: 8 } }
+     * ...
+     * }
+     * ```
+     * 
+ * + * optional .buf.validate.FieldPath field = 5 [json_name = "field"]; + */ + public Builder setField( + build.buf.validate.FieldPath.Builder builderForValue) { + if (fieldBuilder_ == null) { + field_ = builderForValue.build(); + } else { + fieldBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + *
+     * `field` is a machine-readable path to the field that failed validation.
+     * This could be a nested field, in which case the path will include all the parent fields leading to the actual field that caused the violation.
+     *
+     * For example, consider the following message:
+     *
+     * ```proto
+     * message Message {
+     * bool a = 1 [(buf.validate.field).required = true];
+     * }
+     * ```
+     *
+     * It could produce the following violation:
+     *
+     * ```textproto
+     * violation {
+     * field { element { field_number: 1, field_name: "a", field_type: 8 } }
+     * ...
+     * }
+     * ```
+     * 
+ * + * optional .buf.validate.FieldPath field = 5 [json_name = "field"]; + */ + public Builder mergeField(build.buf.validate.FieldPath value) { + if (fieldBuilder_ == null) { + if (((bitField0_ & 0x00000001) != 0) && + field_ != null && + field_ != build.buf.validate.FieldPath.getDefaultInstance()) { + getFieldBuilder().mergeFrom(value); + } else { + field_ = value; + } + } else { + fieldBuilder_.mergeFrom(value); + } + if (field_ != null) { + bitField0_ |= 0x00000001; + onChanged(); + } + return this; + } + /** + *
+     * `field` is a machine-readable path to the field that failed validation.
+     * This could be a nested field, in which case the path will include all the parent fields leading to the actual field that caused the violation.
+     *
+     * For example, consider the following message:
+     *
+     * ```proto
+     * message Message {
+     * bool a = 1 [(buf.validate.field).required = true];
+     * }
+     * ```
+     *
+     * It could produce the following violation:
+     *
+     * ```textproto
+     * violation {
+     * field { element { field_number: 1, field_name: "a", field_type: 8 } }
+     * ...
+     * }
+     * ```
+     * 
+ * + * optional .buf.validate.FieldPath field = 5 [json_name = "field"]; + */ + public Builder clearField() { + bitField0_ = (bitField0_ & ~0x00000001); + field_ = null; + if (fieldBuilder_ != null) { + fieldBuilder_.dispose(); + fieldBuilder_ = null; + } + onChanged(); + return this; + } + /** + *
+     * `field` is a machine-readable path to the field that failed validation.
+     * This could be a nested field, in which case the path will include all the parent fields leading to the actual field that caused the violation.
+     *
+     * For example, consider the following message:
+     *
+     * ```proto
+     * message Message {
+     * bool a = 1 [(buf.validate.field).required = true];
+     * }
+     * ```
+     *
+     * It could produce the following violation:
+     *
+     * ```textproto
+     * violation {
+     * field { element { field_number: 1, field_name: "a", field_type: 8 } }
+     * ...
+     * }
+     * ```
+     * 
+ * + * optional .buf.validate.FieldPath field = 5 [json_name = "field"]; + */ + public build.buf.validate.FieldPath.Builder getFieldBuilder() { + bitField0_ |= 0x00000001; + onChanged(); + return getFieldFieldBuilder().getBuilder(); + } + /** + *
+     * `field` is a machine-readable path to the field that failed validation.
+     * This could be a nested field, in which case the path will include all the parent fields leading to the actual field that caused the violation.
+     *
+     * For example, consider the following message:
+     *
+     * ```proto
+     * message Message {
+     * bool a = 1 [(buf.validate.field).required = true];
+     * }
+     * ```
+     *
+     * It could produce the following violation:
+     *
+     * ```textproto
+     * violation {
+     * field { element { field_number: 1, field_name: "a", field_type: 8 } }
+     * ...
+     * }
+     * ```
+     * 
+ * + * optional .buf.validate.FieldPath field = 5 [json_name = "field"]; + */ + public build.buf.validate.FieldPathOrBuilder getFieldOrBuilder() { + if (fieldBuilder_ != null) { + return fieldBuilder_.getMessageOrBuilder(); + } else { + return field_ == null ? + build.buf.validate.FieldPath.getDefaultInstance() : field_; + } + } + /** + *
+     * `field` is a machine-readable path to the field that failed validation.
+     * This could be a nested field, in which case the path will include all the parent fields leading to the actual field that caused the violation.
+     *
+     * For example, consider the following message:
+     *
+     * ```proto
+     * message Message {
+     * bool a = 1 [(buf.validate.field).required = true];
+     * }
+     * ```
+     *
+     * It could produce the following violation:
+     *
+     * ```textproto
+     * violation {
+     * field { element { field_number: 1, field_name: "a", field_type: 8 } }
+     * ...
+     * }
+     * ```
+     * 
+ * + * optional .buf.validate.FieldPath field = 5 [json_name = "field"]; + */ + private com.google.protobuf.SingleFieldBuilder< + build.buf.validate.FieldPath, build.buf.validate.FieldPath.Builder, build.buf.validate.FieldPathOrBuilder> + getFieldFieldBuilder() { + if (fieldBuilder_ == null) { + fieldBuilder_ = new com.google.protobuf.SingleFieldBuilder< + build.buf.validate.FieldPath, build.buf.validate.FieldPath.Builder, build.buf.validate.FieldPathOrBuilder>( + getField(), + getParentForChildren(), + isClean()); + field_ = null; + } + return fieldBuilder_; + } + + private build.buf.validate.FieldPath rule_; + private com.google.protobuf.SingleFieldBuilder< + build.buf.validate.FieldPath, build.buf.validate.FieldPath.Builder, build.buf.validate.FieldPathOrBuilder> ruleBuilder_; + /** + *
+     * `rule` is a machine-readable path that points to the specific constraint rule that failed validation.
+     * This will be a nested field starting from the FieldConstraints of the field that failed validation.
+     * For custom constraints, this will provide the path of the constraint, e.g. `cel[0]`.
+     *
+     * For example, consider the following message:
+     *
+     * ```proto
+     * message Message {
+     * bool a = 1 [(buf.validate.field).required = true];
+     * bool b = 2 [(buf.validate.field).cel = {
+     * id: "custom_constraint",
+     * expression: "!this ? 'b must be true': ''"
+     * }]
+     * }
+     * ```
+     *
+     * It could produce the following violations:
+     *
+     * ```textproto
+     * violation {
+     * rule { element { field_number: 25, field_name: "required", field_type: 8 } }
+     * ...
+     * }
+     * violation {
+     * rule { element { field_number: 23, field_name: "cel", field_type: 11, index: 0 } }
+     * ...
+     * }
+     * ```
+     * 
+ * + * optional .buf.validate.FieldPath rule = 6 [json_name = "rule"]; + * @return Whether the rule field is set. + */ + public boolean hasRule() { + return ((bitField0_ & 0x00000002) != 0); + } + /** + *
+     * `rule` is a machine-readable path that points to the specific constraint rule that failed validation.
+     * This will be a nested field starting from the FieldConstraints of the field that failed validation.
+     * For custom constraints, this will provide the path of the constraint, e.g. `cel[0]`.
+     *
+     * For example, consider the following message:
+     *
+     * ```proto
+     * message Message {
+     * bool a = 1 [(buf.validate.field).required = true];
+     * bool b = 2 [(buf.validate.field).cel = {
+     * id: "custom_constraint",
+     * expression: "!this ? 'b must be true': ''"
+     * }]
+     * }
+     * ```
+     *
+     * It could produce the following violations:
+     *
+     * ```textproto
+     * violation {
+     * rule { element { field_number: 25, field_name: "required", field_type: 8 } }
+     * ...
+     * }
+     * violation {
+     * rule { element { field_number: 23, field_name: "cel", field_type: 11, index: 0 } }
+     * ...
+     * }
+     * ```
+     * 
+ * + * optional .buf.validate.FieldPath rule = 6 [json_name = "rule"]; + * @return The rule. + */ + public build.buf.validate.FieldPath getRule() { + if (ruleBuilder_ == null) { + return rule_ == null ? build.buf.validate.FieldPath.getDefaultInstance() : rule_; + } else { + return ruleBuilder_.getMessage(); + } + } + /** + *
+     * `rule` is a machine-readable path that points to the specific constraint rule that failed validation.
+     * This will be a nested field starting from the FieldConstraints of the field that failed validation.
+     * For custom constraints, this will provide the path of the constraint, e.g. `cel[0]`.
+     *
+     * For example, consider the following message:
+     *
+     * ```proto
+     * message Message {
+     * bool a = 1 [(buf.validate.field).required = true];
+     * bool b = 2 [(buf.validate.field).cel = {
+     * id: "custom_constraint",
+     * expression: "!this ? 'b must be true': ''"
+     * }]
+     * }
+     * ```
+     *
+     * It could produce the following violations:
+     *
+     * ```textproto
+     * violation {
+     * rule { element { field_number: 25, field_name: "required", field_type: 8 } }
+     * ...
+     * }
+     * violation {
+     * rule { element { field_number: 23, field_name: "cel", field_type: 11, index: 0 } }
+     * ...
+     * }
+     * ```
+     * 
+ * + * optional .buf.validate.FieldPath rule = 6 [json_name = "rule"]; + */ + public Builder setRule(build.buf.validate.FieldPath value) { + if (ruleBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + rule_ = value; + } else { + ruleBuilder_.setMessage(value); + } + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * `rule` is a machine-readable path that points to the specific constraint rule that failed validation.
+     * This will be a nested field starting from the FieldConstraints of the field that failed validation.
+     * For custom constraints, this will provide the path of the constraint, e.g. `cel[0]`.
+     *
+     * For example, consider the following message:
+     *
+     * ```proto
+     * message Message {
+     * bool a = 1 [(buf.validate.field).required = true];
+     * bool b = 2 [(buf.validate.field).cel = {
+     * id: "custom_constraint",
+     * expression: "!this ? 'b must be true': ''"
+     * }]
+     * }
+     * ```
+     *
+     * It could produce the following violations:
+     *
+     * ```textproto
+     * violation {
+     * rule { element { field_number: 25, field_name: "required", field_type: 8 } }
+     * ...
+     * }
+     * violation {
+     * rule { element { field_number: 23, field_name: "cel", field_type: 11, index: 0 } }
+     * ...
+     * }
+     * ```
+     * 
+ * + * optional .buf.validate.FieldPath rule = 6 [json_name = "rule"]; + */ + public Builder setRule( + build.buf.validate.FieldPath.Builder builderForValue) { + if (ruleBuilder_ == null) { + rule_ = builderForValue.build(); + } else { + ruleBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + *
+     * `rule` is a machine-readable path that points to the specific constraint rule that failed validation.
+     * This will be a nested field starting from the FieldConstraints of the field that failed validation.
+     * For custom constraints, this will provide the path of the constraint, e.g. `cel[0]`.
+     *
+     * For example, consider the following message:
+     *
+     * ```proto
+     * message Message {
+     * bool a = 1 [(buf.validate.field).required = true];
+     * bool b = 2 [(buf.validate.field).cel = {
+     * id: "custom_constraint",
+     * expression: "!this ? 'b must be true': ''"
+     * }]
+     * }
+     * ```
+     *
+     * It could produce the following violations:
+     *
+     * ```textproto
+     * violation {
+     * rule { element { field_number: 25, field_name: "required", field_type: 8 } }
+     * ...
+     * }
+     * violation {
+     * rule { element { field_number: 23, field_name: "cel", field_type: 11, index: 0 } }
+     * ...
+     * }
+     * ```
+     * 
+ * + * optional .buf.validate.FieldPath rule = 6 [json_name = "rule"]; + */ + public Builder mergeRule(build.buf.validate.FieldPath value) { + if (ruleBuilder_ == null) { + if (((bitField0_ & 0x00000002) != 0) && + rule_ != null && + rule_ != build.buf.validate.FieldPath.getDefaultInstance()) { + getRuleBuilder().mergeFrom(value); + } else { + rule_ = value; + } + } else { + ruleBuilder_.mergeFrom(value); + } + if (rule_ != null) { + bitField0_ |= 0x00000002; + onChanged(); + } + return this; + } + /** + *
+     * `rule` is a machine-readable path that points to the specific constraint rule that failed validation.
+     * This will be a nested field starting from the FieldConstraints of the field that failed validation.
+     * For custom constraints, this will provide the path of the constraint, e.g. `cel[0]`.
+     *
+     * For example, consider the following message:
+     *
+     * ```proto
+     * message Message {
+     * bool a = 1 [(buf.validate.field).required = true];
+     * bool b = 2 [(buf.validate.field).cel = {
+     * id: "custom_constraint",
+     * expression: "!this ? 'b must be true': ''"
+     * }]
+     * }
+     * ```
+     *
+     * It could produce the following violations:
+     *
+     * ```textproto
+     * violation {
+     * rule { element { field_number: 25, field_name: "required", field_type: 8 } }
+     * ...
+     * }
+     * violation {
+     * rule { element { field_number: 23, field_name: "cel", field_type: 11, index: 0 } }
+     * ...
+     * }
+     * ```
+     * 
+ * + * optional .buf.validate.FieldPath rule = 6 [json_name = "rule"]; + */ + public Builder clearRule() { + bitField0_ = (bitField0_ & ~0x00000002); + rule_ = null; + if (ruleBuilder_ != null) { + ruleBuilder_.dispose(); + ruleBuilder_ = null; + } + onChanged(); + return this; + } + /** + *
+     * `rule` is a machine-readable path that points to the specific constraint rule that failed validation.
+     * This will be a nested field starting from the FieldConstraints of the field that failed validation.
+     * For custom constraints, this will provide the path of the constraint, e.g. `cel[0]`.
+     *
+     * For example, consider the following message:
+     *
+     * ```proto
+     * message Message {
+     * bool a = 1 [(buf.validate.field).required = true];
+     * bool b = 2 [(buf.validate.field).cel = {
+     * id: "custom_constraint",
+     * expression: "!this ? 'b must be true': ''"
+     * }]
+     * }
+     * ```
+     *
+     * It could produce the following violations:
+     *
+     * ```textproto
+     * violation {
+     * rule { element { field_number: 25, field_name: "required", field_type: 8 } }
+     * ...
+     * }
+     * violation {
+     * rule { element { field_number: 23, field_name: "cel", field_type: 11, index: 0 } }
+     * ...
+     * }
+     * ```
+     * 
+ * + * optional .buf.validate.FieldPath rule = 6 [json_name = "rule"]; + */ + public build.buf.validate.FieldPath.Builder getRuleBuilder() { + bitField0_ |= 0x00000002; + onChanged(); + return getRuleFieldBuilder().getBuilder(); + } + /** + *
+     * `rule` is a machine-readable path that points to the specific constraint rule that failed validation.
+     * This will be a nested field starting from the FieldConstraints of the field that failed validation.
+     * For custom constraints, this will provide the path of the constraint, e.g. `cel[0]`.
+     *
+     * For example, consider the following message:
+     *
+     * ```proto
+     * message Message {
+     * bool a = 1 [(buf.validate.field).required = true];
+     * bool b = 2 [(buf.validate.field).cel = {
+     * id: "custom_constraint",
+     * expression: "!this ? 'b must be true': ''"
+     * }]
+     * }
+     * ```
+     *
+     * It could produce the following violations:
+     *
+     * ```textproto
+     * violation {
+     * rule { element { field_number: 25, field_name: "required", field_type: 8 } }
+     * ...
+     * }
+     * violation {
+     * rule { element { field_number: 23, field_name: "cel", field_type: 11, index: 0 } }
+     * ...
+     * }
+     * ```
+     * 
+ * + * optional .buf.validate.FieldPath rule = 6 [json_name = "rule"]; + */ + public build.buf.validate.FieldPathOrBuilder getRuleOrBuilder() { + if (ruleBuilder_ != null) { + return ruleBuilder_.getMessageOrBuilder(); + } else { + return rule_ == null ? + build.buf.validate.FieldPath.getDefaultInstance() : rule_; + } + } + /** + *
+     * `rule` is a machine-readable path that points to the specific constraint rule that failed validation.
+     * This will be a nested field starting from the FieldConstraints of the field that failed validation.
+     * For custom constraints, this will provide the path of the constraint, e.g. `cel[0]`.
+     *
+     * For example, consider the following message:
+     *
+     * ```proto
+     * message Message {
+     * bool a = 1 [(buf.validate.field).required = true];
+     * bool b = 2 [(buf.validate.field).cel = {
+     * id: "custom_constraint",
+     * expression: "!this ? 'b must be true': ''"
+     * }]
+     * }
+     * ```
+     *
+     * It could produce the following violations:
+     *
+     * ```textproto
+     * violation {
+     * rule { element { field_number: 25, field_name: "required", field_type: 8 } }
+     * ...
+     * }
+     * violation {
+     * rule { element { field_number: 23, field_name: "cel", field_type: 11, index: 0 } }
+     * ...
+     * }
+     * ```
+     * 
+ * + * optional .buf.validate.FieldPath rule = 6 [json_name = "rule"]; + */ + private com.google.protobuf.SingleFieldBuilder< + build.buf.validate.FieldPath, build.buf.validate.FieldPath.Builder, build.buf.validate.FieldPathOrBuilder> + getRuleFieldBuilder() { + if (ruleBuilder_ == null) { + ruleBuilder_ = new com.google.protobuf.SingleFieldBuilder< + build.buf.validate.FieldPath, build.buf.validate.FieldPath.Builder, build.buf.validate.FieldPathOrBuilder>( + getRule(), + getParentForChildren(), + isClean()); + rule_ = null; + } + return ruleBuilder_; + } + private java.lang.Object fieldPath_ = ""; /** *
-     * `field_path` is a machine-readable identifier that points to the specific field that failed the validation.
+     * `field_path` is a human-readable identifier that points to the specific field that failed the validation.
      * This could be a nested field, in which case the path will include all the parent fields leading to the actual field that caused the violation.
+     *
+     * Deprecated: use the `field` instead.
      * 
* - * optional string field_path = 1 [json_name = "fieldPath"]; + * optional string field_path = 1 [json_name = "fieldPath", deprecated = true]; + * @deprecated buf.validate.Violation.field_path is deprecated. + * See buf/validate/validate.proto;l=4827 * @return Whether the fieldPath field is set. */ - public boolean hasFieldPath() { - return ((bitField0_ & 0x00000001) != 0); + @java.lang.Deprecated public boolean hasFieldPath() { + return ((bitField0_ & 0x00000004) != 0); } /** *
-     * `field_path` is a machine-readable identifier that points to the specific field that failed the validation.
+     * `field_path` is a human-readable identifier that points to the specific field that failed the validation.
      * This could be a nested field, in which case the path will include all the parent fields leading to the actual field that caused the violation.
+     *
+     * Deprecated: use the `field` instead.
      * 
* - * optional string field_path = 1 [json_name = "fieldPath"]; + * optional string field_path = 1 [json_name = "fieldPath", deprecated = true]; + * @deprecated buf.validate.Violation.field_path is deprecated. + * See buf/validate/validate.proto;l=4827 * @return The fieldPath. */ - public java.lang.String getFieldPath() { + @java.lang.Deprecated public java.lang.String getFieldPath() { java.lang.Object ref = fieldPath_; if (!(ref instanceof java.lang.String)) { com.google.protobuf.ByteString bs = @@ -725,14 +1756,18 @@ public java.lang.String getFieldPath() { } /** *
-     * `field_path` is a machine-readable identifier that points to the specific field that failed the validation.
+     * `field_path` is a human-readable identifier that points to the specific field that failed the validation.
      * This could be a nested field, in which case the path will include all the parent fields leading to the actual field that caused the violation.
+     *
+     * Deprecated: use the `field` instead.
      * 
* - * optional string field_path = 1 [json_name = "fieldPath"]; + * optional string field_path = 1 [json_name = "fieldPath", deprecated = true]; + * @deprecated buf.validate.Violation.field_path is deprecated. + * See buf/validate/validate.proto;l=4827 * @return The bytes for fieldPath. */ - public com.google.protobuf.ByteString + @java.lang.Deprecated public com.google.protobuf.ByteString getFieldPathBytes() { java.lang.Object ref = fieldPath_; if (ref instanceof String) { @@ -747,52 +1782,64 @@ public java.lang.String getFieldPath() { } /** *
-     * `field_path` is a machine-readable identifier that points to the specific field that failed the validation.
+     * `field_path` is a human-readable identifier that points to the specific field that failed the validation.
      * This could be a nested field, in which case the path will include all the parent fields leading to the actual field that caused the violation.
+     *
+     * Deprecated: use the `field` instead.
      * 
* - * optional string field_path = 1 [json_name = "fieldPath"]; + * optional string field_path = 1 [json_name = "fieldPath", deprecated = true]; + * @deprecated buf.validate.Violation.field_path is deprecated. + * See buf/validate/validate.proto;l=4827 * @param value The fieldPath to set. * @return This builder for chaining. */ - public Builder setFieldPath( + @java.lang.Deprecated public Builder setFieldPath( java.lang.String value) { if (value == null) { throw new NullPointerException(); } fieldPath_ = value; - bitField0_ |= 0x00000001; + bitField0_ |= 0x00000004; onChanged(); return this; } /** *
-     * `field_path` is a machine-readable identifier that points to the specific field that failed the validation.
+     * `field_path` is a human-readable identifier that points to the specific field that failed the validation.
      * This could be a nested field, in which case the path will include all the parent fields leading to the actual field that caused the violation.
+     *
+     * Deprecated: use the `field` instead.
      * 
* - * optional string field_path = 1 [json_name = "fieldPath"]; + * optional string field_path = 1 [json_name = "fieldPath", deprecated = true]; + * @deprecated buf.validate.Violation.field_path is deprecated. + * See buf/validate/validate.proto;l=4827 * @return This builder for chaining. */ - public Builder clearFieldPath() { + @java.lang.Deprecated public Builder clearFieldPath() { fieldPath_ = getDefaultInstance().getFieldPath(); - bitField0_ = (bitField0_ & ~0x00000001); + bitField0_ = (bitField0_ & ~0x00000004); onChanged(); return this; } /** *
-     * `field_path` is a machine-readable identifier that points to the specific field that failed the validation.
+     * `field_path` is a human-readable identifier that points to the specific field that failed the validation.
      * This could be a nested field, in which case the path will include all the parent fields leading to the actual field that caused the violation.
+     *
+     * Deprecated: use the `field` instead.
      * 
* - * optional string field_path = 1 [json_name = "fieldPath"]; + * optional string field_path = 1 [json_name = "fieldPath", deprecated = true]; + * @deprecated buf.validate.Violation.field_path is deprecated. + * See buf/validate/validate.proto;l=4827 * @param value The bytes for fieldPath to set. * @return This builder for chaining. */ - public Builder setFieldPathBytes( + @java.lang.Deprecated public Builder setFieldPathBytes( com.google.protobuf.ByteString value) { if (value == null) { throw new NullPointerException(); } fieldPath_ = value; - bitField0_ |= 0x00000001; + bitField0_ |= 0x00000004; onChanged(); return this; } @@ -808,7 +1855,7 @@ public Builder setFieldPathBytes( * @return Whether the constraintId field is set. */ public boolean hasConstraintId() { - return ((bitField0_ & 0x00000002) != 0); + return ((bitField0_ & 0x00000008) != 0); } /** *
@@ -869,7 +1916,7 @@ public Builder setConstraintId(
         java.lang.String value) {
       if (value == null) { throw new NullPointerException(); }
       constraintId_ = value;
-      bitField0_ |= 0x00000002;
+      bitField0_ |= 0x00000008;
       onChanged();
       return this;
     }
@@ -884,7 +1931,7 @@ public Builder setConstraintId(
      */
     public Builder clearConstraintId() {
       constraintId_ = getDefaultInstance().getConstraintId();
-      bitField0_ = (bitField0_ & ~0x00000002);
+      bitField0_ = (bitField0_ & ~0x00000008);
       onChanged();
       return this;
     }
@@ -902,7 +1949,7 @@ public Builder setConstraintIdBytes(
         com.google.protobuf.ByteString value) {
       if (value == null) { throw new NullPointerException(); }
       constraintId_ = value;
-      bitField0_ |= 0x00000002;
+      bitField0_ |= 0x00000008;
       onChanged();
       return this;
     }
@@ -918,7 +1965,7 @@ public Builder setConstraintIdBytes(
      * @return Whether the message field is set.
      */
     public boolean hasMessage() {
-      return ((bitField0_ & 0x00000004) != 0);
+      return ((bitField0_ & 0x00000010) != 0);
     }
     /**
      * 
@@ -979,7 +2026,7 @@ public Builder setMessage(
         java.lang.String value) {
       if (value == null) { throw new NullPointerException(); }
       message_ = value;
-      bitField0_ |= 0x00000004;
+      bitField0_ |= 0x00000010;
       onChanged();
       return this;
     }
@@ -994,7 +2041,7 @@ public Builder setMessage(
      */
     public Builder clearMessage() {
       message_ = getDefaultInstance().getMessage();
-      bitField0_ = (bitField0_ & ~0x00000004);
+      bitField0_ = (bitField0_ & ~0x00000010);
       onChanged();
       return this;
     }
@@ -1012,7 +2059,7 @@ public Builder setMessageBytes(
         com.google.protobuf.ByteString value) {
       if (value == null) { throw new NullPointerException(); }
       message_ = value;
-      bitField0_ |= 0x00000004;
+      bitField0_ |= 0x00000010;
       onChanged();
       return this;
     }
@@ -1028,7 +2075,7 @@ public Builder setMessageBytes(
      */
     @java.lang.Override
     public boolean hasForKey() {
-      return ((bitField0_ & 0x00000008) != 0);
+      return ((bitField0_ & 0x00000020) != 0);
     }
     /**
      * 
@@ -1054,7 +2101,7 @@ public boolean getForKey() {
     public Builder setForKey(boolean value) {
 
       forKey_ = value;
-      bitField0_ |= 0x00000008;
+      bitField0_ |= 0x00000020;
       onChanged();
       return this;
     }
@@ -1067,7 +2114,7 @@ public Builder setForKey(boolean value) {
      * @return This builder for chaining.
      */
     public Builder clearForKey() {
-      bitField0_ = (bitField0_ & ~0x00000008);
+      bitField0_ = (bitField0_ & ~0x00000020);
       forKey_ = false;
       onChanged();
       return this;
diff --git a/src/main/java/build/buf/validate/ViolationOrBuilder.java b/src/main/java/build/buf/validate/ViolationOrBuilder.java
index c9f0a481..caf375c6 100644
--- a/src/main/java/build/buf/validate/ViolationOrBuilder.java
+++ b/src/main/java/build/buf/validate/ViolationOrBuilder.java
@@ -11,34 +11,235 @@ public interface ViolationOrBuilder extends
 
   /**
    * 
-   * `field_path` is a machine-readable identifier that points to the specific field that failed the validation.
+   * `field` is a machine-readable path to the field that failed validation.
    * This could be a nested field, in which case the path will include all the parent fields leading to the actual field that caused the violation.
+   *
+   * For example, consider the following message:
+   *
+   * ```proto
+   * message Message {
+   * bool a = 1 [(buf.validate.field).required = true];
+   * }
+   * ```
+   *
+   * It could produce the following violation:
+   *
+   * ```textproto
+   * violation {
+   * field { element { field_number: 1, field_name: "a", field_type: 8 } }
+   * ...
+   * }
+   * ```
+   * 
+ * + * optional .buf.validate.FieldPath field = 5 [json_name = "field"]; + * @return Whether the field field is set. + */ + boolean hasField(); + /** + *
+   * `field` is a machine-readable path to the field that failed validation.
+   * This could be a nested field, in which case the path will include all the parent fields leading to the actual field that caused the violation.
+   *
+   * For example, consider the following message:
+   *
+   * ```proto
+   * message Message {
+   * bool a = 1 [(buf.validate.field).required = true];
+   * }
+   * ```
+   *
+   * It could produce the following violation:
+   *
+   * ```textproto
+   * violation {
+   * field { element { field_number: 1, field_name: "a", field_type: 8 } }
+   * ...
+   * }
+   * ```
+   * 
+ * + * optional .buf.validate.FieldPath field = 5 [json_name = "field"]; + * @return The field. + */ + build.buf.validate.FieldPath getField(); + /** + *
+   * `field` is a machine-readable path to the field that failed validation.
+   * This could be a nested field, in which case the path will include all the parent fields leading to the actual field that caused the violation.
+   *
+   * For example, consider the following message:
+   *
+   * ```proto
+   * message Message {
+   * bool a = 1 [(buf.validate.field).required = true];
+   * }
+   * ```
+   *
+   * It could produce the following violation:
+   *
+   * ```textproto
+   * violation {
+   * field { element { field_number: 1, field_name: "a", field_type: 8 } }
+   * ...
+   * }
+   * ```
    * 
* - * optional string field_path = 1 [json_name = "fieldPath"]; + * optional .buf.validate.FieldPath field = 5 [json_name = "field"]; + */ + build.buf.validate.FieldPathOrBuilder getFieldOrBuilder(); + + /** + *
+   * `rule` is a machine-readable path that points to the specific constraint rule that failed validation.
+   * This will be a nested field starting from the FieldConstraints of the field that failed validation.
+   * For custom constraints, this will provide the path of the constraint, e.g. `cel[0]`.
+   *
+   * For example, consider the following message:
+   *
+   * ```proto
+   * message Message {
+   * bool a = 1 [(buf.validate.field).required = true];
+   * bool b = 2 [(buf.validate.field).cel = {
+   * id: "custom_constraint",
+   * expression: "!this ? 'b must be true': ''"
+   * }]
+   * }
+   * ```
+   *
+   * It could produce the following violations:
+   *
+   * ```textproto
+   * violation {
+   * rule { element { field_number: 25, field_name: "required", field_type: 8 } }
+   * ...
+   * }
+   * violation {
+   * rule { element { field_number: 23, field_name: "cel", field_type: 11, index: 0 } }
+   * ...
+   * }
+   * ```
+   * 
+ * + * optional .buf.validate.FieldPath rule = 6 [json_name = "rule"]; + * @return Whether the rule field is set. + */ + boolean hasRule(); + /** + *
+   * `rule` is a machine-readable path that points to the specific constraint rule that failed validation.
+   * This will be a nested field starting from the FieldConstraints of the field that failed validation.
+   * For custom constraints, this will provide the path of the constraint, e.g. `cel[0]`.
+   *
+   * For example, consider the following message:
+   *
+   * ```proto
+   * message Message {
+   * bool a = 1 [(buf.validate.field).required = true];
+   * bool b = 2 [(buf.validate.field).cel = {
+   * id: "custom_constraint",
+   * expression: "!this ? 'b must be true': ''"
+   * }]
+   * }
+   * ```
+   *
+   * It could produce the following violations:
+   *
+   * ```textproto
+   * violation {
+   * rule { element { field_number: 25, field_name: "required", field_type: 8 } }
+   * ...
+   * }
+   * violation {
+   * rule { element { field_number: 23, field_name: "cel", field_type: 11, index: 0 } }
+   * ...
+   * }
+   * ```
+   * 
+ * + * optional .buf.validate.FieldPath rule = 6 [json_name = "rule"]; + * @return The rule. + */ + build.buf.validate.FieldPath getRule(); + /** + *
+   * `rule` is a machine-readable path that points to the specific constraint rule that failed validation.
+   * This will be a nested field starting from the FieldConstraints of the field that failed validation.
+   * For custom constraints, this will provide the path of the constraint, e.g. `cel[0]`.
+   *
+   * For example, consider the following message:
+   *
+   * ```proto
+   * message Message {
+   * bool a = 1 [(buf.validate.field).required = true];
+   * bool b = 2 [(buf.validate.field).cel = {
+   * id: "custom_constraint",
+   * expression: "!this ? 'b must be true': ''"
+   * }]
+   * }
+   * ```
+   *
+   * It could produce the following violations:
+   *
+   * ```textproto
+   * violation {
+   * rule { element { field_number: 25, field_name: "required", field_type: 8 } }
+   * ...
+   * }
+   * violation {
+   * rule { element { field_number: 23, field_name: "cel", field_type: 11, index: 0 } }
+   * ...
+   * }
+   * ```
+   * 
+ * + * optional .buf.validate.FieldPath rule = 6 [json_name = "rule"]; + */ + build.buf.validate.FieldPathOrBuilder getRuleOrBuilder(); + + /** + *
+   * `field_path` is a human-readable identifier that points to the specific field that failed the validation.
+   * This could be a nested field, in which case the path will include all the parent fields leading to the actual field that caused the violation.
+   *
+   * Deprecated: use the `field` instead.
+   * 
+ * + * optional string field_path = 1 [json_name = "fieldPath", deprecated = true]; + * @deprecated buf.validate.Violation.field_path is deprecated. + * See buf/validate/validate.proto;l=4827 * @return Whether the fieldPath field is set. */ - boolean hasFieldPath(); + @java.lang.Deprecated boolean hasFieldPath(); /** *
-   * `field_path` is a machine-readable identifier that points to the specific field that failed the validation.
+   * `field_path` is a human-readable identifier that points to the specific field that failed the validation.
    * This could be a nested field, in which case the path will include all the parent fields leading to the actual field that caused the violation.
+   *
+   * Deprecated: use the `field` instead.
    * 
* - * optional string field_path = 1 [json_name = "fieldPath"]; + * optional string field_path = 1 [json_name = "fieldPath", deprecated = true]; + * @deprecated buf.validate.Violation.field_path is deprecated. + * See buf/validate/validate.proto;l=4827 * @return The fieldPath. */ - java.lang.String getFieldPath(); + @java.lang.Deprecated java.lang.String getFieldPath(); /** *
-   * `field_path` is a machine-readable identifier that points to the specific field that failed the validation.
+   * `field_path` is a human-readable identifier that points to the specific field that failed the validation.
    * This could be a nested field, in which case the path will include all the parent fields leading to the actual field that caused the violation.
+   *
+   * Deprecated: use the `field` instead.
    * 
* - * optional string field_path = 1 [json_name = "fieldPath"]; + * optional string field_path = 1 [json_name = "fieldPath", deprecated = true]; + * @deprecated buf.validate.Violation.field_path is deprecated. + * See buf/validate/validate.proto;l=4827 * @return The bytes for fieldPath. */ - com.google.protobuf.ByteString + @java.lang.Deprecated com.google.protobuf.ByteString getFieldPathBytes(); /** diff --git a/src/main/resources/buf/validate/validate.proto b/src/main/resources/buf/validate/validate.proto index 7236347a..f24d8dff 100644 --- a/src/main/resources/buf/validate/validate.proto +++ b/src/main/resources/buf/validate/validate.proto @@ -3732,8 +3732,8 @@ message StringRules { // ```proto // message MyString { // string value = 1 [ - // (buf.validate.field).string.example = 1, - // (buf.validate.field).string.example = 2 + // (buf.validate.field).string.example = "hello", + // (buf.validate.field).string.example = "world" // ]; // } // ``` @@ -4770,9 +4770,62 @@ message Violations { // } // ``` message Violation { - // `field_path` is a machine-readable identifier that points to the specific field that failed the validation. + // `field` is a machine-readable path to the field that failed validation. // This could be a nested field, in which case the path will include all the parent fields leading to the actual field that caused the violation. - optional string field_path = 1; + // + // For example, consider the following message: + // + // ```proto + // message Message { + // bool a = 1 [(buf.validate.field).required = true]; + // } + // ``` + // + // It could produce the following violation: + // + // ```textproto + // violation { + // field { element { field_number: 1, field_name: "a", field_type: 8 } } + // ... + // } + // ``` + optional FieldPath field = 5; + + // `rule` is a machine-readable path that points to the specific constraint rule that failed validation. + // This will be a nested field starting from the FieldConstraints of the field that failed validation. + // For custom constraints, this will provide the path of the constraint, e.g. `cel[0]`. + // + // For example, consider the following message: + // + // ```proto + // message Message { + // bool a = 1 [(buf.validate.field).required = true]; + // bool b = 2 [(buf.validate.field).cel = { + // id: "custom_constraint", + // expression: "!this ? 'b must be true': ''" + // }] + // } + // ``` + // + // It could produce the following violations: + // + // ```textproto + // violation { + // rule { element { field_number: 25, field_name: "required", field_type: 8 } } + // ... + // } + // violation { + // rule { element { field_number: 23, field_name: "cel", field_type: 11, index: 0 } } + // ... + // } + // ``` + optional FieldPath rule = 6; + + // `field_path` is a human-readable identifier that points to the specific field that failed the validation. + // This could be a nested field, in which case the path will include all the parent fields leading to the actual field that caused the violation. + // + // Deprecated: use the `field` instead. + optional string field_path = 1 [deprecated = true]; // `constraint_id` is the unique identifier of the `Constraint` that was not fulfilled. // This is the same `id` that was specified in the `Constraint` message, allowing easy tracing of which rule was violated. @@ -4785,3 +4838,65 @@ message Violation { // `for_key` indicates whether the violation was caused by a map key, rather than a value. optional bool for_key = 4; } + +// `FieldPath` provides a path to a nested protobuf field. +// +// This message provides enough information to render a dotted field path even without protobuf descriptors. +// It also provides enough information to resolve a nested field through unknown wire data. +message FieldPath { + // `elements` contains each element of the path, starting from the root and recursing downward. + repeated FieldPathElement elements = 1; +} + +// `FieldPathElement` provides enough information to nest through a single protobuf field. +// +// If the selected field is a map or repeated field, the `subscript` value selects a specific element from it. +// A path that refers to a value nested under a map key or repeated field index will have a `subscript` value. +// The `field_type` field allows unambiguous resolution of a field even if descriptors are not available. +message FieldPathElement { + // `field_number` is the field number this path element refers to. + optional int32 field_number = 1; + + // `field_name` contains the field name this path element refers to. + // This can be used to display a human-readable path even if the field number is unknown. + optional string field_name = 2; + + // `field_type` specifies the type of this field. When using reflection, this value is not needed. + // + // This value is provided to make it possible to traverse unknown fields through wire data. + // When traversing wire data, be mindful of both packed[1] and delimited[2] encoding schemes. + // + // [1]: https://protobuf.dev/programming-guides/encoding/#packed + // [2]: https://protobuf.dev/programming-guides/encoding/#groups + // + // N.B.: Although groups are deprecated, the corresponding delimited encoding scheme is not, and + // can be explicitly used in Protocol Buffers 2023 Edition. + optional google.protobuf.FieldDescriptorProto.Type field_type = 3; + + // `key_type` specifies the map key type of this field. This value is useful when traversing + // unknown fields through wire data: specifically, it allows handling the differences between + // different integer encodings. + optional google.protobuf.FieldDescriptorProto.Type key_type = 4; + + // `value_type` specifies map value type of this field. This is useful if you want to display a + // value inside unknown fields through wire data. + optional google.protobuf.FieldDescriptorProto.Type value_type = 5; + + // `subscript` contains a repeated index or map key, if this path element nests into a repeated or map field. + oneof subscript { + // `index` specifies a 0-based index into a repeated field. + uint64 index = 6; + + // `bool_key` specifies a map key of type bool. + bool bool_key = 7; + + // `int_key` specifies a map key of type int32, int64, sint32, sint64, sfixed32 or sfixed64. + int64 int_key = 8; + + // `uint_key` specifies a map key of type uint32, uint64, fixed32 or fixed64. + uint64 uint_key = 9; + + // `string_key` specifies a map key of type string. + string string_key = 10; + } +} diff --git a/src/test/java/build/buf/protovalidate/ValidatorDifferentJavaPackagesTest.java b/src/test/java/build/buf/protovalidate/ValidatorDifferentJavaPackagesTest.java index e1a1e292..2e011147 100644 --- a/src/test/java/build/buf/protovalidate/ValidatorDifferentJavaPackagesTest.java +++ b/src/test/java/build/buf/protovalidate/ValidatorDifferentJavaPackagesTest.java @@ -17,7 +17,13 @@ import static org.assertj.core.api.Assertions.assertThat; import build.buf.protovalidate.exceptions.ValidationException; +import build.buf.protovalidate.internal.errors.FieldPathUtils; +import build.buf.validate.FieldConstraints; +import build.buf.validate.FieldPath; +import build.buf.validate.FieldPathElement; import build.buf.validate.Violation; +import com.example.imports.buf.validate.StringRules; +import com.example.imports.validationtest.ExampleFieldConstraints; import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.Message; import java.util.Collections; @@ -76,6 +82,24 @@ public void testValidationFieldConstraints() throws Exception { .build(); Violation expectedViolation = Violation.newBuilder() + .setField( + FieldPath.newBuilder() + .addElements( + FieldPathUtils.fieldPathElement( + com.example.imports.validationtest.ExampleFieldConstraints + .getDescriptor() + .findFieldByNumber( + ExampleFieldConstraints.REGEX_STRING_FIELD_FIELD_NUMBER)))) + .setRule( + FieldPath.newBuilder() + .addElements( + FieldPathUtils.fieldPathElement( + FieldConstraints.getDescriptor() + .findFieldByNumber(FieldConstraints.STRING_FIELD_NUMBER))) + .addElements( + FieldPathUtils.fieldPathElement( + StringRules.getDescriptor() + .findFieldByNumber(StringRules.PATTERN_FIELD_NUMBER)))) .setConstraintId("string.pattern") .setFieldPath("regex_string_field") .setMessage("value does not match regex pattern `^[a-z0-9]{1,9}$`") @@ -110,6 +134,9 @@ public void testValidationOneofConstraints() com.example.imports.validationtest.ExampleOneofConstraints.getDefaultInstance(); Violation expectedViolation = Violation.newBuilder() + .setField( + FieldPath.newBuilder() + .addElements(FieldPathElement.newBuilder().setFieldName("contact_info"))) .setFieldPath("contact_info") .setConstraintId("required") .setMessage("exactly one field is required in oneof") diff --git a/src/test/java/build/buf/protovalidate/ValidatorDynamicMessageTest.java b/src/test/java/build/buf/protovalidate/ValidatorDynamicMessageTest.java index 70db7fde..e3e14358 100644 --- a/src/test/java/build/buf/protovalidate/ValidatorDynamicMessageTest.java +++ b/src/test/java/build/buf/protovalidate/ValidatorDynamicMessageTest.java @@ -17,12 +17,18 @@ import static com.example.imports.validationtest.PredefinedProto.isIdent; import static org.assertj.core.api.Assertions.assertThat; +import build.buf.protovalidate.internal.errors.FieldPathUtils; +import build.buf.validate.FieldConstraints; +import build.buf.validate.FieldPath; +import build.buf.validate.FieldPathElement; import build.buf.validate.Violation; +import com.example.imports.buf.validate.StringRules; import com.example.imports.validationtest.ExamplePredefinedFieldConstraints; import com.example.noimports.validationtest.ExampleFieldConstraints; import com.example.noimports.validationtest.ExampleMessageConstraints; import com.example.noimports.validationtest.ExampleOneofConstraints; import com.example.noimports.validationtest.ExampleRequiredFieldConstraints; +import com.example.noimports.validationtest.PredefinedProto; import com.google.protobuf.DescriptorProtos; import com.google.protobuf.Descriptors; import com.google.protobuf.DynamicMessage; @@ -53,6 +59,23 @@ public void testFieldConstraintDynamicMessage() throws Exception { messageBuilder.getDescriptorForType().findFieldByName("regex_string_field"), "0123456789"); Violation expectedViolation = Violation.newBuilder() + .setField( + FieldPath.newBuilder() + .addElements( + FieldPathUtils.fieldPathElement( + messageBuilder + .getDescriptorForType() + .findFieldByName("regex_string_field")))) + .setRule( + FieldPath.newBuilder() + .addElements( + FieldPathUtils.fieldPathElement( + FieldConstraints.getDescriptor() + .findFieldByNumber(FieldConstraints.STRING_FIELD_NUMBER))) + .addElements( + FieldPathUtils.fieldPathElement( + StringRules.getDescriptor() + .findFieldByNumber(StringRules.PATTERN_FIELD_NUMBER)))) .setConstraintId("string.pattern") .setFieldPath("regex_string_field") .setMessage("value does not match regex pattern `^[a-z0-9]{1,9}$`") @@ -67,6 +90,9 @@ public void testOneofConstraintDynamicMessage() throws Exception { createMessageWithUnknownOptions(ExampleOneofConstraints.getDefaultInstance()); Violation expectedViolation = Violation.newBuilder() + .setField( + FieldPath.newBuilder() + .addElements(FieldPathElement.newBuilder().setFieldName("contact_info"))) .setFieldPath("contact_info") .setConstraintId("required") .setMessage("exactly one field is required in oneof") @@ -108,6 +134,23 @@ public void testRequiredFieldConstraintDynamicMessageInvalid() throws Exception messageBuilder.getDescriptorForType().findFieldByName("regex_string_field"), "0123456789"); Violation expectedViolation = Violation.newBuilder() + .setField( + FieldPath.newBuilder() + .addElements( + FieldPathUtils.fieldPathElement( + messageBuilder + .getDescriptorForType() + .findFieldByName("regex_string_field")))) + .setRule( + FieldPath.newBuilder() + .addElements( + FieldPathUtils.fieldPathElement( + FieldConstraints.getDescriptor() + .findFieldByNumber(FieldConstraints.STRING_FIELD_NUMBER))) + .addElements( + FieldPathUtils.fieldPathElement( + StringRules.getDescriptor() + .findFieldByNumber(StringRules.PATTERN_FIELD_NUMBER)))) .setConstraintId("string.pattern") .setFieldPath("regex_string_field") .setMessage("value does not match regex pattern `^[a-z0-9]{1,9}$`") @@ -139,6 +182,19 @@ public void testPredefinedFieldConstraintDynamicMessageInvalid() throws Exceptio messageBuilder.getDescriptorForType().findFieldByName("ident_field"), "0123456789"); Violation expectedViolation = Violation.newBuilder() + .setField( + FieldPath.newBuilder() + .addElements( + FieldPathUtils.fieldPathElement( + messageBuilder.getDescriptorForType().findFieldByName("ident_field")))) + .setRule( + FieldPath.newBuilder() + .addElements( + FieldPathUtils.fieldPathElement( + FieldConstraints.getDescriptor() + .findFieldByNumber(FieldConstraints.STRING_FIELD_NUMBER))) + .addElements( + FieldPathUtils.fieldPathElement(PredefinedProto.isIdent.getDescriptor()))) .setConstraintId("string.is_ident") .setFieldPath("ident_field") .setMessage("invalid identifier")