【问题标题】:Swagger with Jersey 2 throws java.lang.NoClassDefFoundError: javax/servlet/ServletConfig带有 Jersey 2 的 Swagger 抛出 java.lang.NoClassDefFoundError: javax/servlet/ServletConfig
【发布时间】:2016-12-17 21:57:59
【问题描述】:

尝试设置我的第一个 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'
}

Windows 7 上使用jdk1.8.0_77

但是,如果我注释掉代码中的 swagger 依赖项和 swagger 细节,那么实际的 REST 服务会按预期工作。如何在不使用 servlet 容器的情况下使 swagger 工作? 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);
    }
}

【问题讨论】:

  • 尽管您在问题中提供了详细信息,但还不够。显然,您没有使用 servlet 容器,因此该错误是可以理解的。但是,当您说 when swagger is removed 时,不清楚您的意思。没有它,你的代码会是什么样子?
  • 问题已编辑。这更清楚@Ron 吗?

标签: java eclipse gradle swagger jersey-2.0


【解决方案1】:

所以看起来问题是由于您在非 servlet 环境中运行而产生的。虽然泽西岛支持它,但大摇大摆的核心......不是那么多。这会给特定部署带来一些问题,尽管它们不太常见。

显然,最简单的解决方案是使用 servlet 容器引擎。像 Jetty 这样轻量级的东西可以工作。

【讨论】:

    【解决方案2】:

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

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

    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 类重构为一个新类(在我的外观包中创建)以在非 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;
        }
    }
    

    有什么问题,欢迎提问。

    【讨论】:

      【解决方案3】:

      我遇到了同样的问题,我按照相同的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 提供者一起注册。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-02-09
        • 2016-02-09
        • 1970-01-01
        • 1970-01-01
        • 2023-04-08
        • 2021-10-20
        • 1970-01-01
        相关资源
        最近更新 更多