Jersey 1 ContainerResponseFilter - jax-rs

I have a Jersey 1 ContainerResponseFilter in a shared library, which I register in Jersey 1 web services by specifying the package this filter exists in inside the web.xml eg.
<servlet>
<servlet-name>ServletAdaptor</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>
com.xxx.utils.jersey
</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
<param-value>com.xxx.utils.jersey.CrossDomainFilter</param-value>
</init-param>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>com.xxx.utils.jersey</param-value>
</init-param>
...
</servlet>
I am now trying to use this shared library in a Jersey 2 web service which instead of using the web.xml to configure Jersey uses a class annotated with #ApplicationPath and extending the Jersey ResourceConfig. Inside this class I am not specifying the package of this Jersey 1 filter anywhere.
The problem I am getting is because this Jersey 2 web service doesn't include any Jersey 1 dependencies in the war I am getting a ClassNotFoundException during deployment of the webservice for com.sun.jersey.spi.container.ContainerResponseFilter
Here is an example of how I am creating my config
#ApplicationPath("/")
public class AppConfig extends ResourceConfig
{
private static final String RESOURCE_PACKAGE = "com.xxx.services.rest";
public AppConfig()
{
packages(RESOURCE_PACKAGE);
register(ApiListingResource.class);
register(SwaggerSerializers.class);
BeanConfig beanConfig = new BeanConfig();
beanConfig.setVersion("1.0.0");
beanConfig.setResourcePackage(RESOURCE_PACKAGE);
beanConfig.setSchemes(new String[]{"http"});
beanConfig.setHost("localhost:7001");
beanConfig.setBasePath("/usr/");
beanConfig.setScan(true);
}
}
Is there a way I can make sure this Jersey 1 class is not loaded from the shared library, can I explicitly exclude the package?
EDIT:
A bit more investigation seems to imply it's something to do with CDI, the ContainerResponseFilter is annotated as a #Producer. If I remove the annotation from the class then I no longer receive the exception.
The container I am using is weblogic 12.2.1 which I believe uses Weld as its CDI provider. So I created a beans.xml with the following as indicated by this bit of Weld documentation
<beans xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:weld="http://jboss.org/schema/weld/beans">
<weld:scan>
<weld:exclude name="com.xxx.utils.jersey.**"/>
</weld:scan>
</beans>
But it doesn't seem to solve the issue. Any ideas?

Related

Weblogic 12.1.3 + JAX-RS 2 + jersey multipart

