├── .gitignore
├── src
├── main
│ ├── java
│ │ └── com
│ │ │ └── ziroby
│ │ │ └── hello
│ │ │ ├── service
│ │ │ └── HelloWorldService.java
│ │ │ └── webapp
│ │ │ └── HelloWebapp.java
│ └── webapp
│ │ └── WEB-INF
│ │ └── web.xml
└── test
│ └── java
│ └── com
│ └── ziroby
│ └── hello
│ └── webapp
│ └── HelloIntegrationTest.java
├── .project
├── .classpath
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle/
2 | build
3 | /bin
4 | .settings
5 |
--------------------------------------------------------------------------------
/src/main/java/com/ziroby/hello/service/HelloWorldService.java:
--------------------------------------------------------------------------------
1 | package com.ziroby.hello.service;
2 |
3 | public class HelloWorldService {
4 |
5 | public String sayHello() {
6 | return "Hello, World!";
7 | }
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | jetty-gradle-hello-world
4 |
5 |
6 |
7 | org.eclipse.jdt.core.javanature
8 |
9 |
10 |
11 | org.eclipse.jdt.core.javabuilder
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/main/java/com/ziroby/hello/webapp/HelloWebapp.java:
--------------------------------------------------------------------------------
1 | package com.ziroby.hello.webapp;
2 |
3 | import javax.ws.rs.GET;
4 | import javax.ws.rs.Path;
5 |
6 | import com.ziroby.hello.service.HelloWorldService;
7 |
8 | @Path("/hello")
9 | public class HelloWebapp {
10 | private static HelloWorldService helloWorldService = new HelloWorldService();
11 |
12 | @GET()
13 | public String hello() {
14 | return helloWorldService.sayHello();
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/test/java/com/ziroby/hello/webapp/HelloIntegrationTest.java:
--------------------------------------------------------------------------------
1 | package com.ziroby.hello.webapp;
2 |
3 | import static org.junit.Assert.*;
4 | import static org.hamcrest.CoreMatchers.*;
5 |
6 | import javax.ws.rs.client.Client;
7 | import javax.ws.rs.client.ClientBuilder;
8 | import javax.ws.rs.client.WebTarget;
9 |
10 | import org.junit.Test;
11 |
12 | public class HelloIntegrationTest {
13 | private static String HELLO_URL = "http://localhost:8080/hello";
14 |
15 | @Test
16 | public void testHello() throws Exception {
17 | Client client = ClientBuilder.newClient();
18 | WebTarget webTarget = client.target(HELLO_URL);
19 | String response = webTarget.request().get(String.class);
20 |
21 | assertThat(response, is("Hello, World!"));
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/webapp/WEB-INF/web.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 | Jetty Gradle Hello World
7 |
8 | HelloWorldServlet
9 | org.glassfish.jersey.servlet.ServletContainer
10 |
11 | jersey.config.server.provider.packages
12 | com.ziroby.hello.webapp
13 |
14 |
15 |
16 |
17 |
18 | 1
19 |
20 |
21 | HelloWorldServlet
22 | /*
23 |
24 |
25 |
--------------------------------------------------------------------------------
/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Jetty Gradle Hello World, TDD Style
2 | =====
3 |
4 | I want to make a simple web app with Jetty, using Gradle as the build
5 | tool. But I'm big on Test Driven Development (TDD), so I want to do it
6 | TDD style. I'll be checking in each step to my git repository at
7 | https://github.com/ziroby/jetty-gradle-hello-world
8 |
9 | Gradle Build File
10 | -----
11 |
12 | My first task is to get a simple Gradle build file in place. Looking at
13 | http://stackoverflow.com/questions/7864521/gradle-jettyrun-how-does-this-thing-work
14 | , I get a good starter for a build.gradle file. I add boiler-plate
15 | java build/test stuff, and my build.gradle looks like:
16 |
17 | ```groovy
18 | apply plugin: 'java'
19 | apply plugin: 'jetty'
20 |
21 | repositories {
22 | mavenCentral()
23 | }
24 | dependencies {
25 | testCompile 'junit:junit:4.11'
26 | testCompile 'org.hamcrest:hamcrest-all:1.3'
27 |
28 | }
29 | test {
30 | exclude '**/*IntegrationTest*'
31 | }
32 |
33 | task integrationTest(type: Test) {
34 | include '**/*IntegrationTest*'
35 | doFirst {
36 | jettyRun.httpPort = 8080 // Port for test
37 | jettyRun.daemon = true
38 | jettyRun.execute()
39 | }
40 | doLast {
41 | jettyStop.stopPort = 8091 // Port for stop signal
42 | jettyStop.stopKey = 'stopKey'
43 | jettyStop.execute()
44 | }
45 | }
46 | ```
47 |
48 | I run `gradle build` and get success. Ready for my first test.
49 |
50 | RESTful Server Test
51 | -----
52 |
53 | I want to work from the outside in, so my first test is a test for the
54 | web service. I'm doing "Hello World", so I want a RESTful server that
55 | provides "Hello World" when I do a GET to the top level. But I want
56 | to arrange our server correctly, so I'll have a separate engine that is
57 | called by the server classes. I'll start with a test for the server.
58 |
59 | ```java
60 | public class HelloIntegrationTest {
61 | private static String HELLO_URL = "http://localhost:8080/hello";
62 |
63 | @Test
64 | public void testHello() throws Exception {
65 | Client client = Client.create();
66 | WebResource webResource = client.resource(HELLO_URL);
67 | String response = webResource.get(String.class);
68 |
69 | assertThat(response, is("Hello, World!"));
70 | }
71 | }
72 | ```
73 |
74 | I also pull in Jersey for the web classes.
75 |
76 | ```groovy
77 | dependencies {
78 | testCompile 'junit:junit:4.11'
79 | testCompile 'org.hamcrest:hamcrest-all:1.3'
80 | testCompile 'com.sun.jersey:jersey-client:1.17.1'
81 | testCompile 'com.sun.jersey:jersey-core:1.17.1'
82 | }
83 | ```
84 |
85 | `gradle integrationTest` gets a 404, so the test is written and I can
86 | now write code to make the test pass.
87 |
88 | RESTful Server Code
89 | -----
90 |
91 | I create a server class with JAX-RS annotations.
92 |
93 | ```java
94 | @Path("/hello")
95 | public class HelloWebapp {
96 | @GET()
97 | public String hello() {
98 | return "";
99 | }
100 | }
101 | ```
102 |
103 | And I add dependencies to the Gradle file.
104 |
105 | ```groovy
106 | dependencies {
107 | ...
108 | compile 'com.sun.jersey:jersey-core:1.17.1'
109 | compile 'com.sun.jersey:jersey-server:1.17.1'
110 | compile 'com.sun.jersey:jersey-servlet:1.17.1'
111 | }
112 | ```
113 |
114 | The setup as is creates a web server at
115 | "http://localhost:8080//hello". I want it at root,
116 | "http://localhost:8080/hello", so I have to set the context path in the Gradle
117 | build file.
118 |
119 | ```groovy
120 | jettyRun.contextPath = '/';
121 | ```
122 |
123 | The entire `build.gradle` file is now:
124 |
125 | ```groovy
126 | apply plugin: 'java'
127 | apply plugin: 'jetty'
128 | apply plugin: 'eclipse'
129 |
130 | repositories {
131 | mavenCentral()
132 | }
133 | dependencies {
134 | testCompile 'junit:junit:4.11'
135 | testCompile 'org.hamcrest:hamcrest-all:1.3'
136 | testCompile 'com.sun.jersey:jersey-client:1.17.1'
137 | compile 'com.sun.jersey:jersey-core:1.17.1'
138 | compile 'com.sun.jersey:jersey-server:1.17.1'
139 | compile 'com.sun.jersey:jersey-servlet:1.17.1'
140 | }
141 | test {
142 | exclude '**/*IntegrationTest*'
143 | }
144 |
145 | task integrationTest(type: Test) {
146 | include '**/*IntegrationTest*'
147 | doFirst {
148 | jettyRun.contextPath = '/';
149 | jettyRun.httpPort = 8080 // Port for test
150 | jettyRun.daemon = true
151 | jettyRun.execute()
152 | }
153 | doLast {
154 | jettyStop.stopPort = 8091 // Port for stop signal
155 | jettyStop.stopKey = 'stopKey'
156 | jettyStop.execute()
157 | }
158 | }
159 | ```
160 |
161 | Running this I now get an assertion failure:
162 |
163 | ```
164 | java.lang.AssertionError:
165 | Expected: is "Hello, World!"
166 | but: was ""
167 | ```
168 |
169 | This is the error I was looking for, so I check in the code. I'm not going to
170 | fix this yet, because I need to call my engine to get the string to return.
171 |
172 | The Hello Service
173 | -----
174 |
175 | I want to solve this with a service, so I write it like I already have the
176 | service.
177 |
178 | ```java
179 | @Path("/hello")
180 | public class HelloWebapp {
181 | private static HelloWorldService helloWorldService = new HelloWorldService();
182 |
183 | @GET()
184 | public String hello() {
185 | return helloWorldService.sayHello();
186 | }
187 | }
188 | ```
189 |
190 | The HelloWorldService class is trivial:
191 |
192 | ```java
193 | public class HelloWorldService {
194 | public String sayHello() {
195 | return "Hello, World!";
196 | }
197 | }
198 |
199 | ```
200 |
201 | Now I run `gradle integrationTest`, and it passes, "BUILD SUCCESSFUL". I'm
202 | done.
203 |
204 | The source code is available at
205 | https://github.com/ziroby/jetty-gradle-hello-world .
206 |
207 |
--------------------------------------------------------------------------------