1

Am new to JavaEE and have some issues getting custom ContainerRequestFilter to run in Jersey. I read the jersey documentation some more and created a new clean project straight from the 'jersey-quickstart-webapp', added the filter seen below but no luck (added an empty beans.xml as well).

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.PreMatching;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.Provider;
import java.io.IOException;

@Provider
@PreMatching
public class MyFilter implements ContainerRequestFilter {
    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {
        requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).entity("User cannot access the resource.").build());
    }
}

Was uncertain if Prematching and Provider was complementary or not so i used both then each separately, but didnt work (MyReasource just served as without filter). Tried throwing an exception in MyFilter but that didnt run either.

So i searched through StackOverflow and found 'http://blog.dejavu.sk/2013/11/19/registering-resources-and-providers-in-jersey-2/' which points to that you actually needs to implement registrations in Application or ResourceConfig class. I tried this (didnt work) but i atleast got a warning for the resource class now, 'No resource methods have been found for resource class a.b.MyFilter'

My Application class now looks like below (tried scan package but didnt make a difference. Without the manual filter registration i didnt get the warning either).

import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.ServerProperties;
import javax.ws.rs.ApplicationPath;

@ApplicationPath("resources")
public class RestApplication extends ResourceConfig {
    public RestApplication() {
        //packages("a.b");
        register(MyFilter.class);
        register(MyResource.class);
        property(ServerProperties.TRACING, "ALL");
    }
}

Web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
         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_2_5.xsd">
</web-app>

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>a.b</groupId>
    <artifactId>server</artifactId>
    <packaging>war</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>server</name>
    <build>
        <finalName>server</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.5.1</version>
                <inherited>true</inherited>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.glassfish.jersey</groupId>
                <artifactId>jersey-bom</artifactId>
                <version>${jersey.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.glassfish.jersey.containers</groupId>
            <artifactId>jersey-container-servlet-core</artifactId>
            <!-- use the following artifactId if you don't need servlet 2.x compatibility -->
            <!-- artifactId>jersey-container-servlet</artifactId -->
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.media</groupId>
            <artifactId>jersey-media-moxy</artifactId>
        </dependency>
    </dependencies>
    <properties>
        <jersey.version>2.22.1</jersey.version>
        <failOnMissingWebXml>false</failOnMissingWebXml>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
</project>

All files lies in the 'a.b' (i.e my package) root. Any ideas on how to get the filter actually running and i would be very greatful ;). I presume it shouldnt be this hard to get this working so i guess im missing something here?

Base
  • 1,061
  • 1
  • 11
  • 27

1 Answers1

2

Let me walk you through what's going on. When you first created the jersey-quickstart-webapp archetype, it gave you this

<servlet>
    <servlet-name>Jersey Web Application</servlet-name>
    <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
    <init-param>
        <param-name>jersey.config.server.provider.packages</param-name>
        <param-value>a.b</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

What this init-param jersey.config.server.provider.packages does is tell Jersey what package(s) to scan for resource classes annotated with @Path, and provider classes annotated with @Provider.

So from that point, all you needed to do was add the @Provider to the filter, and it would have worked.

But then you decided to clear out the web.xml and use the ResourceConfig with the @ApplicationPath. For this to work Jersey takes advantage of the Servlet 3.0 pluggability mechanism, as mentioned in this answer. For that to work we need to make sure we have the jar that has the JerseyServletContainerInitializer. That's where we need to look at the pom.xml file

<dependency>
    <groupId>org.glassfish.jersey.containers</groupId>
    <artifactId>jersey-container-servlet-core</artifactId>
    <!-- use the following artifactId if you don't need servlet 2.x compatibility -->
    <!-- artifactId>jersey-container-servlet</artifactId -->
</dependency>

The comment is telling you that if you don't need Servlet 2.5 support, you should use jersey-container-servlet instead of jersey-container-servlet-core. I don't know, it might be poorly worded. Maybe instead it should say if you want Servlet 3.x support, change it. But in any case, the jersey-container-servlet has the JerseyContainerServletInitializer that we need. So if you want to go web.xml-less, then just switch out the dependency.

Community
  • 1
  • 1
Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
  • Thanks, this cleared things up a LOT for me. I understood that xml setup was legacy so thats why i used Application. I, however, had no idea regarding the dependency, i presumed it was just added backwards compability. So as it was set as default i didnt think of changing it. I did however notice that while it now works perfectly on glassfish (Servlet 3.0 pluggability mechanism) it just generates Error 500 om TomEE+ however. I guess this could be a dependency issue (root cause NoSuchMethodError: javax.ws.rs.core.Application.getProperties()Ljava/util/Map). Anyway thanks a lot! – Base Oct 23 '15 at 11:57
  • 1
    TomEE still uses JAX-RS 1.1. Jersey 2.x uses JAX-RS 2. The two are incompatible. When try and run the Jersey 2 app the older JAX-RS classes get loaded and Jersey tries to call a method that JAX-RS 1.1 doesn't have. Even with Glassfish you may run into problems down the line as it already has a version of Jersey. But it is very old. So best thing to do is put your Jersey dependencies in a `provided` ``. That was the jars don't get built into the final app. Glassfish jars are used. It's possible though to upgrade Jersey in Glassfish if you wanted to – Paul Samsotha Oct 23 '15 at 12:11