paradoxical-io / dropwizard.swagger

Add swagger to your admin resource for dropwizard
MIT License
9 stars 1 forks source link

Customizing SwaggerAssetsBundle for Java 7 throws ArrayIndexOutOfBoundesException? #3

Closed jarrodhroberson closed 8 years ago

jarrodhroberson commented 8 years ago
bootstrap.addBundle(new SwaggerAssetsBundle((ApiProvider) environment -> new DocumentsPageApi(getPublicSwagger(environment)), new DocumentsPage()));

I can't seem to get this to work.

bootstrap.addBundle(new SwaggerAssetsBundle(new ApiProvider()
{
    @Nonnull
    public SwaggerApiProvider apply(@Nullable final Environment input)
    {
        final BeanConfig config = new BeanConfig();
        config.setTitle("Public API");
        config.setVersion("1.0.0");
        config.setResourcePackage("com.company.resource");
        config.setScan(true);
        return new DocumentsPageApi(config);
    }
}, new DocumentsPage()));

and I have these defined

@Path("/api/docs")
@Produces(MediaType.TEXT_HTML)
public class DocumentsPage extends SwaggerPagesResource
{ /* intentionally blank */}

@Path("/api/docs")
public class DocumentsPageApi extends SwaggerApiResource
{
    public DocumentsPageApi(@Nonnull final BeanConfig swaggerConfig)
    {
        super(swaggerConfig);
    }
}

I get this stacktrace:

Caused by: java.lang.ArrayIndexOutOfBoundsException: 1
        at org.glassfish.jersey.server.model.Parameter.create(Parameter.java:372)
        at org.glassfish.jersey.server.model.Parameter.create(Parameter.java:417)
        at org.glassfish.jersey.server.model.MethodHandler$ClassBasedMethodHandler.<init>(MethodHandler.java:267)
        at org.glassfish.jersey.server.model.MethodHandler.create(MethodHandler.java:155)
        at org.glassfish.jersey.server.model.ResourceMethod$Builder.createInvocable(ResourceMethod.java:550)
        at org.glassfish.jersey.server.model.ResourceMethod$Builder.build(ResourceMethod.java:536)
        at org.glassfish.jersey.server.model.Resource$Builder.processMethodBuilders(Resource.java:663)
        at org.glassfish.jersey.server.model.Resource$Builder.buildResourceData(Resource.java:599)
        at org.glassfish.jersey.server.model.Resource$Builder.build(Resource.java:655)
        at org.glassfish.jersey.server.model.Resource$Builder.processChildResourceBuilders(Resource.java:671)
        at org.glassfish.jersey.server.model.Resource$Builder.buildResourceData(Resource.java:600)
        at org.glassfish.jersey.server.model.Resource$Builder.build(Resource.java:655)
        at org.glassfish.jersey.server.model.Resource.from(Resource.java:798)
        at org.glassfish.jersey.server.ApplicationHandler.initialize(ApplicationHandler.java:476)
        at org.glassfish.jersey.server.ApplicationHandler.access$500(ApplicationHandler.java:184)
        at org.glassfish.jersey.server.ApplicationHandler$3.call(ApplicationHandler.java:350)
        at org.glassfish.jersey.server.ApplicationHandler$3.call(ApplicationHandler.java:347)
        at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
        at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
        at org.glassfish.jersey.internal.Errors.processWithException(Errors.java:255)
        at org.glassfish.jersey.server.ApplicationHandler.<init>(ApplicationHandler.java:347)
        at org.glassfish.jersey.servlet.WebComponent.<init>(WebComponent.java:390)
        at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:172)
        at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:364)
        at javax.servlet.GenericServlet.init(GenericServlet.java:244)
        at org.eclipse.jetty.servlet.ServletHolder.initServlet(ServletHolder.java:612)

When I comment out that first block the error goes away but does not register the swagger documentation.

devshorts commented 8 years ago

If you use the default provided ones and don't override the docs/pages provider do you still get the same error?

jarrodhroberson commented 8 years ago

This does not throw the ArrayIndexOutOfBoundsException:

        bootstrap.addBundle(new SwaggerAssetsBundle(new ApiProvider()
        {
            @Nonnull
            public SwaggerApiProvider apply(@Nullable final Environment input)
            {
                final BeanConfig config = new BeanConfig();
                config.setTitle("Public API");
                config.setVersion("1.0.0");
                config.setResourcePackage("com.mycompany.resource");
                config.setScan(true);
                return new SwaggerApiResource(config);
            }
        }, new SwaggerPagesResource()));
jarrodhroberson commented 8 years ago

I got it to work, I wanted these as inner classes to my Application class and I had to add static to the class definitions and it started working.

@Path("/docs")
@Produces(MediaType.TEXT_HTML)
public static class DocumentsPage extends SwaggerPagesResource
{ /* intentionally blank */}

@Path("/docs")
public static class DocumentsPageApi extends SwaggerApiResource
{
    public DocumentsPageApi(@Nonnull final BeanConfig swaggerConfig)
    {
        super(swaggerConfig);
    }
}
devshorts commented 8 years ago

Ahh, that'll do it. Thanks!

jakeswenson commented 8 years ago

@devshorts we should try to improve the exception experience here and make debugging easier. Lets file a follow up issue to track that.

devshorts commented 8 years ago

I'm not sure how much we can do here given that the pages are resource blocks, and were nested inside of another class that did not have a resource block. I'd love to get a sample app if possible @jarrodhroberson to see what we can do to make this something that future users wont encounter though

jarrodhroberson commented 8 years ago

Here is an example Application class that failed without the static being added to the class defintions.

package com.gm.gdat.example;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import io.dropwizard.Application;
import io.dropwizard.assets.AssetsBundle;
import io.dropwizard.setup.Bootstrap;
import io.dropwizard.setup.Environment;
import io.paradoxical.dropwizard.swagger.*;
import io.swagger.jaxrs.config.BeanConfig;

public class ExampleApplication extends Application<ExampleConfiguration>
{
    public static void main(@Nonnull final String[] args) throws Exception
    {
        new ExampleApplication().run(args);
    }

    @Override
    public void initialize(final Bootstrap<ExampleConfiguration> bootstrap)
    {
        bootstrap.addBundle(new SwaggerAssetsBundle(new ApiProvider()
        {
            @Nonnull
            public SwaggerApiProvider apply(@Nullable final Environment input)
            {
                final BeanConfig config = new BeanConfig();
                config.setTitle("Public API");
                config.setVersion("1.0.0");
                config.setResourcePackage("com.my.example.resource");
                config.setScan(true);
                return new DocumentsPageApi(config);
            }
        }, new DocumentsPage()));

        bootstrap.addBundle(new AssetsBundle("/assets/", "/app", null, "app"));
        bootstrap.addBundle(new AssetsBundle("/assets/js", "/js", null, "js"));
        bootstrap.addBundle(new AssetsBundle("/assets/css", "/css", null, "css"));
        bootstrap.addBundle(new AssetsBundle("/assets/img", "/img", null, "img"));
    }

    @Override
    public void run(final ExampleConfiguration config, final Environment environment) throws Exception
    {
        /* resources removed for brevity */
    }

    @Path("/docs")
    @Produces(MediaType.TEXT_HTML)
    public static class DocumentsPage extends SwaggerPagesResource
    { /* intentionally blank */}

    @Path("/docs")
    public static class DocumentsPageApi extends SwaggerApiResource
    {
        public DocumentsPageApi(@Nonnull final BeanConfig swaggerConfig)
        {
            super(swaggerConfig);
        }
    }
}