Skip to content

Commit

Permalink
Support HAL-Forms options
Browse files Browse the repository at this point in the history
  • Loading branch information
reda-alaoui committed Nov 9, 2023
1 parent a97cb2b commit fa25c2b
Show file tree
Hide file tree
Showing 11 changed files with 577 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.cosium.hal_mock_mvc;

import com.cosium.hal_mock_mvc.template.options.InlineElementRepresentation;
import com.cosium.hal_mock_mvc.template.options.MapInlineElementRepresentation;
import com.cosium.hal_mock_mvc.template.options.StringInlineElementRepresentation;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fasterxml.jackson.databind.exc.MismatchedInputException;
import java.io.IOException;
import java.util.Map;

/**
* @author Réda Housni Alaoui
*/
class InlineElementRepresentationDeserializer extends StdDeserializer<InlineElementRepresentation> {

public InlineElementRepresentationDeserializer() {
this(null);
}

protected InlineElementRepresentationDeserializer(Class<?> vc) {
super(vc);
}

@Override
public InlineElementRepresentation deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException {

JsonToken currentToken = p.currentToken();
if (currentToken == JsonToken.START_OBJECT) {
Map<String, String> map = p.readValueAs(new StringStringMap());
if (map == null) {
return null;
}
return new MapInlineElementRepresentation(map);
}
if (currentToken == JsonToken.VALUE_STRING) {
String value = p.readValueAs(String.class);
if (value == null) {
return null;
}
return new StringInlineElementRepresentation(value);
}

throw MismatchedInputException.from(
p,
InlineElementRepresentation.class,
"%s should have been either %s or %s. But it is not."
.formatted(currentToken, JsonToken.START_OBJECT, JsonToken.VALUE_STRING));
}

private static class StringStringMap extends TypeReference<Map<String, String>> {}
}
26 changes: 26 additions & 0 deletions core/src/main/java/com/cosium/hal_mock_mvc/JacksonModule.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.cosium.hal_mock_mvc;

import com.cosium.hal_mock_mvc.template.options.InlineElementRepresentation;
import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.databind.module.SimpleModule;

