Pages

Saturday, 19 April 2014

ADF Mobile - Create a new Master Detail record

Usecase:
Suppose you have a WSDL/REST service which has a master detail kind of structure and you want to insert a new record. i.e., say, you have Dept-Emp master detail relationship and you want to insert a new department along with an employee in that department. This post helps you with such a scenario.
Pre-requisites:
Use JDev 11.1.2.4.0 with Mobile support. Have a WSDL/REST Service URL which results in master-detail DC strucutre. I have attached a sample service which is used in this example. However, I have developed the service in 12.1.2.0.0. So, you will need to run the service in the same build to get the WSDL URL and then use the URL in 11.1.2.4.0.
Steps:
Assume you have a Data Control with the structure as below:


Here, the department and employee have a master detail like relationship. To insert a new department and an employee into that department, we follow the below steps. D&D arg0 as an ADF Mobile Form.


Click Ok on the resulting Form dialog.  Similarly, D&D employeeList1 as form.


Next, D&D createNewRecord(Object) method as button.


In the Edit Action Binding, ensure the value under parameters is pointing to parameter iterator.


Deploy to emulator/device.

Snaphots
DB snaphot - Before Insertion



App snapshot:


After clicking createNewRecord, DB structure:



Wednesday, 16 April 2014

Using an external Web service (Amazon Product Advertising API) to display new book releases in ADF Mobile

Usecase:
In this blogpost, I will show you how you can consume the Amazon Product Advertising API in ADF Mobile and display the list of new book releases.

Pre-requisites:
JDeveloper 11.1.2.4.0 with Mobile extension. Some basic knowledge on the Amazon product advertising API can be obtained here.

Background:
I was recently trying to use the Amazon product advertising API to fetch the list of new book releases and display them in ADF Mobile. Amazon requires that anyone using their product advertising API must be registered as an Amazon Associate. Once you register as an Amazon associate, you get a unique associate tag. You would also require an AWS Access Key ID and secret to make calls to the Amazon web service. The details to get these are here. Once you have the keys, calls to the Product Advertising API to fetch new book releases can be made using the HTTP request like:
http://webservices.amazon.com/onca/xml?AWSAccessKeyId=######&AssociateTag=###&BrowseNodeId=283155&Operation=BrowseNodeLookup&ResponseGroup=NewReleases&Service=AWSECommerceService&Timestamp=2014-03-11T10%3A30%3A18.000Z&Version=2011-08-01&Signature=SpteidNFq2wuq15YxU2cRUEB%2BQl7dUx6ARAVhQQP%2FcM%3D

where the Timestamp and Signature are generated by Amazon for each request.
The request of this form will return ASIN and Titles of the most recently released books.
Amazon provides java code that takes care of generating the timestamp and signature for each request. However, the signature code utilizes HMAC-SHA 256 for authentication. ADF Mobile uses JDK 1.4 and unfortunately, JDK 1.4 has no support for HMAC-SHA 256. After some looking around and trying out different things, I came across http://apisigning.com/. Amazon API signing is a provision through which requests can be sent to apisigning and they internally take care of generating the signature and timestamp, and redirect you to the final URL like the one above. In this case, you can make calls to the Amazon API using the URL like:

http://free.apisigning.com/onca/xml?AWSAccessKeyId=###&Service=AWSECommerceService&Operation=BrowseNodeLookup&BrowseNodeId=283155&ResponseGroup=NewReleases&Version=2011-08-01&AssociateTag=###

Here, notice that we are making a call to free.apisigning.com. Internally, it will contact the Amazon server, sign & provide the timestamp to the request, and redirect to the webservice.amazon.com URL.

Approach:
Since we need to get the list of newly released books before the app loads, we will call the API through a java class. In the java class, we will first call api.signing.com, get the final URL with signature and timestamp, parse the response and store the response in an array. We then expose the java class as a bean DC. Once we have the data control, its the normal drag and drop approach to design the AMX page.

