Skip to content

Commit 70d9cab

Browse files
Felix MaiKostyaSha
authored andcommitted
Add mapping annotations to custom constructor (#1047)
* Add mapping annotations to custom constructor * Annotate Volume's custom constructor * Add simple test and appropriate data * Fix #1046 * Add annotated factory method for inconsistent JSON * Enable to handle both JSON responses (w/ and w/o path key) * Add additional test case and data * Rename test data file due to alternative version * Add JavaDocs describing why we need both single-argument constructor and factory method * Fix #1046
1 parent 3993c60 commit 70d9cab

5 files changed

Lines changed: 400 additions & 1 deletion

File tree

src/main/java/com/github/dockerjava/api/model/Volume.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,46 @@
11
package com.github.dockerjava.api.model;
22

3+
import com.fasterxml.jackson.annotation.JsonCreator;
4+
import com.fasterxml.jackson.annotation.JsonProperty;
35
import org.apache.commons.lang.builder.EqualsBuilder;
46
import org.apache.commons.lang.builder.HashCodeBuilder;
57

8+
import javax.annotation.Nonnull;
69
import java.io.Serializable;
710

811
/**
912
* Represents a bind mounted volume in a Docker container.
13+
* <p>
14+
* Due to an inconsistency in the Docker REST API implementation the response to a container
15+
* command might include either {@code "Mounts" : [ { "Destination" : "/path/to/mount" } ]} or
16+
* {@code "Mounts" : [ { "Destination" : { "path" : "/path/to/mount" } } ]} JSON snippets. However,
17+
* both variants have to be mapped to this class. Therefore, both a single-argument constructor
18+
* as well as a single-argument factory method is provided either of which handles the former or
19+
* latter variant (with {@code path} key), respectively.
1020
*
1121
* @see Bind
1222
*/
1323
public class Volume implements Serializable {
1424
private static final long serialVersionUID = 1L;
1525

26+
/**
27+
* Handles the {@code { "Destination" : { "path" : "/path/to/mount" } }} variant.
28+
* @param path the destination path of the bind mounted volume
29+
* @return a volume instance referring to the given path.
30+
*/
31+
@Nonnull
32+
@JsonCreator
33+
public static Volume parse(@JsonProperty("path") String path) {
34+
return new Volume(path);
35+
}
36+
1637
private String path;
1738

39+
/**
40+
* Creates a volume referring to the given path.
41+
* Handles the {@code { "Destination" : "/path/to/mount" }} variant.
42+
* @param path the destination path of the bind mounted volume
43+
*/
1844
public Volume(String path) {
1945
this.path = path;
2046
}

src/test/java/com/github/dockerjava/api/command/CommandJSONSamples.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,11 @@
2424
*/
2525
public enum CommandJSONSamples implements JSONResourceRef {
2626

27-
inspectContainerResponse_full, inspectContainerResponse_full_1_21, inspectContainerResponse_empty;
27+
inspectContainerResponse_full,
28+
inspectContainerResponse_full_1_21,
29+
inspectContainerResponse_full_1_26a,
30+
inspectContainerResponse_full_1_26b,
31+
inspectContainerResponse_empty;
2832

2933
@Override
3034
public String getFileName() {

src/test/java/com/github/dockerjava/api/command/InspectContainerResponseTest.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@
1717

1818
import com.fasterxml.jackson.databind.JavaType;
1919
import com.fasterxml.jackson.databind.ObjectMapper;
20+
import com.github.dockerjava.api.model.Volume;
2021
import com.github.dockerjava.core.RemoteApiVersion;
2122
import org.junit.Test;
2223

2324
import java.io.IOException;
25+
import java.util.List;
2426

2527
import static com.github.dockerjava.test.serdes.JSONSamples.testRoundTrip;
2628
import static com.github.dockerjava.test.serdes.JSONTestHelper.testRoundTrip;
@@ -93,6 +95,38 @@ public void roundTrip_1_21_full() throws IOException {
9395
assertThat(state.getError(), isEmptyString());
9496
}
9597

98+
@Test
99+
public void roundTrip_1_26a_full() throws IOException {
100+
InspectContainerResponse[] responses = testRoundTrip(CommandJSONSamples.inspectContainerResponse_full_1_26a,
101+
InspectContainerResponse[].class);
102+
103+
assertEquals(1, responses.length);
104+
final InspectContainerResponse response = responses[0];
105+
106+
final List<InspectContainerResponse.Mount> mounts = response.getMounts();
107+
assertEquals(mounts.size(), 1);
108+
109+
final InspectContainerResponse.Mount mount = mounts.get(0);
110+
final Volume volume = mount.getDestination();
111+
assertEquals(volume.getPath(), "/var/lib/postgresql/data");
112+
}
113+
114+
@Test
115+
public void roundTrip_1_26b_full() throws IOException {
116+
InspectContainerResponse[] responses = testRoundTrip(CommandJSONSamples.inspectContainerResponse_full_1_26b,
117+
InspectContainerResponse[].class);
118+
119+
assertEquals(1, responses.length);
120+
final InspectContainerResponse response = responses[0];
121+
122+
final List<InspectContainerResponse.Mount> mounts = response.getMounts();
123+
assertEquals(mounts.size(), 1);
124+
125+
final InspectContainerResponse.Mount mount = mounts.get(0);
126+
final Volume volume = mount.getDestination();
127+
assertEquals(volume.getPath(), "/srv/test");
128+
}
129+
96130
@Test
97131
public void roundTrip_empty() throws IOException {
98132
testRoundTrip(CommandJSONSamples.inspectContainerResponse_empty, InspectContainerResponse[].class);
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
[
2+
{
3+
"Driver" : "aufs",
4+
"Path" : "docker-entrypoint.sh",
5+
"Args" : [
6+
"postgres"
7+
],
8+
"SizeRootFs" : null,
9+
"HostConfig" : {
10+
"KernelMemory" : 0,
11+
"MemorySwappiness" : -1,
12+
"PidMode" : "",
13+
"CpuPeriod" : 0,
14+
"LogConfig" : {
15+
"Type" : "json-file",
16+
"Config" : {}
17+
},
18+
"ReadonlyRootfs" : false,
19+
"CgroupParent" : "",
20+
"PublishAllPorts" : false,
21+
"VolumeDriver" : "",
22+
"NetworkMode" : "default",
23+
"BlkioWeight" : 0,
24+
"OomKillDisable" : false,
25+
"Privileged" : false,
26+
"CpusetMems" : "",
27+
"ContainerIDFile" : "",
28+
"ShmSize" : 67108864,
29+
"CpusetCpus" : "",
30+
"CpuShares" : 0,
31+
"PidsLimit" : 0,
32+
"RestartPolicy" : {
33+
"Name" : "",
34+
"MaximumRetryCount" : 0
35+
},
36+
"Memory" : 0,
37+
"MemorySwap" : 0,
38+
"CpuQuota" : 0,
39+
"OomScoreAdj" : false,
40+
"MemoryReservation" : 0
41+
},
42+
"Id" : "58fd1abe8e43a65fb6231b76a9678e7bb4e91686f838945e782a4b74119ce959",
43+
"Volumes" : null,
44+
"State" : {
45+
"Pid" : 0,
46+
"ExitCode" : 0,
47+
"FinishedAt" : "0001-01-01T00:00:00Z",
48+
"Paused" : false,
49+
"Error" : "",
50+
"Status" : "created",
51+
"OOMKilled" : false,
52+
"Health" : null,
53+
"oomkilled" : false,
54+
"StartedAt" : "0001-01-01T00:00:00Z",
55+
"Dead" : false,
56+
"Running" : false,
57+
"Restarting" : false
58+
},
59+
"Config" : {
60+
"OpenStdin" : false,
61+
"Hostname" : "58fd1abe8e43",
62+
"StdinOnce" : false,
63+
"Domainname" : "",
64+
"Env" : [
65+
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/lib/postgresql/10/bin",
66+
"GOSU_VERSION=1.10",
67+
"LANG=en_US.utf8",
68+
"PG_MAJOR=10",
69+
"PG_VERSION=10.4-2.pgdg90+1",
70+
"PGDATA=/var/lib/postgresql/data"
71+
],
72+
"Entrypoint" : [
73+
"docker-entrypoint.sh"
74+
],
75+
"User" : "",
76+
"AttachStdout" : false,
77+
"Cmd" : [
78+
"postgres"
79+
],
80+
"ExposedPorts" : {
81+
"5432/tcp" : {}
82+
},
83+
"Image" : "postgres:latest",
84+
"AttachStderr" : false,
85+
"Labels" : {},
86+
"Volumes" : {
87+
"/var/lib/postgresql/data" : {}
88+
},
89+
"Tty" : false,
90+
"WorkingDir" : "",
91+
"AttachStdin" : false
92+
},
93+
"ProcessLabel" : "",
94+
"HostsPath" : "",
95+
"Name" : "/fmi-test01",
96+
"ExecDriver" : null,
97+
"LogPath" : "",
98+
"ExecIDs" : null,
99+
"MountLabel" : "",
100+
"Created" : "2018-05-30T08:37:12.308001081Z",
101+
"Image" : "sha256:61d053fc271ce1313896a2edf7719fb3b68637b53397e61d8114793b39e9ae65",
102+
"ResolvConfPath" : "",
103+
"HostnamePath" : "",
104+
"RestartCount" : 0,
105+
"NetworkSettings" : {
106+
"GlobalIPv6PrefixLen" : 0,
107+
"LinkLocalIPv6PrefixLen" : 0,
108+
"EndpointID" : "",
109+
"SandboxID" : "",
110+
"GlobalIPv6Address" : "",
111+
"LinkLocalIPv6Address" : "",
112+
"HairpinMode" : false,
113+
"PortMapping" : null,
114+
"SecondaryIPv6Addresses" : null,
115+
"SecondaryIPAddresses" : null,
116+
"Gateway" : "",
117+
"Ports" : null,
118+
"MacAddress" : "",
119+
"Networks" : {
120+
"bridge" : {
121+
"IPv6Gateway" : "",
122+
"IPPrefixLen" : 0,
123+
"GlobalIPv6Address" : "",
124+
"IPAddress" : "",
125+
"EndpointID" : "",
126+
"Aliases" : null,
127+
"GlobalIPv6PrefixLen" : 0,
128+
"Gateway" : "",
129+
"NetworkID" : "",
130+
"IPAMConfig" : null,
131+
"Links" : null,
132+
"MacAddress" : ""
133+
}
134+
},
135+
"IPAddress" : "",
136+
"Bridge" : "",
137+
"IPPrefixLen" : 0,
138+
"IPv6Gateway" : "",
139+
"SandboxKey" : ""
140+
},
141+
"VolumesRW" : null,
142+
"Mounts" : [
143+
{
144+
"RW" : true,
145+
"Driver" : "local",
146+
"Name" : "d9e76cbb4f797b0b8d62f5f4cd46ee6502fc520c6ce1187a62d200bc8364dd74",
147+
"Source" : "/var/lib/docker/volumes/d9e76cbb4f797b0b8d62f5f4cd46ee6502fc520c6ce1187a62d200bc8364dd74/_data",
148+
"Mode" : "",
149+
"Destination" : {
150+
"path" : "/var/lib/postgresql/data"
151+
}
152+
}
153+
]
154+
}
155+
]

0 commit comments

Comments
 (0)