Swagger with Jersey 2抛出java.lang.NoClassDefFoundError:javax / servlet / ServletConfig

时间:2016-08-11 08:53:57

标签: java eclipse gradle swagger jersey-2.0

尝试设置我的第一个REST API(使用Jersey 2和Gradle)并使用swagger添加一些文档。但是当添加swagger依赖项并遵循this swagger文档时," Using a custom Application subclass"方法,它从Eclipse执行main方法时抛出了这个异常:

Exception in thread "main" java.lang.NoClassDefFoundError: javax/servlet/ServletConfig
    at java.lang.Class.getDeclaredMethods0(Native Method)
    at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
    at java.lang.Class.getDeclaredMethods(Class.java:1975)
    at org.glassfish.jersey.server.model.IntrospectionModeller$2.run(IntrospectionModeller.java:253)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.glassfish.jersey.server.model.IntrospectionModeller.getAllDeclaredMethods(IntrospectionModeller.java:247)
    at org.glassfish.jersey.server.model.IntrospectionModeller.checkForNonPublicMethodIssues(IntrospectionModeller.java:172)
    at org.glassfish.jersey.server.model.IntrospectionModeller.doCreateResourceBuilder(IntrospectionModeller.java:119)
    at org.glassfish.jersey.server.model.IntrospectionModeller.access$000(IntrospectionModeller.java:80)
    at org.glassfish.jersey.server.model.IntrospectionModeller$1.call(IntrospectionModeller.java:112)
    at org.glassfish.jersey.server.model.IntrospectionModeller$1.call(IntrospectionModeller.java:109)
    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.model.IntrospectionModeller.createResourceBuilder(IntrospectionModeller.java:109)
    at org.glassfish.jersey.server.model.Resource.from(Resource.java:797)
    at org.glassfish.jersey.server.ApplicationHandler.initialize(ApplicationHandler.java:465)
    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.server.ApplicationHandler.<init>(ApplicationHandler.java:299)
    at org.glassfish.jersey.jdkhttp.JdkHttpHandlerContainer.<init>(JdkHttpHandlerContainer.java:98)
    at org.glassfish.jersey.jdkhttp.JdkHttpServerFactory.createHttpServer(JdkHttpServerFactory.java:111)
    at org.glassfish.jersey.jdkhttp.JdkHttpServerFactory.createHttpServer(JdkHttpServerFactory.java:93)
    at example.MyApp.main(MyApp.java:21)
Caused by: java.lang.ClassNotFoundException: javax.servlet.ServletConfig
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    ... 29 more

我的代码如下所示:

package example;
import static org.glassfish.jersey.jdkhttp.JdkHttpServerFactory.createHttpServer;
import java.net.URI;
import javax.ws.rs.core.UriBuilder;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.server.ResourceConfig;
import com.sun.net.httpserver.HttpServer;
import io.swagger.jaxrs.listing.ApiListingResource;
import io.swagger.jaxrs.listing.SwaggerSerializers;

public class MyApp extends ResourceConfig {

    public static void main(String[] args) throws Throwable {
        URI baseUri = UriBuilder.fromUri("http://localhost/").port(9999).build();
        HttpServer server = createHttpServer(baseUri, new MyApp());
        System.out.println("SERVICE started at: " + baseUri);
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            server.stop(0);
        }));
    }

    public MyApp() {
        packages("example");
        register(SwaggerSerializers.class); // <-- swagger specific
        register(ApiListingResource.class); // <-- swagger specific
        register(JacksonFeature.class);
    }
}

我的gradle依赖

dependencies {
    compile 'com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:+'
    compile 'org.glassfish.jersey.containers:jersey-container-jdk-http:+'
    compile 'org.glassfish.jersey.media:jersey-media-moxy:+'
    compile 'org.glassfish.jersey.media:jersey-media-json-jackson:+'
    compile 'io.swagger:swagger-jersey2-jaxrs:1.5.9'
}

jdk1.8.0_77上使用Windows 7

但是,如果我在代码中注释掉swagger依赖项和swagger细节,那么实际的REST服务将按预期工作。如何在不使用servlet容器的情况下进行招摇? REST服务可以在没有它的情况下工作