Steps:
1. Create an ADF Mobile application. Since we are interested in the ASIN and Title fields of the response, we create a class called NewReleases.java with these two fields and their corresponding getters and setters. This is done in the Model project.
package newReleasePack;

public class NewReleases {
    private String ASIN;
    private String Title;
    public NewReleases() {
        super();
    }
    
    public void setASIN(String ASIN) {
        this.ASIN = ASIN;
    }

    public String getASIN() {
        return ASIN;
    }

    public void setTitle(String Title) {
        this.Title = Title;
    }

    public String getTitle() {
        return Title;
    }
    
}
2. The class which will be converted to DC is named NewReleaseDCClass.java.
package newReleasePack;

import java.io.Reader;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import oracle.adfmf.dc.ws.rest.RestServiceAdapter;
import oracle.adfmf.framework.api.Model;
import oracle.adfmf.java.beans.PropertyChangeListener;
import oracle.adfmf.java.beans.PropertyChangeSupport;
import org.kxml2.io.KXmlParser;
import org.xmlpull.v1.XmlPullParser;
import sun.misc.Service;
public class NewReleaseDCClass {

    private static List newReleasesList = new ArrayList();
    private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
    public NewReleaseDCClass() {
        super();
    }
    public void setNewReleasesList(List newReleasesList) {
        List oldNewReleasesList = NewReleaseDCClass.newReleasesList;
        NewReleaseDCClass.newReleasesList = newReleasesList;
        propertyChangeSupport.firePropertyChange("newReleasesList", oldNewReleasesList, newReleasesList);
    }

    public static List getNewReleasesList() {
        return newReleasesList;
    }

    public void addPropertyChangeListener(PropertyChangeListener l) {
        propertyChangeSupport.addPropertyChangeListener(l);
    }

    public void removePropertyChangeListener(PropertyChangeListener l) {
        propertyChangeSupport.removePropertyChangeListener(l);
    }

