1. Overview
Dropwizard is an open-source Java framework used for the fast development of high-performance RESTful web services. It gathers some popular libraries to create the lightweight package. The main libraries that it uses are Jetty, Jersey, Jackson, JUnit, and Guava. Furthermore, it uses its own library called Metrics.
In this tutorial, we’ll learn how to configure and run a simple Dropwizard application. When we’re done, our application will expose a RESTful API that allows us to obtain a list of stored brands.
2. Maven Dependencies
Firstly, the dropwizard-core dependency is all we need in order to create our service. Let’s add it to our pom.xml:
<dependency>
<groupId>io.dropwizard</groupId>
<artifactId>dropwizard-core</artifactId>
<version>2.0.0</version>
</dependency>
3. Configuration
Now, we’ll create the necessary classes that are needed for every Dropwizard application to run.
Dropwizard applications store properties in YML files. Therefore, we’ll create the introduction-config.yml file in the resource directory:
defaultSize: 5
We can access values in that file by creating a class that extends io.dropwizard.Configuration:
public class BasicConfiguration extends Configuration {
@NotNull private final int defaultSize;
@JsonCreator
public BasicConfiguration(@JsonProperty("defaultSize") int defaultSize) {
this.defaultSize = defaultSize;
}
public int getDefaultSize() {
return defaultSize;
}
}
Dropwizard uses Jackson to deserialize the configuration file into our class. Hence, we’ve used Jackson’s annotations.
Next, let’s create the main application class, which is responsible for preparing our service for usage:
public class IntroductionApplication extends Application<BasicConfiguration> {
public static void main(String[] args) throws Exception {
new IntroductionApplication().run("server", "introduction-config.yml");
}
@Override
public void run(BasicConfiguration basicConfiguration, Environment environment) {
//register classes
}
@Override
public void initialize(Bootstrap<BasicConfiguration> bootstrap) {
bootstrap.setConfigurationSourceProvider(new ResourceConfigurationSourceProvider());
super.initialize(bootstrap);
}
}
Firstly, the main method is responsible for running the application. We could either pass the args to the run method or fill it by ourselves.
The first argument can be either server or check. The check option validates the configuration, while the server option runs the application. The second argument is the location of the configuration file.
Furthermore, the initialize method sets the configuration provider to the ResourceConfigurationSourceProvider, which allows the application to find a given configuration file in the resource directory. It isn’t obligatory to override this method.
Lastly, the run method allows us to access both the Environment and the BaseConfiguration, which we’ll use later in this article.
4. Resource
Firstly, let’s create a domain class for our brand:
public class Brand {
private final Long id;
private final String name;
// all args constructor and getters
}
Secondly, let’s create a BrandRepository class that’ll be responsible for returning brands:
public class BrandRepository {
private final List<Brand> brands;
public BrandRepository(List<Brand> brands) {
this.brands = ImmutableList.copyOf(brands);
}
public List<Brand> findAll(int size) {
return brands.stream()
.limit(size)
.collect(Collectors.toList());
}
public Optional<Brand> findById(Long id) {
return brands.stream()
.filter(brand -> brand.getId().equals(id))
.findFirst();
}
}
Additionally, we were able to use the ImmutableList from Guava because it’s part of Dropwizard itself.
Thirdly, we’ll create a BrandResource class. The Dropwizard uses JAX-RS by default with Jersey as implementation. Therefore, we’ll make use of annotations from this specification to expose our REST API endpoints:
@Path("/brands")
@Produces(MediaType.APPLICATION_JSON)
public class BrandResource {
private final int defaultSize;
private final BrandRepository brandRepository;
public BrandResource(int defaultSize, BrandRepository brandRepository) {
this.defaultSize = defaultSize;
this.brandRepository = brandRepository;
}
@GET
public List<Brand> getBrands(@QueryParam("size") Optional<Integer> size) {
return brandRepository.findAll(size.orElse(defaultSize));
}
@GET
@Path("/{id}")
public Brand getById(@PathParam("id") Long id) {
return brandRepository
.findById(id)
.orElseThrow(RuntimeException::new);
}
}
Additionally, we’ve defined size as Optional in order to use defaultSize from our configuration if the argument is not provided.
Lastly, we’ll register BrandResource in the IntroductionApplicaton class. In order to do that, let’s implement the run method:
@Override
public void run(BasicConfiguration basicConfiguration, Environment environment) {
int defaultSize = basicConfiguration.getDefaultSize();
BrandRepository brandRepository = new BrandRepository(initBrands());
BrandResource brandResource = new BrandResource(defaultSize, brandRepository);
environment
.jersey()
.register(brandResource);
}
All created resources should be registered in this method.
5. Running Application
In this section, we’ll learn how to run the application from the command line.
First, we’ll configure our project to build a JAR file using the maven-shade-plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<configuration>
<createDependencyReducedPom>true</createDependencyReducedPom>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.baeldung.dropwizard.introduction.IntroductionApplication</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
This is the suggested configuration of the plugin. Additionally, we’ve included the path to our main class in the
Finally, we’ll build the application with Maven. Once we have our JAR file, we can run the application:
java -jar target/dropwizard-0.0.1-SNAPSHOT.jar
There’s no need to pass the parameters because we’ve already included them in the IntroductionApplication class.
After that, the console log should end with:
INFO [2020-01-08 18:55:06,527] org.eclipse.jetty.server.Server: Started @1672ms
Now, the application is listening on port 8080, and we can access our brand endpoint at http://localhost:8080/brands.
6. Changing the Default Port
By default, a typical Dropwizard application uses two ports:
- Port 8080 for the main application
- Port 8081 for the administration interface
However, we can change the default ports using either the configuration folder or the command-line arguments.
6.1. Changing Port Through the Configuration File
To change the default port through the configuration file, we need to modify the introduction-config.yml in the resource directory:
server:
applicationConnectors:
- type: http
port: 9090
adminConnectors:
- type: http
port: 9091
This configuration sets the application to run on port 9090 and the admin interface on port 9091. We can apply this configuration by passing the configuration file to the run() method:
// ...
new IntroductionApplication().run("server", "introduction-config.yml");
// ...
Also, we can apply the configuration file through the command line when starting the application:
$ java -jar target/dropwizard-0.0.1-SNAPSHOT.jar server introduction-config.yml
In the command above, we start the application with the server and introduction-config.yml arguments.
6.2. Changing Port Through the Command Line
Alternatively, we can override the port settings using JVM system properties on the command line:
$ java -Ddw.server.applicationConnectors[0].port=9090 \
-Ddw.server.adminConnectors[0].port=9091 \
-jar target/dropwizard-0.0.1-SNAPSHOT.jar server
The -Ddw prefix defines Dropwizard-specific system properties that set the main application port and the administrative interface port. These system properties, if specified, override the configuration file setting. Values in the configuration file are used if no system properties are defined.
7. Health Check
When starting the application, we were informed that the application doesn’t have any health checks. Fortunately, Dropwizard provides an easy solution to add health checks to our application.
Let’s start by adding a simple class that extends com.codahale.metrics.health.HealthCheck:
public class ApplicationHealthCheck extends HealthCheck {
@Override
protected Result check() throws Exception {
return Result.healthy();
}
}
This simple method will return information about the healthiness of our component. We could create multiple health checks, and some of them might fail in certain situations. For instance, we would return Result.unhealthy() if the connection to the database failed.
Lastly, we need to register our health check in the run method of our IntroductionApplication class:
environment
.healthChecks()
.register("application", new ApplicationHealthCheck());
After running the application, we can check the health check response under http://localhost:8081/healthcheck:
{
"application": {
"healthy": true,
"duration": 0
},
"deadlocks": {
"healthy": true,
"duration": 0
}
}
As we can see, our health check has been registered under the application tag.
8. Conclusion
In this article, we’ve learned how to set up the Dropwizard application with Maven.
We’ve discovered that the base setup of the application is really easy and fast. Additionally, Dropwizard includes every library that we need to run the high-performance RESTful web service.
As always, the code for these examples is available over on GitHub.