#1697 - Support for custom property types in HAL FORMS.
As per the discussion in mamund/hal-forms#88, the list of property types in HAL FORMS is not exhaustive. This means we cannot align them with HTML input types and even more so not drop anything not an HTML input type. This is now implemented by switching to generic Strings in the HAL FORMS property DTO and directly piping the value originally registered on the affordance into it.
This commit is contained in:
@@ -19,7 +19,6 @@ import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.hateoas.AffordanceModel.Named;
|
||||
import org.springframework.hateoas.mediatype.html.HtmlInputType;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -44,7 +43,7 @@ final class HalFormsProperty implements Named {
|
||||
private final @JsonInclude(Include.NON_DEFAULT) boolean readOnly, required;
|
||||
private final @Nullable Number min, max;
|
||||
private final @Nullable Long minLength, maxLength;
|
||||
private final @Nullable HtmlInputType type;
|
||||
private final @Nullable String type;
|
||||
private final @Nullable HalFormsOptions options;
|
||||
|
||||
HalFormsProperty() {
|
||||
@@ -69,7 +68,7 @@ final class HalFormsProperty implements Named {
|
||||
private HalFormsProperty(String name, boolean readOnly, @Nullable Object value, String prompt, String regex,
|
||||
boolean templated, //
|
||||
boolean required, boolean multi, String placeholder, @Nullable Number min, @Nullable Number max,
|
||||
@Nullable Long minLength, @Nullable Long maxLength, @Nullable HtmlInputType type,
|
||||
@Nullable Long minLength, @Nullable Long maxLength, @Nullable String type,
|
||||
@Nullable HalFormsOptions options) {
|
||||
|
||||
Assert.notNull(name, "Name must not be null!");
|
||||
@@ -294,7 +293,7 @@ final class HalFormsProperty implements Named {
|
||||
* @param type can be {@literal null}
|
||||
* @return will never be {@literal null}.
|
||||
*/
|
||||
HalFormsProperty withType(@Nullable HtmlInputType type) {
|
||||
HalFormsProperty withType(@Nullable String type) {
|
||||
|
||||
return Objects.equals(this.type, type) ? this
|
||||
: new HalFormsProperty(this.name, this.readOnly, this.value, this.prompt, this.regex, this.templated,
|
||||
@@ -413,7 +412,7 @@ final class HalFormsProperty implements Named {
|
||||
@Nullable
|
||||
@JsonProperty
|
||||
@JsonInclude(Include.NON_NULL)
|
||||
HtmlInputType getType() {
|
||||
String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,6 @@ import org.springframework.context.MessageSourceResolvable;
|
||||
import org.springframework.hateoas.AffordanceModel.InputPayloadMetadata;
|
||||
import org.springframework.hateoas.AffordanceModel.PropertyMetadata;
|
||||
import org.springframework.hateoas.mediatype.MessageResolver;
|
||||
import org.springframework.hateoas.mediatype.html.HtmlInputType;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -84,8 +83,7 @@ class HalFormsPropertyFactory {
|
||||
|
||||
return model.createProperties((payload, metadata) -> {
|
||||
|
||||
String inputTypeSource = metadata.getInputType();
|
||||
HtmlInputType inputType = inputTypeSource == null ? null : HtmlInputType.of(inputTypeSource);
|
||||
String inputType = metadata.getInputType();
|
||||
HalFormsOptions options = optionsFactory.getOptions(payload, metadata);
|
||||
|
||||
HalFormsProperty property = new HalFormsProperty()
|
||||
|
||||
@@ -37,6 +37,7 @@ import org.hibernate.validator.constraints.Range;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.CsvSource;
|
||||
import org.springframework.hateoas.InputType;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.hateoas.LinkRelation;
|
||||
import org.springframework.hateoas.RepresentationModel;
|
||||
@@ -246,6 +247,23 @@ class HalFormsTemplateBuilderUnitTest {
|
||||
assertThat(templates.get("default").getTarget()).endsWith("/example");
|
||||
}
|
||||
|
||||
@Test // #1697
|
||||
void exposesCustomInputType() {
|
||||
|
||||
RepresentationModel<?> models = new RepresentationModel<>(
|
||||
Affordances.of(Link.of("/example", LinkRelation.of("example"))) //
|
||||
.afford(HttpMethod.POST) //
|
||||
.withInput(WithCustomInputType.class) //
|
||||
.toLink());
|
||||
|
||||
Map<String, HalFormsTemplate> templates = new HalFormsTemplateBuilder(new HalFormsConfiguration(),
|
||||
MessageResolver.DEFAULTS_ONLY).findTemplates(models);
|
||||
|
||||
assertThat(templates.get("default").getPropertyByName("property")).hasValueSatisfying(it -> {
|
||||
assertThat(it.getType()).isEqualTo("custom");
|
||||
});
|
||||
}
|
||||
|
||||
@Getter
|
||||
static class PatternExample extends RepresentationModel<PatternExample> {
|
||||
|
||||
@@ -283,4 +301,11 @@ class HalFormsTemplateBuilderUnitTest {
|
||||
@DecimalMax("5.3") //
|
||||
BigDecimal decimal;
|
||||
}
|
||||
|
||||
@Getter
|
||||
static class WithCustomInputType {
|
||||
|
||||
@InputType("custom") //
|
||||
String property;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user