├── .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 | --------------------------------------------------------------------------------