JAX-RS: How to extend Application class to scan packages?

13,159

Solution 1

"Is there a specific Java equivalent?"

Simply leave the class empty, meaning do not override getClasses() or getSingletons(). Per the spec - 2.3.2:

[...]

In either of the latter two cases, if both Application.getClasses and Application.getSingletons return an empty list then all root resource classes and providers packaged in the web application MUST be included in the published JAX-RS application. If either getClasses or getSingletons return a non-empty list then only those classes or singletons returned MUST be included in the published JAX-RS application.

So you can simply do

@ApplicationPath("oauth")
public class OAuthApplication extends Application {}

and your classpath will get scanned for @Path and @Provider classes. Override either method (returning a non-empty set), and only those classes will be added.

It should also be noted that public Map<String, Object> getProperties() can be safely overridden. You can use this to add arbitrary properties (even to register classes/features), as seen here, or if you need to configure a provider, you can do so in a Feature or DynamicFeature as seen here

Solution 2

It is very simple:

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("/webapi")
public class MyApp extends Application {

}

This will scan all the classes annotated with @Provider and @Path.

Solution 3

Is a combination of all Application class, ResourceClass and @ApplicationPath

in agreement with the docs and the class ResourceConfig implements by jersey the way to do is:

@ApplicationPath(value = "/resource")
public class ApplicationREST extends ResourceConfig {

    public ApplicationREST() {
        //add single resources
        register(SimpleResource1.class);
        register(SimpleResource2.class);
        ...

        //enable multipar feature
        register(MultiPartFeature.class);
        ...            

        //enable scan package and recursive
        packages(true, "com.example.rest");
    }
}

I hope this helps you

Share:
13,159
daydreamer
Author by

daydreamer

Hello Viewer, Some of the places to see my work are BonsaiiLabs My Website

Updated on June 05, 2022

Comments

  • daydreamer
    daydreamer almost 2 years

    Currently, I do something similar to

    import javax.annotation.Nonnull;
    import javax.ws.rs.ApplicationPath;
    import javax.ws.rs.core.Application;
    import java.util.Collections;
    import java.util.HashSet;
    import java.util.Set;
    
    @ApplicationPath("oauth")
    public class OAuthApplication extends Application {
        final Set<Class<?>> classes = new HashSet<>();
    
        @Nonnull
        @Override
        public Set<Class<?>> getClasses() {
            classes.add(RegisterResource.class);
            return Collections.unmodifiableSet(classes);
        }
    }
    

    No if I add ten new Resources on the ApplicationPath, I need to do

        classes.add(<ClassName>.class);
    

    ten times, it is tedious and sometimes forgetful as well.

    Does JAX-RS or RESTEasy provide the way so that I can mention the package name and classes are scanned under it?

    I know Jersey has something as

    public class MyApplication extends ResourceConfig {
        public MyApplication() {
            packages("org.foo.rest;org.bar.rest");
        }
    }
    

    Reference

    Any thoughts/ideas?

    UPDATE

    Seems we can do following in web.xml

       <context-param>
          <param-name>resteasy.scan</param-name>
          <param-value>true</param-value>
       </context-param>
    

    Is there a specific Java equivalent?

  • Michael Repucci
    Michael Repucci over 7 years
    Perhaps this should be a separate question, but I'm finding that, with the solution suggested here, my JAX-RS application isn't automatically picking up some registered ExceptionMapper providers that reside in a separate EJB package in the EAR, which also contains the WAR. I'd rather not have to explicitly add every class, as the OP indicates, but do need the kind of "add package" shortcut that Jersey provides, and still can't find a way to do this with RESTEasy. Any thoughts?
  • Michael Repucci
    Michael Repucci over 7 years
    Seems like I need a different question because explicitly adding all the classes in an overridden getClasses() method actually doesn't work either. Nor does registering them as a Feature. There must be something special about these ExceptionMapper providers. Hmm...
  • Michael Repucci
    Michael Repucci over 7 years
    Making a little progress ... the Wildfly logs indicate that one of the exceptions that appears to not be properly handled is an EJBException: ERROR [io.undertow.request] (default task-121) UT005023: Exception handling request to /rest/authenticate: org.jboss.resteasy.spi.UnhandledException: javax.ejb.EJBException: io.jsonwebtoken.ExpiredJwtException. Adding an ExceptionMapper for EJBException does allow me to handle this exception, but I'm not fully understanding why this occurs, when an ExpiredJwtException thrown in my EJB package (rather than the WAR) doesn't exhibit this problem.
  • Michael Repucci
    Michael Repucci over 7 years
    In the end, my problem was due to how unchecked (System) exceptions get wrapped by the container in an EJBException (see stackoverflow.com/a/19563956/304620). The solution, in my case, was to denote io.jsonwebtoken.ExpiredJwtException in the ejb-jar.xml to make it an Application (checked) exception.
  • Seyed Ali Roshan
    Seyed Ali Roshan almost 7 years
    I used it but at first, it gave me 500 for not registering MultiPartFeature and after register it, it gave 404 for all my APIs. any idea?