values() {
+ return this.values;
}
/**
diff --git a/spawn-docker/src/main/java/build/spawn/docker/option/DockerOption.java b/spawn-docker/src/main/java/build/spawn/docker/option/DockerOption.java
index 18e039b..c5bef95 100644
--- a/spawn-docker/src/main/java/build/spawn/docker/option/DockerOption.java
+++ b/spawn-docker/src/main/java/build/spawn/docker/option/DockerOption.java
@@ -9,9 +9,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -21,23 +21,20 @@
*/
import build.base.configuration.Option;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.node.ObjectNode;
/**
- * An {@link Option} to set up a {@code Docker Engine} JSON-based request.
+ * Sealed marker interface for options that influence a {@code Docker Engine} request body.
+ *
+ * Serialization of each concrete type is handled entirely by the command that issues the
+ * request, keeping Jackson (and any future JSON library) out of the public API.
+ *
+ * The sealed hierarchy ensures that any new subtype must be handled exhaustively wherever
+ * a pattern-matching switch over {@link DockerOption} is used — enforced at compile time.
*
* @author brian.oliver
* @since Jun-2021
*/
-public interface DockerOption
- extends Option {
-
- /**
- * Configures the provided {@link ObjectNode} for the {@code Docker Engine} request.
- *
- * @param objectNode the {@link ObjectNode}
- * @param objectMapper the {@link ObjectMapper}
- */
- void configure(ObjectNode objectNode, ObjectMapper objectMapper);
+public sealed interface DockerOption
+ extends Option
+ permits Bind, Command, ExposedPort, ExtraHost, Link, PublishAllPorts, PublishPort {
}
diff --git a/spawn-docker/src/main/java/build/spawn/docker/option/ExposedPort.java b/spawn-docker/src/main/java/build/spawn/docker/option/ExposedPort.java
index 3546fbd..8ff5358 100644
--- a/spawn-docker/src/main/java/build/spawn/docker/option/ExposedPort.java
+++ b/spawn-docker/src/main/java/build/spawn/docker/option/ExposedPort.java
@@ -22,8 +22,6 @@
import build.base.configuration.CollectedOption;
import build.base.foundation.Strings;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.node.ObjectNode;
import java.util.LinkedHashSet;
import java.util.Objects;
@@ -99,21 +97,6 @@ public String toString() {
return "ExposedPort{" + this.port + '/' + this.type.toString().toLowerCase() + '}';
}
- @Override
- public void configure(final ObjectNode objectNode, final ObjectMapper objectMapper) {
-
- // ensure the "ExposedPorts" exists as an ArrayNode
- final ObjectNode exposedPorts = objectNode.get("ExposedPorts") == null
- || !(objectNode.get("ExposedPorts") instanceof ObjectNode)
- ? objectMapper.createObjectNode()
- : (ObjectNode) objectNode.get("ExposedPorts");
-
- // add the ExposedPort
- exposedPorts.set(this.port + "/" + this.type.toString().toLowerCase(), objectMapper.createObjectNode());
-
- objectNode.set("ExposedPorts", exposedPorts);
- }
-
/**
* Creates a {@link Type#TCP} exposed port.
*
diff --git a/spawn-docker/src/main/java/build/spawn/docker/option/ExtraHost.java b/spawn-docker/src/main/java/build/spawn/docker/option/ExtraHost.java
index 8c22c3f..3939c04 100644
--- a/spawn-docker/src/main/java/build/spawn/docker/option/ExtraHost.java
+++ b/spawn-docker/src/main/java/build/spawn/docker/option/ExtraHost.java
@@ -22,9 +22,6 @@
import build.base.configuration.AbstractValueOption;
import build.base.configuration.CollectedOption;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.node.ArrayNode;
-import com.fasterxml.jackson.databind.node.ObjectNode;
import java.util.LinkedHashSet;
@@ -35,7 +32,7 @@
* @author brian.oliver
* @since Aug-2021
*/
-public class ExtraHost
+public final class ExtraHost
extends AbstractValueOption
implements DockerOption, CollectedOption {
@@ -58,24 +55,4 @@ public static ExtraHost of(final String host) {
return new ExtraHost(host);
}
- @Override
- public void configure(final ObjectNode objectNode, final ObjectMapper objectMapper) {
-
- // ensure the "/HostConfig" exists
- final ObjectNode hostConfig = objectNode.get("HostConfig") == null
- ? objectMapper.createObjectNode()
- : (ObjectNode) objectNode.get("HostConfig");
-
- objectNode.set("HostConfig", hostConfig);
-
- // ensure "/HostConfig/ExtraHosts" exists
- final ArrayNode extraHosts = hostConfig.get("ExtraHosts") == null
- ? objectMapper.createArrayNode()
- : (ArrayNode) hostConfig.get("ExtraHosts");
-
- hostConfig.set("ExtraHosts", extraHosts);
-
- // add this ExtraHost
- extraHosts.add(get());
- }
}
diff --git a/spawn-docker/src/main/java/build/spawn/docker/option/Link.java b/spawn-docker/src/main/java/build/spawn/docker/option/Link.java
index e0c7919..ec087a5 100644
--- a/spawn-docker/src/main/java/build/spawn/docker/option/Link.java
+++ b/spawn-docker/src/main/java/build/spawn/docker/option/Link.java
@@ -21,9 +21,6 @@
*/
import build.base.configuration.CollectedOption;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.node.ArrayNode;
-import com.fasterxml.jackson.databind.node.ObjectNode;
import java.util.LinkedHashSet;
import java.util.Objects;
@@ -34,7 +31,7 @@
* @author anand.sankaran
* @since Aug-2022
*/
-public class Link
+public final class Link
implements DockerOption, CollectedOption {
/**
@@ -63,27 +60,6 @@ private Link(final String existingNameOrId,
this.nameToLink = nameToLink;
}
- @Override
- public void configure(final ObjectNode objectNode, final ObjectMapper objectMapper) {
-
- // ensure the "HostConfig" exists an ObjectNode
- final ObjectNode hostConfig = objectNode.get("HostConfig") == null
- || !(objectNode.get("HostConfig") instanceof ObjectNode)
- ? objectMapper.createObjectNode()
- : (ObjectNode) objectNode.get("HostConfig");
-
- // ensure the "Links" exists as an ObjectNode
- final ArrayNode links = hostConfig.get("Links") == null
- || !(hostConfig.get("Links") instanceof ArrayNode)
- ? objectMapper.createArrayNode()
- : (ArrayNode) hostConfig.get("Links");
-
- links.add(this.existingNameOrId + ":" + this.nameToLink);
-
- hostConfig.set("Links", links);
- objectNode.set("HostConfig", hostConfig);
- }
-
@Override
public boolean equals(final Object object) {
if (this == object) {
diff --git a/spawn-docker/src/main/java/build/spawn/docker/option/PublishAllPorts.java b/spawn-docker/src/main/java/build/spawn/docker/option/PublishAllPorts.java
index de7ef13..c46f690 100644
--- a/spawn-docker/src/main/java/build/spawn/docker/option/PublishAllPorts.java
+++ b/spawn-docker/src/main/java/build/spawn/docker/option/PublishAllPorts.java
@@ -9,9 +9,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -21,8 +21,6 @@
*/
import build.base.configuration.Default;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.node.ObjectNode;
/**
* A {@link DockerOption} to publish {@link ExposedPort}s for a {@link build.spawn.docker.Container}.
@@ -44,17 +42,7 @@ public enum PublishAllPorts
*/
DISABLED;
- @Override
- public void configure(final ObjectNode objectNode, final ObjectMapper objectMapper) {
-
- // ensure the "HostConfig" exists an ObjectNode
- final ObjectNode hostConfig = objectNode.get("HostConfig") == null
- || !(objectNode.get("HostConfig") instanceof ObjectNode)
- ? objectMapper.createObjectNode()
- : (ObjectNode) objectNode.get("HostConfig");
-
- hostConfig.put("PublishAllPorts", this == ENABLED);
-
- objectNode.set("HostConfig", hostConfig);
+ public boolean isEnabled() {
+ return this == ENABLED;
}
}
diff --git a/spawn-docker/src/main/java/build/spawn/docker/option/PublishPort.java b/spawn-docker/src/main/java/build/spawn/docker/option/PublishPort.java
index 01566cd..5071c02 100644
--- a/spawn-docker/src/main/java/build/spawn/docker/option/PublishPort.java
+++ b/spawn-docker/src/main/java/build/spawn/docker/option/PublishPort.java
@@ -21,9 +21,6 @@
*/
import build.base.configuration.CollectedOption;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.node.ArrayNode;
-import com.fasterxml.jackson.databind.node.ObjectNode;
import java.net.InetSocketAddress;
import java.util.LinkedHashSet;
@@ -126,47 +123,6 @@ public String toString() {
+ '}';
}
- @Override
- public void configure(final ObjectNode objectNode, final ObjectMapper objectMapper) {
-
- // ensure the "HostConfig" exists an ObjectNode
- final ObjectNode hostConfig = objectNode.get("HostConfig") == null
- || !(objectNode.get("HostConfig") instanceof ObjectNode)
- ? objectMapper.createObjectNode()
- : (ObjectNode) objectNode.get("HostConfig");
-
- // ensure the "PortBindings" exists as an ObjectNode
- final ObjectNode portBindings = hostConfig.get("PortBindings") == null
- || !(hostConfig.get("PortBindings") instanceof ObjectNode)
- ? objectMapper.createObjectNode()
- : (ObjectNode) hostConfig.get("PortBindings");
-
- final String key = this.port + "/" + this.type.toString().toLowerCase();
-
- // ensure the PortBinding exists as an ArrayNode
- final ArrayNode array = portBindings.get(key) == null
- || !(portBindings.get(key) instanceof ArrayNode)
- ? objectMapper.createArrayNode()
- : (ArrayNode) portBindings.get(key);
-
- // create the PortBinding
- final ObjectNode portBinding = objectMapper.createObjectNode();
- final InetSocketAddress address = this.socketAddress
- .orElse(new InetSocketAddress("localhost", this.port));
-
- if (!address.getHostName().equals("localhost")) {
- portBinding.put("HostIp", address.getHostName());
- }
-
- portBinding.put("HostPort", Integer.toString(address.getPort()));
-
- array.add(portBinding);
-
- portBindings.set(key, array);
- hostConfig.set("PortBindings", portBindings);
- objectNode.set("HostConfig", hostConfig);
- }
-
/**
* Creates a {@link Type#TCP} exposed port.
*
diff --git a/spawn-docker/src/main/java/module-info.java b/spawn-docker/src/main/java/module-info.java
index 28b6c01..45b2952 100644
--- a/spawn-docker/src/main/java/module-info.java
+++ b/spawn-docker/src/main/java/module-info.java
@@ -32,8 +32,6 @@
requires transitive build.codemodel.injection;
- requires com.fasterxml.jackson.databind;
-
exports build.spawn.docker;
exports build.spawn.docker.option;
diff --git a/spawn-docker/src/test/java/build/spawn/docker/option/PublishPortTests.java b/spawn-docker/src/test/java/build/spawn/docker/option/PublishPortTests.java
index 6edd72b..650ef8f 100644
--- a/spawn-docker/src/test/java/build/spawn/docker/option/PublishPortTests.java
+++ b/spawn-docker/src/test/java/build/spawn/docker/option/PublishPortTests.java
@@ -1,8 +1,5 @@
package build.spawn.docker.option;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.node.ArrayNode;
-import com.fasterxml.jackson.databind.node.ObjectNode;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
@@ -16,21 +13,17 @@
class PublishPortTests {
/**
- * Ensure that configuring multiple external bindings for the same internal port
- * accumulates all bindings rather than silently discarding prior ones.
+ * Ensure that two {@link PublishPort} instances with the same internal port but different external ports
+ * are not equal, preserving the distinct bindings when collected.
*/
@Test
- void shouldAccumulateMultipleBindingsForSamePort() {
- final var objectMapper = new ObjectMapper();
- final var container = objectMapper.createObjectNode();
+ void distinctExternalPortsProduceDifferentInstances() {
+ final var first = PublishPort.of(8080, PublishPort.Type.TCP, 8080);
+ final var second = PublishPort.of(8080, PublishPort.Type.TCP, 9090);
- // configure two distinct external ports mapped to the same internal port
- PublishPort.of(8080, PublishPort.Type.TCP, 8080).configure(container, objectMapper);
- PublishPort.of(8080, PublishPort.Type.TCP, 9090).configure(container, objectMapper);
-
- final var portBindings = (ObjectNode) container.path("HostConfig").path("PortBindings");
- final var array = (ArrayNode) portBindings.get("8080/tcp");
-
- assertThat(array).hasSize(2);
+ assertThat(first).isNotEqualTo(second);
+ assertThat(first.port()).isEqualTo(8080);
+ assertThat(second.port()).isEqualTo(8080);
+ assertThat(first.type()).isEqualTo(PublishPort.Type.TCP);
}
}