Links: Table of Contents | Single HTML

Chapter 25. Migration Guide

25.1. Migrating from Jersey 2.6 to 2.7

25.1.1. Changes

  • Until version 2.6, Jersey was compiled with Java SE 6. This has changes in Jersey 2.7. Now almost all Jersey components are compiled with Java SE 7 target. It means, that you will need at least Java SE 7 to be able to compile and run your application that is using latest Jersey. Only core-common and core-client modules are still compiled with Java class version runnable with Java SE 6.

  • MVC support: method writeTo of TemplateProcessor was modified by adding an argument MultivaluedMap<String, Object> httpHeaders. This is an incompatible change (the method was modified directly in the interface). All Jersey provided MVC implementation were adjusted but if you have your own MVC implementation then you need to modify the method signature of the implementation.

  • A minor JAX-RS incompatibility issue has been recently discovered and reported (see JERSEY-2387). As part of the fix, minor breaking changes related to URI resolving and creation have been introduced in the behavior of UriBuilder, Link.Builder and WebTarget classes. It is no longer possible to successfully build a new URI instance from a UriBuilder that contains unresolved template parameters. An IllegalArgumentException will be thrown in such case, as mandated by JAX-RS API javadoc. Similarly, it is not possible to successfully create a Link instance from a URI template with unresolved template parameters. Also, it is not possible to successfully send a request on a WebTarget that represents a URI template that does not have all the template parameters properly resolved. Any attempt to do so will fail with an exception. Note that this also applies to any managed clients injected into JAX-RS server-side components using Uri annotation.

    In Jersey 2.6 and earlier, producing a URI from an incompletely resolved URI template would succeed and all unresolved template parameter locations would be encoded without change into the resulting URI, for example "/path/{param}" would be implicitly encoded as "/path/%7Bparam%7D". While we do not expect our users to depend on this functionality, if the former behavior is desired for some reason, UriComponent.encodeTemplateNames method can be used instead:

    URI.create(UriComponent.encodeTemplateNames(UriBuilder.fromUri("/path/{param}").toTemplate()));

    or simply

    URI.create(UriComponent.encodeTemplateNames("/path/{param}"));

25.2. Migrating from Jersey 2.5.1 to 2.6

25.2.1. Guava and ASM have been embedded

Jersey no longer depend directly on Guava and ASM artifacts which means that users are free to use their own versions of mentioned libraries.

New bundle has been created for Guava (bundles/repackaged/jersey-guava), with Maven coordinates: org.glassfish.jersey.bundles.repackaged:jersey-guava

(Repackaged) ASM is now part of Jersey Server. Jersey currently uses ASM 5 for package-scanning capabilities.

25.2.2. New deprecated APIs / internal classes

Following APIs were deprecated:

  • org.glassfish.jersey.message.internal.HttpDateFormat - method getPreferedDateFormat() has been marked as deprecated due to typo in the name. New method getPreferredDateFormat() should be used instead.

25.2.3. Removed deprecated APIs

