Skip to content

Commit

Permalink
Add MvcMethod object for setMvcMethod and getMvcMethod.
Browse files Browse the repository at this point in the history
- fix #3532
- jooby-apt option will be off by default in next major release
  • Loading branch information
jknack committed Sep 19, 2024
1 parent 7433c2c commit 51d5937
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 18 deletions.
60 changes: 55 additions & 5 deletions jooby/src/main/java/io/jooby/Route.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
package io.jooby;

import java.io.Serializable;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
Expand Down Expand Up @@ -370,12 +373,55 @@ public interface Handler extends Serializable, Aware {
if (contentType == null) {
throw new UnsupportedMediaType(null);
}
if (!ctx.getRoute().getConsumes().stream().anyMatch(contentType::matches)) {
if (ctx.getRoute().getConsumes().stream().noneMatch(contentType::matches)) {
throw new UnsupportedMediaType(contentType.getValue());
}
}
};

/**
* Carry metadata for mvc/controller method.
*
* @param declaringClass Controller class.
* @param name Method name.
* @param returnType Method return type.
* @param parameterTypes Method argument types.
*/
public record MvcMethod(
@NonNull Class<?> declaringClass,
@NonNull String name,
@NonNull Class<?> returnType,
Class<?>... parameterTypes) {

/**
* Convert to {@link java.lang.reflect.Method}.
*
* @return A {@link java.lang.reflect.Method}.
*/
public Method toMethod() {
try {
return declaringClass.getDeclaredMethod(name, parameterTypes);
} catch (NoSuchMethodException e) {
throw SneakyThrows.propagate(e);
}
}

/**
* Convert to {@link MethodHandle}.
*
* @return A {@link MethodHandle}.
*/
public MethodHandle toMethodHandle() {
var lookup = MethodHandles.publicLookup();
var methodType = MethodType.methodType(returnType, parameterTypes);
try {
return lookup.findVirtual(declaringClass, name, methodType);
} catch (NoSuchMethodException | IllegalAccessException e) {
throw SneakyThrows.propagate(e);
}
}
}

/** Favicon handler as a silent 404 error. */
public static final Handler FAVICON = ctx -> ctx.send(StatusCode.NOT_FOUND);

Expand Down Expand Up @@ -423,7 +469,7 @@ public interface Handler extends Serializable, Aware {

private Boolean nonBlocking;

private Method mvcMethod;
private MvcMethod mvcMethod;

private boolean httpHead;

Expand Down Expand Up @@ -655,7 +701,9 @@ public boolean isNonBlockingSet() {
* Route return type.
*
* @return Return type.
* @deprecated Marked for removal on 4.0
*/
@Deprecated
public @Nullable Type getReturnType() {
return returnType;
}
Expand All @@ -665,7 +713,9 @@ public boolean isNonBlockingSet() {
*
* @param returnType Return type.
* @return This route.
* @deprecated Marked for removal on 4.0
*/
@Deprecated
public @NonNull Route setReturnType(@Nullable Type returnType) {
this.returnType = returnType;
return this;
Expand Down Expand Up @@ -1046,7 +1096,7 @@ public boolean isTransactional(boolean defaultValue) {
*
* @return Method for MVC/Controller. Not available for lambda routes.
*/
public @Nullable Method getMvcMethod() {
public @Nullable MvcMethod getMvcMethod() {
return mvcMethod;
}

Expand All @@ -1056,7 +1106,7 @@ public boolean isTransactional(boolean defaultValue) {
* @param mvcMethod Mvc/controller method.
* @return This route
*/
public @NonNull Route setMvcMethod(@Nullable Method mvcMethod) {
public @NonNull Route setMvcMethod(@Nullable MvcMethod mvcMethod) {
this.mvcMethod = mvcMethod;
return this;
}
Expand All @@ -1067,7 +1117,7 @@ public boolean isTransactional(boolean defaultValue) {
* @param mvcMethod Mvc/controller method.
* @return This route
*/
public @NonNull Route mvcMethod(@Nullable Method mvcMethod) {
public @NonNull Route mvcMethod(@Nullable MvcMethod mvcMethod) {
return setMvcMethod(mvcMethod);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public MvcContext(
this.debug = Options.boolOpt(processingEnvironment, Options.DEBUG, false);
this.incremental = Options.boolOpt(processingEnvironment, Options.INCREMENTAL, true);
this.returnType = Options.boolOpt(processingEnvironment, Options.RETURN_TYPE, false);
this.mvcMethod = Options.boolOpt(processingEnvironment, Options.MVC_METHOD, false);
this.mvcMethod = Options.boolOpt(processingEnvironment, Options.MVC_METHOD, true);
this.services = Options.boolOpt(processingEnvironment, Options.SERVICES, true);
this.routerPrefix = Options.string(processingEnvironment, Options.ROUTER_PREFIX, "");
this.routerSuffix = Options.string(processingEnvironment, Options.ROUTER_SUFFIX, "_");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,10 +156,15 @@ public List<String> generateMapping(boolean kt) {
CodeBlock.of(
indent(2),
".setMvcMethod(",
router.getTargetType().getSimpleName(),
kt ? "" : "new ",
"io.jooby.Route.MvcMethod(",
router.getTargetType().getQualifiedName().toString(),
clazz(kt),
".getMethod(",
", ",
string(getMethodName()),
", ",
type(kt, returnType.getRawType().toString()),
clazz(kt),
paramString.isEmpty() ? "" : ", " + paramString,
"))",
semicolon(kt),
Expand Down
16 changes: 11 additions & 5 deletions modules/jooby-apt/src/test/java/tests/i2629/Issue2629.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
*/
package tests.i2629;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.*;

import java.util.List;
import java.util.Map;
Expand All @@ -30,9 +29,16 @@ public void shouldSetMvcMethod() throws Exception {
assertEquals("foo:[12]:true", router.get("/2629", ctx).value().toString());
var route = app.getRoutes().get(0);
assertNotNull(route.getMvcMethod());
assertEquals(
"foo:[14]:false",
route.getMvcMethod().invoke(new C2629(), "foo", List.of(14), false));
try {
assertEquals(
"foo:[14]:false",
route
.getMvcMethod()
.toMethodHandle()
.invoke(new C2629(), "foo", List.of(14), Boolean.FALSE));
} catch (Throwable cause) {
fail(cause);
}
});
}
}
16 changes: 11 additions & 5 deletions modules/jooby-apt/src/test/java/tests/i2629/Issue2629b.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
*/
package tests.i2629;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.*;

import java.util.Map;

Expand All @@ -29,9 +28,16 @@ public void shouldSetMvcMethod() throws Exception {
assertEquals("foo/1/2.0/GET/3/4.0/true", router.get("/2629", ctx).value().toString());
var route = app.getRoutes().get(0);
assertNotNull(route.getMvcMethod());
assertEquals(
"bar/5/6.0/GET/7/8.0/false",
route.getMvcMethod().invoke(new C2629b(), "bar", 5, 6d, ctx, 7l, 8f, false));
try {
assertEquals(
"bar/5/6.0/GET/7/8.0/false",
route
.getMvcMethod()
.toMethodHandle()
.invoke(new C2629b(), "bar", 5, 6d, ctx, 7l, 8f, false));
} catch (Throwable e) {
fail(e);
}
});
}
}

0 comments on commit 51d5937

Please sign in to comment.