Disable default Swagger jaxrs2 openapi url - java

we are documenting our JAX-RS API with swagger. By using the swagger-jaxrs2 package, we can create an build our api documentation very well.
The only thing we want to change: the default "openapi"-Url.
By registering Swaggers OpenApiResource Class, our application produces everytime the default "[host]/openapi" Endpoint.
We are able to create our own endpoint which serves the openapi-spec, but we cannot disable this default endpoint.
Every hint is welcome! Tank you in advance.

We solved with a workaround: Modifing javax.ws.rs.core.Application to load just the Endpoints which we provide by our own, ignoring any other 3rdParty endpoint like the swagger-jaxrs2 openapi or openapi.{type:json|yaml}
#ApplicationPath("")
public class OurApplication extends javax.ws.rs.core.Application {
#Override
public Set<Class<?>> getClasses() {
// Start detecting only classes in your package! provided 3rdParty packages
// (like io.swagger.v3.jaxrs2.integration.resources) won't be provided
Reflections ourClasses = new Reflections("our.package.naming");
// Scan your classed for #javax.ws.rs.Path Annotaion. We need just collect
// API-Endpoints
Set<Class<?>> ourEndpoints = ourClasses.getTypesAnnotatedWith(Path.class);
// fyi - log the registered classes / endpoints
System.out.println("Providing "+ ourEndpoints);
// return endpoints to provide it in your application
return ourEndpoints;
}
}
HINT: Due to #ApplicationPath annotation there is no need to modify web.xml.
The Reflections we used are provided by maven:
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.9.12</version>
</dependency>
Watch https://github.com/ronmamo/reflections for more information about the reflections package.
We didn't find a better solution but this is what worked for us. Enjoy it.

Related

How to disable CompositeDiscoveryClient and SimpleDiscoveryClient in service discovery library

We've written an in-house service discovery (SD) client based on the spring-cloud-commons SPI, meaning it provides implementations for interfaces ServiceRegistry and DiscoveryClient and some other Spring-provided abstractions.
Apps that use our library merely add it to their pom file, and it autowires the DiscoveryClient with its own implementation, InHouseDiscoveryClient
<dependency>
<groupId>blah.blah<groupId>
<artifactId>inhouse-service-discovery-client<artifactId>
<dependency>
However, rather than referring to InHouseDiscoveryClient in code, it's best practices to use the interface DiscoveryClient as shown below
# Good
#Autowired
DiscoveryClient client;
# Bad (binds app to a particular SD implementation)
#Autowired
InHouseDiscoveryClient client;
As such, we are required to add spring-cloud-commons to the project.
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-commons</artifactId>
</dependency>
This is where the issue starts. The commons library actually autowires two additional implementations of DiscoveryClient - the SimpleDiscoveryClient and the CompositeDiscoveryClient.
This makes for an odd user experience for our clients. Instead of simply having InHouseDiscoveryClient, users find themselves with these additional beans.
Is it possible to prevent spring-cloud-commons's DiscoveryClient implementations from autowiring? And if so, can this be done in our library rather than in the end-user's applications?
I ended up extended AutoConfigurationImportFilter in my library to remove the autowired beans from cloud-commons. I also removed it's health indicator, but we had a very particular reason to do so - most probably would rather keep it.
my.package
public class StratusDiscoveryExclusionFilter implements AutoConfigurationImportFilter {
private static final Set<String> SHOULD_SKIP = new HashSet<>(
Arrays.asList(
// DiscoveryClient Beans
"org.springframework.cloud.client.discovery.composite.CompositeDiscoveryClientAutoConfiguration",
"org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClientAutoConfiguration",
// Health indicators
"org.springframework.cloud.client.CommonsClientAutoConfiguration")
);
/**
* For each class name, provide an assocated boolean array indicated whether or not to include
*/
#Override
public boolean[] match(String[] classNames, AutoConfigurationMetadata metadata) {
boolean[] matches = new boolean[classNames.length];
for (int i = 0; i < classNames.length; i++) {
matches[i] = !SHOULD_SKIP.contains(classNames[i]);
}
return matches;
}
}
I think add a reference to this in my library's spring.factories file
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=my.package.MyExclusionFilter

Implementing generic JAX-RS web service using javax.ws.rs.core.Application

