All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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