I’m involved in a project that uses Dropwizard so I thought it’s time I had a play with the Dropwizard framework (or whatever it is) so I asked Google for some suggestions (as you do) and it offered me the Getting Started page.
A great introduction, but I hit a problem when I tried to run the application –
C:\Projects\dwfilters>java -jar target\dwfilters-0.0.1-SNAPSHOT.jar server hello-world.yml INFO [2017-03-20 22:31:27,200] org.eclipse.jetty.util.log: Logging initialized @996ms INFO [2017-03-20 22:31:27,274] io.dropwizard.server.ServerFactory: Starting hello-world INFO [2017-03-20 22:31:27,282] io.dropwizard.server.DefaultServerFactory: Registering jersey handler with root path prefix: / INFO [2017-03-20 22:31:27,297] io.dropwizard.server.DefaultServerFactory: Registering admin handler with root path prefix: / INFO [2017-03-20 22:31:27,331] org.eclipse.jetty.setuid.SetUIDListener: Opened application@6c5945a7{HTTP/1.1}{0.0.0.0:8080} INFO [2017-03-20 22:31:27,331] org.eclipse.jetty.setuid.SetUIDListener: Opened admin@2f05be7f{HTTP/1.1}{0.0.0.0:8081} INFO [2017-03-20 22:31:27,335] org.eclipse.jetty.server.Server: jetty-9.2.z-SNAPSHOT ERROR [2017-03-20 22:31:27,758] org.glassfish.jersey.internal.Errors: Following issues have been detected: WARNING: No injection source found for a parameter of type public sjw.test.dwfilters.api.Saying sjw.test.dwfilters.resources.HelloWorldResource.sayHello(java.util.Optional) at index 0. WARN [2017-03-20 22:31:27,762] /: unavailable ! org.glassfish.jersey.server.model.ModelValidationException: Validation of the application resource model has failed during application initialization. ! [[FATAL] No injection source found for a parameter of type public sjw.test.dwfilters.api.Saying sjw.test.dwfilters.resources.HelloWorldResource.sayHello(java.util.Optional) at index 0.; source='ResourceMethod{httpMethod=GET, consumedTypes=[], producedTypes=[application/json], suspended=false, suspendTimeout=0, suspendTimeoutUnit=MILLISECONDS, invocable=Invocable{handler=ClassBasedMethodHandler{handlerClass=class sjw.test.dwfilters.resources.HelloWorldResource, handlerConstructors=[org.glassfish.jersey.server.model.HandlerConstructor@400d912a]}, definitionMethod=public sjw.test.dwfilters.api.Saying sjw.test.dwfilters.resources.HelloWorldResource.sayHello(java.util.Optional), parameters=[Parameter [type=class java.util.Optional, source=name, defaultValue=null]], responseType=class sjw.test.dwfilters.api.Saying}, nameBindings=[]}']
I spent a while trying to work out what the problem was and found various suggestions which I couldn’t make sense of in my situation.
To cut a long story short, the problem turned out to be the use of the @QueryParam("name") Optional
parameter in the HelloWorldResource
sayHello
method.
Initially, I discovered that the Optional
class is a Java 8 feature and needs additional Java 8 compatibility library. Unfortunately, adding this additional library caused another issue, class not found.
So, the quick fix was to change the sayHello
method as follows:
@GET @Timed public Saying sayHello(@QueryParam("name") String name) { final String value = String.format(template, name == null ? defaultName : name); return new Saying(counter.incrementAndGet(), value); }
The Full Solution
However, while this solved my initial issue, it needed further investigation. And, of course, it turns out it was a daft mistake on my part!
The problem was caused because, after initially walking through the example, I changed the DropWizard version to a different one matching that in the system I am working with.
So, I returned to the code, and reviewed each version of the DropWizard Getting Started page and discovered that earlier versions of the page use Google Guava to provide the Optional class – not the Java 8 version. Switching the import – and changing name.orElse(...)
to name.or(...)
– solved the problem.
Here’s a summary of the behaviour of the different versions of DropWizard:
- 0.6.2 – didn’t appear to exist when I set it as the version in my Maven pom.xml
- 0.7.*, 0.8.* – only works with Google’s Guava version.
- 0.9.* – works with both Google Guava and Java 8’s version (with the Java 8 Bundle).
- 1.0.* – works with both Google Guava and Java 8’s version (and the Java 8 Bundle makes no difference either way).
Just to make this nice and easy, the older versions have an import:
import com.google.common.base.Optional;
and use name.or(...)
in the sayHello
method:
@GET @Timed public Saying sayHello(@QueryParam("name") Optional<String> name) { final String value = String.format(template, name.or(defaultName)); return new Saying(counter.incrementAndGet(), value); }
This approach works with all versions – however, the newer versions (after 1.0.0) switched to the Java 8 version:
import java.util.Optional;
and use name.orElse(...)
in the sayHello
method:
@GET @Timed public Saying sayHello(@QueryParam("name") Optional<String> name) { final String value = String.format(template, name.orElse(defaultName)); return new Saying(counter.incrementAndGet(), value); }
And for completeness, the Java 8 approach may also be used in versions 0.9.* by including the Java 8 Bundle in the Maven pom.xml dependencies:
<dependency> <groupId>io.dropwizard.modules</groupId> <artifactId>dropwizard-java8</artifactId> <version>0.9.0-1</version> </dependency>
and adding the bundle in the Application’s initialise method:
@Override public void initialize(Bootstrap<HelloWorldConfiguration> bootstrap) { bootstrap.addBundle(new Java8Bundle()); ... }
Hope this helps someone else save an evening of frustration.
I had this exact same issue., using google optional worked for me. Thanks
But I could not get java8 bundle solution working.
Thanks a lot for the solution.
Thanks … this solved problem
Thanks, you solved my problem