diff --git a/src/main/java/org/springframework/hateoas/mediatype/hal/forms/HalFormsOptions.java b/src/main/java/org/springframework/hateoas/mediatype/hal/forms/HalFormsOptions.java index 2bb2f33f..8410c5e7 100644 --- a/src/main/java/org/springframework/hateoas/mediatype/hal/forms/HalFormsOptions.java +++ b/src/main/java/org/springframework/hateoas/mediatype/hal/forms/HalFormsOptions.java @@ -23,6 +23,7 @@ import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.annotation.JsonProperty; @@ -61,7 +62,7 @@ public interface HalFormsOptions { Assert.notNull(values, "Values must not be null!"); - return new Inline(values, null, null, null, null); + return new Inline(values, null, null, null, null, null); } /** @@ -74,7 +75,7 @@ public interface HalFormsOptions { Assert.notNull(link, "Link must not be null!"); - return new Remote(link, null, null, null, null); + return new Remote(link, null, null, null, null, null); } /** @@ -122,14 +123,18 @@ public interface HalFormsOptions { @Nullable Long getMaxItems(); + @Nullable + Object getSelectedValue(); + public static abstract class AbstractHalFormsOptions> implements HalFormsOptions { private final @Nullable String promptField, valueField; private final @Nullable Long minItems, maxItems; + private final @Nullable Object selectedValue; protected AbstractHalFormsOptions(@Nullable String promptRef, @Nullable String valueRef, @Nullable Long minItems, - @Nullable Long maxItems) { + @Nullable Long maxItems, @Nullable Object selectedValue) { Assert.isTrue(minItems == null || minItems >= 0, "MinItems must be greater than or equal to 0!"); @@ -137,6 +142,7 @@ public interface HalFormsOptions { this.valueField = valueRef; this.minItems = minItems; this.maxItems = maxItems; + this.selectedValue = selectedValue; } /* @@ -179,6 +185,17 @@ public interface HalFormsOptions { return maxItems; } + /* + * (non-Javadoc) + * @see org.springframework.hateoas.mediatype.hal.forms.HalFormsOptions#getSelectedValue() + */ + @Nullable + @Override + @JsonIgnore + public Object getSelectedValue() { + return selectedValue; + } + /** * Configures the given field to be used as prompt field. * @@ -191,7 +208,7 @@ public interface HalFormsOptions { throw new IllegalArgumentException("Prompt field has to either be null or actually have text!"); } - return with(promptField, valueField, minItems, maxItems); + return with(promptField, valueField, minItems, maxItems, selectedValue); } /** @@ -206,7 +223,7 @@ public interface HalFormsOptions { throw new IllegalArgumentException("Value field has to either be null or actually have text!"); } - return with(promptField, valueField, minItems, maxItems); + return with(promptField, valueField, minItems, maxItems, selectedValue); } /** @@ -221,7 +238,7 @@ public interface HalFormsOptions { throw new IllegalArgumentException("minItems has to be null or greater or equal to zero!"); } - return with(promptField, valueField, minItems, maxItems); + return with(promptField, valueField, minItems, maxItems, selectedValue); } /** @@ -230,13 +247,23 @@ public interface HalFormsOptions { * @param maxItems must be {@literal null} or greater than zero. * @return */ - public T withMaxItems(Long maxItems) { + public T withMaxItems(@Nullable Long maxItems) { if (maxItems != null && maxItems <= 0) { throw new IllegalArgumentException("maxItems has to be null or greater than zero!"); } - return with(promptField, valueField, minItems, maxItems); + return with(promptField, valueField, minItems, maxItems, selectedValue); + } + + /** + * Configured the value to be initially selected + * + * @param value + * @return + */ + public T withSelectedValue(@Nullable Object value) { + return with(promptField, valueField, minItems, maxItems, value); } /** @@ -249,7 +276,7 @@ public interface HalFormsOptions { * @return */ protected abstract T with(@Nullable String promptRef, @Nullable String valueRef, @Nullable Long minItems, - @Nullable Long maxItems); + @Nullable Long maxItems, @Nullable Object selectedValue); } public static class Inline extends AbstractHalFormsOptions { @@ -262,9 +289,9 @@ public interface HalFormsOptions { * @param valueRef */ private Inline(Collection values, @Nullable String promptRef, @Nullable String valueRef, - @Nullable Long minItems, @Nullable Long maxItems) { + @Nullable Long minItems, @Nullable Long maxItems, @Nullable Object selectedValue) { - super(promptRef, valueRef, minItems, maxItems); + super(promptRef, valueRef, minItems, maxItems, selectedValue); Assert.notNull(values, "Values must not be null!"); @@ -283,12 +310,12 @@ public interface HalFormsOptions { /* * (non-Javadoc) - * @see org.springframework.hateoas.mediatype.hal.forms.HalFormsOptions.AbstractHalFormsOptions#with(java.lang.String, java.lang.String, java.lang.Long, java.lang.Long) + * @see org.springframework.hateoas.mediatype.hal.forms.HalFormsOptions.AbstractHalFormsOptions#with(java.lang.String, java.lang.String, java.lang.Long, java.lang.Long, java.lang.Object) */ @Override protected Inline with(@Nullable String promptRef, @Nullable String valueRef, @Nullable Long minItems, - @Nullable Long maxItems) { - return new Inline(inline, promptRef, valueRef, minItems, maxItems); + @Nullable Long maxItems, @Nullable Object selectedValue) { + return new Inline(inline, promptRef, valueRef, minItems, maxItems, selectedValue); } } @@ -302,9 +329,9 @@ public interface HalFormsOptions { private final Link link; private Remote(Link link, @Nullable String promptRef, @Nullable String valueRef, @Nullable Long minItems, - @Nullable Long maxItems) { + @Nullable Long maxItems, @Nullable Object selectedValue) { - super(promptRef, valueRef, minItems, maxItems); + super(promptRef, valueRef, minItems, maxItems, selectedValue); Assert.notNull(link, "Link must not be null!"); @@ -323,12 +350,12 @@ public interface HalFormsOptions { /* * (non-Javadoc) - * @see org.springframework.hateoas.mediatype.hal.forms.HalFormsOptions.Foo#withFoo(java.lang.String, java.lang.String) + * @see org.springframework.hateoas.mediatype.hal.forms.HalFormsOptions.AbstractHalFormsOptions#with(java.lang.String, java.lang.String, java.lang.Long, java.lang.Long, java.lang.Object) */ @Override protected Remote with(@Nullable String promptRef, @Nullable String valueRef, @Nullable Long minItems, - @Nullable Long maxItems) { - return new Remote(link, promptRef, valueRef, minItems, maxItems); + @Nullable Long maxItems, @Nullable Object selectedValue) { + return new Remote(link, promptRef, valueRef, minItems, maxItems, selectedValue); } } } diff --git a/src/main/java/org/springframework/hateoas/mediatype/hal/forms/HalFormsProperty.java b/src/main/java/org/springframework/hateoas/mediatype/hal/forms/HalFormsProperty.java index 38139dd8..1cab152f 100644 --- a/src/main/java/org/springframework/hateoas/mediatype/hal/forms/HalFormsProperty.java +++ b/src/main/java/org/springframework/hateoas/mediatype/hal/forms/HalFormsProperty.java @@ -38,7 +38,8 @@ import com.fasterxml.jackson.annotation.JsonProperty; @JsonInclude(Include.NON_DEFAULT) final class HalFormsProperty implements Named { - private final String name, value, prompt, regex, placeholder; + private final String name, prompt, regex, placeholder; + private final Object value; private final boolean templated, multi; private final @JsonInclude(Include.NON_DEFAULT) boolean readOnly, required; private final @Nullable Long min, max, minLength, maxLength; @@ -64,12 +65,13 @@ final class HalFormsProperty implements Named { this.options = null; } - private HalFormsProperty(String name, boolean readOnly, String value, String prompt, String regex, boolean templated, + private HalFormsProperty(String name, boolean readOnly, @Nullable Object value, String prompt, String regex, + boolean templated, boolean required, boolean multi, String placeholder, @Nullable Long min, @Nullable Long max, @Nullable Long minLength, @Nullable Long maxLength, @Nullable HtmlInputType type, @Nullable HalFormsOptions options) { - Assert.notNull(name, "name must not be null!"); + Assert.notNull(name, "Name must not be null!"); this.name = name; this.readOnly = readOnly; @@ -132,7 +134,7 @@ final class HalFormsProperty implements Named { * @param value * @return */ - HalFormsProperty withValue(String value) { + HalFormsProperty withValue(@Nullable Object value) { return this.value == value ? this : new HalFormsProperty(this.name, this.readOnly, value, this.prompt, this.regex, this.templated, this.required, @@ -329,7 +331,7 @@ final class HalFormsProperty implements Named { } @JsonProperty - String getValue() { + Object getValue() { return this.value; } diff --git a/src/main/java/org/springframework/hateoas/mediatype/hal/forms/HalFormsPropertyFactory.java b/src/main/java/org/springframework/hateoas/mediatype/hal/forms/HalFormsPropertyFactory.java index 30905e8f..22754a2f 100644 --- a/src/main/java/org/springframework/hateoas/mediatype/hal/forms/HalFormsPropertyFactory.java +++ b/src/main/java/org/springframework/hateoas/mediatype/hal/forms/HalFormsPropertyFactory.java @@ -80,12 +80,13 @@ class HalFormsPropertyFactory { return Collections.emptyList(); } - HalFormsOptionsFactory options = configuration.getOptionsFactory(); + HalFormsOptionsFactory optionsFactory = configuration.getOptionsFactory(); return model.createProperties((payload, metadata) -> { String inputTypeSource = metadata.getInputType(); HtmlInputType inputType = inputTypeSource == null ? null : HtmlInputType.of(inputTypeSource); + HalFormsOptions options = optionsFactory.getOptions(payload, metadata); HalFormsProperty property = new HalFormsProperty() .withName(metadata.getName()) @@ -97,7 +98,8 @@ class HalFormsPropertyFactory { .withMaxLength(metadata.getMaxLength()) .withRegex(lookupRegex(metadata)) // .withType(inputType) // - .withOptions(options.getOptions(payload, metadata)); + .withValue(options != null ? options.getSelectedValue() : null) // + .withOptions(options); Function factory = I18nedPropertyMetadata.factory(payload, property); diff --git a/src/test/java/org/springframework/hateoas/mediatype/hal/forms/HalFormsTemplateBuilderUnitTest.java b/src/test/java/org/springframework/hateoas/mediatype/hal/forms/HalFormsTemplateBuilderUnitTest.java index c8ee13e5..e74a8384 100644 --- a/src/test/java/org/springframework/hateoas/mediatype/hal/forms/HalFormsTemplateBuilderUnitTest.java +++ b/src/test/java/org/springframework/hateoas/mediatype/hal/forms/HalFormsTemplateBuilderUnitTest.java @@ -158,7 +158,7 @@ class HalFormsTemplateBuilderUnitTest { } @Test // #1483 - void rendersRegisteredSuggest() { + void rendersInlineOptions() { List values = Arrays.asList("1234123412341234", "4321432143214321"); @@ -182,6 +182,30 @@ class HalFormsTemplateBuilderUnitTest { }); } + @Test // #1510 + void propagatesSelectedValueToProperty() { + + String selected = "1234123412341234"; + List values = Arrays.asList(selected, "4321432143214321"); + + HalFormsConfiguration configuration = new HalFormsConfiguration() + .withOptions(PatternExample.class, "number", + metadata -> HalFormsOptions.inline(values).withSelectedValue(selected)); + + RepresentationModel models = new RepresentationModel<>( + Affordances.of(Link.of("/example", LinkRelation.of("create"))) + .afford(HttpMethod.POST) + .withInput(PatternExample.class) + .toLink()); + + Map templates = new HalFormsTemplateBuilder(configuration, MessageResolver.DEFAULTS_ONLY) + .findTemplates(models); + + assertThat(templates.get("default").getPropertyByName("number")).hasValueSatisfying(it -> { + assertThat(it.getValue()).isEqualTo(selected); + }); + } + @Getter static class PatternExample extends RepresentationModel {