protovalidate-java is the Java language implementation of protovalidate designed to validate Protobuf messages at runtime based on user-defined validation constraints. Powered by Google's Common Expression Language (CEL), it provides a flexible and efficient foundation for defining and evaluating custom validation rules. The primary goal of protovalidate is to help developers ensure data consistency and integrity across the network without requiring generated code.
Head over to the core protovalidate repository for:
- The API definition: used to describe validation constraints
- Documentation: how to apply
protovalidateeffectively - Migration tooling: incrementally migrate from
protoc-gen-validate - Conformance testing utilities: for acceptance testing of
protovalidateimplementations
Other protovalidate runtime implementations include:
- C++:
protovalidate-cc - Go:
protovalidate-go - Python:
protovalidate-python
And others coming soon:
- TypeScript:
protovalidate-ts
To include protovalidate-java in your project, add the following to your build file:
dependencies {
implementation 'build.buf:protovalidate:<version>'
}Remember to always check for the latest version of protovalidate-java on the project's GitHub releases page to ensure you're using the most up-to-date version.
Validation constraints are defined directly within .proto files. Documentation for adding constraints can be found in the protovalidate project README and its comprehensive docs.
syntax="proto3";
packagemy.package;
import"google/protobuf/timestamp.proto";
import"buf/validate/validate.proto";
messageTransaction {
uint64id=1 [(buf.validate.field).uint64.gt = 999];
google.protobuf.Timestamppurchase_date=2;
google.protobuf.Timestampdelivery_date=3;
stringprice=4 [(buf.validate.field).cel = {
id: "transaction.price",
message: "price must be positive and include a valid currency symbol ($ or £)",
expression: "(this.startsWith('$') || this.startsWith('£')) && double(this.substring(1)) > 0"
}];
option(buf.validate.message).cel= {
id: "transaction.delivery_date",
message: "delivery date must be after purchase date",
expression: "this.delivery_date > this.purchase_date"
};
}In your Java code, create an instance of the Validator class and use the validate method to validate your messages.
// Import the required packagespackagebuild.buf;
importbuild.buf.protovalidate.results.ValidationException;
importbuild.buf.protovalidate.results.ValidationResult;
importcom.my.package.Transaction;
importcom.google.protobuf.Timestamp;
importbuild.buf.protovalidate.Validator;
importbuild.buf.protovalidate.Config;
publicclassMain {
// Create timestamps for purchase and delivery dateTimestamppurchaseDate = Timestamp.newBuilder().build();
TimestampdeliveryDate = Timestamp.newBuilder().build();
// Create a transaction object using the Builder patternTransactiontransaction =
Transaction.newBuilder()
.setId(1234)
.setPrice("$5.67")
.setPurchaseDate(purchaseDate)
.setDeliveryDate(deliveryDate)
.build();
// Create a validator object with the default ConfigurationValidatorvalidator = newValidator();
// Validate the transaction object using the validatortry {
ValidationResultresult = validator.validate(transaction);
// Check if there are any validation violationsif (result.violations.isEmpty()) {
// No violations, validation successfulSystem.out.println("Validation succeeded");
} else {
// Print the violations if any foundSystem.out.println(result.toString());
}
} catch (ValidationExceptione) {
// Catch and print any ValidationExceptions thrown during the validation processSystem.out.println("Validation failed: " + e.getMessage());
}
}protovalidatecore repository- Buf
- CEL Spec
Offered under the Apache 2 license.