207207import com .fasterxml .jackson .annotation .JsonInclude ;
208208import com .fasterxml .jackson .databind .ObjectMapper ;
209209import com .fasterxml .jackson .databind .module .SimpleModule ;
210+ import com .google .common .collect .ImmutableMap ;
210211import com .google .common .collect .ImmutableSet ;
211212import com .google .common .io .ByteStreams ;
212213import com .google .common .primitives .Primitives ;
218219import org .jooby .Jooby ;
219220import org .jooby .Request ;
220221import org .jooby .Response ;
222+ import org .jooby .Result ;
221223import org .jooby .Route ;
222224import org .jooby .Session ;
225+ import org .jooby .Status ;
223226import org .jooby .Upload ;
224227import org .jooby .apitool .RouteMethod ;
225228import org .jooby .apitool .RouteParameter ;
@@ -409,9 +412,22 @@ public List<RouteMethod> parse(String classname) throws Exception {
409412 returnType = TypeDescriptorParser .parse (loader ,
410413 Optional .ofNullable (method .signature ).orElse (method .desc ));
411414 }
415+ Integer status ;
416+ if (returnType instanceof TypeWithStatus ) {
417+ status = ((TypeWithStatus ) returnType ).status ;
418+ returnType = ((TypeWithStatus ) returnType ).type ();
419+ } else {
420+ status = null ;
421+ }
412422 List <RouteParameter > parameters = params (loader , owner , lambda .pattern , method );
423+ RouteResponse routeResponse = new RouteResponse (simplifyType (returnType ));
424+ if (status != null ) {
425+ routeResponse .status (ImmutableMap .of (status ,
426+ Try .apply (() -> Status .valueOf (status .intValue ()).reason ())
427+ .orElse (status .toString ())));
428+ }
413429 RouteMethod route = new RouteMethod (lambda .name , lambda .pattern ,
414- new RouteResponse ( simplifyType ( returnType )) ).parameters (parameters );
430+ routeResponse ).parameters (parameters );
415431 javadoc (route , javadoc .pop (lambda .declaringClass , lambda .name , lambda .pattern ));
416432 methods .add (route );
417433 } else {
@@ -984,12 +1000,16 @@ private java.lang.reflect.Type returnType(final ClassLoader loader,
9841000 .map (previous -> {
9851001 /** return 1; return true; return new Foo(); */
9861002 if (previous instanceof MethodInsnNode ) {
987- MethodInsnNode methodNode = ((MethodInsnNode ) previous );
988- if (methodNode .name .equals ("<init>" )) {
989- return loadType (loader , methodNode .owner );
1003+ MethodInsnNode minnsn = ((MethodInsnNode ) previous );
1004+ if (minnsn .name .equals ("<init>" )) {
1005+ return loadType (loader , minnsn .owner );
9901006 }
991- String desc = methodNode .desc ;
992- return TypeDescriptorParser .parse (loader , desc );
1007+ String desc = minnsn .desc ;
1008+ java .lang .reflect .Type type = TypeDescriptorParser .parse (loader , desc );
1009+ if (type .getTypeName ().equals (Result .class .getName ())) {
1010+ return new TypeWithStatus (type , statusCodeFor (minnsn ));
1011+ }
1012+ return type ;
9931013 }
9941014 /** return "String" | int | double */
9951015 if (previous instanceof LdcInsnNode ) {
@@ -1009,6 +1029,28 @@ private java.lang.reflect.Type returnType(final ClassLoader loader,
10091029 }).orElse (Object .class );
10101030 }
10111031
1032+ private Integer statusCodeFor (MethodInsnNode node ) {
1033+ if (node .name .equals ("noContent" )) {
1034+ return 204 ;
1035+ }
1036+ if (node .name .equals ("with" )) {
1037+ AbstractInsnNode previous = node .getPrevious ();
1038+ if (previous instanceof IntInsnNode ) {
1039+ return ((IntInsnNode ) previous ).operand ;
1040+ }
1041+ if (previous instanceof FieldInsnNode ) {
1042+ String owner = ((FieldInsnNode ) previous ).owner .replace ("/" , "." );
1043+ if (owner .equals (Status .class .getName ())) {
1044+ String statusName = ((FieldInsnNode ) previous ).name ;
1045+ return Try .apply (() -> Status .class .getDeclaredField (statusName ).get (null ))
1046+ .map (it -> ((Status ) it ).value ())
1047+ .orElse (null );
1048+ }
1049+ }
1050+ }
1051+ return null ;
1052+ }
1053+
10121054 @ SuppressWarnings ("unchecked" )
10131055 static java .lang .reflect .Type localVariable (final ClassLoader loader , final MethodNode m ,
10141056 final VarInsnNode varInsn ) {
@@ -1058,7 +1100,7 @@ public void write(final char[] cbuf, final int off, final int len) throws IOExce
10581100
10591101 @ Override
10601102 public void flush () throws IOException {
1061- log .debug ("{}:\n {}" , owner , buff );
1103+ log .info ("{}:\n {}" , owner , buff );
10621104 }
10631105
10641106 @ Override
@@ -1148,4 +1190,25 @@ private static RouteParameter toRouteParameter(String pattern, final Parameter p
11481190 return new RouteParameter (pname , kind .get (), p .getParameterizedType (), null );
11491191 }
11501192
1193+ private static class TypeWithStatus implements java .lang .reflect .Type {
1194+ private final java .lang .reflect .Type forwarding ;
1195+ final Integer status ;
1196+
1197+ TypeWithStatus (java .lang .reflect .Type forwarding , Integer status ) {
1198+ this .forwarding = forwarding ;
1199+ this .status = status ;
1200+ }
1201+
1202+ public java .lang .reflect .Type type () {
1203+ if (status != null && status == 204 && forwarding .getTypeName ().equals (Result .class .getName ())) {
1204+ return void .class ;
1205+ }
1206+ return forwarding ;
1207+ }
1208+
1209+ @ Override public String getTypeName () {
1210+ return forwarding .getTypeName ();
1211+ }
1212+ }
1213+
11511214}
0 commit comments