Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Give Your Old School API Some Love

DZone's Guide to

Give Your Old School API Some Love

Free Resource

Learn how API management supports better integration in Achieving Enterprise Agility with Microservices and API Management, brought to you in partnership with 3scale

If you’re an assiduous reader of this blog, then you probably already heard about our vision around APIs, our Anypoint API Manager solution and all our RAML based stories. Those are our recommended way of approaching REST APIs and if you haven’t already, we all highly recommend you to take a look at them. However, we’re about connecting everything, everywhere. Thus we recognize that there are a lot of APIs out there built in plain old Java code and a migration process is not something you can do overnight. If you own such an API, this post is about us wanting to help you too. Anypoint Platform includes a Jersey module to allow embedding Jersey-based APIs into the runtime, reusing the Java code powering your API but still gaining access to all the other features of the platform. In Mule 3.6 we upgraded our supported Jersey version from 1.6 to v2.11 to give you access to the latest and greatest that Jersey has to offer.

A little bit about Jersey

Jersey is the reference implementation for the JAX-RS specification about RESTful services in Java. In their own words: “Jersey framework is more than the JAX-RS Reference Implementation. Jersey provides it’s own API that extend the JAX-RS toolkit with additional features and utilities to further simplify RESTful service and client development. Jersey also exposes numerous extension SPIs so that developers may extend Jersey to best suit their needs.”

For more information on Jersey and access to its user guide, you can visit their website following this link.

A quick tour

For those of you not really familiar with our Jersey support, here’re a couple of quick examples on how you can use it. First, you declare a flow starting with an http inbound endpoint and then passing on control to the Jersey component:

    <flow name="helloWorldResource">
        <http:inbound-endpoint host="localhost" port="${port}" exchange-pattern="request-response"/>

        <jersey:resources>
            <component class="org.mule.module.jersey.HelloWorldResource"/>
        </jersey:resources>
    </flow>

The HelloWorldResource would look something like this:

@Path("/helloworld")
public class HelloWorldResource {

    @POST
    @Produces("text/plain")
    public String sayHelloWorld() {
        return "Hello World";
    }
}

You can also declare your own custom context resolvers:

<flow name="helloWorldResource">
    <http:inbound-endpoint host="localhost" port="${port}" exchange-pattern="request-response"/>

    <jersey:resources>
        <component class="org.mule.module.jersey.HelloWorldResource"/>
        <jersey:context-resolver class="org.mule.module.jersey.contextresolver.NullContextResolver" />
        <jersey:context-resolver class="org.mule.module.jersey.contextresolver.JaxbCustomContextResolver" />
    </jersey:resources>
</flow>

Your own exception mappers:

<flow name="helloWorldResource">
    <http:inbound-endpoint host="localhost" port="${port}" exchange-pattern="request-response"/>

    <jersey:resources>
        <component class="org.mule.module.jersey.HelloWorldResource"/>
        <jersey:exception-mapper class="org.mule.module.jersey.exception.BeanBadRequestExceptionMapper"/>
        <jersey:exception-mapper class="org.mule.module.jersey.exception.HelloWorldExceptionMapper"/>
    </jersey:resources>
</flow>

You can even use interface bindings to invoke your very own Mule flows from your Jersey resource in a completely decoupled way!

<flow name="test">
    <http:inbound-endpoint host="localhost" port="${port}" exchange-pattern="request-response"/>

    <jersey:resources>
        <component class="org.mule.module.jersey.HelloWorldComponent">
            <binding interface="org.mule.module.jersey.HelloWorldInterface">
                <flow-ref name="TransformationFlow" />
            </binding>
        </component>
    </jersey:resources>
</flow>

<flow name="TransformationFlow">
    <set-payload value="Hello World!" />
</flow>
@Path("/")
public class HelloWorldComponent {

    private HelloWorldInterface helloWorldBinding;

    @GET
    @Path("/sayHello")
    @Produces("text/plain")
    public String sayHelloFromBinding() {
        return helloWorldBinding.sayHello("s");
    }

    public void setHelloWorldBinding(HelloWorldInterface helloWorldBinding) {
        this.helloWorldBinding = helloWorldBinding;
    }

    public HelloWorldInterface getHelloWorldBinding() {
        return this.helloWorldBinding;
    }
    
    public static interface HelloWorldInterfac {

        public String sayHello(String s);
    }

}

So What's New?

