Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Path Parameter annotations in interface are parsed as body param #1506

Closed
mohitmutha opened this issue Oct 20, 2015 · 9 comments
Closed

Path Parameter annotations in interface are parsed as body param #1506

mohitmutha opened this issue Oct 20, 2015 · 9 comments

Comments

@mohitmutha
Copy link

When the @PathParam is annotated only to the interface method it is parsed as a body parameter in the swagger.json.

I have a interface for my endpoint which describes the JAX-RS endpoint. I want to have the JAX-RS annotations in the interface and the swagger annotations in the implementation

@Path("/myep")
@Produces(MediaType.APPLICATION_JSON)
public interface MyEndpointInterface{
 @GET
 @Path("/{id}")
public Response getMyData(@PathParam("id") Long id);
}

@Api(value = "/myep")
public class MyEndpointImpl extends MyEndpointInterface{
@ApiOperation(value = "Blah")
@Override
public Response getMyData(Long id){
 //My Impl
}
}

In the case above the id parameter is parsed as a body parameter.

I think the reason for this is the way parameter annotations of a method are read in the Reader.java (line 838).

Annotation[][] paramAnnotations = method.getParameterAnnotations();

Because of this only the annotations on the child method get parsed and the ones defined in the interface are not parsed.

I have created a workaround in ReflectionUtils.java to parse the parameter annotations in the base classes and interface as well. Please let me know if the same is acceptable

//Change in Reader.java
Annotation[][] paramAnnotations = ReflectionUtils.getParameterAnnotations(method);

//Method in ReflectionUtils.java
public static Annotation[][] getParameterAnnotations(Method method) {
  Annotation[][] methodAnnotations = method.getParameterAnnotations();
  Method overriddenmethod = getOverriddenMethod(method);

  if (overriddenmethod != null) {
   Annotation[][] overriddenAnnotations = overriddenmethod.getParameterAnnotations();


   for (int i = 0; i < methodAnnotations.length; i++) {
     List<Type> types = new ArrayList();
    for(int j = 0; j < methodAnnotations[i].length; j++){
     types.add(methodAnnotations[i][j].annotationType());
    }
    for(int j = 0; j < overriddenAnnotations[i].length; j++){
     if(!types.contains(overriddenAnnotations[i][j].annotationType())){
      methodAnnotations[i] = ArrayUtils.add(methodAnnotations[i], overriddenAnnotations[i][j]);
     }
    }

   }
  }
  return methodAnnotations;
 }
@webron
Copy link
Contributor

webron commented Oct 20, 2015

This is using which version?

@mohitmutha
Copy link
Author

1.5.4-SNAPSHOT

Master branch

@soltani-a
Copy link

same problem for me
version 1.5.5

@fehguy
Copy link
Contributor

fehguy commented Jan 4, 2016

@ssoltanid can you create a pull request? Looks like a proposed solution is above.

@nooruddin
Copy link

I have the same issue where swagger won't look for jax-rs annotations in interface.
Here is the sample code.

Interface:

package com.example.sampleapi;

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

@Path("authenticationStuff")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public interface ISampleRest {

    @Path("getMethod")
    @GET
    public Response demoGetMethod(@QueryParam("welcomeWho") final String welcomeWho);
}

Implementation:

package com.example.webapi.sample;

import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.CacheControl;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.TextNode;
import com.tutelatechnologies.dashboard.DashboardInterfaceEngine.server.sampleapi.ISampleRest;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiParam;

@Path("authenticationStuff")
@Produces(MediaType.APPLICATION_JSON)
@Api(value = "/authenticationStuff", tags = "authenticationStuff")
public class SampleRest implements ISampleRest {

    final JsonNodeFactory factory = JsonNodeFactory.instance;

    @Override
    public Response demoGetMethod(@ApiParam("welcomeWho") final String welcomWho) {
        TextNode textNode = factory.textNode("called get method by: " + welcomWho);
        return getNoCacheResponseBuilder(Response.Status.OK).entity(textNode).build();
    }

    private Response.ResponseBuilder getNoCacheResponseBuilder(Response.Status status) {
        CacheControl cc = new CacheControl();
        cc.setNoCache(true);
        cc.setMaxAge(-1);
        cc.setMustRevalidate(true);

        return Response.status(status).cacheControl(cc);
    }
}

@webron
Copy link
Contributor

webron commented Apr 22, 2016

@mohitmutha, @ssoltanid, @nooruddin - 1.5.9-SNAPSHOT has been pushed with the merged PRs that are meant to fix the issue. Can you give it a try and confirm it resolves the case?

@nooruddin
Copy link

I pulled out latest snapshot and plugged it in. It's seamlessly working now.
Thanks for the update.

@nooruddin
Copy link

In jersey, I guess annotation inheritance works for method level. But one does need to specify the produces and path annotations at implementation class level. So in that sense, every other annotations are inherited from interface properly now.

@mohitmutha
Copy link
Author

Great! Works as expected now.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants