Class Question

java.lang.Object
nz.org.riskscape.wizard.Question

public class Question extends Object

A Question to ask the user within a Survey.

Questions can have a predicate test (i.e. askWhen(Predicate) associated with them to control whether or not they should be asked. Questions may be optional or required, and may accept multiple Answers. Questions can have dependencies (i.e. #dependsOn(String), so they don't get asked until after an earlier Question has been answered.

  • Field Details

    • HIDDEN_VALUE

      public static final Question.Hidden HIDDEN_VALUE

      The only instance of the hidden value you'll ever need. Should be stored as the bound value in a Response object, with an empty string or empty list as the user's original value (or some other non null and empty value)

    • DEFAULT_I18N_LOOKUP

      public static final Question.I18nLookupFunction DEFAULT_I18N_LOOKUP
    • ONE_REQUIRED

      public static final com.google.common.collect.Range<Integer> ONE_REQUIRED
    • ONE_AT_LEAST

      public static final com.google.common.collect.Range<Integer> ONE_AT_LEAST
    • OPTIONAL_ONE

      public static final com.google.common.collect.Range<Integer> OPTIONAL_ONE
    • OPTIONAL_MANY

      public static final com.google.common.collect.Range<Integer> OPTIONAL_MANY
    • NO_VALUE

      public static final String NO_VALUE

      Assigned to annotations without values, so that we don't have to deal with null

      See Also:
  • Constructor Details

    • Question

      public Question(String name, Class<?> parameterType)
  • Method Details

    • isComposite

      public static boolean isComposite(Class<?> clazz)
      Returns:
      true if the given type is for a "composite" question, i.e. a question that is actually split into several composite sub-parts
    • getCompositeSubparts

      public static List<Question> getCompositeSubparts(Question question, Class<?> clazz)
      Returns:
      a list of the sub-parts to a composite question, or an empty list if given class is is not composite or has no composite fields
    • formatName

      public static String formatName(String name)
      Returns:
      a cleaned up name that is OK to use as a label for this question
    • readyToBeAsked

      public boolean readyToBeAsked(IncrementalBuildState buildState)

      Checks the dependent questions have already been asked and the question is applicable.

    • isFollowing

      public boolean isFollowing(Question question)
      Returns:
      true if this question is dependent on (i.e. follows) the given question.
    • atLeastOne

      public Question atLeastOne()
    • requiredOne

      public Question requiredOne()
    • optionalOne

      public Question optionalOne()
    • optionalMany

      public Question optionalMany()
    • hidden

      public Question hidden()

      Constructs a clone of this question, but makes it a hidden question. A hidden question is one that doesn't require any input from the user, but is needed for some automatic changes to take place. For example, a hidden question might be at the end of a set of questions to plop a name on the last pipeline step to give it a well-known name for later questions to locate it simply. A hidden question should be processed automatically as soon as the previous question is answered. Note that hidden questions won't be supported by the original Survey APIs and is destined for use with the newer Survey2 APIs

      Returns:
      a new question with the arity set to one and the type as Question.Hidden
    • parseAnnotations

      public Question parseAnnotations(String... newAnnotationStrings)
      Parameters:
      newAnnotationStrings - a list of annotations to parse, each string can be either a tag (which will be assigned NO_VALUE) or a tag=value string.
      Returns:
      a copy of this Question but with the given tags replacing whatever was there before.
    • withAnnotations

      public Question withAnnotations(String k1, String v1)
      Returns:
      a copy of this Question but with the given tags replacing whatever was there before
    • withAnnotations

      public Question withAnnotations(String k1, String v1, String k2, String v2)
      Returns:
      a copy of this Question but with the given tags replacing whatever was there before
    • withAnnotations

      public Question withAnnotations(String k1, String v1, String k2, String v2, String k3, String v3)
      Returns:
      a copy of this Question but with the given tags replacing whatever was there before
    • hasAnnotation

      public boolean hasAnnotation(String tag)
      Returns:
      true if there is a tag attached to this Question that matches the given string
    • hasAnnotationWithValue

      public boolean hasAnnotationWithValue(String tag, String value)
      Returns:
      true if there is a tag attached to this Question that matches the tag and it has contains value
    • getAnnotation

      public Optional<String> getAnnotation(String tag)
    • dependsOn

      public Question dependsOn(Question newDependsOn)

      Make a new Question that's dependent on the given questionName being asked first. Note that these dependencies are only for Questions within the same QuestionSet.

    • withType

      public Question withType(Class<?> newParameterType)

      Clone this question, but with a new parameter type field.

    • askWhen

      public Question askWhen(Predicate<IncrementalBuildState> conditionMet)

      Adds a predicate condition that should be met before this question is asked.

    • isSingleValueQuestion

      public boolean isSingleValueQuestion()
      Returns:
      true if this question wants at most one answer
    • isRequired

      public boolean isRequired()
      Returns:
      true if at least one response is required for this question
    • isOptional

      public boolean isOptional()

      The opposite (negation) of isRequired

      Returns:
      true if this question is not hidden but can be skipped
    • isHidden

      public boolean isHidden()
      Returns:
      true if this question should be hidden from the user. See hidden()
    • isRequired

      public boolean isRequired(IncrementalBuildState buildState)

      Check if the question is really required. A question if required if it should be asked, and also requires an answer.

      Returns:
      true if question requires a response
    • checkValidity

      public void checkValidity(List<Object> values)

      sanity checking code to prevent an invalid answer being recorded - the errors are not meant for human consumption but we might want to adapt them later

    • requireSingleValueQuestion

      public void requireSingleValueQuestion()

      Explosive method for API users to fail fast if when they do a single value thing on a multi value question

    • getId

      public String getId()

      Returns a unique ID for the Question (which is dependent on the QuestionSet it belongs to.

    • toParameter

      public nz.org.riskscape.engine.bind.Parameter toParameter()

      Returns a Parameter representing this question (so that saved wizard answers can be overridden from the CLI).

    • toString

      public String toString()
      Overrides:
      toString in class Object
    • getQuestionSet

      public QuestionSet getQuestionSet()
      Returns:
      the QuestionSet this question belongs to
      Throws:
      IllegalStateException - if this question is unassigned
    • getPhase

      public Phase getPhase()
      Returns:
      the phase this question is connected to (via its QuestionSet)
    • isUnassigned

      public boolean isUnassigned()
      Returns:
      true if the question does not yet belong to a QuestionSet. A question can assigned to a set by calling the inSet clone method.
    • inSet

      public Question inSet(QuestionSet newQuestionSet)
      Returns:
      a clone of this Question but with it assigned to the given question set
    • withName

      public Question withName(String newName)
    • withI18nLookup

      public Question withI18nLookup(Question.I18nLookupFunction newLookup)
    • withI18nLookup

      public Question withI18nLookup(BiFunction<String,Locale,String> newLookup)
    • atLocation

      public Question atLocation(ChangeLocation newChangeLocation)
    • getTitle

      public Optional<String> getTitle(Locale locale)
    • getDescription

      public Optional<String> getDescription(Locale locale)
    • getSummary

      public Optional<String> getSummary(Locale locale)

      Returns of concise bit of text that summarizes this question. This is really closer to title, and title should be 'prompt', but to avoid churn, this gets a the new name instead of renaming all the things

    • getMessage

      public Optional<String> getMessage(String suffix, Locale locale)
    • getMessageSource

      public nz.org.riskscape.engine.i18n.MessageSource getMessageSource()
    • getSurvey

      public Survey getSurvey()
    • withChoices

      public Question withChoices(Function<IncrementalBuildState,List<Choice>> newFunction)
    • getChoices

      public List<Choice> getChoices(IncrementalBuildState buildState)
      Returns:
      A list of Choices that are acceptable, predefined answers for this question
    • isComposite

      public boolean isComposite()
      Returns:
      true if this is a "composite" question, i.e. a question that is actually split into several composite sub-parts
    • getCompositeSubparts

      public List<Question> getCompositeSubparts()
      Returns:
      a list of the sub-parts to a composite question
    • getDependsOn

      public Optional<Question> getDependsOn()
    • isAskAs

      public boolean isAskAs()
      Returns:
      true if this question can be converted to a differently asked question for a customized UI, while recording the result as some other type.
    • withAskAs

      public <T> Question withAskAs(Class<T> newAskAsType, Function<T,String> newAskAsFunction)
    • withAskAs

      public Question withAskAs(AskAs<?> newAskAs)
    • getAskAs

      public Optional<AskAs> getAskAs()
    • getAskedAs

      public Question getAskedAs()
    • getSubQuestion

      public Optional<Question> getSubQuestion(String fieldName)
      Returns:
      the composite sub-question that corresponds to the given fieldName
    • getName

      @NonNull public @NonNull String getName()
    • getParameterType

      @NonNull public @NonNull Class<?> getParameterType()
    • getShouldBeAsked

      @NonNull public @NonNull Predicate<IncrementalBuildState> getShouldBeAsked()
    • getArity

      @NonNull public @NonNull com.google.common.collect.Range<Integer> getArity()
    • getAnnotations

      @NonNull public @NonNull com.google.common.collect.ImmutableMap<String,String> getAnnotations()
    • getI18nLookup

      public Question.I18nLookupFunction getI18nLookup()
    • getChoiceFunction

      public Function<IncrementalBuildState,List<Choice>> getChoiceFunction()
    • getChangeLocation

      @NonNull public @NonNull ChangeLocation getChangeLocation()
      Returns:
      a ChangeLocation that is associated with this question. The ChangeLocation provides an indication to UIs and to Survey code of where the change triggered by a response to this question should be applied. It defaults to 'at the last change', which is what 90% of questions will want to do when incrementally building.
    • equals

      public boolean equals(Object o)
      Overrides:
      equals in class Object
    • canEqual

      protected boolean canEqual(Object other)
    • hashCode

      public int hashCode()
      Overrides:
      hashCode in class Object