Friday, August 2, 2013

JDeveloper 12c: Create RESTful Service from Java Class

With JDeveloper 12c finally it is possible to create RESTful Services from a Java Class. The implementation is based on Jersey following the Java EE 6 specification JAX-RS. For testing JDeveloper includes a comprehensive Tooling. In general RESTful services are really popular for mobile applications, e.g. ADF Mobile.

Get started
Create a simple Java Class for your business domain object plus a Service Facade that you want to expose as a RESTful Service.
Make sure to annotate the class with the @XmlRootElement otherwise the REST Service will not work for this domain object.

Next create a simple service facade with some test data, e.g.
package enpit.sample.adf12c.pojorest.model;
import java.util.ArrayList;
import java.util.Date;import java.util.List;

public class PersonService {

    
private List<Person> persons;
    
private Person person;

    
public PersonService() {
        
super();
        
this.persons = new ArrayList<Person>();
        
for (long i = 0; i < 10; i++) {
            Person p = 
new Person();
            p.setId(i);
            p.setFirstname(
"Firstname " + i);
            p.setLastname(
"Last " + i);
            p.setHiredate(
new Date());
            
this.persons.add(p);
        }
        
this.person = this.persons.get(0);
    }

    public List<Person> getPersons(){
        return this.persons;
    }

    public void addPerson(Person person) {
        System.out.println(
"add person " + person);

        
if(person != null){
            getPersons().add(person);
        }
    }
    public Person getPerson(){
        
return person;
    }
}

So far there is nothing special. 

Create RESTful Service with the help of JDeveloper 12c
Now comes the interesting part. Select the PersonService.java in the application navigator and
choose "Create RESTful Service…"

You will get a wizard to specify the RESTful Service interface. Set the desired root path. Choose the desired media types and the Methods you want to expose as REST Service
After finishing the wizard the following happens
- JAX-RS Annotations are generated  on the Java Class
package enpit.sample.adf12c.pojorest.model;
import java.util.ArrayList;
import java.util.Date;import java.util.List;import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;import javax.ws.rs.POST;import javax.ws.rs.Path;import
 javax.ws.rs.Produces;