Following, already deprecated, APIs were removed:

  • org.glassfish.jersey.client.filter.HttpBasicAuthFilter and org.glassfish.jersey.client.filter.HttpDigestAuthFilter (use HttpAuthenticationFeature instead)

  • org.glassfish.jersey.apache.connector.ApacheClientProperties.HTTP_PARAMS (use org.glassfish.jersey.apache.connector.ApacheClientProperties#REQUEST_CONFIG instead), org.glassfish.jersey.apache.connector.ApacheClientProperties.PROXY_URI, org.glassfish.jersey.apache.connector.ApacheClientProperties.PROXY_USERNAME, org.glassfish.jersey.apache.connector.ApacheClientProperties.PROXY_PASSWORD (use corresponding ClientProperties instead.

  • org.glassfish.jersey.server.validation.ValidationConfig.setMessageInterpolator org.glassfish.jersey.server.validation.ValidationConfig.setTraversableResolver org.glassfish.jersey.server.validation.ValidationConfig.setConstraintValidatorFactory org.glassfish.jersey.server.validation.ValidationConfig.setParameterNameProvider (use corresponding methods of the same class without "set" prefix in the method names).

  • org.glassfish.jersey.server.mvc.MvcProperties (use properties of org.glassfish.jersey.server.mvc.MvcFeature instead).

  • MVC does not allow to specify the resolving class. Resolving class is used to create a path of the template. Changes are:

    Annotation attribute Class<?> org.glassfish.jersey.server.mvc.Template.resolvingClass() (the attribute was obsolete and therefore removed. Resolving class now always the resource class in which the MVC resource method is defined).

    resolvingClass was removed from Viewable. The constructor no longer accepts this argument and there is no getter for this field.

  • org.glassfish.jersey.server.mvc.freemarker.FreemarkerProperties (use FreemarkerMvcFeature instead)

  • org.glassfish.jersey.server.mvc.jsp.JspProperties (use JspMvcFeature instead)

  • org.glassfish.jersey.server.model.RuntimeResource.getFirstParentResource() (use Resource.getParent() instead).

  • WADL is by default displayed in the simplified form. It does not contain supporting resources like OPTIONS methods or /application.wadl itself. In order to get the full WADL use query param detail=true. For example make a GET request to http://localhost:8080/application.wadl?detail=true.

25.3. Migrating from Jersey 2.5 to 2.5.1

  • WADL is by default displayed in the simplified form. It does not contain supporting resources like OPTIONS methods or /application.wadl itself. In order to get the full WADL use query param detail=true. For example make a GET request to http://localhost:8080/application.wadl?detail=true.

25.4. Migrating from Jersey 2.4.1 to 2.5

25.4.1. Client-side API and SPI changes

  • Client chunked encoding configuration behaviour has changed:

    Jersey client uses chunked encoding (streaming) for serialization of the entity as a default option. Before Jersey 2.5 release entity buffering has been used by default. The size of the chunk can still be controlled by ClientProperties.CHUNKED_ENCODING_SIZE property, this property however no longer enforces the use of chunked encoding. To control request entity buffering and chunked transfer coding selection, please utilize use the new ClientProperties.REQUEST_ENTITY_PROCESSING property. The behaviour of the property is however not unified across the available Connector implementations and depends on the connector implementation configured for the Client instance. Default connector produced by HttpUrlConnectorProvider still uses buffering as default options due to bugs in HttpURLConnection. On the other hand, Jetty HTTP Client based connectors produced by JettyConnectorProvider do not support chunked encoding at all.

    Please note that this is not a newly introduced limitation - it's merely an official acknowledgement of the fact that different connectors have different capabilities and limitations - something that has always been part of the individual connector implementations, it just was not publicly acknowledged.

  • New ConnectorProvider SPI has been introduced to decouple Connector instantiation from Client instance boot-strapping. As such, the connector(Connector) method has been removed from ClientConfig API. It has been replaced with a newly introduced connectorProvider(ConnectorProvider) method.

  • org.glassfish.jersey.client.HttpUrlConnector has been removed from the public API. HttpUrlConnectorProvider should be used to produce HttpURLConnection connector instances instead.

  • ClientProperties.HTTP_URL_CONNECTION_SET_METHOD_WORKAROUND property has been moved to the new HttpUrlConnectorProvider has been introduced in Jersey 2.4) has been moved to the new HttpUrlConnectorProvider class as this property is specific to the connector instances created by HttpUrlConnectorProvider only. The property has been also renamed to HttpUrlConnector.SET_METHOD_WORKAROUND. The name of the property remains the same - jersey.config.client.httpUrlConnection.setMethodWorkaround.

  • ClientProperties.HTTP_URL_CONNECTOR_FIX_LENGTH_STREAMING property (that class as this property is specific to the connector instances created by HttpUrlConnectorProvider only. The property has been also renamed to HttpUrlConnectorProvider.USE_FIXED_LENGTH_STREAMING and the new property name is jersey.config.client.httpUrlConnector.useFixedLengthStreaming.

  • org.glassfish.jersey.grizzly.connector.GrizzlyConnector has been removed from the public API. GrizzlyConnectorProvider should be used to produce Grizzly Asynchronous HTTP Client connector instances instead.

  • Public constructor has been removed from the ApacheConnector API. ApacheConnectorProvider should be used to provide Apache HTTP Client connector instances instead.

  • Public constructor has been removed from the JettyConnector API. JettyConnectorProvider should be used to provide Jetty HTTP Client connector instances instead.

  • Renamed property CACHING_TEMPLATES_ENABLED in MustacheMvcFeature from jersey.config.server.mvc.caching.mustache.enabled to jersey.config.server.mvc.caching.mustache.

  • Authentication filters org.glassfish.jersey.client.filter.HttpBasicAuthFilter and org.glassfish.jersey.client.filter.HttpDigestAuthFilter were deprecated and replaced by HttpAuthenticationFeature.

25.4.2. Other changes

  • The ContainerLifecycleListener invokes event onStartup and onShutdown also when application is being started or stopped because of application redeploy. The interface was marked as a Beta now.

  • The monitoring statistics method ApplicationStatistics.getDestroyTime() is deprecated and returns always null. Use ContainerLifecycleListener to listen on application destroy and get the destroy time.

  • org.glassfish.jersey.spi.ResponseExecutorsProvider contract has been completely removed from the Jersey SPI as it was inconsistently used by Jersey runtime and we did not find a suitable use case where a custom response executor would make sense. While we have no indication that the removed SPI is used in the Jersey community, please do not hesitate to contact us in case you think that you have a valid use case where the use of a custom response executor makes sense.

  • org.glassfish.jersey.spi.RequestsExecutorsProvider contract has been renamed to RequestExecutorProvider. It has been also extended with an additional releaseRequestingExecutor method to address executor shutdown handling issues reported in JERSEY-2205. As such, any custom implementation of the SPI is now required to implement the new method.

25.5. Migrating from Jersey 2.4 to 2.4.1

  • The unsupported ClientProperties.BUFFER_RESPONSE_ENTITY_ON_EXCEPTION property, with value of jersey.config.client.bufferResponseEntityOnException, has been removed from the API. Since Jersey 2.4 where JERSEY-2157 issue has been fixed, Jersey client runtime automatically buffers error response entities. This behavior is automatic and there is no need to set any property.

25.6. Migrating from Jersey 2.3 to 2.4

  • All deprecated SSE InboundEvent getData(...) methods have been removed from the API. Use the new readData(...) methods have been introduced instead in Jersey 2.3 for consistency with other parts of client-side JAX-RS API. Access to the raw SSE event data content is provided via a InboundEvent's byte[] getRawData() method that has been too introduced in Jersey 2.3.

  • All EJB and CDI integration classes have been moved into internal Jersey packages, to clearly state the integration code should not be used as a public API.

25.7. Migrating from Jersey 2.0, 2.1 or 2.2 to 2.3

  • All existing SSE InboundEvent getData(...) methods have been made deprecated and new readData(...) methods have been introduced instead for consistency with other parts of client-side JAX-RS API. The deprecated getData(...) methods will be removed in Jersey 2.4. A new SSE InboundEvent byte[] getRawData() method has been introduced to provide access to the raw SSE event data content.

  • Generic Broadcaster methods for adding/removing BroadcasterListener registrations have been renamed from addBroadcasterListener/removeBroadcasterListener to simply add/remove.

  • Generic Broadcaster (and transitively, SseBroadcaster) add/remove methods - that are responsible for adding/removing BroadcasterListener and ChunkedOutput (or EventOutput) registrations - no longer try to avoid duplicate registrations by comparing hash code of the added/removed instance with the hash codes of already registered instances. This behavior has been identified as a potential source of hard to discover bugs and was removed as such. The issue with the former behavior was that hash codes as integer values provide only a very limited value space that could lead to false-positive duplicate registration rejections, especially with larger number of simultaneously connected SSE clients (represented by ChunkedOutput or EventOutput broadcaster registrations). Consequently, users who rely on the old registration behavior in their application code need to adapt the code to the revised behavior of Broadcaster add/remove methods.

25.8. Migrating from Jersey 1.x to 2.0

This chapter is a migration guide for people switching from Jersey 1.x. Since many of the Jersey 1.x features became part of JAX-RS 2.0 standard which caused changes in the package names, we decided it is a good time to do a more significant incompatible refactoring, which will allow us to introduce some more interesting new features in the future. As the result, there are many incompatibilities between Jersey 1.x and Jersey 2.0. This chapter summarizes how to migrate the concepts found in Jersey 1.x to Jersey/JAX-RS 2.0 concepts.

25.8.1. Server API

Jersey 1.x contains number of proprietary server APIs. This section covers migration of application code relying on those APIs.

25.8.1.1. Injecting custom objects

Jersey 1.x have its own internal dependency injection framework which handles injecting various parameters into field or methods. It also provides a way how to register custom injection provider in Singleton or PerRequest scopes. Jersey 2.x uses HK2 as dependency injection framework and users are also able to register custom classes or instances to be injected in various scopes.

Main difference in Jersey 2.x is that you don't need to create special classes or providers for this task; everything should be achievable using HK2 API. Custom injectables can be registered at ResourceConfig level by adding new HK2 Module or by dynamically adding binding almost anywhere using injected HK2 Services instance.

Jersey 1.x Singleton:

ResourceConfig resourceConfig = new DefaultResourceConfig();
resourceConfig.getSingletons().add(
        new SingletonTypeInjectableProvider<Context, SingletonType>(
                SingletonType.class, new SingletonType()) {});

Jersey 1.x PerRequest:

ResourceConfig resourceConfig = new DefaultResourceConfig();
resourceConfig.getSingletons().add(
        new PerRequestTypeInjectableProvider<Context, PerRequestType>() {
            @Override
            public Injectable<PerRequestType> getInjectable(ComponentContext ic, Context context) {
                //...
            }
        });

Jersey 2.0 HK2 Module:

public static class MyBinder extends AbstractBinder {

    @Override
    protected void configure() {
        // request scope binding
        bind(MyInjectablePerRequest.class).to(MyInjectablePerRequest.class).in(RequestScope.class);
        // singleton binding
        bind(MyInjectableSingleton.class).in(Singleton.class);
        // singleton instance binding
        bind(new MyInjectableSingleton()).to(MyInjectableSingleton.class);
    }

}

// register module to ResourceConfig (can be done also in constructor)
ResourceConfig rc = new ResourceConfig();
rc.addClasses(/* ... */);
rc.addBinders(new MyBinder());

Jersey 2.0 dynamic binding:

public static class MyApplication extends Application {

    @Inject
    public MyApplication(ServiceLocator serviceLocator) {
        System.out.println("Registering injectables...");

        DynamicConfiguration dc = Injections.getConfiguration(serviceLocator);

        // request scope binding
        Injections.addBinding(
        Injections.newBinder(MyInjectablePerRequest.class).to(MyInjectablePerRequest.class).in(RequestScoped.class),
                dc);

        // singleton binding
        Injections.addBinding(
                Injections.newBinder(MyInjectableSingleton.class)
                        .to(MyInjectableSingleton.class)
                        .in(Singleton.class),
                dc);

        // singleton instance binding
        Injections.addBinding(
                Injections.newBinder(new MyInjectableSingleton())
                        .to(MyInjectableSingleton.class),
                dc);

        // request scope binding with specified custom annotation
        Injections.addBinding(
                Injections.newBinder(MyInjectablePerRequest.class)
                        .to(MyInjectablePerRequest.class)
                        .qualifiedBy(new MyAnnotationImpl())
                        .in(RequestScoped.class),
                dc);

        // commits changes
        dc.commit();
    }

    @Override
    public Set<Class<?>> getClasses() {
        return ...
    }}

25.8.1.2. ResourceConfig Reload

In Jersey 1, the reload functionality is based on two interfaces:

  1. com.sun.jersey.spi.container.ContainerListener
  2. com.sun.jersey.spi.container.ContainerNotifier

Containers, which support the reload functionality implement the ContainerListener interface, so that once you get access to the actual container instance, you could call it's onReload method and get the container re-load the config. The second interface helps you to obtain the actual container instance reference. An example on how things are wired together follows.

Example 25.1. Jersey 1 reloader implementation

public class Reloader implements ContainerNotifier {
    List<ContainerListener> ls;

    public Reloader() {
        ls = new ArrayList<ContainerListener>();
    }

    public void addListener(ContainerListener l) {
        ls.add(l);
    }

    public void reload() {
        for (ContainerListener l : ls) {
            l.onReload();
        }
    }
}


Example 25.2. Jersey 1 reloader registration

Reloader reloader = new Reloader();
resourceConfig.getProperties().put(ResourceConfig.PROPERTY_CONTAINER_NOTIFIER, reloader);


In Jersey 2, two interfaces are involved again, but these have been re-designed.

  1. org.glassfish.jersey.server.spi.Container
  2. org.glassfish.jersey.server.spi.ContainerLifecycleListener

The Container interface introduces two reload methods, which you can call to get the application re-loaded. One of these methods allows to pass in a new ResourceConfig instance. You can register your implementation of ContainerLifecycleListener the same way as any other provider (i.e. either by annotating it by @Provider annotation or adding it to the Jersey ResourceConfig directly either using the class (using ResourceConfig.addClasses()) or registering a particular instance using ResourceConfig.addSingletons() method.

An example on how things work in Jersey 2 follows.

Example 25.3. Jersey 2 reloader implementation

public class Reloader implements ContainerLifecycleListener {

    Container container;

    public void reload(ResourceConfig newConfig) {
        container.reload(newConfig);
    }

    public void reload() {
        container.reload();
    }

    @Override
    public void onStartup(Container container) {
        this.container = container;
    }

    @Override
    public void onReload(Container container) {
        // ignore or do whatever you want after reload has been done
    }

    @Override
    public void onShutdown(Container container) {
        // ignore or do something after the container has been shutdown
    }
}


Example 25.4. Jersey 2 reloader registration

Reloader reloader = new Reloader();
resourceConfig.addSingletons(reloader);
                        


25.8.1.3. MessageBodyReaders and MessageBodyWriters ordering

JAX-RS 2.0 defines new order of MessageBodyWorkers - whole set is sorted by declaration distance, media type and source (custom providers having higher priority than default ones provided by Jersey). JAX-RS 1.x ordering can still be forced by setting parameter MessageProperties.LEGACY_WORKERS_ORDERING ("jersey.config.workers.legacyOrdering") to true in ResourceConfig or ClientConfig properties.

25.8.2. Migrating Jersey Client API

JAX-RS 2.0 provides functionality that is equivalent to the Jersey 1.x proprietary client API. Here is a rough mapping between the Jersey 1.x and JAX-RS 2.0 Client API classes:

Table 25.1. Mapping of Jersey 1.x to JAX-RS 2.0 client classes

Jersey 1.x ClassJAX-RS 2.0 ClassNotes
com.sun.jersey.api.client.Client ClientBuilder For the static factory methods and constructors.
  Client For the instance methods.
com.sun.jersey.api.client.WebResource WebTarget  
com.sun.jersey.api.client.AsyncWebResource WebTarget You can access async versions of the async methods by calling WebTarget.request().async()

The following sub-sections show code examples.

25.8.2.1. Making a simple client request

Jersey 1.x way:

Client client = Client.create();
WebResource webResource = client.resource(restURL).path("myresource/{param}");
String result = webResource.pathParam("param", "value").get(String.class);

JAX-RS 2.0 way:

Client client = ClientBuilder.newClient();
WebTarget target = client.target(restURL).path("myresource/{param}");
String result = target.pathParam("param", "value").get(String.class);

25.8.2.2. Registering filters

Jersey 1.x way:

Client client = Client.create();
WebResource webResource = client.resource(restURL);
webResource.addFilter(new HTTPBasicAuthFilter(username, password));

JAX-RS 2.0 way:

Client client = ClientBuilder.newClient();
WebTarget target = client.target(restURL);
target.register(new HttpBasicAuthFilter(username, password));

25.8.2.3. Setting "Accept" header

Jersey 1.x way:

Client client = Client.create();
WebResource webResource = client.resource(restURL).accept("text/plain");
ClientResponse response = webResource.get(ClientResponse.class);

JAX-RS 2.0 way:

Client client = ClientBuilder.newClient();
WebTarget target = client.target(restURL);
Response response = target.request("text/plain").get();

25.8.2.4. Attaching entity to request

Jersey 1.x way:

Client client = Client.create();
WebResource webResource = client.resource(restURL);
ClientResponse response = webResource.post(ClientResponse.class, "payload");

JAX-RS 2.0 way:

Client client = ClientBuilder.newClient();
WebTarget target = client.target(restURL);
Response response = target.request().post(Entity.text("payload"));

25.8.2.5. Setting SSLContext and/or HostnameVerifier

Jersey 1.x way:

HTTPSProperties prop = new HTTPSProperties(hostnameVerifier, sslContext);
DefaultClientConfig dcc = new DefaultClientConfig();
dcc.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, prop);
Client client = Client.create(dcc);

Jersey 2.0 way:

Client client = ClientBuilder.newBuilder()
        .sslContext(sslContext)
        .hostnameVerifier(hostnameVerifier)
        .build();