dependencies {
    compile 'com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:+'
    compile 'org.glassfish.jersey.containers:jersey-container-jdk-http:+'
    compile 'org.glassfish.jersey.media:jersey-media-moxy:+'
    compile 'org.glassfish.jersey.media:jersey-media-json-jackson:+'
//    compile 'io.swagger:swagger-jersey2-jaxrs:1.5.9'
}

代码:

package example;
import static org.glassfish.jersey.jdkhttp.JdkHttpServerFactory.createHttpServer;
import java.net.URI;
import javax.ws.rs.core.UriBuilder;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.server.ResourceConfig;
import com.sun.net.httpserver.HttpServer;
import io.swagger.jaxrs.listing.ApiListingResource;
import io.swagger.jaxrs.listing.SwaggerSerializers;

public class MyApp extends ResourceConfig {

    public static void main(String[] args) throws Throwable {
        URI baseUri = UriBuilder.fromUri("http://localhost/").port(9999).build();
        HttpServer server = createHttpServer(baseUri, new MyApp());
        System.out.println("SERVICE started at: " + baseUri);
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            server.stop(0);
        }));
    }

    public MyApp() {
        packages("example");
        // register(SwaggerSerializers.class); // <-- swagger specific
        // register(ApiListingResource.class); // <-- swagger specific
        register(JacksonFeature.class);
    }
}

3 个答案:

答案 0 :(得分:4)

因此看起来问题源于您在非servlet环境中运行。虽然泽西岛支持它,但是swagger-core ......并非如此。这对特定部署提出了一些问题,尽管它们不太常见。

显然,最简单的解决方案是使用servlet-container引擎。像Jetty这样的轻量级产品可以工作。

答案 1 :(得分:0)

我知道这有点晚了,但是我遇到了同样的问题,并想出了一个在非servlet环境中大张旗鼓运行的解决方案。

希望对下一个开发人员有所帮助。

pom.xml

    <dependencies>

        <dependency>
            <groupId>org.glassfish.jersey.containers</groupId>
            <artifactId>jersey-container-grizzly2-http</artifactId>
        </dependency>

        <dependency>
            <groupId>org.glassfish.jersey.inject</groupId>
            <artifactId>jersey-hk2</artifactId>
        </dependency>

         <dependency>
            <groupId>org.glassfish.jersey.media</groupId>
            <artifactId>jersey-media-json-binding</artifactId>
        </dependency>

        <dependency>
            <groupId>org.eclipse.persistence</groupId>
            <artifactId>org.eclipse.persistence.jpa</artifactId>
            <version>2.7.1</version>
        </dependency>

        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>1.4.196</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.9</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>io.swagger</groupId>
            <artifactId>swagger-jersey2-jaxrs</artifactId>
            <version>1.5.0</version>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.5</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.5</version>
        </dependency>

    </dependencies>
...
 <properties>
        <jersey.version>2.28</jersey.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 </properties>

Main.java

package me.nunum.whereami;

import me.nunum.whereami.facade.ApiListingResource;
import me.nunum.whereami.framework.interceptor.PrincipalInterceptor;
import org.glassfish.grizzly.http.server.CLStaticHttpHandler;
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.grizzly.http.server.ServerConfiguration;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.server.ResourceConfig;


import java.io.IOException;
import java.net.URI;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Main class.
 */
public class Main {
    // Base URI the Grizzly HTTP server will listen on
    private static final String BASE_URI = "http://0.0.0.0:8080";

    private static final  Logger LOGGER = Logger.getLogger("Main");

    /**
     * Starts Grizzly HTTP server exposing JAX-RS resources defined in this application.
     *
     * @return Grizzly HTTP server.
     */
    public static HttpServer startServer() {

        // create a resource config that scans for JAX-RS resources and providers
        // in me.nunum.whereami.facade package
        final ResourceConfig rc = new ResourceConfig().packages("me.nunum.whereami.facade");
        rc.setApplicationName("where");

        rc.register(PrincipalInterceptor.class);
        rc.register(ApiListingResource.class);
        rc.register(io.swagger.jaxrs.listing.SwaggerSerializers.class);

        // create and start a new instance of grizzly http server
        // exposing the Jersey application at BASE_URI
        return GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI), rc);
    }

    /**
     * Main method.
     *
     * @param args
     * @throws IOException
     */
    public static void main(String[] args) throws IOException {
        final HttpServer server = startServer();


        ClassLoader loader = Main.class.getClassLoader();
        CLStaticHttpHandler docsHandler = new CLStaticHttpHandler(loader, "swagger-ui/dist/");
        docsHandler.setFileCacheEnabled(false);

        ServerConfiguration cfg = server.getServerConfiguration();
        cfg.addHttpHandler(docsHandler, "/docs/");

        Main.LOGGER.log(Level.INFO,"Jersey app started with WADL available at "
                + "{0} \nHit enter to stop it...", BASE_URI);
        System.in.read();
        server.shutdown();
    }
}

