Class FormDef

java.lang.Object
org.apache.juneau.console.widgets.FormDef
All Implemented Interfaces:
Widget

@BeanType(properties="contractVersion,template,fields,sections") public class FormDef extends Object implements Widget
The declarative source of a row-action modal's input form (the form half of a present=dialog action).
A widget contract driven by a view-module runtime

Like ModalDef, this is a general widget contract that lives in this module while the browser runtime that paints it ships with the rich-view module. Nothing here depends on that module.

Flat or sectioned

A form declares either a flat fields list or an ordered list of FormDef.Sections, never both: the flat list is the single-section case. Sections render as a ribbon-format strip above one visible pane; they are a layout of one dialog, not a stack of dialogs, so they cost nothing against the runtime's modal-depth cap.

Typed inputs, not markup

The client paints fields as native <input> / <textarea> / <select> / <button> elements via createElement. Labels and option text use textContent; prefills use .value / .checked. The runtime never assigns innerHTML from this payload. Only the types on the allowlist (text, textarea, password, checkbox, toggle, select, action) are legal — that is the XSS bound: hostile prefill cannot become an element.

template may name a server-side template for authors. It is not a client HTML sink; the shipped juneau-views.js ignores it.

Per-widget contract version (fail-loud when a form is present)

This bean validates fail-closed and carries an instance contractVersion. The version defaults to CONTRACT_VERSION from the instant the form is constructed — a raw builder no longer leaks an unversioned form regardless of whether checked() is invoked. The client refuses to open a form-bearing dialog whose version does not match the one its runtime bakes in.

This constant moves in lockstep with ModalDef.CONTRACT_VERSION and the runtime's baked-in literal, because the runtime compares one literal against both the modal's and the form's version. Bumping any two of the three makes every form-bearing dialog refuse to open.

Example:

FormDef form = FormDef.create() .field(FormDef.Input.of("resolution", "Resolution comment", "textarea") .required() .value(""));

See Also:
Since:
10.0.0
  • Field Details

    • CONTRACT_VERSION

      public static final String CONTRACT_VERSION
      The frozen form contract version. Bumped only on a breaking wire change to this form contract.
      See Also:
    • contractVersion

      The frozen form contract version discriminator.

      Defaults to CONTRACT_VERSION from the instant this form is constructed, independent of checked(). Guaranteed present is not the same as guaranteed valid: presence is this field's whole job, structural well-formedness is validate()'s (see checked()).

    • template

      public String template
      Optional FreeMarker template reference for server authors; ignored by the client.
    • fields

      Typed inputs in display order for a flat, single-section form; omitted from the wire when none are declared.

      Mutually exclusive with sections — a flat fields list is the single-section case, so declaring both is an authoring error validate() rejects rather than silently picking one.

    • sections

      Optional ordered sections for a multi-section form; omitted from the wire when none are declared.

      Mutually exclusive with fields (see that field). A single-element sections list is legal but pointless: it renders a one-tab strip where a flat fields list would render none.

  • Constructor Details

  • Method Details

    • create

      public static FormDef create()
      Starts an empty form (add fields and/or a template).
      Returns:
      A new FormDef.
    • ofTemplate

      public static FormDef ofTemplate(String template)
      Creates a form sourced from the specified FreeMarker template reference.
      Parameters:
      template - The template reference (a resolvable URL/name). Must not be null or blank.
      Returns:
      A new FormDef.
      Throws:
      IllegalArgumentException - If template is null or blank.
    • template

      public FormDef template(String value)
      Sets the optional server-author template reference. The client never treats this as HTML.
      Parameters:
      value - The template reference. Must not be null or blank.
      Returns:
      This object.
      Throws:
      IllegalArgumentException - If value is null or blank.
    • field

      public FormDef field(FormDef.Input value)
      Adds one typed input field.
      Parameters:
      value - The input. Must not be null.
      Returns:
      This object.
      Throws:
      IllegalArgumentException - If value is null.
    • section

      Adds one section, making this a multi-section form.
      Parameters:
      value - The section. Must not be null.
      Returns:
      This object.
      Throws:
      IllegalArgumentException - If value is null.
    • validate

      public void validate()
      Fail-closed bean validation.

      Does not require contractVersion to already be set — a raw-built form validated directly must not false-refuse on a null version. A form with neither fields nor sections is a no-op (a template-only / fieldless form is a shipped shape).

      Field names are unique across the whole form, not per section: every control shares one submit body and one dialog-scoped element-id namespace, so two sections declaring the same name would collide in both.

      Specified by:
      validate in interface Widget
      Throws:
      IllegalArgumentException - If both fields and sections are declared, if sections is declared but empty, if two sections share an id, or if any field is not well-formed or two fields share a name.
    • checked

      public FormDef checked()
      The serving-path hook: re-stamps CONTRACT_VERSION (already set by construction; this repairs a version a caller explicitly cleared) then validates.

      contractVersion no longer depends on this being called. Structural validation no longer depends on it either for a form served over REST: nested inside a returned ModalDef, this form is reached by WidgetsMixin.WidgetValidationProcessor's call to ModalDef.validate(), which recurses into this bean's own validate(), fail-closed with a 500, whether or not the producing endpoint called ModalDef.checked(). This method (via ModalDef.checked()) remains the only fail-closed structural validation a non-REST producer has — a direct Json.of(...) serialization, for instance — and calling it for a REST-bound form stays safe (validation is idempotent) even though it is no longer strictly required there.

      Returns:
      This object.
      Throws:
      IllegalArgumentException - If this form is not well-formed.