![JAR search and dependency download from the Maven repository](/logo.png)
fr.landel.utils.assertor.StepAssertor Maven / Gradle / Ivy
/*-
* #%L
* utils-assertor
* %%
* Copyright (C) 2016 - 2018 Gilles Landel
* %%
* 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.
* #L%
*/
package fr.landel.utils.assertor;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.BiPredicate;
import java.util.function.Function;
import java.util.function.Predicate;
import fr.landel.utils.assertor.commons.MessageAssertor;
import fr.landel.utils.assertor.commons.ParameterAssertor;
import fr.landel.utils.assertor.enums.EnumAnalysisMode;
import fr.landel.utils.assertor.enums.EnumOperator;
import fr.landel.utils.assertor.enums.EnumStep;
import fr.landel.utils.assertor.enums.EnumType;
import fr.landel.utils.commons.CastUtils;
import fr.landel.utils.commons.ObjectUtils;
import fr.landel.utils.commons.StringUtils;
import fr.landel.utils.commons.builder.ToStringBuilder;
import fr.landel.utils.commons.builder.ToStringStyles;
/**
* Class to store results of assertion at each step. It contains the current
* result and the list of parameters added at each assertion.
*
*
* What it's stored:
*
*
* - object: the object to check
* - type: the type of object to check
* - operator: the operator applied to the next step
* - not: if not has to be applied to the next step
* - preconditionOK: if preconditions are valid (here we ensured that the
* check will not throw a {@link NullPointerException} by example)
* - valid: the result of the check (the associated function is only run if
* preconditions are ok)
* - preconditionMessage: the message applied if preconditions aren't
* valid
* - message: the message applied if preconditions are valid and check result
* is ko
* - parameters: the whole list of parameters (includes previous checked
* object and assertion parameters)
*
*
* @since Aug 7, 2016
* @author Gilles
*
* @param
* the type of assertor result
*/
public class StepAssertor implements Serializable {
/**
* serialVersionUID
*/
private static final long serialVersionUID = -8316517833558101416L;
private static final String ERROR_STEP_TYPE = "stepType is missing";
private static final String ATT_OBJECT = "object";
private static final String ATT_TYPE = "type";
private static final String ATT_ANALYSIS_MODE = "analysisMode";
private static final String ATT_OPERATOR = "operator";
private static final String ATT_NOT = "not";
private static final String ATT_KEY = "key";
private static final String ATT_KEY_NOT = "key not";
private static final String ATT_PARAMETERS = "parameters";
private static final String ATT_MESSAGE = "message";
private final StepAssertor> previousStep;
private final Optional> subStep;
private final Optional>> subAssertor;
private final Optional> mapper;
private final EnumAnalysisMode analysisMode;
private final EnumStep stepType;
private final T object;
private final EnumType type;
private final boolean checked;
private final EnumOperator operator;
private final boolean not;
// (object) -> precondition OK?
private Predicate preChecker;
// default key message (used id precondition ko or message null)
private CharSequence messageKey;
private boolean messageKeyNot;
// (object, not) -> valid?
private BiPredicate checker;
// if 'not' is directly applied by checker
private boolean notAppliedByChecker;
private MessageAssertor message;
private List> parameters;
/**
* Base constructor
*
* @param stepType
* the step type
* @param previousStep
* the previous step
* @param subStep
* the sub step
* @param object
* the object under check
* @param type
* the object type
* @param checked
* if the object has to be checked
* @param operator
* the operator for the previous combination (with next step)
* @param not
* if NOT operator is applied on the next checker
* @param analysisMode
* the analysis preferred mode
* @param
* the previous step type
* @param
* the sub step type
*/
private > StepAssertor(final EnumStep stepType, final StepAssertor previousStep,
final StepAssertor subStep, final Function subAssertor, final Function mapper, final T object,
final EnumType type, final boolean checked, final EnumOperator operator, final boolean not,
final EnumAnalysisMode analysisMode) {
this.stepType = stepType;
this.subStep = Optional.ofNullable(subStep);
this.subAssertor = CastUtils.cast(Optional.ofNullable(subAssertor));
this.mapper = CastUtils.cast(Optional.ofNullable(mapper));
this.previousStep = previousStep;
this.object = object;
this.type = type;
this.checked = checked;
this.operator = operator;
this.not = not;
this.analysisMode = ObjectUtils.defaultIfNull(analysisMode, EnumAnalysisMode.STANDARD);
}
/**
* Constructor for each {@link Assertor#that}
*
* @param object
* the object under check
* @param type
* the type of the object
* @param analysisMode
* the analysis preferred mode
*/
public StepAssertor(final T object, final EnumType type, final EnumAnalysisMode analysisMode) {
this(EnumStep.CREATION, null, null, null, null, object, type, true, null, false, analysisMode);
}
/**
* Constructor for predicate {@code Assertor.of...}
*
* @param type
* the type of object
* @param analysisMode
* the analysis preferred mode
*/
public StepAssertor(final EnumType type, final EnumAnalysisMode analysisMode) {
this(EnumStep.PREDICATE, null, null, null, null, null, type, false, null, false, analysisMode);
}
/**
* Combining constructor, for (NOT operator) (not is set to true)
*
* @param previousStep
* the previous step
*/
public StepAssertor(final StepAssertor previousStep) {
this(EnumStep.NOT, previousStep, null, null, null, null, null, false, null, true, previousStep.getAnalysisMode());
}
/**
* Combining constructor, for (NOT operator) (not is set to true)
*
* @param previousStep
* the previous step
* @param object
* the object under check
*/
public StepAssertor(final StepAssertor previousStep, final T object) {
// the type is not required already loaded from predicate step
this(EnumStep.PREDICATE_OBJECT, previousStep, null, null, null, object, null, true, null, false, previousStep.getAnalysisMode());
}
/**
* Combining constructor with new object, for (AND, OR and XOR combinations)
*
* @param previousStep
* the previous step
* @param object
* the object under check
* @param type
* the object type
* @param operator
* the operator for the next combination
* @param analysisMode
* the analysis preferred mode
* @param
* the type of previous step object
*/
public StepAssertor(final StepAssertor previousStep, final T object, final EnumType type, final EnumOperator operator,
final EnumAnalysisMode analysisMode) {
this(EnumStep.OBJECT, previousStep, null, null, null, object, type, true, operator, false, analysisMode);
}
/**
* Combining constructor with new object, for (AND, OR and XOR combinations)
*
* @param previousStep
* the previous step
* @param mapper
* the mapper function
* @param type
* the object type
* @param operator
* the operator for the next combination
* @param analysisMode
* the analysis preferred mode
* @param
* the type of previous step object
*/
public StepAssertor(final StepAssertor previousStep, final Function mapper, final EnumType type,
final EnumOperator operator, final EnumAnalysisMode analysisMode) {
this(EnumStep.PROPERTY, previousStep, null, null, mapper, null, type, true, operator, false, analysisMode);
}
/**
*
* Combining constructor, for (AND, OR and XOR combinations)
*
* @param previousStep
* The previous step
* @param operator
* The operator for the next combination
*/
public StepAssertor(final StepAssertor previousStep, final EnumOperator operator) {
this(EnumStep.OPERATOR, previousStep, null, null, null, null, null, false, operator, false, previousStep.getAnalysisMode());
}
/**
* Standard combining constructor for sub Assertor (not is set to false)
*
* @param previousStep
* the previous step
* @param subStep
* the sub step
* @param operator
* The operator for the next combination
* @param
* the sub step type
*/
public StepAssertor(final StepAssertor previousStep, final StepAssertor subStep, final EnumOperator operator) {
this(EnumStep.SUB, previousStep, subStep, null, null, null, null, false, operator, false, previousStep.getAnalysisMode());
}
/**
* Standard combining constructor for sub Assertor (not is set to false)
*
* @param previousStep
* the previous step
* @param subAssertor
* the sub assertor function
* @param operator
* The operator for the next combination
* @param
* the sub step type
* @param
* the output step type
*/
public > StepAssertor(final StepAssertor previousStep, final Function subAssertor,
final EnumOperator operator) {
this(EnumStep.SUB_ASSERTOR, previousStep, null, subAssertor, null, null, null, false, operator, false,
previousStep.getAnalysisMode());
}
/**
* Standard combining constructor (not is set to false)
*
* @param previousStep
* The previous step
* @param preChecker
* the checker for preconditions
* @param checker
* the main checker (only applied if preChecker returns true)
* @param notAppliedByChecker
* if 'not' is directly applied by checker
* @param message
* the error message (only applied if preChecker returns true and
* checker returns false)
* @param messageKey
* the default message key (used if preChecker returns false or
* if checker returns false and message is null)
* @param messageKeyNot
* if the message key has to be suffixed by NOT
* @param parameters
* the list of parameters for the current step
*/
@SafeVarargs
public StepAssertor(final StepAssertor previousStep, final Predicate preChecker, final BiPredicate checker,
final boolean notAppliedByChecker, final MessageAssertor message, final CharSequence messageKey, final boolean messageKeyNot,
final ParameterAssertor>... parameters) {
this(EnumStep.ASSERTION, previousStep, null, null, null, null, null, false, null, false, previousStep.getAnalysisMode());
this.messageKey = messageKey;
this.messageKeyNot = messageKeyNot;
this.preChecker = preChecker;
this.checker = checker;
this.notAppliedByChecker = notAppliedByChecker;
this.message = message;
this.parameters = new ArrayList<>(Arrays.asList(parameters));
}
/**
* Standard combining constructor without precondition (not is set to false)
*
* @param previousStep
* The previous step
* @param checker
* the main checker (only applied if preChecker returns true)
* @param notAppliedByChecker
* if 'not' is directly applied by checker
* @param message
* the error message (only applied if preChecker returns true and
* checker returns false)
* @param messageKey
* the default message key (used if preChecker returns false or
* if checker returns false and message is null)
* @param messageKeyNot
* if the message key has to be suffixed by NOT
* @param parameters
* the list of parameters for the current step
*/
@SafeVarargs
public StepAssertor(final StepAssertor previousStep, final BiPredicate checker, final boolean notAppliedByChecker,
final MessageAssertor message, final CharSequence messageKey, final boolean messageKeyNot,
final ParameterAssertor>... parameters) {
this(previousStep, null, checker, notAppliedByChecker, message, messageKey, messageKeyNot, parameters);
}
/**
* @return the preChecker
*/
public Predicate getPreChecker() {
return this.preChecker;
}
/**
* @return the checker
*/
public BiPredicate getChecker() {
return this.checker;
}
/**
* @return the messageKey
*/
public CharSequence getMessageKey() {
return this.messageKey;
}
/**
* @return the message
*/
public MessageAssertor getMessage() {
return this.message;
}
/**
* @return the stepType
*/
public EnumStep getStepType() {
return this.stepType;
}
/**
* @return the previousStep
*/
public StepAssertor> getPreviousStep() {
return this.previousStep;
}
/**
* @return the object
*/
public T getObject() {
return this.object;
}
/**
* @return the type
*/
public EnumType getType() {
return this.type;
}
/**
* @return the checked
*/
public boolean isChecked() {
return this.checked;
}
/**
* @return the operator
*/
public EnumOperator getOperator() {
return this.operator;
}
/**
* @return the not
*/
public boolean isNot() {
return this.not;
}
/**
* @return the subStep
*/
public Optional> getSubStep() {
return this.subStep;
}
/**
* If the NOT is directly managed by the checker
*
* @return the notAppliedByChecker
*/
public boolean isNotAppliedByChecker() {
return this.notAppliedByChecker;
}
/**
* @return the preferred analysis mode
*/
public EnumAnalysisMode getAnalysisMode() {
return this.analysisMode;
}
/**
* @return the mapper function
*/
public Optional> getMapper() {
return this.mapper;
}
/**
* @return the sub assertor
*/
public Optional>> getSubAssertor() {
return this.subAssertor;
}
/**
* @return the clone of parameters
*/
public List> getParameters() {
return this.parameters;
}
/**
* @return the messageKeyNot
*/
public boolean isMessageKeyNot() {
return this.messageKeyNot;
}
@Override
public String toString() {
Objects.requireNonNull(this.stepType, ERROR_STEP_TYPE);
final ToStringBuilder sb = new ToStringBuilder(ToStringStyles.JSON_SPACED);
sb.append(this.stepType.name());
switch (this.stepType) {
case CREATION:
sb.append(ATT_OBJECT, this.object);
sb.append(ATT_TYPE, this.type);
sb.append(ATT_ANALYSIS_MODE, this.analysisMode);
break;
case OBJECT:
sb.append(ATT_OBJECT, this.object);
sb.append(ATT_TYPE, this.type);
sb.append(ATT_ANALYSIS_MODE, this.analysisMode);
sb.append(ATT_OPERATOR, this.operator);
break;
case PROPERTY:
sb.append(ATT_TYPE, this.type);
sb.append(ATT_ANALYSIS_MODE, this.analysisMode);
sb.append(ATT_OPERATOR, this.operator);
break;
case PREDICATE:
sb.append(ATT_TYPE, this.type);
sb.append(ATT_ANALYSIS_MODE, this.analysisMode);
break;
case PREDICATE_OBJECT:
sb.append(ATT_OBJECT, this.object);
sb.append(ATT_ANALYSIS_MODE, this.analysisMode);
break;
case NOT:
sb.append(ATT_NOT, this.not);
break;
case ASSERTION:
sb.append(ATT_KEY, this.messageKey);
sb.append(ATT_KEY_NOT, this.messageKeyNot);
sb.appendAndFormat(ATT_PARAMETERS, this.parameters, StringUtils::joinComma);
sb.append(ATT_MESSAGE, this.message);
break;
case OPERATOR: // intentional fall-through
case SUB_ASSERTOR: // intentional fall-through
case SUB: // intentional fall-through
default:
sb.append(ATT_OPERATOR, this.operator);
}
return sb.build();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy