X
  • ADF
    October 17, 2013

Simple GET operation with JSON data in ADF Mobile

Guest Author

Usecase:

This sample uses a RESTful service which contains a GET
method that fetches employee details for an employee with given employee ID
along with other methods. The data is fetched in JSON format.

This RESTful service is then invoked via ADF Mobile and the
JSON data thus obtained is parsed and rendered in mobile in a table.

Prerequisite:

Download JDev build JDEVADF_11.1.2.4.0_GENERIC_130421.1600.6436.1
or higher with mobile support. 

Steps:

Create a REST service using three classes, Employee.java, EmployeeList.java and EmployeeService.java (as shown below). EmployeeService.java will function as the main RESTful service class.This is a
simple service with a method, getEmpById(id) that takes employee ID as
parameter and produces employee details in JSON format. 

package project1;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class Employee {
String name;
int id;
String desig;
int salary;
public void setDesig(String desig) {
this.desig = desig;
}
public String getDesig() {
return desig;
}
public void setSalary(int salary) {
this.salary = salary;
}
public int getSalary() {
return salary;
}
public void setDept(String dept) {
this.dept = dept;
}
public String getDept() {
return dept;
}
String dept;
public Employee() {
super();
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setId(int id) {
this.id = id;
}
public int getId() {
return id;
}
}

package project1;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlElement;
@XmlRootElement
public class EmployeeList {
private List list = new ArrayList();
public EmployeeList() {
}
public EmployeeList(List list) {
super();
this.list = list;
}

@XmlElement
public List getList() {
return list;
}
}

package project1;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
@Path("project1")
public class EmployeeService {
private static List employeeList = new CopyOnWriteArrayList();
public EmployeeService() {
addEmp();
}
@GET
@Produces("application/json")
public EmployeeList getEmpList() {
return new EmployeeList(employeeList);
}
@PUT
@Consumes("application/json")
@Produces("application/json")
public EmployeeList addEmployee(Employee emp) {
employeeList.add(emp);
return new EmployeeList(employeeList);
}
@DELETE
@Produces("application/json")
public EmployeeList deleteEmployee(@QueryParam("name") String name) {
employeeList.remove(getEmp(name));
return new EmployeeList(employeeList);
}
@POST
@Produces("application/json")
public EmployeeList updateEmployee(@QueryParam("id") int id,@QueryParam("name") String name) {
Employee emp1 = new Employee();
emp1 = getEmpById(id);
if(emp1 != null)
emp1.setName(name);
return new EmployeeList(employeeList);
}
public Employee getEmp(String name) {
Iterator i = employeeList.iterator();
while (i.hasNext()) {
Employee e = (Employee)i.next();
if (e.getName().equalsIgnoreCase(name))
return e;
}
return null;
}
@GET
@Produces("application/json")
@Path("/getById/{id}")
public Employee getEmpById(@PathParam("id") int id) {
Iterator i = employeeList.iterator();
while (i.hasNext()) {
Employee e = (Employee)i.next();
if (e.getId() == id)
return e;
}
return null;
}
public void addEmp() {
if (employeeList.isEmpty()) {
Employee emp1 = new Employee();
emp1.setId(1);
emp1.setName("Arnold");
emp1.setDept("IT");
emp1.setDesig("Director");
emp1.setSalary(80000);
employeeList.add(emp1);
Employee emp2 = new Employee();
emp2.setId(2);
emp2.setName("Myra");
emp2.setDept("HR");
emp2.setDesig("Officer");
emp2.setSalary(5000);
employeeList.add(emp2);
}
}
}

Copy the target URL generated on running this service. The
target URL will be as shown below:

http://127.0.0.1:7101/JSONService-Project1-context-root/jersey/project1

Now, let us invoke this service in our mobile application.
For this, create an ADF Mobile application. 

Gallery

Name the application JSON_SearchByEmpID
and finish the wizard.

appName

Now, let us create a connection to our service. To do this,
we create a URL Connection. Invoke new gallery wizard on ApplicationController
project. 

newGallery

Select URL Connection option.

urlConn

In the Create URL Connection window, enter connection name
as ‘conn’. For URL endpoint, supply
the URL you copied earlier on running the service. Remember to use your system
IP instead of localhost. Test the connection and click OK.

conn

At this point, a connection to the REST service has been
created.

Since JSON data is not supported directly in WSDC wizard, we
need to invoke the operation through Java code using RestServiceAdapter. For
this, in the ApplicationController project, create a Java class called ‘EmployeeDC’.
We will be creating DC from this class.

javaclass

Add
the following code to the newly created class to invoke the getEmpById method.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

public Employee fetchEmpDetails(){

RestServiceAdapter
restServiceAdapter = Model.createRestServiceAdapter();

restServiceAdapter.clearRequestProperties();

restServiceAdapter.setConnectionName("conn"); //URL
connection created with this name

restServiceAdapter.setRequestType(RestServiceAdapter.REQUEST_TYPE_GET);

restServiceAdapter.addRequestProperty("Content-Type",
"application/json");

restServiceAdapter.addRequestProperty("Accept",
"application/json; charset=UTF-8");

restServiceAdapter.setRetryLimit(0);

restServiceAdapter.setRequestURI("/getById/"+inputEmpID);

String response =
"";

JSONBeanSerializationHelper jsonHelper = new
JSONBeanSerializationHelper();

try {

response =
restServiceAdapter.send(""); //Invoke the GET operation

System.out.println("Response
received!");

Employee
responseObject = (Employee) jsonHelper.fromJSON(Employee.class, response);

return
responseObject;

} catch (Exception e)
{

}

return null;

}

Here, in lines
2 to 9, we create the RestServiceAdapter and set various properties required to
invoke the web service. At line 4, we are pointing to the connection ‘conn’ created previously.

Since we want to invoke getEmpById method of the service,
which is defined by the URL

http://IP:7101/REST_Sanity_JSON-Project1-context-root/resources/project1/getById/{id}

we are
updating the request URI to point to this URI at line 9. inputEmpID is
a variable that will hold the value input by the user for employee ID. This we
will be creating in a while.

As the
method we are invoking is a GET operation and consumes json data, these
properties are being set in lines 5 through 7. Finally, we are sending the
request in line 13.

In line 15, we use jsonHelper.fromJSON to
convert received JSON data to a Java object. The required Java objects' structure
is defined in class Employee.java whose structure is provided later. Since the
response from our service is a simple response consisting of attributes like
employee Id, name, design etc, we will just return this parsed response (line 16)
and use it to create DC.

As mentioned
previously, we would like the user to input the employee ID for which he/she
wants to perform search. So, in the same class, define a variable inputEmpID which will hold the value
input by the user. Generate accessors for this variable.

accessor

Lastly, we
need to create Employee class. Employee class will define how we want to
structure the JSON object received from the service. To design the Employee
class, run the services’ method in the browser or via analyzer using path
parameter as 1. This will give you the output JSON structure.

jsonOutput

Ours is a
simple service that returns a JSONObject with a set of data. Hence, Employee
class will just contain this set of data defined with the proper data types.

Create Employee.java
in the same project as EmployeeDC.java and write the below code:

package application;

import oracle.adfmf.java.beans.PropertyChangeListener;

import oracle.adfmf.java.beans.PropertyChangeSupport;

public class Employee {

private String dept;

private String desig;

private int id;

private String name;

private int salary;

private PropertyChangeSupport
propertyChangeSupport = new PropertyChangeSupport(this);

public void setDept(String
dept) {

        String oldDept = this.dept;

this.dept = dept;

propertyChangeSupport.firePropertyChange("dept", oldDept,
dept);

}

public String getDept() {

return dept;

}

public void setDesig(String
desig) {

String oldDesig =
this.desig;

this.desig = desig;

propertyChangeSupport.firePropertyChange("desig", oldDesig,
desig);

}

public String getDesig() {

return desig;

}

public void setId(int id) {

int oldId = this.id;

this.id = id;

propertyChangeSupport.firePropertyChange("id",
oldId, id);

}

public int getId() {

return id;

}

public void setName(String name) {

String oldName = this.name;

this.name = name;

propertyChangeSupport.firePropertyChange("name",
oldName, name);

}

public String getName() {

return name;

}

public void setSalary(int
salary) {

int oldSalary =
this.salary;

this.salary = salary;

propertyChangeSupport.firePropertyChange("salary", oldSalary,
salary);

}

public int getSalary() {

return salary;

}

public void
addPropertyChangeListener(PropertyChangeListener l) {

propertyChangeSupport.addPropertyChangeListener(l);

}

public void
removePropertyChangeListener(PropertyChangeListener l) {

propertyChangeSupport.removePropertyChangeListener(l);

    }

}

Now, let us create a DC out of EmployeeDC.java.

createDC

 DC as shown below is created.

DC

Now, you can
design the mobile page as usual and invoke the operation of the service. To
design the page, go to ViewController project and locate adfmf-feature.xml.
Create a new feature called ‘SearchFeature
by clicking the plus icon.

feature

Go the content tab and add an amx page. Call it SearchPage.amx.

createPage

Call it SearchPage.amx. Remove primary and secondary buttons as we don’t need them and rename the header.

preview

Drag and drop inputEmpID from the DC palette onto Panel Page in the structure pane as
input text with label.

inputText

Next, drop
fetchEmpDetails method as an ADF button.

fetchButton

For a change,
let us display the output in a table component instead of the usual form.
However, you will notice that if you drag and drop Employee onto the structure
pane, there is no option for ADF Mobile Table. Hence, we will need to create
the table on our own.

To do this, let us first drop Employee as an ADF Read -Only form. This step is needed to
get the required bindings. We will be deleting this form in a while.

form

finalPage

Now, from
the Component palette, search for ‘Table Layout’. Drag and drop this below the
command button. 

table tableStructure

Within the
tablelayout, insert ‘Row Layout’ and ‘Cell Format’ components. Final table structure
should be as shown below. Here, we have also defined some inline styling to
render the UI in a nice manner.

<amx:tableLayout id="tl1" borderWidth="2"
halign="center" inlineStyle="vertical-align:middle;"

width="100%" cellPadding="10">

<amx:rowLayout
id="rl1" >

<amx:cellFormat
id="cf1" width="30%">

<amx:outputText
value="#{bindings.dept.hints.label}" id="ot7"
inlineStyle="color:rgb(0,148,231);"/>

</amx:cellFormat>

<amx:cellFormat
id="cf2">

<amx:outputText
value="#{bindings.dept.inputValue}" id="ot8" />

</amx:cellFormat>

</amx:rowLayout>

<amx:rowLayout
id="rl2">

<amx:cellFormat
id="cf3" width="30%">

<amx:outputText
value="#{bindings.desig.hints.label}" id="ot9"
inlineStyle="color:rgb(0,148,231);"/>

</amx:cellFormat>

<amx:cellFormat id="cf4"
>

<amx:outputText
value="#{bindings.desig.inputValue}" id="ot10"/>

</amx:cellFormat>

</amx:rowLayout>

<amx:rowLayout
id="rl3">

<amx:cellFormat
id="cf5" width="30%">

<amx:outputText
value="#{bindings.id.hints.label}" id="ot11"
inlineStyle="color:rgb(0,148,231);"/>

</amx:cellFormat>

<amx:cellFormat
id="cf6" >

<amx:outputText
value="#{bindings.id.inputValue}" id="ot12"/>

</amx:cellFormat>

</amx:rowLayout>

<amx:rowLayout
id="rl4">

<amx:cellFormat
id="cf7" width="30%">

<amx:outputText
value="#{bindings.name.hints.label}" id="ot13"
inlineStyle="color:rgb(0,148,231);"/>

</amx:cellFormat>

<amx:cellFormat
id="cf8">

<amx:outputText
value="#{bindings.name.inputValue}" id="ot14"/>

</amx:cellFormat>

</amx:rowLayout>

<amx:rowLayout
id="rl5">

<amx:cellFormat
id="cf9" width="30%">

<amx:outputText
value="#{bindings.salary.hints.label}" id="ot15"
inlineStyle="color:rgb(0,148,231);"/>

</amx:cellFormat>

<amx:cellFormat
id="cf10">

<amx:outputText
value="#{bindings.salary.inputValue}" id="ot16"/>

</amx:cellFormat>

</amx:rowLayout>

    </amx:tableLayout>

The values
used in the output text of the table come from the bindings obtained from the
ADF Form created earlier. As we have used the bindings and don’t need the form
anymore, let us delete the form. 

tableImg

One last thing before we deploy. When user changes employee ID, we want to clear the
table contents. For this we associate a value change listener with the input
text box.

valChange

Click New in the resulting dialog to create a managed bean.

valChangeDialog managedBean

Next, we create a method within the managed bean. For this, click on the New button
associated with method. Call the method ‘empIDChange’.

newMethod empIDChange

Open
myClass.java and write the below code in empIDChange().

public void empIDChange(ValueChangeEvent valueChangeEvent) {

// Add event code here...

//Resetting the values to
blank values when employee id changes

AdfELContext adfELContext =
AdfmfJavaUtilities.getAdfELContext();

ValueExpression ve =
AdfmfJavaUtilities.getValueExpression("#{bindings.dept.inputValue}",
String.class);

ve.setValue(adfELContext,
"");

ve =
AdfmfJavaUtilities.getValueExpression("#{bindings.desig.inputValue}",
String.class);

ve.setValue(adfELContext,
"");

ve =
AdfmfJavaUtilities.getValueExpression("#{bindings.id.inputValue}",
int.class);

ve.setValue(adfELContext,
"");

ve =
AdfmfJavaUtilities.getValueExpression("#{bindings.name.inputValue}",
String.class);

ve.setValue(adfELContext,
"");

ve =
AdfmfJavaUtilities.getValueExpression("#{bindings.salary.inputValue}",
int.class);

ve.setValue(adfELContext,
"");

}

That’s it. Deploy the application to android emulator or device. Some snippets from the app.

Snapshot1 Snapshot2

Join the discussion

Comments ( 3 )
  • guest Wednesday, February 26, 2014

    Getting connection refused exception when trying to invoke the REST service for GET operation.

    It says cannot connect localhost on port 7101 connection refused.. How to overcome this issue.


  • Padmaja Thursday, February 27, 2014

    Verify that you have used your system IP address instead of localhost while

    creating URL Connection. Also, check the port at which your service is deployed

    and point to that port.


  • guest Thursday, February 27, 2014

    Changing from localhost to System IP address worked. Thank You.


Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.