Skip to content

Commit

Permalink
resolve #10 ResourceInstaller looks for @path annotation on directly …
Browse files Browse the repository at this point in the history
…implemented interfaces
  • Loading branch information
xvik committed Jun 18, 2016
1 parent 265de38 commit 9a47c74
Show file tree
Hide file tree
Showing 8 changed files with 132 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
* Update to guice 4.1.0
* ResourceInstaller looks for @Path on directly implemented interface (#10)

### 3.2.0 (2016-01-23)
* Clear possible duplicate guicey bundle instances
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@

/**
* Jersey resource installer.
* Search classes annotated with {@link Path}. Directly register instance in jersey context to force singleton.
* Search classes annotated with {@link Path} or implementing interfaces annotated with {@link Path}
* (only directly implemented). Directly register instance in jersey context to force singleton.
* If we register it by type, then we could use prototype beans (resource instance created on each request),
* which will lead to performance overhead. To ovoid misuse, singleton resources are forced. Override installer
* if you really need prototype resources.
Expand All @@ -34,7 +35,8 @@ public class ResourceInstaller implements FeatureInstaller<Object>, BindingInsta

@Override
public boolean matches(final Class<?> type) {
return FeatureUtils.hasAnnotation(type, Path.class);
return !type.isInterface()
&& (FeatureUtils.hasAnnotation(type, Path.class) || hasMatchedInterfaces(type));
}

@Override
Expand All @@ -60,4 +62,16 @@ public void install(final AbstractBinder binder, final Injector injector, final
public void report() {
// dropwizard logs installed resources
}

private boolean hasMatchedInterfaces(final Class<?> type) {
boolean matches = false;
// looking only first interface level
for (Class<?> iface : type.getInterfaces()) {
if (iface.isAnnotationPresent(Path.class)) {
matches = true;
break;
}
}
return matches;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package ru.vyarus.dropwizard.guice.cases.ifaceresource

import ru.vyarus.dropwizard.guice.cases.ifaceresource.support.InterfaceResourceApp
import ru.vyarus.dropwizard.guice.cases.ifaceresource.support.ResourceImpl
import ru.vyarus.dropwizard.guice.module.installer.feature.jersey.ResourceInstaller
import ru.vyarus.dropwizard.guice.module.installer.internal.FeaturesHolder
import ru.vyarus.dropwizard.guice.test.spock.UseDropwizardApp
import spock.lang.Specification

import javax.inject.Inject


/**
* @author Vyacheslav Rusakov
* @since 18.06.2016
*/
@UseDropwizardApp(InterfaceResourceApp)
class InterfaceResourceDefinitionTest extends Specification {

@Inject
FeaturesHolder holder

def "Check resources recognition"() {

expect: "only one resource recognized"
holder.getFeatures(ResourceInstaller) == [ResourceImpl]
}

def "Check resource registered"() {

expect: 'resource called'
new URL("http://localhost:8080/res").getText() == 'called!'
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package ru.vyarus.dropwizard.guice.cases.ifaceresource.support

import io.dropwizard.Application
import io.dropwizard.setup.Bootstrap
import io.dropwizard.setup.Environment
import ru.vyarus.dropwizard.guice.GuiceBundle
import ru.vyarus.dropwizard.guice.support.TestConfiguration

/**
* @author Vyacheslav Rusakov
* @since 18.06.2016
*/
class InterfaceResourceApp extends Application<TestConfiguration> {

@Override
void initialize(Bootstrap<TestConfiguration> bootstrap) {
bootstrap.addBundle(GuiceBundle.<TestConfiguration> builder()
.enableAutoConfig(this.class.package.name)
.build()
);
}

@Override
void run(TestConfiguration configuration, Environment environment) throws Exception {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package ru.vyarus.dropwizard.guice.cases.ifaceresource.support

/**
* This resource could not be recognized because @Path annotation is not on 1st level interface.
*
* @author Vyacheslav Rusakov
* @since 18.06.2016
*/
class InvisibleResourceImpl implements SecondLevelResource {

@Override
String latest() {
return null
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package ru.vyarus.dropwizard.guice.cases.ifaceresource.support

import javax.ws.rs.GET
import javax.ws.rs.Path
import javax.ws.rs.Produces
import javax.ws.rs.core.Response

/**
* @author Vyacheslav Rusakov
* @since 18.06.2016
*/
@Path("/res")
@Produces('application/json')
interface ResourceContract {

@GET
@Path("/")
String latest();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package ru.vyarus.dropwizard.guice.cases.ifaceresource.support
/**
* @author Vyacheslav Rusakov
* @since 18.06.2016
*/
class ResourceImpl implements ResourceContract {

@Override
String latest() {
return "called!"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package ru.vyarus.dropwizard.guice.cases.ifaceresource.support

/**
* @author Vyacheslav Rusakov
* @since 18.06.2016
*/
interface SecondLevelResource extends ResourceContract {

}

0 comments on commit 9a47c74

Please sign in to comment.