Skip to content

Commit

Permalink
Adding support for default Methods in the Proxy Target
Browse files Browse the repository at this point in the history
Modified the `GuardMethodHandler` to correctly wrap any `default` methods available
on a `Target` interface.
  • Loading branch information
kdavisk6 committed May 9, 2019
1 parent fcc3a15 commit a0674c1
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 34 deletions.
27 changes: 4 additions & 23 deletions feignx-core/src/main/java/feign/proxy/GuardMethodHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,22 @@ public class GuardMethodHandler implements TargetMethodHandler {
* @param target instance this method is for.
*/
@SuppressWarnings("JavaReflectionMemberAccess")
public GuardMethodHandler(Method method, Target<?> target) {
public GuardMethodHandler(Method method, Target<?> target, Object proxy) {
Assert.isNotNull(method, "method is required.");
Assert.isNotNull(target, "target is required.");
try {
/* attempt to create a new instance of the target type */
Class<?> targetType = target.type();
Constructor<Lookup> constructor = Lookup.class.getConstructor(Class.class);
Constructor<Lookup> constructor = Lookup.class.getDeclaredConstructor(Class.class);

/* this is the line that breaks on JDK 9+, it violates the new security rules */
constructor.setAccessible(true);

/* create a temporary instance of the target and execute the method */
this.guardMethodHandle = constructor.newInstance(targetType)
.in(targetType)
.unreflectSpecial(method, targetType);
.unreflectSpecial(method, targetType)
.bindTo(proxy);
} catch (InstantiationException | InvocationTargetException | NoSuchMethodException
| IllegalAccessException ie) {
/* either the type does not expose a type that can be instantiated or
Expand All @@ -53,26 +54,6 @@ public GuardMethodHandler(Method method, Target<?> target) {
}
}

/**
* Bind the HttpMethod Handler to the proxy.
*
* @param proxy to bind to.
*/
GuardMethodHandler bind(Object proxy) {
this.guardMethodHandle.bindTo(proxy);
this.bound = true;
return this;
}

/**
* If this HttpMethod Handler has been bound to a proxy.
*
* @return {@literal true} if this method handler is already bound, {@literal false} otherwise.
*/
boolean isBound() {
return this.bound;
}

/**
* Execute the HttpMethod Handler.
*
Expand Down
9 changes: 2 additions & 7 deletions feignx-core/src/main/java/feign/proxy/ProxyTarget.java
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl
/* default, static and non-annotated methods will not be in the map */
if (method.isDefault()) {
/* create the handler */
methodHandler = this.createGuardMethodHandler(method, this);
methodHandler = this.createGuardMethodHandler(method, proxy);

/* add it to the map for later use */
this.methodHandlerMap.put(method, methodHandler);
Expand Down Expand Up @@ -118,13 +118,8 @@ private void buildMethodHandlerMap(Target<?> target, Collection<TargetMethodDefi
}

private TargetMethodHandler createGuardMethodHandler(Method method, Object proxy) {
TargetMethodHandler methodHandler;

/* create a new Guard HttpMethod Handler and register it to the map */
methodHandler = new GuardMethodHandler(method, this)
.bind(proxy);

return methodHandler;
return new GuardMethodHandler(method, this, proxy);
}

@Override
Expand Down
18 changes: 14 additions & 4 deletions feignx-core/src/test/java/feign/FeignTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;

import feign.FeignTests.GitHub.Repository;
import feign.contract.Header;
import feign.contract.Headers;
import feign.contract.Param;
Expand All @@ -24,17 +23,24 @@ void createTarget_andExecuteRequest() {
}

@Test
void throwUnsupportedOperationException_whenMethodIsNotRegistered() {
void defaultMethods_areNotManaged() {
GitHub gitHub = Feign.builder()
.target(GitHub.class, "https://api.github.com");
String owner = gitHub.getOwner();
assertThat(owner).isEqualTo("owner");
}

@Test
void throwUnsupportedOperationException_whenMethodIsNotRegisteredAndNotDefault() {
GitHub gitHub = Feign.builder()
.target(GitHub.class, "https://api.github.com");

/* the get repositories method is not annotated, thus not registered */
assertThrows(UnsupportedOperationException.class,
gitHub::getContributors);

}

@Request("https://api.github.com")

interface GitHub {

@Request("/users/{owner}/repos")
Expand All @@ -43,6 +49,10 @@ interface GitHub {

List<String> getContributors();

default String getOwner() {
return "owner";
}

class Repository {

private String name;
Expand Down

0 comments on commit a0674c1

Please sign in to comment.