Servlet 3.0-enabled containers allows us to skip the web.xml servlet configuration and automatically scan your code for resources and providers once you extend javax.ws.rs.core.Application, annotate it with #ApplicationPath and do not override the getClasses() method. (hope I got all of that right :\)
At the moment I am using the Jersey implementation and securing resource methods using #RolesAllowed annotations. For this I need to register the org.glassfish.jersey.server.filter.RolesAllowedDynamicFeature Provider class, however, the only ways I'm aware of to do this is either to:
Register the class in the getClasses() method of my Application class (which, I think, will cause the Servlet 3.0 container NOT to auto-scan)
Continue to use the web.xml Jersey servlet setup with
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>org.glassfish.jersey.server.filter.RolesAllowedDynamicFeature</param-value>
</init-param>
Now the context behind this question is that I might have to switch to using RESTeasy and if I use option 1 it adds a Jersey dependency in the code and the code is no longer generic.
How do I write my code to use security annotations while maintaining generic JAX-RS code that could be deployed to another Servlet 3.0 JAX-RS implementation?
One option is to use a javax.ws.rs.core.Feature (a JAX-RS standard class). You can register any components there, and then annotate the class with #Provider, and it will be picked up like any other #Provider or #Path annotated class
#Provider
public class MyFeature implements Feature {
#Overrride
public boolean configure(FeatureContext context) {
context.register(RolesAllowedDynamicFeature.class);
}
}
Do note that since you are using the Jersey feature, your app is no longer implementation independent, so you might as well use Jersey all the way. For one, Jersey does not recommend scanning the class-path, which is the affect of doing what you are doing. Instead Jersey has a mechanism that allows you to recursively scan a package (and its sub-packages). So you could instead do
#ApplicationPath("..")
public class AppConfig extends ResourceConfig {
public AppConfig() {
packages("the.packages.to.scan");
register(RolesAllowedDynamicFeature.class);
}
}
Note that ResourceConfig is a sub-class of Application
See Also:
When to Use JAX-RS Class-path Scanning Mechanism
Sevlet Based Deployment - Servlet 3.x Container
Note:
If you wanted to stick to the classpath scanning mechanism, and wanted to keep the project independent of any Jersey dependencies, you could also override Map<String, Object> getProperties() in the Application class. In the returned Map, you could add the property that you would otherwis have added in the web.xml
#Override
public Map<String, Object> getProperties() {
Map<String, Object> props = new HashMap<>();
props.put("jersey.config.server.provider.classnames",
"org.glassfish.jersey.server.filter.RolesAllowedDynamicFeature");
return props;
}
But even though the source code is implementation independent, the application is still dependent on the Jersey roles feature. If you decided you wanted to port, you would still need a replacement for the feature.
If you wanted to stay completely independent, you could implement the feature yourself. It's not all that complicated. You can check out the source code for RolesAllowedDynamicFeature. If you decide to try and implement the same, just annotate your implementation class with #Provider, and it should get picked up.

Swagger Spring API

I am using Spring Swagger library v1.0.2
Maven:
<dependency>
<groupId>com.mangofactory</groupId>
<artifactId>swagger-springmvc</artifactId>
<version>1.0.2</version>
</dependency>
I am able to scan my REST APIs and view it on the Swagger UI. I have even implemented OAuth and it is working great.
However, there is one feature that I need to implement. I want to hide some of the REST APIs. I need to do this at the class level as well as on the method level. I read about an 'hidden' attribute in the #Api annotation. I set it to 'true' but I can still see my class and all its method being displayed in the Swagger UI.
Example:
#Api(
description="This class is not covered by Spring security.",
value="/unauthorize",
hidden=true)
#RequestMapping("/unauthorize")
#Controller
public class UnauthorizeResource {}
Can someone please tell me how I can prevent the 'UnauthorizeResource' class from being displayed?
You can utilize the #ApiIgnore annotation:
#ApiIgnore
#RequestMapping("/unauthorize")
#Controller
public class UnauthorizeResource {}

reflections library inside Wildfly 8.0.2

