Skip to content

Instantly share code, notes, and snippets.

@ben-manes
Last active August 11, 2017 07:13
Show Gist options
  • Save ben-manes/af6ab5e857f29f55d990 to your computer and use it in GitHub Desktop.
Save ben-manes/af6ab5e857f29f55d990 to your computer and use it in GitHub Desktop.
Swagger 1.5.1-M1 + RestEasy 3.x + Guice 4
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import com.google.inject.Singleton;
/**
* Allow CORS for Swagger specification api.
*
* @author ben.manes@gmail.com (Ben Manes)
*/
@Singleton
final class ApiOriginFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse res = (HttpServletResponse) response;
res.addHeader("Access-Control-Allow-Origin", "*");
res.addHeader("Access-Control-Allow-Headers", "Content-Type");
res.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
chain.doFilter(request, response);
}
@Override
public void destroy() {}
@Override
public void init(FilterConfig filterConfig) throws ServletException {}
}
dependencies {
compile dependencies.create('com.wordnik:swagger-jersey2-jaxrs:1.5.1-M1') {
exclude group: 'org.glassfish.jersey.containers'
exclude group: 'org.glassfish.jersey.media'
}
}
import java.util.HashSet;
import java.util.Set;
import org.reflections.Reflections;
import org.reflections.scanners.ResourcesScanner;
import org.reflections.scanners.SubTypesScanner;
import org.reflections.scanners.TypeAnnotationsScanner;
import org.reflections.util.ClasspathHelper;
import org.reflections.util.ConfigurationBuilder;
import com.wordnik.swagger.annotations.Api;
import com.wordnik.swagger.jaxrs.config.BeanConfig;
import com.wordnik.swagger.models.Contact;
import com.wordnik.swagger.models.Info;
import com.wordnik.swagger.models.License;
/**
* A {@link BeanConfig} that supports multiple resource packages. This can be removed in Swagger M2
* where this enhancement is supported (and directly ported from).
*
* @author ben.manes@gmail.com (Ben Manes)
*/
final class ResourceConfig extends BeanConfig {
@Override
public Set<Class<?>> classes() {
ConfigurationBuilder config = new ConfigurationBuilder();
Set<String> acceptablePackages = new HashSet<String>();
if (getResourcePackage() != "") {
String[] parts = getResourcePackage().split(",");
for (String pkg : parts) {
if (!"".equals(pkg)) {
acceptablePackages.add(pkg);
config.addUrls(ClasspathHelper.forPackage(pkg));
}
}
}
config.setScanners(new ResourcesScanner(),
new TypeAnnotationsScanner(), new SubTypesScanner());
setInfo(new Info()
.title(getTitle())
.version(getVersion())
.description(getDescription())
.termsOfService(getTermsOfServiceUrl()));
if (getContact() != null) {
getInfo().contact(new Contact().name(getContact()));
}
if ((getLicense() != null) && (getLicenseUrl() != null)) {
getInfo().license(new License().name(getLicense()).url(getLicenseUrl()));
}
getSwagger().setInfo(getInfo());
Set<Class<?>> classes = new Reflections(config).getTypesAnnotatedWith(Api.class);
Set<Class<?>> output = new HashSet<Class<?>>();
for (Class<?> cls : classes) {
if (acceptablePackages.contains(cls.getPackage().getName())) {
output.add(cls);
}
}
return output;
}
}
import javax.servlet.ServletContextListener;
import com.google.inject.multibindings.Multibinder;
import com.google.inject.servlet.ServletModule;
import com.wordnik.swagger.jaxrs.listing.ApiListingResource;
import com.wordnik.swagger.jaxrs.listing.SwaggerSerializers;
/**
* A module to install <a href="http://swagger.io">Swagger</a> with JAX-RS scanning.
*
* @author ben.manes@gmail.com (Ben Manes)
*/
public final class SwaggerModule extends ServletModule {
@Override
protected void configureServlets() {
Multibinder.newSetBinder(binder(), ServletContextListener.class)
.addBinding().to(SwaggerServletContextListener.class);
bind(SwaggerApiListingResource.class);
bind(SwaggerSerializers.class);
filter("/api/*").through(ApiOriginFilter.class);
}
@Path("/api")
static final class SwaggerApiListingResource extends ApiListingResourceJSON {}
}
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.jboss.resteasy.util.GetRestful;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
import com.wordnik.swagger.config.ScannerFactory;
import com.wordnik.swagger.jaxrs.config.BeanConfig;
/**
* A context listener that scans for APIs and configures Swagger.
*
* @author ben.manes@gmail.com (Ben Manes)
*/
final class SwaggerServletContextListener implements ServletContextListener {
private final Config config = ConfigFactory.load().getConfig(getClass().getPackage().getName());
private final Injector injector;
@Inject
SwaggerServletContextListener(Injector injector) {
this.injector = injector;
}
@Override
public void contextInitialized(ServletContextEvent event) {
BeanConfig beanConfig = getBeanConfig();
event.getServletContext().setAttribute("reader", beanConfig);
event.getServletContext().setAttribute("swagger", beanConfig.getSwagger());
event.getServletContext().setAttribute("scanner", ScannerFactory.getScanner());
}
private BeanConfig getBeanConfig() {
BeanConfig beanConfig = new ResourceConfig();
beanConfig.setHost(getConfigString("host"));
beanConfig.setTitle(getConfigString("title"));
beanConfig.setVersion(getConfigString("version"));
beanConfig.setContact(getConfigString("contact"));
beanConfig.setLicense(getConfigString("license"));
beanConfig.setBasePath(getConfigString("base_path"));
beanConfig.setLicenseUrl(getConfigString("licenseUrl"));
beanConfig.setDescription(getConfigString("description"));
beanConfig.setPrettyPrint(getConfigString("pretty_print"));
beanConfig.setTermsOfServiceUrl(getConfigString("terms_of_service_url"));
// Must be called last
beanConfig.setResourcePackage(resourcePackages());
beanConfig.setScan(true);
return beanConfig;
}
@Nullable
private String getConfigString(String path) {
return config.hasPath(path) ? config.getString(path) : null;
}
/** Returns a comma separated list of resource packages. */
private String resourcePackages() {
return injector.getBindings().keySet().stream()
.map(key -> key.getTypeLiteral().getRawType())
.filter(GetRestful::isRootResource)
.map(clazz -> clazz.getPackage().getName())
.distinct()
.collect(Collectors.joining(","));
}
@Override
public void contextDestroyed(ServletContextEvent event) {}
}
@lpellegr
Copy link

@ben-manes, could you please add an example for the configuration of the web.xml?

@KangoV
Copy link

KangoV commented Apr 7, 2016

Thanks for this. I'm trying to add a swagger module to GWizard :) Lots of learning to do.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment