MessageValidator.java
/*
* Copyright 2019 Providence Authors
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 net.morimekta.providence.util;
import net.morimekta.providence.PMessage;
import net.morimekta.providence.PMessageOrBuilder;
import net.morimekta.providence.descriptor.PField;
import net.morimekta.providence.descriptor.PMessageDescriptor;
import javax.annotation.Nonnull;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
/**
* Class that handles validation of the structure or content of a message
* type. This this can do much more fine grained validation than just assigning
* required fields.
*
* @param <M> The message type to be validated.
* @param <E> The exception to be thrown on validation failure.
* @deprecated Use {@link MessageValidation}.
*/
@Deprecated
public class MessageValidator<
M extends PMessage<M>,
E extends Exception> {
private final MessageValidation<M, E> validation;
/**
* Validate a message using the built expectations.
*
* @param message The message to be validated.
* @throws E On not valid message.
*/
@SuppressWarnings("unchecked")
public void validate(PMessageOrBuilder<M> message) throws E {
validation.validate(message);
}
/**
* Just see if the message is valid or not. Does not
*
* @param message The message to be validated.
* @return True if the message is valid, false otherwise.
*/
@SuppressWarnings("unchecked")
public boolean isValid(PMessageOrBuilder<M> message) {
return validation.isValid(message);
}
/**
* Just see if the message is valid or not. Does not
*
* @param message The message to be validated.
* @param messageConsumer Consumer of validation errors on the message.
*/
@SuppressWarnings("unchecked")
public void collectValidationErrors(PMessageOrBuilder<M> message, Consumer<String> messageConsumer) {
try {
validation.validate(message);
} catch (Exception e) {
messageConsumer.accept(e.getMessage());
}
}
/**
* Create a message validator that throws specific exception on failure.
*
* @param descriptor The message type descriptor to be validated.
* @param onMismatch Function producer for thrown exceptions.
* @param <M> Message type.
* @param <E> Exception type.
* @return The message validator builder.
*/
public static <M extends PMessage<M>, E extends Exception>
MessageValidator.Builder<M, E> builder(
@Nonnull PMessageDescriptor<M> descriptor,
@Nonnull Function<String, E> onMismatch) {
return new Builder<>(descriptor, onMismatch);
}
/**
* Builder vlass for message validators.
*
* @param <M> Message type.
* @param <E> Exception type.
* @deprecated Use {@link MessageValidation}.
*/
@Deprecated
public static class Builder<
M extends PMessage<M>,
E extends Exception> {
/**
* Build the validator.
*
* @return The validator instance.
*/
@Nonnull
public MessageValidator<M, E> build() {
return new MessageValidator<>(this);
}
/**
* Make a specific expectation for the message.
*
* @param text The message text on expectation failure.
* @param predicate Expectation predicate.
* @return The builder instance.
*/
@Nonnull
public Builder<M, E> expect(@Nonnull String text,
@Nonnull Predicate<M> predicate) {
builder.expect(new MessageValidation.PredicateExpectation<>(predicate, text));
return this;
}
/**
* Given the field and type descriptor (which must match the field type),
* build an inner validator to check the value of the field.
*
* @param field The field to check.
* @param descriptor The message descriptor matching the field.
* @param builderConsumer Consumer to configure the inner validator.
* @param <M2> The inner message type.
* @return The builder instance.
*/
@Nonnull
public <M2 extends PMessage<M2>>
Builder<M, E> expect(@Nonnull PField<M> field,
@Nonnull PMessageDescriptor<M2> descriptor,
@Nonnull Consumer<Builder<M2, E>> builderConsumer) {
builder.expectIfPresent(field, descriptor, b2 -> {
builderConsumer.accept(new Builder<>(b2));
});
return this;
}
/**
* Expect the message to be non-null value.
*
* @return The builder instance.
*/
@Nonnull
public Builder<M, E> expectNotNull() {
builder.expectNotNull();
return this;
}
/**
* Expect the message to be non-null value.
*
* @param text The failure message on null value.
* @return The builder instance.
*/
@Nonnull
public Builder<M, E> expectNotNull(@Nonnull String text) {
builder.expectNotNull();
return this;
}
/**
* Expect field to be present on message.
*
* @param fields The fields to be present.
* @return The builder instance.
*/
@Nonnull
@SafeVarargs
public final Builder<M, E> expectPresent(@Nonnull PField<M>... fields) {
builder.expectPresent(fields);
return this;
}
/**
* Expect field to be present on message.
*
* @param text The failure message on missing field.
* @param field The field to be present.
* @return The builder instance.
*/
@Nonnull
public Builder<M, E> expectPresent(@Nonnull String text, @Nonnull PField<M> field) {
builder.expect(new MessageValidation.PredicateExpectation<>(message -> message.has(field), text));
return this;
}
/**
* Expect field to be present on message.
*
* @param fields The fields to be present.
* @return The builder instance.
*/
@Nonnull
@SafeVarargs
public final Builder<M, E> expectMissing(@Nonnull PField<M>... fields) {
builder.expectMissing(fields);
return this;
}
/**
* Expect field to be present on message.
*
* @param text The failure message on present field.
* @param field The field to be present.
* @return The builder instance.
*/
@Nonnull
public Builder<M, E> expectMissing(@Nonnull String text, @Nonnull PField<M> field) {
builder.expect(new MessageValidation.PredicateExpectation<>(message -> !message.has(field), text));
return this;
}
private Builder(PMessageDescriptor<M> descriptor, @Nonnull Function<String, E> onMismatch) {
builder = MessageValidation.builder(descriptor, e -> onMismatch.apply(e.getMessage()));
}
private Builder(MessageValidation.Builder<M, E> builder) {
this.builder = builder;
}
private final MessageValidation.Builder<M, E> builder;
}
private MessageValidator(Builder<M, E> builder) {
validation = builder.builder.build();
}
}