将io.swagger.jaxrs.listing.ApiListingResource类重构为新类(在我的Facade包中创建),以在非Servlet环境中工作。

package me.nunum.whereami.facade;

import io.swagger.annotations.ApiOperation;
import io.swagger.config.FilterFactory;
import io.swagger.config.Scanner;
import io.swagger.config.SwaggerConfig;
import io.swagger.core.filter.SpecFilter;
import io.swagger.core.filter.SwaggerSpecFilter;
import io.swagger.jaxrs.Reader;
import io.swagger.jaxrs.config.JaxrsScanner;
import io.swagger.jaxrs.config.ReaderConfig;
import io.swagger.jaxrs.listing.SwaggerSerializers;
import io.swagger.models.Swagger;
import io.swagger.util.Yaml;

import java.util.*;
import javax.inject.Singleton;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Cookie;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Path("/api/doc")
@Singleton
public class ApiListingResource {
    static boolean initialized = false;
    Logger LOGGER = LoggerFactory.getLogger(io.swagger.jaxrs.listing.ApiListingResource.class);


    public Swagger mSwaggerConfig;

    public ApiListingResource() {
        mSwaggerConfig = new Swagger();
        mSwaggerConfig.setBasePath("/");
    }

    public ApiListingResource(Swagger swagger){
        this.mSwaggerConfig = swagger;
    }

    protected synchronized Swagger scan(Application app) {
        Swagger swagger = null;
        Scanner scanner = new Scanner() {
            @Override
            public Set<Class<?>> classes() {
                return app.getClasses();
            }

            @Override
            public boolean getPrettyPrint() {
                return false;
            }

            @Override
            public void setPrettyPrint(boolean b) {

            }
        };
        this.LOGGER.debug("using scanner " + scanner);
        SwaggerSerializers.setPrettyPrint(scanner.getPrettyPrint());
        swagger = this.mSwaggerConfig;
        new HashSet();
        Set classes;

        if (scanner instanceof JaxrsScanner) {
            classes = null;
        } else {
            classes = scanner.classes();
        }

        if (classes != null) {
            Reader reader = new Reader(swagger, new ReaderConfig() {
                @Override
                public boolean isScanAllResources() {
                    return false;
                }

                @Override
                public Collection<String> getIgnoredRoutes() {
                    return new ArrayList<>();
                }
            });
            swagger = reader.read(classes);
            if (scanner instanceof SwaggerConfig) {
                swagger = ((SwaggerConfig)scanner).configure(swagger);
            } else {
                SwaggerConfig configurator = new SwaggerConfig() {
                    @Override
                    public Swagger configure(Swagger swagger) {
                        return swagger;
                    }

                    @Override
                    public String getFilterClass() {
                        return "";
                    }
                };
                this.LOGGER.debug("configuring swagger with " + configurator);
                configurator.configure(swagger);
            }

        }

        initialized = true;
        return swagger;
    }

    @GET
    @Produces({"application/json"})
    @Path("/swagger.json")
    @ApiOperation(
            value = "The swagger definition in JSON",
            hidden = true
    )
    public Response getListingJson(@Context Application app, @Context HttpHeaders headers, @Context UriInfo uriInfo) {
        Swagger swagger = this.mSwaggerConfig;
        if (!initialized) {
            this.mSwaggerConfig = this.scan(app);
        }

        if (swagger != null) {
            SwaggerSpecFilter filterImpl = FilterFactory.getFilter();
            if (filterImpl != null) {
                SpecFilter f = new SpecFilter();
                swagger = f.filter(swagger, filterImpl, this.getQueryParams(uriInfo.getQueryParameters()), this.getCookies(headers), this.getHeaders(headers));
            }

            return Response.ok().entity(swagger).build();
        } else {
            return Response.status(404).build();
        }
    }

