Sunday, July 17, 2016

Workaround for ADF BC REST Custom Method Configuration

This post is based on JDEV 12.2.1.1, it seems like there is issue with ADF BC REST custom method definition in this release. I'm glad it is not runtime issue, but related to design time JDEV wizard incorrect functionality. I will explain how to bypass it, when you want to expose custom REST method in 12.2.1.1.

Sample application (ADFBCRestApp_v8.zip) implements custom method, exposed through ADF BC REST - calculateEmployees. This method is created in VO Implementation class and it accepts two parameters - firstName and lastName. Method works correctly, I can execute it through POST, by passing predefined payload with method name and parameters (read more in developer guide - 22.12.5 Executing a Custom Action):


Make sure not to forget to specify Content-Type, otherwise POST request to ADF BC REST will fail:


Let's see custom method implementation and where workaround is required. Custom method is using View Criteria to filter VO and return estimated row count. All fine here:


Method should be exposed through VO client interface:


We should generate custo method binding registry in REST resource custom methods section (client interface). In JDEV 12.2.1 this works by clicking checkbox for Enable, but in JDEV 12.2.1.1 the same throws error (can't enable custom method to be called through REST):


Luckily there is a workaround. We can define method binding manually, go to source mode in REST resource definition dialog and add methodAction for custom method. You can replace method name, ID, instance name, etc. REST resource definition looks very similar to page definition file we are using to define bindings available for ADF Faces. ADF BC REST interface seems to be designed on common principles with ADF bindings, at least from definition point of view:

12 comments:

Giuseppe said...

I followed your instructions, I created a simple HelloWorld method exposed througth a VO. I pasted the following string in pageDefinition (xml at AM level)

MethodName="halloWord" IsViewObjectMethod="true" DataControl="RestServicesAMDataControl"
InstanceName="data.RestServicesAMDataControl.TaskTreeLevelVO"
ReturnName="data.RestServicesAMDataControl.methodResults.halloWord_RestServicesAMDataControl_TaskTreeLevelVO_halloWord_result"
IterBinding="TaskTreeLevelVOIter" >



My method is

public String halloWord(String name){
System.out.println("sono entrato");

return "hallo "+ name;
}

And i call it with a POST like this

POST /SimpleRestServices-RESTWebService-context-root/rest/v1/TaskTreeLevel HTTP/1.1
HOST: 127.0.0.1:7101
content-type: application/x-www-form-urlencoded
content-length: 108

{
"name": "halloWord",
"parameters": [
{
"name": "John"
}
]
}

But I got the following exception

WatchData: MESSAGE = [ServletContext@2006521797[app:SimpleRestServices module:SimpleRestServices-RESTWebService-context-root path:null spec-version:3.1]] Servlet failed with an Exception
oracle.jbo.JboException: JBO-29114 ADFContext is not setup to process messages for this exception. Use the exception stack trace and error code to investigate the root cause of this exception. Root cause error code is JBO-29000. Error message parameters are {0=oracle.xml.parser.v2.XMLParseException, 1=Expected name instead of .}
at oracle.jbo.uicli.mom.CpxUtils.getCpxListFromMetadata(CpxUtils.java:512)
at oracle.jbo.uicli.mom.JUMetaObjectManager.loadCpx(JUMetaObjectManager.java:915)
at oracle.adf.model.BindingContext.initialize(BindingContext.java:469)
...
Caused By: oracle.xml.parser.v2.XMLParseException; lineNumber: 4; columnNumber: 22; Expected name instead of .
at oracle.xml.parser.v2.XMLError.flushErrors1(XMLError.java:326)
at oracle.xml.parser.v2.XMLReader.scanNameChars(XMLReader.java:1313)

But I cannot find the corrupted xml. Is there a solution to this problem?

Andrej Baranovskij said...

Yes, you should search for the mistype in your XML code.

Regards,
Andrejus

Alfredo Rodríguez said...

Hi Andrejus,

Good job! it's very useful. I would like if is possible call to service that's a view with bind variable and return row? I don't know if it's possible directly or by method. In my case query it takes a lot of time and I need pass a parameter.

Regards,
Alfre.

Andrej Baranovskij said...

Yes, this is possible - we can use VO Bind Variables in ADF BC REST call. I will explain it in my next posts.

Regards,
Andrejus

Giuseppe said...

Hi Andrejus, I cannot find the XML (I send a JSON text and not XML).

I didn't write any xml file (except the xml in your post, but I have already checked it)

Is there a way to find the corrupted xml (JDeveloper doesn't display errors)?

Andrej Baranovskij said...

Something must be corrupted in your app - try to create again and follow step by step example from my post.

Andrejus

Anonymous said...

Hi Andrejus,

All work fine but I'm having an issue with the returned JSON format, since I'm returning a toString of a JSONArray Object.

Before returning to the consumer the result format is correct when printed on the console:

{"Salary":3000,"Email":"KFEENEY","FirstName":"Kevin","CommissionPct":null,"DepartmentsVO":oracle.jbo.server.ViewRowSetImpl@4f54f346,"PhoneNumber":"650.507.9822","HireDate":2006-05-23 00:00:00.0,"LastName":"Feeney","DepartmentId":50,"EmployeesVO":oracle.jbo.server.ViewRowSetImpl@30375970,"EmployeeId":197,"JobId":"SH_CLERK","ManagerId":124}



After returning to the consumer(using Potsman) the result format is not correct(presence of escapes backslashes):

{
"result" : "{\"Salary\":3000,\"Email\":\"KFEENEY\",\"FirstName\":\"Kevin\",\"CommissionPct\":null,\"DepartmentsVO\":oracle.jbo.server.ViewRowSetImpl@22889d95,\"PhoneNumber\":\"650.507.9822\",\"HireDate\":2006-05-23 00:00:00.0,\"LastName\":\"Feeney\",\"DepartmentId\":50,\"EmployeesVO\":oracle.jbo.server.ViewRowSetImpl@59a60685,\"EmployeeId\":197,\"JobId\":\"SH_CLERK\",\"ManagerId\":124}"
}

Thank you very much.

Kiran K said...

Can you please let me know whether this is supported in 11g (Studio Edition Version 11.1.1.9.0).

Andrej Baranovskij said...

No, ADF BC REST is available from 12.2.1

Regards,
Andrejus

Sarah Justina said...

Hi Andrejus,
How do I invoke a custom VO method exposed in REST from JET?
I'm using an oj.Collection. How do I set the method name and parameters before I call collection.refresh()?
Assume my parameters are like
{
"name" : "execEmpSearch",
"parameters" : [
{
"firstName" : "Steven"
},
{
"lastName" : "King"
}
]
}
Could you help me or point me to some documentation?

Regards,
Sarah

Andrej Baranovskij said...

Hi,

You cant call custom REST method through oj.Collection. You should use Ajax POST call to do this. In this example I'm calling custom ADF BC REST method through POST: http://andrejusb.blogspot.lt/2016/10/oracle-jet-and-adf-bc-rest-security.html

Andrejus

Sarah Justina said...

Hi Andrejus,
Thank you. Worked like a charm.

Regards,
Sarah