I am trying to scan classes with Reflections library, if I add the Dynamic Web project to another project (plain Java one), I get the classes I want, but if run inside a #Startup bean, it is empty.
Here is the code:
Reflections reflections = new Reflections(
new ConfigurationBuilder().filterInputsBy(
new FilterBuilder.Include(
FilterBuilder.prefix("my.package")
)
).setUrls(
ClasspathHelper.forJavaClassPath()
).setScanners(
new SubTypesScanner(false)
)
);
Set<Class<? extends Object>> testClasses = reflections.getSubTypesOf(Object.class);
The tv,goopi should be changed to whatever package prefix used.
the testClasses Set is empty.
If the same code is running in a different project referencing this one, no other change, then the Set is populated with all classes inside the package.
The Maven dependency for Reflections is:
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.9.9-RC1</version>
</dependency>
Wildfly 8.2.0.
For now, I can save the file extracted in the external project and use the load function, but this will not be dynamic as it should be.
I struggled with this one for quite a while, it looks like due to the way it works, without getting the full java class path (makes it very heavy) you should load reflect a little bit later. This is mostly due to dynamic class creation during the EJB initialization phase, Startup beans included.
To load the full class path (from a startup bean)
urls.addAll(ClasspathHelper.forJavaClassPath());
To make it cross JEE friendly,
e.g. wild-fly, you need to reflect from a Servlet Context listener. For me the right place was in the constructor but a static field may work.
public class GuiceContext implements ServletContextListener
{
#Override
public void contextInitialized(ServletContextEvent servletContextEvent)
{
ClasspathHelper.forWebInfLib(servletContextEvent.getServletContext());
ClasspathHelper.forWebInfClasses(servletContextEvent.getServletContext());
}
Try and get your beans to initialize stand-alone without dependencies. You can also use a custom injector like Guice to push your beans. In this case you would use the GuiceServletContextListener class.
You are excluding direct exclusions of Object.class, this startup bean in this instance may not be loading due to this.
new SubTypesScanner(false);
A complete library with org.reflections and guice directly implemented can be found at https://github.com/GedMarc/GuiceInjection

How does ServiceLocator find #Service and #Contact automatically in HK2?

According to HK2 #Service javadoc
Annotation placed on classes that are to be automatically added to an
hk2 ServiceLocator.
I don't know how to make ServiceLocator find annotated classes automatically.
TestService
#Contract
public interface TestService {
}
TestServiceImpl
#Service
public class TestServiceImpl implements TestService {
}
Main
public static void main(String[] args) {
ServiceLocator locator = ServiceLocatorUtilities.createAndPopulateServiceLocator();
TestService service = locator.getService(TestServiceImpl.class);
System.out.println(service); // null
}
The result is always null. I have to add Descriptor so the ServiceLocator can find it.
public static void main(String[] args) {
ServiceLocator locator = ServiceLocatorUtilities.createAndPopulateServiceLocator();
DynamicConfigurationService dcs = locator.getService(DynamicConfigurationService.class);
DynamicConfiguration config = dcs.createDynamicConfiguration();
config.bind(BuilderHelper.link(TestServiceImpl.class).to(TestService.class).in(Singleton.class).build());
config.commit();
TestService service = locator.getService(TestServiceImpl.class);
System.out.println(service); // TestServiceImpl instance
}
How do I let ServiceLocator find the annotated classes automatically ? Did I misunderstand something ?
You need to run the hk2-inhabitant-generator over your built classes in order to get automatic detection of services. There is more information here as well.
What that step does in the build process is to create a file named META-INF/hk2-locator/default with information about services. The createAndPopulateServiceLocator call then reads those files and automatically adds those service descriptors into the returned ServiceLocator.
FYI, I was so frustrated with the reliance on the inhabitant files rather than having the capability for runtime scanning of annotated classes, I wrote this project:
https://github.com/VA-CTT/HK2Utilities
Since Eclipse / Maven / inhabitant runtime generators wouldn't play nice, it was nearly impossible to debug code that made use of HK2 in eclipse without runtime scanning.
The HK2Utilities package is available in central:
<dependency>
<groupId>gov.va.oia</groupId>
<artifactId>HK2Utilities</artifactId>
<version>1.4.1</version>
</dependency>
To use it, you just call:
ServiceLocator locator = HK2RuntimeInitializer.init("myName", false, new String[]{"my.package.one", "my.package.two"});
This will scan the runtime classpath for classes in the packages listed, and automatically populate the service locator with them.
You don't ever have to generate inhabitant files with this model - and in practice, I found it to be faster performing than the inhabitant processing code as well (not that the performance matters much for this one-time operation)
---edit---
I still maintain this code - the current release is:
<dependency>
<groupId>net.sagebits</groupId>
<artifactId>HK2Utilities</artifactId>
<version>1.5.2</version>
</dependency>
And the project location is now:
https://github.com/darmbrust/HK2Utilities
Well now (2.6.1) all you need to do is add the dependencies - javax.inject, hk2-utils, hk2-api and hk2-metadata-generator.
When you build the project, javac compiler will generate a 'default' file in META-INF containing the wiring as follows:
[service-class-name]S
contract={contract-class-name}
This will be registered by the ServiceLocator during the run.
This should be sufficient. However if that does not work, there are other options,
mvn plugin
org.glassfish.hk2
hk2-inhabitant-generator
2.5.0-b36
generate-inhabitants
cmd line tool
java org.jvnet.hk2.generator.HabitatGenerator
[--file jarFileOrDirectory]
[--outjar jarFile]
[--locator locatorName]
[--verbose]
More on this https://javaee.github.io/hk2/inhabitant-generator.html

Categories