    @GET
    @Produces({"application/yaml"})
    @Path("/swagger.yaml")
    @ApiOperation(
            value = "The swagger definition in YAML",
            hidden = true
    )
    public Response getListingYaml(@Context Application app, @Context HttpHeaders headers, @Context UriInfo uriInfo) {
        Swagger swagger = this.mSwaggerConfig;
        if (!initialized) {
            this.mSwaggerConfig = this.scan(app);
        }

        try {
            if (swagger != null) {
                SwaggerSpecFilter filterImpl = FilterFactory.getFilter();
                this.LOGGER.debug("using filter " + filterImpl);
                if (filterImpl != null) {
                    SpecFilter f = new SpecFilter();
                    swagger = f.filter(swagger, filterImpl, this.getQueryParams(uriInfo.getQueryParameters()), this.getCookies(headers), this.getHeaders(headers));
                }

                String yaml = Yaml.mapper().writeValueAsString(swagger);
                String[] parts = yaml.split("\n");
                StringBuilder b = new StringBuilder();
                String[] arr$ = parts;
                int len$ = parts.length;

                for(int i$ = 0; i$ < len$; ++i$) {
                    String part = arr$[i$];
                    int pos = part.indexOf("!<");
                    int endPos = part.indexOf(">");
                    b.append(part);
                    b.append("\n");
                }

                return Response.ok().entity(b.toString()).type("application/yaml").build();
            }
        } catch (Exception var16) {
            var16.printStackTrace();
        }

        return Response.status(404).build();
    }

    protected Map<String, List<String>> getQueryParams(MultivaluedMap<String, String> params) {
        Map<String, List<String>> output = new HashMap();
        if (params != null) {
            Iterator i$ = params.keySet().iterator();

            while(i$.hasNext()) {
                String key = (String)i$.next();
                List<String> values = (List)params.get(key);
                output.put(key, values);
            }
        }

        return output;
    }

    protected Map<String, String> getCookies(HttpHeaders headers) {
        Map<String, String> output = new HashMap();
        if (headers != null) {
            Iterator i$ = headers.getCookies().keySet().iterator();

            while(i$.hasNext()) {
                String key = (String)i$.next();
                Cookie cookie = (Cookie)headers.getCookies().get(key);
                output.put(key, cookie.getValue());
            }
        }

        return output;
    }

    protected Map<String, List<String>> getHeaders(HttpHeaders headers) {
        Map<String, List<String>> output = new HashMap();
        if (headers != null) {
            Iterator i$ = headers.getRequestHeaders().keySet().iterator();

            while(i$.hasNext()) {
                String key = (String)i$.next();
                List<String> values = (List)headers.getRequestHeaders().get(key);
                output.put(key, values);
            }
        }

        return output;
    }
}

任何问题,请问。

答案 2 :(得分:0)

我遇到了同样的问题,我通过遵循相同的swagger documentation解决了这个问题,唯一的区别是我提供了自己的ApiListingResource实现

package com.example;

import com.fasterxml.jackson.core.JsonProcessingException;
import io.swagger.annotations.ApiOperation;
import io.swagger.jaxrs.config.BeanConfig;
import io.swagger.models.Swagger;
import io.swagger.util.Yaml;

import javax.enterprise.context.ApplicationScoped;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;

@Path("/docs")
@ApplicationScoped
public class ApiListingResource {

    private final Swagger swagger;

    public ApiListingResource() {
        BeanConfig beanConfig = new BeanConfig();
        beanConfig.setTitle("MY REST API");
        beanConfig.setVersion("v1");
        beanConfig.setBasePath("/api");
        beanConfig.setResourcePackage("com.example.resource");
        beanConfig.setScan(true);
        this.swagger = beanConfig.getSwagger();
    }

    @GET
    @Produces({"application/json"})
    @Path("/swagger.json")
    public Response getListingJson() {
        return Response.ok(this.swagger).build();
    }

    @GET
    @Produces({"application/yaml"})
    @Path("/swagger.yaml")
    public Response getListingYaml() throws JsonProcessingException {
        String yaml = Yaml.mapper().writeValueAsString(this.swagger);
        return Response.ok(yaml).build();
    }
}

然后,我与SwaggerSerializers提供者一起注册了资源。