# `<serializedBean>` format reference

Inside every `<screen>`, `<action>`, `<formComponent>`, `<group>`, `<style>`, `<link>`, and `<application>` element, the bean's properties are encoded as a sequence of `<property>` elements inside `<serializedBean>`.

For property *availability* (which properties exist on a given bean class), see `bean-index.md` and `beans/*.md`.

> The format is a reshaped form of Java `XMLEncoder` output. Setter calls become `<property name="X">`, collection adds become `<add>`, map entries become `<entry>`, array slots become `<element>`. Some XMLEncoder constructs are not reshaped and pass through as `<void>`. This can happen for serialized custom beans. Do not use this form for new content. 

## Contents

- [Anatomy](#anatomy)
- [Property forms](#property-forms)
- [`<object>` — constructors and setter calls](#object--constructors-and-setter-calls)
- [`<add>` — collection mutations](#add--collection-mutations)
- [`<entry>` — map mutations](#entry--map-mutations)
- [`<element>` — array slots](#element--array-slots)
- [Defaults: omit, don't write](#defaults-omit-dont-write)
- [`@id` / `@idref` — preserve, don't add](#id--idref--preserve-dont-add)
- [Whitespace](#whitespace)

## Anatomy

```xml
<serializedBean>
  <property name="frameHeight" type="int" value="550" />
  <property name="frameWidth" type="int" value="600" />
</serializedBean>
```

A `<serializedBean>` with no non-default property values has no children at all (or is omitted entirely from the parent — see *Defaults*).

The `beanClass="…"` FQN that names the target bean lives on the **enclosing** element (`<screen beanClass="…">`, `<action beanClass="…">`, etc.). Inside `<serializedBean>` you only set properties.

## Property forms

Every `<property>` carries `name="…"` and takes one of these forms:

### 1. Primitive scalar
`@type` is one of `boolean`, `byte`, `char`, `short`, `int`, `long`, `float`, `double`. Value is in `@value`. No children.

```xml
<property name="enabled" type="boolean" value="true" />
<property name="frameHeight" type="int" value="550" />
```

### 2. String scalar
`@type="string"`. Value is element text content.

```xml
<property name="title" type="string">Welcome</property>
```

### 3. Enum
`@type="enum"`, `@class` (FQN of the enum), `@value` (constant name from `name()`). No children.

```xml
<property name="fontStyle" type="enum"
          class="com.install4j.runtime.beans.formcomponents.FontStyle"
          value="BOLD" />
```

### 4. Null
`@type="null"`. Nothing else.

```xml
<property name="labelWidgetStyleId" type="null" />
```

### 5. Array
`@type="array"` plus `@length`, plus exactly one of `@elementType` (primitive / string element type) or `@class` (object element type, FQN). Children are `<element index="N">`.

For primitive / string element types the value is in the `<element>`'s text or `@value`:

```xml
<property name="listEntries" type="array" elementType="string" length="1">
  <element index="0">${installer:jvmLocations}</element>
</property>
```

For object element types, each `<element>` contains a single `<object>` child:

```xml
<property name="files" type="array" class="java.io.File" length="1">
  <element index="0">
    <object class="java.io.File">
      <string>${installer:vmoptionsTargetDirectory}/hello.vmoptions</string>
    </object>
  </element>
</property>
```

### 6. Object value
No `@type`. The element contains a single `<object>` child that constructs the property's value.

```xml
<property name="buttonImage">
  <object class="com.install4j.api.beans.ExternalFile">
    <string>./sample.png</string>
  </object>
</property>
```

### 7. Mutation
No `@type`. Children are `<property>` / `<add>` / `<entry>` that *mutate* the property's existing value (the property is not reassigned) — append to a collection, put into a map, or set sub-properties on the existing instance.

```xml
<property name="coupledComponentIds">
  <add type="string">3900</add>
</property>
```

## `<object>` — constructors and setter calls

`<object class="FQN">` constructs an instance. Children come in two parts, in order:

1. **Constructor arguments** — typed value elements (`<string>`, `<int>`, `<boolean>`, `<long>`, `<double>`, `<float>`, `<short>`, `<byte>`, `<char>`, `<null/>`, nested `<object>`, or `<array>` for an array argument).
2. **Setter calls** — `<property>` children applied after construction.

Example with constructor args (`Insets(top, left, bottom, right)`):

```xml
<property name="insets">
  <object class="java.awt.Insets">
    <int>0</int>
    <int>20</int>
    <int>0</int>
    <int>0</int>
  </object>
</property>
```

Example with setter calls (`ScriptProperty` with its `value` set after no-arg construction):

```xml
<property name="script">
  <object class="com.install4j.api.beans.ScriptProperty">
    <property name="value" type="string">JVMSelector.JVMLocation[] locations = ...
return true;</property>
  </object>
</property>
```

Nested-bean properties follow the same pattern — look the nested class up in `bean-index.md` for its property table.

## `<add>` — collection mutations

Used inside a [Mutation form](#7-mutation) `<property>`. Carries the same value attributes as a `<property>` (see [Property forms](#property-forms)) but without `@name`.

```xml
<property name="coupledComponentIds">
  <add type="string">3900</add>
  <add type="string">3743</add>
</property>
```

## `<entry>` — map mutations

Used inside a [Mutation form](#7-mutation) `<property>` for `Map` puts. Contains exactly two child value elements (in order: key, value). Insertion order is preserved.

```xml
<property name="environmentVariables">
  <entry>
    <string>PATH</string>
    <string>${PATH};C:\custom\bin</string>
  </entry>
  <entry>
    <string>JAVA_HOME</string>
    <string>${installer:sys.installationDir}/jre</string>
  </entry>
</property>
```

## `<element>` — array slots

Used inside an [Array](#5-array) `<property>`. `@index` is required and zero-based. For primitive/string arrays the value is in `@value` or text content; for object arrays the value is a single `<object>` child.

`@length` on the parent `<property>` must equal the number of `<element>` children, and indices must be contiguous starting at 0.

## Defaults: omit, don't write

The encoder writes only properties whose value differs from the default returned by a freshly-constructed bean. When editing:

- **To leave a property at its default**: do not write the `<property>` element at all. Don't write `<property name="X" type="null"/>` either — that explicitly assigns null, which may differ from the default.
- **To reset a previously-set property**: delete its `<property>` element. The default takes over.
- **To set a String property to the empty string explicitly**: `<property name="X" type="string"></property>`. This is *only* meaningful when the default is non-empty; otherwise the element is redundant.

## `@id` / `@idref` — preserve, don't add

You may encounter `<property … id="SomeName">` or `<object class="…" id="SomeName">` in existing files, paired with `<object idref="SomeName"/>` somewhere else. These are XMLEncoder-style aliases used when the same instance is shared across multiple properties.

- **When editing existing XML**: if you change a property that carries `id="…"`, keep the `id` attribute (or remove every `idref` to it).
- **When writing new XML**: never add `id`/`idref`. Inline the value at every site that needs it — install4j does not require reference identity for configuration values.

## Whitespace

Text content inside `<property type="string">…</property>`, `<add type="string">…</add>`, and `<element>` slots is preserved verbatim. This matters for:

- Multi-line script bodies inside `ScriptProperty` (each line break ends up in the runtime script source).
- File paths and command lines (a stray leading space changes the meaning).
- Sibling script blocks (`<condition>`, `<validation>`, `<preActivation>`, `<postActivation>`, `<initScript>`, `<visibilityScript>`) — these are children of bean *containers*, not part of `<serializedBean>`, but follow the same rule.

Do not reformat with an XML pretty-printer that normalises text-node whitespace.

---

When in doubt about an unfamiliar property type (`ExternalFile`, `LightOrDarkColor`, `Insets`, custom delegates), grep `samples/` for the type name to find a real-world encoding before constructing one by hand.
