Chapter 24. Migration Guide
Prev |  | Next

Links: Table of Contents | Single HTML

## Chapter 24. Migration Guide

## 24.1. 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.

## 24.2. 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.

## 24.3. 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.

## 24.4. 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.

### 24.4.1. Server API

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

#### 24.4.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 ...
        }}

#### 24.4.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 24.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 24.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 24.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 24.4. Jersey 2 reloader registration

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

#### 24.4.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.

### 24.4.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 24.1. Mapping of Jersey 1.x to JAX-RS 2.0 client classes

Jersey 1.x Class | JAX-RS 2.0 Class | Notes
--- | --- | ---
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.

#### 24.4.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);

#### 24.4.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));

#### 24.4.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();

#### 24.4.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"));

#### 24.4.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();

Prev |  | Next
Chapter 23. Building and Testing Jersey | Home | Appendix A. Configuration Properties