    public NewReleases[] allNewReleases() {
        String response = "";
        try {
            HttpURLConnection ucon = null;
            URL url =
                new URL("http://free.apisigning.com/onca/xml?AWSAccessKeyId=####&Service=AWSECommerceService&Operation=BrowseNodeLookup&BrowseNodeId=283155&ResponseGroup=NewReleases&Version=2011-08-01&AssociateTag=####");
            ucon = (HttpURLConnection)url.openConnection();
            ucon.setFollowRedirects(false); //to stop auto redirect
            ucon.setInstanceFollowRedirects(false); //to stop auto redirect
            ucon.connect();
            System.out.println("Connected to free signing");
            String newUrlLoc = ucon.getHeaderField("Location"); //extract the value of Location header which contains the new URL with timestamp & signature
            System.out.println(" After  getting response code");
            ucon.disconnect(); //disconnect from free.apisigning.com
            System.out.println("After  disconnect ");
            URL newUrl = new URL(newUrlLoc); //connect to new URL to get the query parameters
            String requestQuery = newUrl.getQuery(); // get the query parameters
            
            RestServiceAdapter restServiceAdapter = Model.createRestServiceAdapter();
            restServiceAdapter.clearRequestProperties();
            restServiceAdapter.setConnectionName("conn"); //URL connection to http://webservices.amazon.com/onca/xml
            restServiceAdapter.setRequestURI("?"+requestQuery); // appending the parameters with timestamp & signature
            restServiceAdapter.setRequestType(RestServiceAdapter.REQUEST_TYPE_GET);
            restServiceAdapter.addRequestProperty("Content-Type", "text/xml;charset=UTF-8");
            restServiceAdapter.addRequestProperty("Accept", "application/xml");
            restServiceAdapter.setRetryLimit(0);
            response = restServiceAdapter.send("");
            System.out.println("Response received!" + response);
            
            //parsing the response. Refer http://stick2code.blogspot.com/2014/04/xml-parsing-in-adf-mobile.html for explanation
            KXmlParser parser = new KXmlParser(); //create a parser instance
            Reader stream = new StringReader(response);
            parser.setInput(stream);
            parser.nextTag();
            parser.require(XmlPullParser.START_TAG, null, "BrowseNodeLookupResponse");
            parser.nextTag();
            parser.require(XmlPullParser.START_TAG, null, "OperationRequest");
            parser.skipSubTree();
            parser.nextTag();
            parser.require(XmlPullParser.START_TAG, null, "BrowseNodes");
            parser.nextTag();
            parser.require(XmlPullParser.START_TAG, null, "Request");
            parser.skipSubTree();
            parser.nextTag();
            parser.require(XmlPullParser.START_TAG, null, "BrowseNode");
            parser.nextTag();
            parser.require(XmlPullParser.START_TAG, null, "BrowseNodeId");
            parser.nextText();
            parser.require(XmlPullParser.END_TAG, null, "BrowseNodeId");
            parser.nextTag();
            parser.require(XmlPullParser.START_TAG, null, "Name");
            parser.nextText();
            parser.require(XmlPullParser.END_TAG, null, "Name");
            parser.nextTag();
            parser.require(XmlPullParser.START_TAG, null, "NewReleases");
            while (parser.nextTag() != XmlPullParser.END_TAG) {
                parser.require(XmlPullParser.START_TAG, null, "NewRelease");
                NewReleases newRelaseObj = new NewReleases();
                while (parser.nextTag() != XmlPullParser.END_TAG) {
                    String tagName = parser.getName();
                    if (tagName.equals("ASIN")) {
                        String asin = parser.nextText();
                        newRelaseObj.setASIN(asin);
                    } else if (tagName.equals("Title")) {
                        String title = parser.nextText();
                        newRelaseObj.setTitle(title);
                    }
                    parser.require(XmlPullParser.END_TAG, null, tagName);
                }
                newReleasesList.add(newRelaseObj);
                parser.require(XmlPullParser.END_TAG, null, "NewRelease");
            }
            parser.require(XmlPullParser.END_TAG, null, "NewReleases");
            parser.nextTag();
            parser.require(XmlPullParser.START_TAG, null, "TopItemSet");
            parser.skipSubTree();
            parser.nextTag();
            parser.require(XmlPullParser.END_TAG, null, "BrowseNode");
            parser.nextTag();
            parser.require(XmlPullParser.END_TAG, null, "BrowseNodes");
            parser.nextTag();
            parser.require(XmlPullParser.END_TAG, null, "BrowseNodeLookupResponse");
            NewReleases[] newRel = (NewReleases[])newReleasesList.toArray(new NewReleases[newReleasesList.size()]); //store the ASIN and titles in an array
            return newRel;
        } catch (InvalidKeyException e) {
            System.out.println("InvalidKeyException" + e);
        } catch (NoSuchAlgorithmException e) {
            System.out.println("NoSuchAlgorithmException" + e);
        } catch (UnsupportedEncodingException e) {
            System.out.println("UnsupportedEncodingException" + e);
        } catch (Exception e) {
            System.out.println("Exception" + e);
            System.out.println(e.getStackTrace());
            e.printStackTrace();
        }
        return null;
    }
}

Here, the important method is allNewReleases(). In this, we are creating a HttpURLConnection to freesigning API. Since this URL redirects the request to webservices.amazon.com after appending the timestamp & signature, the HTTP response of this request is 302 and the Location header contains the new request URL. We are picking up this new URL using getHeaderField.
We are then getting the query parameters from this new URL and using restServiceAdapter.setRequestURI to set the parameters to the request. Note that the connection has been created to the URL http://webservices.amazon.com/onca/xml. This will enable us to use RestServiceAdapter for the main request. After setting other headers(done before the try block in my code), the request is sent. On receiving the response, the response is parsed and set into an array. For parsing the XML response, refer my previous blog.
3. Next, we create Bean DC out of this class, by right clicking on the class and selecting 'Create Data Control'.


