I'm trying to use Swagger to document my Rest API. I want to make use of #BeanParam annotation, however Swagger interprets the bean model as a single body. I've changed my swagger dependency to swagger-jersey2-jaxrs_2.10 but that made Wildfly unable to start cause of WELD-001408 error (as in first link below). I have read a lot of stuff, but nothing seems to solve my problem:
https://developer.jboss.org/thread/240847
https://github.com/swagger-api/swagger-core/issues/446
https://groups.google.com/forum/#!msg/swagger-swaggersocket/K5TFkxIcRQs/A34nupqPTTcJ
I've tried by changing dependencies in my pom.xml according to linked threads, now it looks like this:
<dependency>
<groupId>com.wordnik</groupId>
<artifactId>swagger-annotations</artifactId>
<version>1.3.12</version>
</dependency>
<dependency>
<groupId>com.wordnik</groupId>
<artifactId>swagger-core_2.10</artifactId>
<version>1.3.12</version>
</dependency>
<dependency>
<groupId>com.wordnik</groupId>
<artifactId>swagger-jersey2-jaxrs_2.10</artifactId>
<version>1.3.12</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers.glassfish</groupId>
<artifactId>jersey-gf-cdi</artifactId>
<version>2.14</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>2.14</version>
</dependency>
Moreover, I have a custom servlet for Swagger:
public class SwaggerServlet extends HttpServlet {
private static final long serialVersionUID = 4104485315753399385L;
#Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
BeanConfig beanConfig = new BeanConfig();
beanConfig.setVersion("1.0.2");
beanConfig.setBasePath("/CityAlertsWeb/service");
beanConfig.setResourcePackage("pl.cityalerts.web.controllers");
beanConfig.setScan(true);
ClassReaders.setReader(new JerseyApiReader());
}
}
Is there any way to make #BeanParam work in Swagger with Resteasy?
Should I add any other dependency?
With such a config I'm getting:
...
Caused by: java.lang.RuntimeException: Unable to instantiate ContextResolver
at org.jboss.resteasy.spi.ResteasyProviderFactory.registerProvider(ResteasyProviderFactory.java:1607)
at org.jboss.resteasy.spi.ResteasyProviderFactory.registerProvider(ResteasyProviderFactory.java:1310)
at org.jboss.resteasy.spi.ResteasyProviderFactory.registerProvider(ResteasyProviderFactory.java:1232)
at org.jboss.resteasy.spi.ResteasyDeployment.registerProvider(ResteasyDeployment.java:531)
at org.jboss.resteasy.spi.ResteasyDeployment.registration(ResteasyDeployment.java:338)
at org.jboss.resteasy.spi.ResteasyDeployment.start(ResteasyDeployment.java:241)
at org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap.contextInitialized(ResteasyBootstrap.java:28)
at io.undertow.servlet.core.ApplicationListeners.contextInitialized(ApplicationListeners.java:173)
at io.undertow.servlet.core.DeploymentManagerImpl.deploy(DeploymentManagerImpl.java:187)
... 7 more
Caused by: java.lang.IllegalArgumentException: Unable to find a public constructor for provider class org.glassfish.jersey.media.multipart.MultiPartProperties$Feature$MultiPartContextResolver
at org.jboss.resteasy.spi.ResteasyProviderFactory.createConstructorInjector(ResteasyProviderFactory.java:2184)
at org.jboss.resteasy.spi.ResteasyProviderFactory.createProviderInstance(ResteasyProviderFactory.java:2173)
at org.jboss.resteasy.spi.ResteasyProviderFactory.addContextResolver(ResteasyProviderFactory.java:1072)
at org.jboss.resteasy.spi.ResteasyProviderFactory.registerProvider(ResteasyProviderFactory.java:1601)
... 15 more
Thanks
Even though RESTEasy 3.X has been officially released about a year and a half ago, it is still fairly uncommon, at least in our experience.
Swagger-core comes in several flavors, as a Play module, Servlet, and JAX-RS. When it comes to JAX-RS, there's a basic JAX-RS implementation for JAX-RS 1.X and then there are specific implementations for Jersey 1.X and Jersey 2.X.
The Jersey 1.X and 2.X implementations include support for file uploads in those libraries as, unfortunately, file uploads are not part of the JAX-RS specification and end up being implementation-specific.
However, another difference in the Jersey 2.X specific implementation is the support for JAX-RS 2.0, which includes the #BeanParam support. At the moment, there is no general-purpose JAX-RS 2.0 module.
From the original link, it seems there's a conflict between JBoss/WildFly and loading the Jersey dependencies, which the Jersey 2.X flavor pulls in. Based on the interactions in the comments, the solution is to exclude (<exclusion>) the org.glassfish.jersey.media:jersey-media-multipart dependency (which is indeed the one for file upload support) and adding it again manually in the main pom.xml. While not an elegant solution, it works as a workaround.
I would also suggest opening an issue about it in the swagger-core repository. I imagine JAX-RS 2.0 adoption will grow over time and we should give it proper support.
Related
In order to use Java API for JSON Binding (JSON-B), I have found it necessary to include the following three dependencies in my Maven POM:
<!-- https://mvnrepository.com/artifact/jakarta.json.bind/jakarta.json.bind-api -->
<dependency>
<groupId>jakarta.json.bind</groupId>
<artifactId>jakarta.json.bind-api</artifactId>
<version>1.0.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.eclipse/yasson -->
<dependency>
<groupId>org.eclipse</groupId>
<artifactId>yasson</artifactId>
<version>1.0.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.glassfish/javax.json -->
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
<version>1.1.4</version>
</dependency>
The first two make sense to me.
jakarta.json.bind-api is the JSON-B API defined by JSR 367.
yasson is the reference implementation of that API, Eclipse Yasson.
➥ But what exactly does the third dependency, javax.json from Glassfish, bring to the party? Why is it required for my app to work?
If omitted, when running Jsonb jsonb = JsonbBuilder.create();, I get this error:
javax.json.JsonException: Provider org.glassfish.json.JsonProviderImpl not found
I am confused because I thought Yasson is my JSON processing implementation.
Actually, your code should only depend on the api jakarta.json.bind-api, so you don't accidentally use implementation details from yasson, e.g. the internal org.eclipse.yasson.internal.ReflectionUtils. To do this, you should add <scope>runtime</scope> to your yasson dependency. Only to run it, you need an implementation, and you picked the reference implementation yasson.
But JSON-B is just a layer on top of JSON-P: it does the binding part, while it delegates all the raw JSON processing to JSON-P. You can mix and match any JSON-B implementation with any JSON-P implementation.
As yasson has to be able to work with any JSON-P implementation, it can't have a hard dependency on, e.g., Glassfish JSON-P; you have to specify it yourself (also with a runtime scope). The error message you see mentions Glassfish, as that's the fallback implementation JSON-P is looking for.
Recently I tried to deploy a Jersey2 application to Glassfish4.1. I had lots of dependency issues and found a lot of ClassCastException.
Later I found the user guide here: https://jersey.java.net/documentation/latest/modules-and-dependencies.html#servlet-app-glassfish
I have to configure pom.xml like:
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>2.23.1</version>
<scope>provided</scope>
</dependency>
If you are using Glassfish application server, you don't need to package anything with your application, everything is already included. You just need to declare (provided) dependency on JAX-RS API to be able to compile your application.
My question is that why Glassfish have to provide jersey2 (JSR implementation) itself for application. Why not just let application to choose the JSR implementation it is using?
I also add glassfish-web.xml under WEB-INF:
<glassfish-web-app>
<class-loader delegate="false" />
</glassfish-web-app>
According to the document here (https://docs.oracle.com/cd/E19798-01/821-1752/beagb/index.html):
It will let Glassfish to load classes under WEB-INF/lib/ first. But why does Glassfish still use its own jersey version and javax version?
For javax, I guess Glassfish is a java application version and it only support specific JSR implementations. So when I choose JSR implementation in my application, and I have to find out the correct version of Glassfish.
But why is jersey2 so special that glassfish have to provide it. What if I want to use another version of jersey2?
Updated:
I ran some more tests.
When I deployed a jersey1 application (jersey1 is included in war file) to glassfish4 and asked glassfish4 to delegate class loader process to its parent, and this application works, and application can handle incoming rest requests. Why? I guess since glassfish does not have jersey1 included, it will load jersey1 from libraries inside war file, and glassfish4 is actually working with jersey1. Does this mean I can override glassfish default behavior to let application to choose the JAX-RS implementation.
And if I replaced jersey1 with jersey2 and still let glassfish4 to load libraries from war first, there was an exception thrown:
WebModule[/invoiceLoader]StandardWrapper.Throwable
java.lang.ClassCastException: Cannot cast org.glassfish.jersey.gf.cdi.internal.CdiComponentProvider to org.glassfish.jersey.server.spi.ComponentProvider
at java.lang.Class.cast(Class.java:3369)
at org.glassfish.jersey.internal.ServiceFinder$LazyObjectIterator.hasNext(ServiceFinder.java:713)
at org.glassfish.jersey.server.ApplicationHandler.getRankedComponentProviders(ApplicationHandler.java:743)
at org.glassfish.jersey.server.ApplicationHandler.access$600(ApplicationHandler.java:184)
at org.glassfish.jersey.server.ApplicationHandler$4.get(ApplicationHandler.java:406)
at org.glassfish.jersey.server.ApplicationHandler$4.get(ApplicationHandler.java:399)
at org.glassfish.jersey.internal.util.collection.Values$LazyValueImpl.get(Values.java:340)
at org.glassfish.jersey.server.ApplicationHandler.createApplication(ApplicationHandler.java:366)
at org.glassfish.jersey.server.ApplicationHandler.<init>(ApplicationHandler.java:342)
at org.glassfish.jersey.servlet.WebComponent.<init>(WebComponent.java:392)
at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:177)
How did this exception happen?
My question is that why Glassfish have to provide jersey2 (JSR implementation) itself for application. Why not just let application to choose the JSR implementation it is using?
Because Glassfish is a Java EE compliant server, and JAX-RS is part of the EE spec. So it needs an implementation of JAX-RS to run a JAX-RS application. It just happens to use Jersey as the implementation , just like JBoss uses RESTEasy. If the server didn't have an implementation, then it wouldn't be EE compliant. An application should be able to run a complete EE application only compiling the application against the single EE jar. It shouldn't have to know anything about implementations.
What if I want to use another version of jersey2?
You can just try to replace all the Jersey implementation jars with new ones. See Updating Jersey 2 in GlassFish 4.
We are in the OSGi world.
JPA 2.1 supports injectable EntityListner.
And EclipseLink supports JPA 2.1.
But the OSGi Enterprise Spec 4.x only supports JPA 2.0.
So it seems that injectable EntityListener doesn't work in OSGi, even when EclipseLink supports them.
Is it currently possible to define EntityListener in blueprint.xml and use them for injection? This would allow to inject OSGi Services into an Entity Listener. (Currently we need an explicit lookup using FrameworkUtil to do the lookup.)
Has anybody done so successfully and can share some hints, especially in regard to the used bundle (versions)?
Have you tried using the following maven dependency with org.eclipse.persistence.jpa.PersistenceProvider in the provider-Element of the persistence.xml? In the case of a JEE application server, the classloader would prefer libraries packaged with the deployed application by the ones bundled with the server itself.
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>eclipselink</artifactId>
<version>2.5.1</version>
<scope>provided</scope>
</dependency>
the Apache CXF project offers a proxy based client implementation for REST services. This looks like:
Resource resource = JAXRSClientFactory.create( baseAddress, Resource.class )
Does anyone know a similar implementation for Jersey?
I spotted an approach using #HyperMediaController annotations, but I want to stick to JSR-311 default annotations like #Path and #Get ...
Has anyone an idea?
A proxy implementation exists, but unfortunately it's not even mentioned in Jersey Client API documentation (neither in Jersey User Guide) as of version 2.22.1.
What I found was JavaDoc for WebResourceFactory, even better is the package JavaDoc. Here's a snippet from the JavaDoc on the usage of the WebResourceFactory:
Client client = ClientBuilder.newClient();
WebTarget target = client.target("http://localhost:8080/");
MyResourceIfc resource = WebResourceFactory.newResource(MyResourceIfc.class, target);
In Maven you then need:
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-proxy-client</artifactId>
<version>2.22.1</version>
</dependency>
in addition to
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>2.22.1</version>
</dependency>
I found WebResourceFactory miss generic types supports and it's source code was really hard to understand. So we created https://github.com/adaptris/jaxrs-client-proxy and we are currently devloping it.
To use it you need to build a resource:
ResourceBuilder builder = new ResourceBuilder();
resource = builder.
url("https://host/api").
build(Resource.class);
client = resource.get();
Then you can call client - which is proxy of your jax-rs annotation described interface (Resource.class). You should close a resource after stoping using it as it is recommended by jax-rs client api.
resource.close()
More details on github projet page.
I created an own implementation. See utils-apl-derived wiki page therefore.
I want to consume a REST service in my web app (.war with 6.0.0.Final), but have problems adding jersey-client libs:
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>1.9.1</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
With this configuration I get the following error during JBoss startup:
08:11:28,297 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].
[localhost].[/test]] Exception starting filter Resteasy:
java.lang.ClassCastException: com.aht.erp.web.rest.JaxRsActivator
cannot be cast to javax.ws.rs.core.Application
My webapp has an activated JAX-RS with the following annotation:
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
#ApplicationPath("/rest")
public class JaxRsActivator extends Application {}
If I don't add the dependecy my war starts fine, but of course I get a NoClassDefFoundError: com/sun/jersey/api/client/config/ClientConfig when the jersey-client is called. By excluding jersey-core I get this error: NoClassDefFoundError: com/sun/jersey/core/util/FeaturesAndProperties.
I believe the problem is that you are trying to mix two different jax-rs implementations in your web app. For your RESTful resource you are using RESTEasy, while on the client side you want to use Jersey - all utilized by the same jar. However the Jersey client depends on Jersey core, which conflicts with RESTEasy. So, you'll either have to rely on RESTEasy client API, or switch to Jersey for your server-side as well.