+ /**
+ * Container for a profile field.
+ */
+ public class Field {
+
+ /** The ID of the field. */
+ private final String id;
+
+ /** The name of the field. */
+ private String name;
+
+ /** The value of the field. */
+ private String value;
+
+ /**
+ * Creates a new field with a random ID.
+ */
+ private Field() {
+ this(UUID.randomUUID().toString());
+ }
+
+ /**
+ * Creates a new field with the given ID.
+ *
+ * @param id
+ * The ID of the field
+ */
+ private Field(@Nonnull String id) {
+ this.id = checkNotNull(id, "id must not be null");
+ }
+
+ /**
+ * Returns the ID of this field.
+ *
+ * @return The ID of this field
+ */
+ @Nonnull
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Returns the name of this field.
+ *
+ * @return The name of this field
+ */
+ @Nonnull
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Sets the name of this field. The name must not be {@code null} and
+ * must not match any other fields in this profile but my match the name
+ * of this field.
+ *
+ * @param name
+ * The new name of this field
+ * @return This field
+ */
+ @Nonnull
+ public Field setName(@Nonnull String name) {
+ checkNotNull(name, "name must not be null");
+ checkArgument(getFieldByName(name) == null, "name must be unique");
+ this.name = name;
+ return this;
+ }
+
+ /**
+ * Returns the value of this field.
+ *
+ * @return The value of this field
+ */
+ @Nullable
+ public String getValue() {
+ return value;
+ }
+
+ /**
+ * Sets the value of this field. While {@code null} is allowed, no
+ * guarantees are made that {@code null} values are correctly persisted
+ * across restarts of the plugin!
+ *
+ * @param value
+ * The new value of this field
+ * @return This field
+ */
+ @Nonnull
+ public Field setValue(@Nullable String value) {
+ this.value = value;
+ return this;
+ }
+
+ //
+ // OBJECT METHODS
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals(Object object) {
+ if (!(object instanceof Field)) {
+ return false;
+ }
+ Field field = (Field) object;
+ return id.equals(field.id);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return id.hashCode();
+ }
+
+ }
+
+ /**
+ * Exception that signals the addition of a field with an empty name.
+ */
+ public static class EmptyFieldName extends IllegalArgumentException { }
+
+ /**
+ * Exception that signals the addition of a field that already exists.
+ */
+ public static class DuplicateField extends IllegalArgumentException { }
+