4. Drop NewReleases under allNewReleases in DC palette as ADF Form. Also drop the navigation buttons and the app is ready.
Below is a snapshot. I have also used a listView to show the new releases.


Complete app can be found here. Don't forget to replace the AWSAccessKeyId and AssociateTag with the values generated for you in NewReleaseDCClass.java.

Wednesday, 9 April 2014

Parsing XML in ADF Mobile using kXML


This sample will show you how you can parse a complex XML structure using kXML parser.

The XML data that I parse is the response received from Amazon Product Advertising API. It has the structure as shown in the attached XML. I am particularly interested in the values held by the ASIN and the Title tags, which I am pushing into a list.

A snapshot of the XML structure is shown below:


So, in the backing bean, the kXML parser code for this will look like below:

            KXmlParser parser = new KXmlParser(); //create a parser instance
            Reader stream = new StringReader(response); //response holds the XML
            parser.setInput(stream);
            parser.nextTag(); //go to first tag
            //Verify the tag name is BrowseNodeLookupResponse
            parser.require(XmlPullParser.START_TAG, null, "BrowseNodeLookupResponse");
            parser.nextTag(); //go to next tag
            //Verify the tag name is OperationRequest
            parser.require(XmlPullParser.START_TAG, null, "OperationRequest");
            parser.skipSubTree(); //not interested in these tags, so skip the whole set
            parser.nextTag(); //go to next tag
            parser.require(XmlPullParser.START_TAG, null, "BrowseNodes");
            parser.nextTag();
            parser.require(XmlPullParser.START_TAG, null, "Request");
            parser.skipSubTree();
            parser.nextTag();
            parser.require(XmlPullParser.START_TAG, null, "BrowseNode");
            parser.nextTag();
            parser.require(XmlPullParser.START_TAG, null, "BrowseNodeId");
            parser.nextText();
            parser.require(XmlPullParser.END_TAG, null, "BrowseNodeId");
            parser.nextTag();
            parser.require(XmlPullParser.START_TAG, null, "Name");
            parser.nextText(); //Name tag contains text data, so use nextText
            //Verify closing tag of Name is present
            parser.require(XmlPullParser.END_TAG, null, "Name");
            parser.nextTag();
            parser.require(XmlPullParser.START_TAG, null, "NewReleases");
            //loop through contents of NewReleases
            while (parser.nextTag() != XmlPullParser.END_TAG) {
                parser.require(XmlPullParser.START_TAG, null, "NewRelease");
                NewReleases newRelaseObj = new NewReleases();
                //loop through the NewRelelase tags
                while (parser.nextTag() != XmlPullParser.END_TAG) {
                    String tagName = parser.getName();//get the name if the tag
                    if (tagName.equals("ASIN")) {
                        String asin = parser.nextText();//contents of tag
                        newRelaseObj.setASIN(asin);//push into the list
                    } else if (tagName.equals("Title")) {
                        String title = parser.nextText();
                        newRelaseObj.setTitle(title);
                    }
                    parser.require(XmlPullParser.END_TAG, null, tagName);
                }
                newReleasesList.add(newRelaseObj);
                parser.require(XmlPullParser.END_TAG, null, "NewRelease");
            }
            parser.require(XmlPullParser.END_TAG, null, "NewReleases");
            parser.nextTag();
            parser.require(XmlPullParser.START_TAG, null, "TopItemSet");
            parser.skipSubTree();
            parser.nextTag();
            parser.require(XmlPullParser.END_TAG, null, "BrowseNode");
            parser.nextTag();
            parser.require(XmlPullParser.END_TAG, null, "BrowseNodes");
            parser.nextTag();
            parser.require(XmlPullParser.END_TAG, null, "BrowseNodeLookupResponse");
            :
            :
The explanation for the parser code is inline. Do check my other blog where this parsed XML data comes into action.

Sunday, 6 April 2014

Jquery Not able to find Form by Name

