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 1a45233
Show file tree
Hide file tree
Showing 13 changed files with 416 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.cosium.hal_mock_mvc;

import com.fasterxml.jackson.databind.Module;
import org.springframework.context.annotation.Bean;

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

@Bean
public Module halMockMvcJacksonModule() {
return new JacksonModule();
}
}
27 changes: 27 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,27 @@
package com.cosium.hal_mock_mvc;

import com.cosium.hal_mock_mvc.template.options.InlineElementRepresentation;
import com.cosium.hal_mock_mvc.template.options.InlineElementRepresentationDeserializer;
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) {
@JsonProperty("templated") Boolean templated,
@JsonProperty("options") OptionsRepresentation options) {
this.name = requireNonNull(name);
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
@@ -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,54 @@
package com.cosium.hal_mock_mvc.template.options;

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
*/
public 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>> {}
}
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);
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);
}
}
2 changes: 2 additions & 0 deletions core/src/test/java/com/cosium/hal_mock_mvc/App.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
import org.springframework.hateoas.config.EnableHypermediaSupport;

/**
* @author Réda Housni Alaoui
*/
@EnableHypermediaSupport(type = {HAL_FORMS, HAL})
@SpringBootApplication
@Import(HalMockMvcConfiguration.class)
@ComponentScan(basePackages = "com.cosium.hal_mock_mvc")
public class App {
public static void main(String[] args) {
Expand Down
Loading

0 comments on commit 1a45233

Please sign in to comment.