While migrating one of our projects to Java 9(build 9+181), I am facing a peculiar problem what looks like an incorrect implementation in some library in use related to type inference and java-module. I am using a dropwizard-core(1.1.0)
and guice(4.1.0)
configurations as follows:
public class CustomService extends io.dropwizard.Application<CustomServiceConfig> {
public static void main(String[] args) throws Exception {
new CustomService().run(args);
}
// other initializations
@Override
public void run(CustomServiceConfig config, io.dropwizard.setup.Environment environment) throws Exception {
com.google.inject.Injector injector = createInjector(config, environment);
environment.jersey().register(injector.getInstance(SomeResource.class)); //line 45
environment.healthChecks().register("DBHealth", injector.getInstance(HealthCheck.class));
environment.servlets().addFilter("Filter-Name", SomeFilter.class)
.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), true, "/*");
}
private com.google.inject.Injector createInjector(CustomServiceConfig config, Environment environment) {
return com.google.inject.Guice.createInjector(new CustomServiceModule(config, environment));
}
}
public class CustomServiceModule extends com.google.inject.AbstractModule {
private final CustomServiceConfig serviceConfig;
private final Environment environment;
public CustomServiceModule(CustomServiceConfig serviceConfig, Environment environment) {
this.serviceConfig = serviceConfig;
this.environment = environment;
}
@Override
protected void configure() {
bind(SomeInterface.class).to(SomeInterfaceImpl.class);
..
}
}
The configuration works fine for me with the following combination :
But as I switch to the module structure and then try and compile the maven module consisting of those classes, I get these errors during mvn clean install
:
[ERROR] ../service/service/CustomService.java:[45,29] incompatible types: inference variable T has incompatible bounds equality constraints: base.SomeResource upper bounds: java.lang.Class<?>,java.lang.Object [ERROR] ../service/service/CustomService.java:[56,31] no suitable method found for addFilter(java.lang.String,java.lang.Class< SomeFilter >) [ERROR] method io.dropwizard.jetty.setup.ServletEnvironment.addFilter(java.lang.String,javax.servlet.Filter) is not applicable [ERROR] (argument mismatch; java.lang.Class< SomeFilter > cannot be converted to javax.servlet.Filter)
I am not sure why these errors occurred and if they could be related to the module structure in use.
Q1. Is there any type-inference related change that can impact the maven compilation with module structure changes(if this is possible) keeping in mind the dependencies used?
Also while migrating, I have mostly used the automatic module names as suggested by IntelliJ to construct the module-info
as :
module service {
// Internal modules which compile successfully
requires model;
requires util;
// Dependent library modules
requires httpcore;
requires guice;
requires guava;
requires dropwizard.core;
requires mongo.java.driver;
requires org.apache.commons.lang3;
requires javax.servlet.api;
}
Q2. If this is not a regression issue while migrating, why did this not fail with our previous setup? Does this also mandate a code change in our service or shall we wait for libraries to move to modules if that might help?
Note: Have tried to look into the usage of the dependency versions and class implementation. They are same in both the previous and current setup.
Do let me know for any further information I could help with.
Update: I was able to reproduce the same in a microservice sample created by me to isolate it from the rest of my project.
From the sample project I was able to fix the compilation issue. There were 2 exceptions in com.SomeService#run
method. There were missing modules in your module-info.java, once you add these the code should compile.
requires dropwizard.jersey;
requires dropwizard.jetty;
JerseyEnvironment
comes from io.dropwizard:dropwizard-jersey:1.1.0
ServletEnvironment
comes from io.dropwizard:dropwizard-jetty:1.1.0
Since they are different jars, they export different modules. Hence, the requires needs to be explicitly added. Your code works fine without module-info.java because at that time module system is not used.
I found the fix by doing the below, method mentioned in comments:
@Override
public void run(SomeServiceConfig config, Environment environment) throws Exception {
Injector injector = Guice.createInjector(new SomeServiceModule());
// Fix: Extract to variable to find Type of jersey and then find the module to add under requires
JerseyEnvironment jersey = environment.jersey();
jersey.register(injector.getInstance(SomeResource.class));
// Fix 2: Same method as Fix 1
ServletEnvironment servlets = environment.servlets();
servlets.addFilter("Some-Filter", SomeFilter.class);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With