jeudi 2 juillet 2015

How do Jersey2 initialize javax.ws.rs.client object at source code level?

According to the official document of Jersey, it's quite easy to create a javax.ws.rs.client object:

Client client = ClientBuilder.newClient();

But when you look into the source code, ClientBuilder is abstract class:

public abstract class ClientBuilder implements Configurable<ClientBuilder> {

    /**
     * Name of the property identifying the {@link ClientBuilder} implementation
     * to be returned from {@link ClientBuilder#newBuilder()}.
     */
    public static final String JAXRS_DEFAULT_CLIENT_BUILDER_PROPERTY =
            "javax.ws.rs.client.ClientBuilder";
    /**
     * Default client builder implementation class name.
     */
    private static final String JAXRS_DEFAULT_CLIENT_BUILDER =
            "org.glassfish.jersey.client.JerseyClientBuilder";

    /**
     * Create a new {@code ClientBuilder} instance using the default client builder
     * implementation class provided by the JAX-RS implementation provider.
     *
     * @return new client builder instance.
     */
    public static ClientBuilder newBuilder() {
        try {
            Object delegate =
                    FactoryFinder.find(JAXRS_DEFAULT_CLIENT_BUILDER_PROPERTY,
                            JAXRS_DEFAULT_CLIENT_BUILDER);
            if (!(delegate instanceof ClientBuilder)) {
                Class pClass = ClientBuilder.class;
                String classnameAsResource = pClass.getName().replace('.', '/') + ".class";
                ClassLoader loader = pClass.getClassLoader();
                if (loader == null) {
                    loader = ClassLoader.getSystemClassLoader();
                }
                URL targetTypeURL = loader.getResource(classnameAsResource);
                throw new LinkageError("ClassCastException: attempting to cast"
                        + delegate.getClass().getClassLoader().getResource(classnameAsResource)
                        + " to " + targetTypeURL);
            }
            return (ClientBuilder) delegate;
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

    /**
     * Create a new {@link Client} instance using the default client builder implementation
     * class provided by the JAX-RS implementation provider.
     *
     * @return new client instance.
     */
    public static Client newClient() {
        return newBuilder().build();
    }

/**
     * Build a new client instance using all the configuration previously specified
     * in this client builder.
     *
     * @return a new client instance.
     */
    public abstract Client build();

As you could see above, build() method is abstract without any implementation, which seems do nothing about the javax.ws.rs.client initialization.

So my guess is that newBuilder() method use some kind of reflection to leverage org.glassfish.jersey.client.JerseyClientBuilder. So it's actually JerseyClientBuilder to make the initialization.

So my questions are:

  • Is my guess correct? If no, how to initialize client?

  • Why use such approach in newBuilder() method? What's the advantage? Is Client client = JerseyClientBuilder.build(); more clear?

  • Could you elaborate more about newBuilder() method? Don't understand why finally have a targetTypeURL object.





Aucun commentaire:

Enregistrer un commentaire