/**
* @author Réda Housni Alaoui
*/
class JacksonModule extends SimpleModule {

public JacksonModule() {
addDeserializer(
InlineElementRepresentation.class, new InlineElementRepresentationDeserializer());
}

@Override
public String getModuleName() {
return "com.cosium.hal_mock_mvc";
}

@Override
public Version version() {
return Version.unknownVersion();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import static java.util.Objects.requireNonNull;

import com.cosium.hal_mock_mvc.template.options.OptionsRepresentation;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Optional;
Expand All @@ -16,6 +17,7 @@ public class TemplatePropertyRepresentation {
private final String prompt;
private final String regex;
private final boolean templated;
private final OptionsRepresentation options;

@JsonCreator
TemplatePropertyRepresentation(
Expand All @@ -24,13 +26,15 @@ public class TemplatePropertyRepresentation {
@JsonProperty("value") String value,
@JsonProperty("prompt") String prompt,
@JsonProperty("regex") String regex,
@JsonProperty("templated") Boolean templated) {
this.name = requireNonNull(name);
@JsonProperty("templated") Boolean templated,
@JsonProperty("options") OptionsRepresentation options) {
this.name = requireNonNull(name, "Attribute 'name' is missing");
this.required = Optional.ofNullable(required).orElse(false);
this.value = value;
this.prompt = Optional.ofNullable(prompt).orElse(name);
this.regex = regex;
this.templated = Optional.ofNullable(templated).orElse(false);
this.options = options;
}

public String name() {
Expand All @@ -56,4 +60,8 @@ public Optional<String> regex() {
public boolean templated() {
return templated;
}

public Optional<OptionsRepresentation> options() {
return Optional.ofNullable(options);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public class TemplateRepresentation {
@JsonProperty("properties") List<TemplatePropertyRepresentation> properties,
@JsonProperty("target") String target) {
this.title = title;
this.method = requireNonNull(method);
this.method = requireNonNull(method, "Attribute 'method' is missing");
this.contentType = Optional.ofNullable(contentType).orElse(MediaType.APPLICATION_JSON_VALUE);
Map<String, TemplatePropertyRepresentation> mutablePropertyByName =
Optional.ofNullable(properties).orElseGet(Collections::emptyList).stream()
Expand Down
1 change: 1 addition & 0 deletions core/src/main/java/com/cosium/hal_mock_mvc/Templates.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public class Templates {
body =
new ObjectMapper()
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
.registerModule(new JacksonModule())
.readValue(jsonBody, HalFormsBody.class);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.cosium.hal_mock_mvc.template.options;

/**
* @author Réda Housni Alaoui
*/
public sealed interface InlineElementRepresentation
permits MapInlineElementRepresentation, StringInlineElementRepresentation {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.cosium.hal_mock_mvc.template.options;

import java.util.Map;
import java.util.Optional;

/**
* @author Réda Housni Alaoui
*/
public record MapInlineElementRepresentation(Map<String, String> map)
implements InlineElementRepresentation {

public MapInlineElementRepresentation(Map<String, String> map) {
this.map = Optional.ofNullable(map).map(Map::copyOf).orElseGet(Map::of);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.cosium.hal_mock_mvc.template.options;

import static java.util.Objects.requireNonNull;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Optional;

/**
* @author Réda Housni Alaoui
*/
public class OptionsLinkRepresentation {

private final String href;
private final String type;
private final boolean templated;

@JsonCreator
public OptionsLinkRepresentation(
@JsonProperty("href") String href,
@JsonProperty("type") String type,
@JsonProperty("templated") Boolean templated) {
this.href = requireNonNull(href, "Attribute 'href' is missing");
this.type = type;
this.templated = Optional.ofNullable(templated).orElse(false);
}

public String href() {
return href;
}

public Optional<String> type() {
return Optional.ofNullable(type);
}

public boolean templated() {
return templated;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package com.cosium.hal_mock_mvc.template.options;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;
import java.util.Optional;

/**
* @author Réda Housni Alaoui
*/
public class OptionsRepresentation {

private final List<InlineElementRepresentation> inline;
private final OptionsLinkRepresentation link;
private final Long maxItems;
private final long minItems;
private final String promptField;
private final List<String> selectedValues;
private final String valueField;

@JsonCreator
public OptionsRepresentation(
@JsonProperty("inline") List<InlineElementRepresentation> inline,
@JsonProperty("link") OptionsLinkRepresentation link,
@JsonProperty("maxItems") Long maxItems,
@JsonProperty("minItems") Long minItems,
@JsonProperty("promptField") String promptField,
@JsonProperty("selectedValues") List<String> selectedValues,
@JsonProperty("valueField") String valueField) {
this.inline = Optional.ofNullable(inline).map(List::copyOf).orElseGet(List::of);
this.link = link;
this.maxItems = maxItems;
this.minItems = Optional.ofNullable(minItems).orElse(0L);
this.promptField = promptField;
this.selectedValues = Optional.ofNullable(selectedValues).map(List::copyOf).orElseGet(List::of);
this.valueField = valueField;
}

public List<InlineElementRepresentation> inline() {
return inline;
}

public Optional<OptionsLinkRepresentation> link() {
return Optional.ofNullable(link);
}

public Optional<Long> maxItems() {
return Optional.ofNullable(maxItems);
}

public long minItems() {
return minItems;
}

public Optional<String> promptField() {
return Optional.ofNullable(promptField);
}

public List<String> selectedValues() {
return selectedValues;
}

public Optional<String> valueField() {
return Optional.ofNullable(valueField);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.cosium.hal_mock_mvc.template.options;

import static java.util.Objects.requireNonNull;

/**
* @author Réda Housni Alaoui
*/
public record StringInlineElementRepresentation(String value)
implements InlineElementRepresentation {

public StringInlineElementRepresentation {
requireNonNull(value);
}
}
Loading

0 comments on commit fa25c2b

Please sign in to comment.