I started out writing a form and at one point got stuck as the jquery that i wrote just refused to identify my form. The first thing i checked was the page source and it did have the form element.Now this was very strange as i was not able to retrieve the node no matter what i did.
When i checked the nodes for the element i could see that the form was missing, I was able to retrieve the parent as well as the child of this form.

Solution:
Added an id to the parent div of the form and then wrote the output to console using document.getElementById('parentDivId'), and I could see that the resulting html did not contain the form tag, but the view page source did show the tags. The issue was that the form that i was trying to access was actually wrapped around another form tag, thus the browser was ignoring this form node at runtime, hence it was appearing in page source but not in the actual run time DOM. Usually nesting a form tag gives an error on the jsp editor, but the reason why i was not able to catch this was because my child form was being added using a tag.

Conclusion:
Ensure that form tag is never nested. 

Wednesday, 2 April 2014

Intercept HTTP Requests sent from browser on the Android Emulator

Usecase:
In my previous post, I showed you how you can intercept/monitor HTTP requests arising from your app deployed on the emulator. In this post, I will show you how the requests arising from the emulator's browser can be intercepted/monitored using HTTP Analyzer.

Steps:
At JDeveloper End:
Same as my last post. Note down the host and port values.

At Android Emulator end:
Follow the below steps to ensure that the browser requests go via the HTTP Analyzer.












In the Edit Access Point screen, change the proxy to 10.0.2.2 and port to the HTTP Analyzer port. Retain other values as shown.



 Now, if you open a browser on the emulator and try to open a site, you will get a certificate pop up.


Click Continue on it and you can now see the HTTP requests going through the HTTP Analyzer.


Intercept HTTP Requests sent from app on Android emulator

Usecase:
In this usecase, I will show you how you can track HTTP requests fired from a custom application deployed on the Android emulator. We will be tracking the requests using HTTP Analyzer, which is an in-built tool provided by JDeveloper. This is especially handy if you are using ADF Mobile and want to monitor your HTTP/web service requests.

Steps:
At JDeveloper end:
In JDeveloper, go to Tools-> HTTP Analyzer. The analyzer window opens up next to server console. Click on Analyzer Preferences.



Note down the host and port values.Also, start the HTTP Analyzer.



At Android emulator end:
Close the emulator if it is open. Go to the folder in which 'emulator' resides (In my case, it was something like C:\Android\adt-bundle-windows-x86_64-20130219\sdk\tools) and invoke a command prompt. Type in the command:

emulator -avd emuName -http-proxy http://<SYSTEM_IP>:<PORT>

where emuName should be replaced with your emulator instance's name; SYSTEM_IP should be replaced with your system's IP address and PORT should be the port where HTTP Analyzer is running(noted down previously).
This will start the android emulator for you and redirect all the requests through the HTTP Analyzer.
That's it! Run your app on the emulator and you should be able to see the requests being logged in HTTP Analyzer.

Sample interception:



Tuesday, 1 April 2014

SOLVED: ExpressionFactory NoSuchMethodError while Saving

While Working with spring using jpa(Hibernate) for persistance got the below error related to no NoSuchMethodError. On checking further noticed that this happened when the an attempt was being done to save the record.
Solution :: Change the jsp-api version to 2.2