I have a server Weblogic 12.1.3, with JAX-RS 2.x installed as a shared library (see e.g. https://docs.oracle.com/middleware/1213/wls/RESTF/use-jersey20-ri.htm#RESTF297). This shared library includes e.g. javax.ws.rs-api-2.0.jar and jersey-media-multipart-2.5.1.jar.
Please notice I am not sure that my webapp is really using this shared library, or it is using the standard JAX-RS 1.x library.
Now I want to upload files in multipart/form-data format, so I guess I need to add this dependency on my project:
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>2.5.1</version>
<scope>provided</scope>
</dependency>
However, the deploy fails, with error:
java.lang.ClassNotFoundException: org.glassfish.jersey.media.multipart.FormDataContentDisposition
So, I thought I could put my own library within my webapp:
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>2.5.1</version>
</dependency>
In this second case, the deploy fails with the following error:
java.lang.ClassNotFoundException: org.glassfish.jersey.ExtendedConfig
Any idea? Thank you.
At last, I got it work. I was missing both configuration in weblogic.xml and web.xml (I didn't know it was necessary web.xml).
Weblogic.xml:
<wls:weblogic-web-app xmlns:wls="http://xmlns.oracle.com/weblogic/weblogic-web-app" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd http://xmlns.oracle.com/weblogic/weblogic-web-app http://xmlns.oracle.com/weblogic/weblogic-web-app/1.9/weblogic-web-app.xsd">
<!-- Questo è per referenzialre la shared library jax-rs 2.x -->
<wls:library-ref>
<wls:library-name>jax-rs</wls:library-name>
<wls:specification-version>2</wls:specification-version>
<wls:implementation-version>2.5.1</wls:implementation-version>
<wls:exact-match>false</wls:exact-match>
</wls:library-ref>
<wls:container-descriptor>
<wls:prefer-application-packages>
<!-- apis -->
<wls:package-name>javax.ws.rs.*</wls:package-name>
<!-- guava -->
<wls:package-name>com.google.common.*</wls:package-name>
<!-- jersey1 providers -->
<wls:package-name>com.sun.jersey.*</wls:package-name>
<!-- media providers -->
<wls:package-name>org.eclipse.persistence.jaxb.rs.*</wls:package-name>
<wls:package-name>org.codehaus.jackson.jaxrs.*</wls:package-name>
<!-- wls -->
<wls:package-name>weblogic.jaxrs.api.client.*</wls:package-name>
<wls:package-name>weblogic.jaxrs.internal.api.client.*</wls:package-name>
<wls:package-name>weblogic.jaxrs.dispatch.*</wls:package-name>
<wls:package-name>weblogic.jaxrs.monitoring.util.*</wls:package-name>
</wls:prefer-application-packages>
</wls:container-descriptor>
<wls:context-root>uploader</wls:context-root>
</wls:weblogic-web-app>
Web.xml:
<servlet>
<servlet-name>JAX-RS</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer
</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>mypackage.jaxrs.JAXRSApplication
</param-value>
</init-param>
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>org.glassfish.jersey.filter.LoggingFilter;org.glassfish.jersey.media.multipart.MultiPartFeature
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>JAX-RS</servlet-name>
<url-pattern>/v1/*</url-pattern>
</servlet-mapping>
Notice in particular the reference to MultiPartFeature.
Edit
As I thought, the web.xml is not necessary. You can put all the properties inside the Application class. The configuration above is more or less equivalent to the following
#ApplicationPath("/v1")
public class JAXRSApplication extends Application {
#Override
public Map<String, Object> getProperties() {
Map<String, Object> properties = new HashMap<>();
properties.put("jersey.config.server.provider.packages", "mypackage");
properties.put("jersey.config.server.provider.classnames",
"org.glassfish.jersey.filter.LoggingFilter;org.glassfish.jersey.media.multipart.MultiPartFeature");
return properties;
}
}

Interceptor issue with Java EE7

I'm testing / switching to Java EE7 (Glassfish 4) and one of the issues I have is with Interceptors, whenever I try to run the project I am getting the following error.
SEVERE: Exception while loading the app : CDI deployment
failure:WELD-001417 Enabled interceptor class
com.xxxxxx.security.SecuredInterceptor in
file:/home/xxxxxx/xxxxxx/target/xxxxxx/WEB-INF/beans.xml#7 is neither
annotated #Interceptor nor registered through a portable extension
I'm looking at section 1.3.6 of the CDI 1.1 specification it doesn't look like anything has changed, so what am I doing wrong?
Here is the code I am using;
#InterceptorBinding
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.TYPE, ElementType.METHOD})
public #interface Secured {}
#Secured
#Interceptor
public class SecuredInterceptor implements Serializable
{
#AroundInvoke
public Object interceptSecured(InvocationContext ic) throws Exception
{
// Do Stuff
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
bean-discovery-mode="annotated">
<interceptors>
<class>com.xxxxxx.security.SecuredInterceptor</class>
</interceptors>
</beans>
From section 12.1 of the CDI spec.
A bean archive which contains a beans.xml file with no version has a default bean discovery mode of all.
Your version 1.1 beans.xml has bean-discovery-mode="annotated". Change beans.xml to bean-discovery-mode="all" and my guess is it will work just like it does when you remove the version from beans.xml and use the old namespace, as in a CDI 1.0.
Seems to be Glassfish bug related to 1.1 version of beans.xml
https://java.net/jira/browse/GLASSFISH-20667

Primefaces fileupload filter when web.xml not used

I want to use the primefaces fileupload control in my jboss 7 web application. As I don't use any web.xml (not required with Java EE 6), how can I specify the filter required to make the fileupload work properly? Should I create a web.xml for that or can I use annotations instead?
Thank you in advance!
Technically, you should indeed be creating a web.xml file yourself. It's not that hard, just create a file in /WEB-INF/web.xml with the following kickoff template:
<?xml version="1.0" encoding="UTF-8"?>
<web-app
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<!-- Your config here. -->
</web-app>
If you've really a hard head in and have some big aversion against "XML boilerplate", then you could always homebrew a filter class which extends the PrimeFaces file upload filter with the desired #WebFilter annotation.
package com.example;
import javax.servlet.annotation.WebFilter;
import org.primefaces.webapp.filter.FileUploadFilter;
#WebFilter("*.jsf") // Or #WebFilter(servletNames={"Faces Servlet"})
public class AnnotatedPrimeFacesFileUploadFilter extends FileUploadFilter {
// NOOP.
}

JAX-RS custom pathparam validator

I'm currently experimenting with some RESTful JAX and I want to validate a custom input. Normally regex would be fine but I need to do a more extensive check (~10 different regex patterns). I found this page when searching for jaxrs validation. I noted it says "Draft" but I thought I'd give it a try.
I wrote my parameter annotation like this:
#Target(ElementType.PARAMETER)
#Retention(RetentionPolicy.RUNTIME)
#Constraint(validatedBy = FooBarValidator.class)
public #interface FooBarParam
{
}
The validator looks like this:
#Provider
public class FooBarValidator
implements ConstraintValidator<FooBar, Long>
{
#Override
public void initialize(FooBar constraintAnnotation)
{
}
#Override
public boolean isValid(Long value, ConstraintValidatorContext context)
{
// validation goes here, this is a test validation
return (value > 50);
}
}
The web service looks like this:
#javax.ejb.Stateless
#Path("test")
public class testRS
{
#GET
#Path("foobar/{fooBar: [0-9]+}")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.TEXT_PLAIN)
public String testService(#FooBar #PathParam("fooBar") Long fooBar)
{
return "tested with: " + fooBar;
}
}
But if I call my web service with my browser using "http://localhost:8080/jaxtest/rest/test/foobar/11" the web service gets called and I'm presented with "tested with: 11". The web service works fine, except the validator doesn't get called.
I've tried setting breakpoints in the validator class and the annotation interface but none are hit.
I've got a sneaking suspicion that I'm doing something that isn't possible because of the "Draft" header in the referenced documentation. So if I'm doing something wrong or if there are alternatives, I'm glad to hear it.
Thanks to the hint #PiotrKochański gave me I've successfully implemented exactly what I wanted. The biggest problem was that I'm bound to using Glassfish. By default Glassfish uses Jersey to handle JAX stuff.
It took me well over 10 hours of struggling to complete this so let this be a time saver for anyone who stumbles upon this.
First of all, use Maven, this makes your life so much easier.
Second step, add the JBoss repo to your pom.xml
<repositories>
<repository>
<id>jboss-public-repository-group</id>
<name>JBoss Public Maven Repository Group</name>
<url>https://repository.jboss.org/nexus/content/groups/public-jboss/</url>
<layout>default</layout>
<releases>
<enabled>true</enabled>
<updatePolicy>never</updatePolicy>
</releases>
<snapshots>
<enabled>true</enabled>
<updatePolicy>never</updatePolicy>
</snapshots>
</repository>
</repositories>
Third step, add dependencies to pom.xml
<!-- Needed for validator interceptors -->
<dependency>
<groupId>org.jboss.seam.rest</groupId>
<artifactId>seam-rest</artifactId>
<version>3.1.0.Final</version>
</dependency>
<!-- JBoss' RS implementation -->
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<version>2.3.4.Final</version>
</dependency>
<!-- Because I use JSON I need RESTeasy be able to handle this -->
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jettison-provider</artifactId>
<version>2.3.4.Final</version>
</dependency>
<!-- This is THE part that integrates validation in RESTeasy -->
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-hibernatevalidator-provider</artifactId>
<version>2.3.4.Final</version>
</dependency>
The last dependency took me quite a while. The docs #PiotrKochański pointed to didn't mention this. However in another version of the docs I found this:
The integration between the API implementation and RESTEasy is done through the resteasy-hibernatevalidator-provider component. In order to integrate, we need to add resteasy-hibernatevalidator-provider and hibernate-validator to the classpath. With maven it's just a matter of including the following dependency:
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-hibernatevalidator-provider</artifactId>
<version>2.3-RC1</version>
</dependency>
The fourth step was to add this to web.xml
<context-param>
<param-name>resteasy.scan</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>resteasy.servlet.mapping.prefix</param-name>
<param-value>/rest</param-value>
</context-param>
<listener>
<listener-class>org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>
</listener>
<servlet>
<servlet-name>REST Service</servlet-name>
<servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>REST Service</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
The fifth step was to modify the web service class like this:
#javax.ejb.Stateless
#Path("test")
public class testRS
{
#GET
#Path("foobar/{fooBar}")
#Produces(MediaType.APPLICATION_JSON)
#org.jboss.resteasy.spi.validation.ValidateRequest
public String testService(#FooBar #PathParam("fooBar") Long fooBar)
{
return "tested with: " + fooBar;
}
}
The sixth step was to modify the #interface to this:
#Target(ElementType.PARAMETER)
#Retention(RetentionPolicy.RUNTIME)
#Constraint(validatedBy = FooBarValidator.class)
public #interface FooBarParam
{
String message() default "{constraint.FooBar}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
Also as a bonus; I came across a presentation about Bean Validation by Emmanuel Bernard I thought I might share as this explains a lot of interesting stuff.
The page you found is one of the proposal on what should go into JAX-RS 2.0 (which is not final and there is no implementation of that). The plan is for JAX-RS 2.0 to integrate with Bean Validation - but as I said, that's not implemented yet.
Currently, if you want to validate input, you can declare the parameter as String (instead of Long) and do the validation as part of the resource method. Then convert to Long if the validation passes.

p:fileupload doesnt work on Websphere 8

I wonder if anyone managed to get Primefaces' p:fileupload component work on Websphere Application Server 8.
I use Primefaces 2.2.1 version.
JSF code:
<h:form enctype="multipart/form-data">
<p:fileUpload
fileUploadListener="#{mailBean.handleFileUpload}"
multiple="true"
label="choose"
allowTypes="*.jpg;*.png;*.gif;"
description="Images"/>
</h:form>
Managed Bean code:
public void handleFileUpload(FileUploadEvent event)
{
files.add(event.getFile());
logger.info("File uploaded into MailBean: " + event.getFile());
System.out.println("File uploaded into MailBean: " + event.getFile());
}
Web.xml filter: (Servlet 3.0)
<filter>
<filter-name>PrimeFaces FileUpload Filter</filter-name>
<filter-class>org.primefaces.webapp.filter.FileUploadFilter</filter-class>
<init-param>
<param-name>thresholdSize</param-name>
<param-value>51200</param-value>
</init-param>
<init-param>
<param-name>uploadDirectory</param-name>
<param-value>c:/temp/pf</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>PrimeFaces FileUpload Filter</filter-name>
<servlet-name>Faces Servlet</servlet-name>
</filter-mapping>
The component says HTTP error and turns into red, on the console I get a ViewExpiredException by Myfaces:
Caused by: javax.faces.application.ViewExpiredException: /createmail.xhtml
No saved view state could be found for the view identifier: /createmail.xhtml
at org.apache.myfaces.lifecycle.RestoreViewExecutor.execute(RestoreViewExecutor.java:128)
at org.apache.myfaces.lifecycle.LifecycleImpl.executePhase(LifecycleImpl.java:171)
at org.apache.myfaces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:189)
I even tried with two other versions of Mojarra instead of Myfaces, but I got errors (2.1: handler doesnt get invoked, 2.0.3: viewexpired)
Did u have the .jars and the web.xml config (remove "c:", the default is that route) ? I had the same problem but then i restarted my WAS 8.5 and it worked.
I'm using Websphere 7 with JSF 2.0 with Mojarra 2 and PrimeFaces 3.4.2 (common-fileupload-1.2.2.jar and common-io-1.3.2.jar)
I see the fileUpload don't call the bean in WebSphere.
I see the bar that load the file but don't arrive the event on the managedBean.
It seems as if some other filter in Websphere capture the HTTP request and you can't get data sent by fileUpload because are just consumed :(