@Path(
"rest")
@Produces(value = { "application/json""application/xml" })
@Consumes(value = { "application/json""application/xml" })
public class PersonService {

    
private List<Person> persons;
    
private Person person;

    
public PersonService() {
        
super();
        
this.persons = new ArrayList<Person>(){
        
for (long i = 0; i < 10; i++) {
            Person p = 
new Person();
            p.setId(i);
            p.setFirstname(
"Firstname " + i);
            p.setLastname(
"Last " + i);
            p.setHiredate(
new Date());
            
this.persons.add(p);
        }
        
this.person = this.persons.get(0);
    }

    @GET
    @Path(
"/persons")
    
public List<Person> getPersons(){
        
return this.persons;
    }

    @POST
    @Path(
"/person")    
    
public void addPerson(@FormParam("person"Person person) {
        System.out.println("add person " + person);

        
if(person != null){
            getPersons().add(person);
        }
    }

    @GET
    @Path(
"/person")
    
public Person getPerson(){
        
return person;
    }
}

- web.xml is created. The Jersey Servlet is configured properly.

Testing the RESTful Service in JDeveloper 12c
Jdeveloper is quite powerful. It lets you test the RESTful service right in the IDE.
Right-Click on the PersonService.java class and choose Run.

In background WebLogic Server 12c starts and the RESTFul Service gets deployed.

The WADL is kind of WSDL for RESTful Services. Clicking on the "Target Application WADL" URL brings you to the overview of the provided service operations

You can test each Service Operation right from the IDE. Pressing the "Test" Button brings you to the HTTP Analyzer Screen.
Here you can choose the Method, change HTTP Headers (e.g. what kind of media type you want to accept).
Press "Send Request" to actually test the Service Operation. Make sure to change the view to "HTTP Content" not "WADL Structure" otherwise you want see the pretty formatted output on the right hand side.

Change the Accept-Header to application/json and send the request again. The output automatically will be in JSON format.
The HTTP Analyzer is even so good to parse the POST Parameter to create a good looking form for data entry

Conclusion
Creating and Testing RESTful Services is really simple with JDeveloper 12c.

8 comments:

  1. Andreas - this doesn't work as posted. When completing the wizard, I get a warning that content cannot be supported without creating an entity provider. Ignoring the warning allows the service to be created, including the WADL, but in running the tests from the HTTP Analyzer, no content is ever transported. Ideas?
    Thanks!

    ReplyDelete
  2. Hello Nagamo,
    first of all, sorry for the late response.

    The warning "content cannot be supported without creating an entity provider" is new to me. Can't reproduce. Or maybe it has to do with unsupported Types you are using in your code. Not sure.

    I would advice to post your issue on OTN forum with concrete steps to reproduce: https://forums.oracle.com/community/developer/english/development_tools/application_development_in_java/jdeveloper_and_adf

    Sorry.

    Regards,
    Andreas

    ReplyDelete
  3. Is there a way to remove the double quotes from numerics? For example, id: "0" should be id: 0 most charting applications don't do well with numbers wrapped in double quotes.

    ReplyDelete
  4. I am not sure if it is available out of the box. But I guess you can do it with an ObjectMapper. smth like that:

    ..
    objectMapper.configure( JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS, false );
    ..

    ReplyDelete
  5. Hi Andreas. I tried this and it worked fine except for the POST method. I could not get the prompt fields for the Person object to show up. I'm using JDev 12.1.3 and I believe you were using 12.1.2. Do you know if there was some sort of change between the two?

    ReplyDelete
  6. Hi Ken,

    thanks for the feedback. Yes I tested with jdev 12.1.2. I have not tried the sample with 12.1.3 so far.

    ReplyDelete
  7. Hi Andreas,

    I'm also not able to test it as posted.I'm using Oracle Jdeveloper 12.1.3.0.0

    Thanks,
    Gaurav

    ReplyDelete
  8. Hi Andreas,
    I use the jdev 12.1.3.0.0 to create the same application as you said in this page. but i got com.sun.jersey.spi.container.servlet.ServletContainer class not found exception. and i fix it by importing
    asm-3.1.jar,
    jackson-core-asl-1.1.1.jar,
    jersey-client-1.1.5.jar,
    jersey-core-1.1.5.jar,
    jersey-json-1.1.5.jar,
    jersey-server-1.1.5.jar,
    jettison-1.1.jar,
    jsr311-api-1.1.1.jar
    However, new exception occurs
    java.lang.ClassCastException: Cannot cast oracle.wsm.agent.handler.jaxrs.RESTResourceFilterFactory to com.sun.jersey.spi.container.ResourceFilterFactory
    at java.lang.Class.cast(Class.java:3094)
    at com.sun.jersey.core.spi.component.ProviderServices.getServices(ProviderServices.java:138)
    at com.sun.jersey.server.impl.container.filter.FilterFactory.(FilterFactory.java:86)
    at com.sun.jersey.server.impl.application.WebApplicationImpl.initiate(WebApplicationImpl.java:882)
    at com.sun.jersey.server.impl.application.WebApplicationImpl.initiate(WebApplicationImpl.java:589)
    Truncated. see log file for complete stacktrace
    >
    <2015-11-4 下午03时26分24秒 CST> (FilterFactory.java:86)
    at com.sun.jersey.server.impl.application.WebApplicationImpl.initiate(WebApplicationImpl.java:882)
    at com.sun.jersey.server.impl.application.WebApplicationImpl.initiate(WebApplicationImpl.java:589)
    Truncated. see log file for complete stacktrace
    >
    <2015-11-4 下午03时26分24秒 CST>
    <2015-11-4 下午03时26分24秒 CST>
    <2015-11-4 下午03时26分24秒 CST> (FilterFactory.java:86)
    at com.sun.jersey.server.impl.application.WebApplicationImpl.initiate(WebApplicationImpl.java:882)
    at com.sun.jersey.server.impl.application.WebApplicationImpl.initiate(WebApplicationImpl.java:589)
    Truncated. see log file for complete stacktrace

    ReplyDelete