์ฌ๊ธฐ ์ ์ค๋ช ๋ ์์ต์๋ฅผ ๋ฐ๋ผ "์ฌ์ฉ์ ์ง์ ์์ฉ ํ๋ก๊ทธ๋จ ํ์ ํด๋์ค ์ฌ์ฉ" ์ ๊ทผ ๋ฐฉ์์ผ๋ก Jersey 2.23.2๋ก Swagger๋ฅผ ์ค์ ํฉ๋๋ค. ๋ค์ ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค.
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
์ด StackOverflow ํ ๋ก ๋ ์ฐธ์กฐํ์ญ์์ค .
์ด๊ฒ์ stackoverflow์์ ๋ต๋ณ๋์์ต๋๋ค. ์๋ธ๋ฆฟ ์ข ์์ฑ์ ์ถ๊ฐํ๊ธฐ ๋งํ๋ฉด๋ฉ๋๋ค.
์๋ ํ์ธ์ @fehguy
๋๋ ๊ฐ์ ๋ฌธ์ ์ ๋ถ๋ช์ณค๋ค. GrizzlyServer๋ฅผ ์ฌ์ฉํ๊ณ ์์ต๋๋ค. ์๋ฒ ์ ํ์ ํผํ๊ณ ์ถ์ต๋๋ค. Grizzly์์ ์ ํํ์ง ์๊ณ swagger๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๊น? ๊ทธ๋ ๋ค๋ฉด pom.xml์ ์ด๋ค ์ข ์์ฑ์ ์ถ๊ฐํด์ผ ํฉ๋๊น?
๋ค์ ์ข ์์ฑ์ ์ถ๊ฐํ๋ฉด ์ ์๊ฒ ํจ๊ณผ์ ์ด์์ต๋๋ค.
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-grizzly2-servlet</artifactId>
</dependency>
์๋ ํ์ธ์,
3๋ ํ ์ฐ๋ฆฌ๋ ๋์ผํ ๋ฒ๊ทธ๋ฅผ ๊ฐ์ง๊ณ ์์ต๋๋ค. ๋ชจ๋ ์๋ธ๋ฆฟ ์ด์ํ ๊ตฌ์ฑ ์์ด ์ด๋ฏธ grizzly HTTP ์๋ฒ์ ๊ฐ์ Java HTTP ์๋ฒ๋ฅผ ์คํํ๊ณ ์๋๋ฐ ์ ์๋ธ๋ฆฟ ๊ธฐ๋ฐ ํ๋ก์ ํธ๋ก ๋ณ๊ฒฝํด์ผ ํฉ๋๊น?
์ด๊ฒ์ ์ข ์์ฑ swagger-jersey2-jaxrs ์์ ApiListingResource ํด๋์ค๊ฐ ์๋ธ๋ฆฟ ์ธ์คํด์ค๊ฐ ์ฃผ์ ๋๊ธฐ๋ฅผ ์ํ๊ธฐ ๋๋ฌธ์ ๋ฐ์ํฉ๋๋ค. ๋ค๋ฅธ ๊ตฌํ์ ์ ๊ณตํ์ง ์๋ ์ด์
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")
<strong i="10">@Singleton</strong>
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() {
<strong i="11">@Override</strong>
public Set<Class<?>> classes() {
return app.getClasses();
}
<strong i="12">@Override</strong>
public boolean getPrettyPrint() {
return false;
}
<strong i="13">@Override</strong>
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() {
<strong i="14">@Override</strong>
public boolean isScanAllResources() {
return false;
}
<strong i="15">@Override</strong>
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() {
<strong i="16">@Override</strong>
public Swagger configure(Swagger swagger) {
return swagger;
}
<strong i="17">@Override</strong>
public String getFilterClass() {
return "";
}
};
this.LOGGER.debug("configuring swagger with " + configurator);
configurator.configure(swagger);
}
}
initialized = true;
return swagger;
}
<strong i="18">@GET</strong>
@Produces({"application/json"})
@Path("/swagger.json")
@ApiOperation(
value = "The swagger definition in JSON",
hidden = true
)
public Response getListingJson(<strong i="19">@Context</strong> Application app, <strong i="20">@Context</strong> HttpHeaders headers, <strong i="21">@Context</strong> 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();
}
}
<strong i="22">@GET</strong>
@Produces({"application/yaml"})
@Path("/swagger.yaml")
@ApiOperation(
value = "The swagger definition in YAML",
hidden = true
)
public Response getListingYaml(<strong i="23">@Context</strong> Application app, <strong i="24">@Context</strong> HttpHeaders headers, <strong i="25">@Context</strong> 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;
}
}
Maven ์์นด์ด๋ธ์์ Jersey ์์ ํ๋ก์ ํธ๋ฅผ ์ ํํ๋ฉด "jersey-container-grizzly2-http" ์ข ์์ฑ์ผ๋ก ๋๋๊ธฐ ๋๋ฌธ์ ์๋ก์ด ์ฌ๋๋ค์ ์ปจํ ์ด๋/์๋ธ๋ฆฟ์ ๋ํ ํผ๋์ ์ผ๋์ ๋์ง ์๊ณ swagger ์ค์ ์ ์๋ฃํ์ง ์์ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ ์ด ๋ง์ ํ๋ ๊ฒ์ ๋๋ค.
์ด๊ฒ์ด ์ด ๋ฌธ์ ์ ๋ํ ๋์ ํด๊ฒฐ์ฑ ์ ๋๋ค.
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")
<strong i="6">@ApplicationScoped</strong>
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();
}
<strong i="7">@GET</strong>
@Produces({"application/json"})
@Path("/swagger.json")
public Response getListingJson() {
return Response.ok(this.swagger).build();
}
<strong i="8">@GET</strong>
@Produces({"application/yaml"})
@Path("/swagger.yaml")
public Response getListingYaml() throws JsonProcessingException {
String yaml = Yaml.mapper().writeValueAsString(this.swagger);
return Response.ok(yaml).build();
}
}
io.swagger.jaxrs.listing
์ ๊ณตํ ๋ฆฌ์์ค ๋์ ์ด ๋ฆฌ์์ค๋ฅผ ๋ฑ๋กํ์ต๋๋ค.
๋๋จธ์ง ๊ตฌ์ฑ์ ๋ฌธ์์ ์ค๋ช
๋ ๊ฒ๊ณผ ๋์ผํฉ๋๋ค.
๊ฐ์ฅ ์ ์ฉํ ๋๊ธ
๋ค์ ์ข ์์ฑ์ ์ถ๊ฐํ๋ฉด ์ ์๊ฒ ํจ๊ณผ์ ์ด์์ต๋๋ค.