java.lang.NoSuchMethodError: javax.el. .newInstance()Ljavax/el/ExpressionFactory;
 at org.hibernate.validator.internal.engine.messageinterpolation.InterpolationTerm.(InterpolationTerm.java:60)
 at org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator.interpolateExpression(ResourceBundleMessageInterpolator.java:227)
 at org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator.interpolateMessage(ResourceBundleMessageInterpolator.java:187)
 at org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator.interpolate(ResourceBundleMessageInterpolator.java:120)
 at org.springframework.validation.beanvalidation.LocaleContextMessageInterpolator.interpolate(LocaleContextMessageInterpolator.java:50)
 at org.hibernate.validator.internal.engine.ValidationContext.interpolate(ValidationContext.java:370)
 at org.hibernate.validator.internal.engine.ValidationContext.createConstraintViolation(ValidationContext.java:284)
 at org.hibernate.validator.internal.engine.ValidationContext.createConstraintViolations(ValidationContext.java:246)
 at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.validateSingleConstraint(ConstraintTree.java:289)
 at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.validateConstraints(ConstraintTree.java:133)
 at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.validateConstraints(ConstraintTree.java:91)
 at org.hibernate.validator.internal.metadata.core.MetaConstraint.validateConstraint(MetaConstraint.java:85)
 at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraint(ValidatorImpl.java:478)
 at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForDefaultGroup(ValidatorImpl.java:424)
 at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForCurrentGroup(ValidatorImpl.java:388)
 at org.hibernate.validator.internal.engine.ValidatorImpl.validateInContext(ValidatorImpl.java:340)
 at org.hibernate.validator.internal.engine.ValidatorImpl.validate(ValidatorImpl.java:158)
 at org.hibernate.cfg.beanvalidation.BeanValidationEventListener.validate(BeanValidationEventListener.java:137)
 at org.hibernate.cfg.beanvalidation.BeanValidationEventListener.onPreInsert(BeanValidationEventListener.java:95)
 at org.hibernate.action.internal.EntityIdentityInsertAction.preInsert(EntityIdentityInsertAction.java:202)
 at org.hibernate.action.internal.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:91)
 at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:480)
 at org.hibernate.engine.spi.ActionQueue.addResolvedEntityInsertAction(ActionQueue.java:191)
 at org.hibernate.engine.spi.ActionQueue.addInsertAction(ActionQueue.java:175)
 at org.hibernate.engine.spi.ActionQueue.addAction(ActionQueue.java:210)
 at org.hibernate.event.internal.AbstractSaveEventListener.addInsertAction(AbstractSaveEventListener.java:324)
 at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:288)
 at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:194)
 at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:125)
 at org.hibernate.jpa.event.internal.core.JpaPersistEventListener.saveWithGeneratedId(JpaPersistEventListener.java:84)
 at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:206)
 at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:149)
 at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:75)
 at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:807)
 at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:780)
 at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:785)
 at org.hibernate.jpa.spi.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:1181)
 at sun.reflect.GeneratedMethodAccessor17.invoke(Unknown Source)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
 at java.lang.reflect.Method.invoke(Method.java:606)
 at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:257)
 at com.sun.proxy.$Proxy33.persist(Unknown Source)
 at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:358)
 at sun.reflect.GeneratedMethodAccessor16.invoke(Unknown Source)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
 at java.lang.reflect.Method.invoke(Method.java:606)
 at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:358)
 at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:343)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
 at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:98)
 at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:262)
 at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
 at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
 at org.springframework.data.jpa.repository.support.LockModeRepositoryPostProcessor$LockModePopulatingMethodIntercceptor.invoke(LockModeRepositoryPostProcessor.java:92)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
 at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
 at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
 at com.sun.proxy.$Proxy35.save(Unknown Source)
 at com.test.amazon.core.AmazonItemRepositoryService.saveAmazonItemEntity(AmazonItemRepositoryService.java:16)
 at com.test.amazon.core.AmazonItemRepositoryService$$FastClassBySpringCGLIB$$a7cf6840.invoke()
 at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
 at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:711)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
 at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:98)
 at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:262)
 at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
 at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
 at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:644)

The erorr is quite informative that the method newInstance is not found, which was the case when the actaul method was checked. The root cause for this error is the use of the class ExpressionFactory did not contain the method newInstance as the methods were introduced in jsp-api 2.2.
Maven dependency causing Error:

  <dependency>
   <groupid>javax.servlet.jsp</groupid>
   <artifactid>jsp-api</artifactid>
   <version>2.1</version>
   <scope>provided</scope>
  </dependency>


The issue is resolved with the below Maven dependency:

  <dependency>
   <groupid>javax.servlet.jsp</groupid>
   <artifactid>jsp-api</artifactid>
   <version>2.2</version>
   <scope>provided</scope>
  </dependency>