For starters, you now have access to the features in Jersey 2.0 and the JAX-RS 2.0 specification. Notice that if you want to update an existent API build using Jersey 1.x, this might require you to perform some code changes since the latest JAX-RS and Jersey are not backwards compatible with the 1.x versions.

There’re also some new features from the Mule namespace as well!

Your own properties

Now you can execute each resource passing your own set of server properties. For example, the following configuration specifies its very own set of language mappings:

<flow name="helloWorld">
    <http:inbound-endpoint host="localhost" port="${port}" exchange-pattern="request-response"/>

    <jersey:resources>
        <component class="org.mule.module.jersey.HelloWorldResource"/>
        <jersey:property key="jersey.config.server.languageMappings" value="english : en, french : fr" />
    </jersey:resources>
</flow>

Auto discover your extensions

Jersey is the proud owner of a very extensible Java API to allow developers modify almost every aspect of its inner working. A very popular request has always been to allow this from the Mule configuration. Because Jersey provides so many extension points, we choose to enable this using auto discovery capabilities. Per Jersey’s own API, every class annotated with the @Provider annotation can be used as an extension point. From the Mule namespace, we now allow specifying a list of java packages to scan for classes with such annotation. Every discovered class will be automatically registered in the resource’s context.

Here’s an example of how to register your own JAXB body writers and readers for an hypothetical Person class:

<flow name="helloWorldResource">
    <http:inbound-endpoint host="localhost" port="${port}" exchange-pattern="request-response"/>
 
    <jersey:resources>
        <component class="org.mule.module.jersey.HelloWorldResource"/>
        <jersey:package packageName="com.my.project.jersey.readers" />
        <jersey:package packageName="com.my.project.jersey.writers" />
    </jersey:resources>
</flow>

Here the packages com.my.project.jersey.readers and com.my.project.jersey.writers are being scanned and, for example, the following providers would be discovered:

package com.my.project.jersey.writers;

@Provider
@Produces("application/xml")
public class MyBeanMessageBodyWriter implements MessageBodyWriter<MyBean> {
 
    @Override
    public boolean isWriteable(Class<?> type, Type genericType,
                               Annotation[] annotations, MediaType mediaType) {
        return type == Person.class;
    }
 
    @Override
    public long getSize(MyBean myBean, Class<?> type, Type genericType,
                        Annotation[] annotations, MediaType mediaType) {
        // deprecated by JAX-RS 2.0 and ignored by Jersey runtime
        return 0;
    }
 
    @Override
    public void writeTo(Person person,
                        Class<?> type,
                        Type genericType,
                        Annotation[] annotations,
                        MediaType mediaType,
                        MultivaluedMap<String, Object> httpHeaders,
                        OutputStream entityStream)
                        throws IOException, WebApplicationException {
 
        try {
            JAXBContext jaxbContext = JAXBContext.newInstance(Person.class);
            jaxbContext.createMarshaller().marshal(person, entityStream);
        } catch (JAXBException jaxbException) {
            throw new ProcessingException(
                "Error serializing a Person to the output stream", jaxbException);
        }
    }
}
package com.my.project.jersey.readers;

@Provider
public static class MyBeanMessageBodyReader implements MessageBodyReader<MyBean> {
 
@Override
public boolean isReadable(Class<?> type, Type genericType,
    Annotation[] annotations, MediaType mediaType) {
    return type == Person.class;
}
 
@Override
public MyBean readFrom(Class<MyBean> type,
    Type genericType,
    Annotation[] annotations, MediaType mediaType,
    MultivaluedMap<String, String> httpHeaders,
    InputStream entityStream)
        throws IOException, WebApplicationException {
 
    try {
        JAXBContext jaxbContext = JAXBContext.newInstance(MyBean.class);
        return (Person) jaxbContext.createUnmarshaller()
            .unmarshal(entityStream);
        return myBean;
    } catch (JAXBException jaxbException) {
        throw new ProcessingException("Error deserializing a Person.",
            jaxbException);
    }
}
}

Summary

With this upgrade we hope to continue supporting as many API scenarios as possible. Hopefully, this will enable you to combine the goodies of Jersey and the Java APIs with the power of the AnyPoint platform. Nevertheless, you may want to consider trying out the Anypoint Platform for APIs in order to get a next generation experience in designing, exposing, managing and consuming your APIs.

Remember…

Unleash the power of your APIs with future-proof API management - Create your account and start your free trial today, brought to you in partnership with 3scale.

Topics:

Published at DZone with permission of Mariano Gonzalez, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}