Friday, September 25, 2015

Google Analytics Reporting

This document shows that how to create a custom google analytics report to analyze a web application and its users behavior.
Create a Sample Web Application using Eclipse
In the example below we have created a sample Dynamic Web Application “DynoWeb” using Eclipse with few test jsp pages.
Map localhost 8080 to a domain using fiddler:
Google Analytics requires us to provide a valid domain to generate a analytics report, hence we can’t configure localhost:8080.
As a workaround we can use Fiddler to map the localhost:8080 to point a logical domain name
1.       Download and Install Fiddler
2.       Navigate to Fiddler menu:- Tools > HOSTS.. (Click to select)
3.       Add a line like this in the dialog that appears :
localhost:8080 www.sanjay-local-dev.com



  1. Save the file & then check out your application url using following domain name instead of localhost:8080.
i.e. http://www.sanjay-local-dev.com/DynoWeb/index.jsp

Create a google analytics account for your web application
Now create a google analytics account with the domain: http://www.sanjay-local-dev.com
It requires you to provide some basic information like Property name, default URL, Industry category etc. Once successfully created it will provide you a Tracker ID (i.e. UA-68126XXX-1) which you will need to provide in your page within google analytics script.
Add the google analytics script to your page.
Now as we have created a google analytics account, we are ready to enable our jsps to start reporting data to google.
Add the following in your jsp page before the end of <head> tag.
<script>
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','//www.google-analytics.com/analytics_debug.js','ga');

  ga('create', '<<UA-XXXXXXXX-X>>', {
         'cookieDomain': 'none'
       });

  ga('send', 'pageview');

</script>

Note :
·         Replace the highlighted tracker id <<UA-XXXXXXXX-X>> with the one generated for you.
·         We have added 'cookieDomain': 'none' to enable the testing from localhost.

Test your google analytics report.
You can test your google analytics report to verify if your pages are sending the data to google correctly.
To see your report:
1.      Sign in to your Google Analytics account.
2.      Navigate to your view.
3.      Select the Reporting tab.
4.      Select Audience Overview from Left menu.
5.      You should be able to see your first google analytics report. If you see some activities in your report, it means its configured correctly.



Testing Real Time data:
You can also monitor activity as it happens on your site or app. Real-Time allows you to monitor activity as it happens on your site or app. The reports are updated continuously and each hit is reported seconds after it occurs. For example, you can see how many people are on your site right now, which pages or events they're interacting with, and which goal conversions have occurred.
To see Real-Time:
6.      Sign in to your Google Analytics account.
7.      Navigate to your view.
8.      Select the Reporting tab.
9.      Select Real-Time.




Creating Custom Dimensions and Metrics


Dimensions and metrics go hand in hand.  We can create a custom dimension and Metrics to generate the report for any application specific entity which is not covered by google, for example a healthcare blog can create a dimension for analyzing how many users of certain age group read about a specific disease. You can define dimension as an agegroup and then create different metrices around it (i.e. Parkinson, Lukemia, Arthiritis etc).

Report would look like this :

----------------------------------------------------------------------------------------------------------------
AgeGroup                             |     Parkinson                 | Lukemia               |  Arthiritis
----------------------------------------------------------------------------------------------------------------
30-40                                    |     1980                         | 789                        |  1200
----------------------------------------------------------------------------------------------------------------
40-50                                    |     3420                         | 900                        |  1200
----------------------------------------------------------------------------------------------------------------
50-60                                    |     1000                         | 2502                        |  5020
----------------------------------------------------------------------------------------------------------------
60-70                                    |     400                           | 990                        |  1723
----------------------------------------------------------------------------------------------------------------








 Creates a Custom Report

We can create a Custom report and add the custom Dimensions and metrics to this custom report.









Tuesday, August 11, 2015

A sample project using Spring MVC, Jquery and JQGrid to display the list of Object returned as a JSON object:

Following is a sample project using Spring MVC, Jquery and JQGrid to display the list of Employees returned as a JSON object:

The jsp in screenshot shows the list of employees.

I assume the user already knows how spring MVC works, so I am not explaining how Spring MVC works in this post.

You can download this sample maven project from github. 
https://github.com/SanjayIngole/jqgrid-example-parent

Here is an overview:
1. Jquery makes an Ajax call in Spring Controller method to get the ArrayList of objects (Employees).


 $.when($.getJSON('/jqgridexample/views/web/getemployees')).then(function (data) {

.....
 Rest of the code
....

));

2. In Spring Controller we map a method getEmployees to url '/web/getemployees' called from jquery. 
This method returns the ArrayList of Employees. Spring MVC takes care of converting this to a JSON Object.

@RequestMapping(value = "/web/getemployees", method = RequestMethod.GET)
public @ResponseBody
ArrayList<Employee> getEmployees(HttpServletRequest request) {


final ArrayList<Employee> employees = getMockEmployees();

return employees;
}

3. Jquery receives a list of employees as a JSON object.

[{"empID":100,"firstName":"John","lastName":"Oliver","address":"123 Hollywood Blvd, LA","phone":"4572312222"},{"empID":101,"firstName":"Barack","lastName":"Obama","address":"001 White House, DC","phone":"1010100101"},{"empID":102,"firstName":"Tom","lastName":"Cruise","address":"333 Sunset Blvd, LA","phone":"8272828222"},{"empID":103,"firstName":"Ed","lastName":"Sheeran","address":"6377 Kings Drive, London","phone":"9298292222"}]

4. This list is used to populate the jqgrid. In this case we are mapping individual fields before passing to jqgrid.

$("#employees").jqGrid({
   datatype: "local",
   height: 250,
   width: 700,
   colNames: ['EMPLOYEE ID', 'FIRST NAME', 'LAST NAME', 'ADDRESS', 'PHONE'],
   colModel: [{
       name: 'empID',
       index: 'empID',
       width: 10,
       sorttype: "int"},
   {
       name: 'firstName',
       index: 'firstName',
       width: 50},
   {
       name: 'lastName',
       index: 'lastName',
       width: 50},
   {
       name: 'address',
       index: 'address',
       width: 100},
   {
       name: 'phone',
       index: 'phone',
       width: 10}
   ],
});

var names = ['empID', 'firstName', 'lastName', 'address', 'phone'];
var employeedata = [];

for (var i = 0; i < data.length; i++) {
   employeedata[i] = {};
   employeedata[i][names[0]] = data[i].empID;
   employeedata[i][names[1]] = data[i].firstName;
   employeedata[i][names[2]] = data[i].lastName;
   employeedata[i][names[3]] = data[i].address;
   employeedata[i][names[4]] = data[i].phone;
}

for (var i = 0; i <= employeedata.length; i++) {
   $("#employees").jqGrid('addRowData', i + 1, employeedata[i]);
}

$("#employees").jqGrid('setGridParam', {ondblClickRow: function(rowid,iRow,iCol,e){alert('double clicked');}});

});

This example can be downloaded from github. Please drop me a question if required.

https://github.com/SanjayIngole/jqgrid-example-parent




Wednesday, July 22, 2015

Jquery Confirm Yes No example in JSfiddle

Following example shows the confirmation dialog box with a yes/no buttons using Jquery.

We have a employee table with radio buttons. A user can select a radio button and click on the delete button to delete the employee record.

I have created a simple Confirm dialog with not much styling, but we can always customize the html to make it look better.

Example :




A working example can be seen in JSFiddle at : http://jsfiddle.net/sanjayingole/9Lyfy9ay/1/

Javascript : 

// openDeleteConfirmDialog opens the confirmation dialog box
function openDeleteConfirmDialog() {
   
$("#selectedEmployee").html($("td[id='"+ $("input[name='empid']:checked").val() +"']").html());
   
    // Define the Dialog and its properties.
    $("#confirmDeleteDialog").dialog({
        resizable: false,
        modal: true,
        title: "Modal",
        height: 150,
        width: 500,
        buttons: {
            "Yes": function () {
                $(this).dialog('close');
                performAction(true);
            },
                "No": function () {
                $(this).dialog('close');
                performAction(false);
            }
        }
    });
}

// Call the openDeleteConfirmDialog method on Buttons click
$('#btnDeleteEmployee').click(openDeleteConfirmDialog);

// delete record if user clicked Yes on confirmation dialog
function performAction(action) {
    if (action) {
        $("input[name='empid']:checked").parent().parent().hide();
        $("#confirmMessage").html("Successfully Deleted Employee : " + $("td[id='"+ $("input[name='empid']:checked").val() +"']").html());
    } else {
    // Do nothing
    }
}

HTML Code:

<H1>Employee Records </H1>
<div id="confirmMessage">  
</div>
<table>
     <tr>
        <th></th>
        <th>Employee Name</th>
        <th>Address</th>
        <th>Phone No.</th>
    </tr>
     <tr>
        <td><input type="radio" name ="empid" id="empid" value="empid1"></input></td>
        <td id="empid1">John Oliver</td>
        <td>123 Abbey Road, Chicago</td>
        <td>123-232-1233</td>
    </tr>
     <tr>
        <td><input type="radio" name ="empid" id="empid"  value="empid2"></input></td>
        <td id="empid2">Madonna</td>
        <td>2017 Lomard St, San Francisco</td>
        <td>874-522-3511</td>
    </tr>
     <tr>
        <td><input type="radio" name ="empid" id="empid"  value="empid3"></input></td>
        <td id="empid3">Adam Sandler</td>
        <td>787 Beverly Hills, LA</td>
        <td>434-215-5590</td>
    </tr>
    <tr>
        <td><input type="radio" name ="empid" id="empid"  value="empid4"></input></td>
        <td id="empid4">Jack Nicholson</td>
        <td>6789 Hollywood Blv, LA</td>
        <td>898-431-6574</td>
    </tr>
<table>

<input type="button" id="btnOpenDialog" value="Delete Employee Record"/>

<div id="confirmDeleteDialog" class="confirmDeleteDialog"
style="border: 1px solid #000000; display: none;">
<div class="sectionHeader" style="top: 0px;">
<span class="sectionTitle">Delete Employee Record</span>
        <span id="selectedEmployee"></span>
</div>
</div>

CSS Code :

table {
    background : #DfDfFF;
    border : 1px dotted;
    margin-left 30px;
    margin-bottom : 30px;
}
th {
    border : 1px solid;
}
td {
    border : 1px solid;
}

#btnDeleteEmployee {
  margin-left : 270px;
}
#confirmMessage {
    background-color : rgb(183, 240, 121);
    width : 455px;
}
.confirmDeleteDialog {
width : 700px;
height : 100px;
padding : 20px;
background-color : #d6d8d9;
background: #d6d8d9;
}

.ui-dialog-titlebar {display:none;}

.ui-widget-overlay {
background: black;
opacity: .8;
filter: Alpha(Opacity=30);

}


Tuesday, July 21, 2015

Uncaught InvalidCharacterError: Failed to execute 'createElement' on 'Document': The tag name provided ('') is not a valid name.(anonymous function) @ (index):62

Getting following error while calling an old javascript method which dynamically creates a column in a table.

Uncaught InvalidCharacterError: Failed to execute 'createElement' on 'Document': The tag name provided ('<TD class="column" style="white-space:nowrap; text-align:right;">') is not a valid name.(anonymous function) @ (index):62

I reproduced the same on jsfiddle with following code (http://jsfiddle.net/sanjayingole/068ut9tp/1/)

<div id="employeeDiv" class="tableDiv empDiv">
    <table id="employeeTable">    
    </table>
</div>

<!-- Javascript to dynamically create TD tag-->
<script>
var newTable=document.getElementById("employeeTable");

newtablebody = document.createElement("TBODY");
newRow   = document.createElement("TR");

//The Javascript tries to create the TD element with some html code. 
//Which is causing this error.
newCell = document.createElement("<TD class=\"column\" style=\"white-space:nowrap; text-align:right;\">");


textNode = document.createTextNode(displayname);
newCell.appendChild(textNode);
newRow.appendChild(newCell);

</script>

Solution:

Initially I suspected the double quotes was causing the problem and changed it to single quotes instead, but that dint solve the problem either.
Following worked fine :
Instead of creating elements like :

              document.createElement("<TD class=\"column\" style=\"white-space:nowrap; text-align:right;\">");

use following :

newCell = document.createElement("TD");   
newCell.setAttribute("style", "white-space:nowrap; text-align:right;");

Following example shows the fix :
http://jsfiddle.net/sanjayingole/068ut9tp/3/


Personally Jquery would be a lot convenient to implement dynamic components. For example datatables are very easy to implement and rendering part is taken care of by jquery.

Monday, July 20, 2015

Google Chrome throwing : Uncaught TypeError: Cannot read property 'value' of undefined

Just found this Javascript error in google chrome which causes form submission failure. The same code works fine in Internet Explorer.

Uncaught TypeError: Cannot read property 'value' of undefined
Looks like the chrome is trying to access these element before the page is loaded as adding this js after body tag doesn't throw the same error.

Generate and Using SSH Key


An SSH key allows you to login to a server from another computer without a password. This is useful when we access the remote server frequently and want to be automatically authenticated through SSH.
Two basic steps:
1. Generate an SSH key on your computer.
2. Copy the generated SSH key on the target Server. 
The target server authenticates any incoming SSH request using the key provided in SSH request.
Following explains how to generate and use SSH Key :

To generate a ssh file run the following command :

ssh-keygen -t rsa -C <<key name>>

i.e.
bash-3.2$ ssh-keygen -t rsa -C "testsshprofile"

The above will als ask for a passphrase, which is optional, but provids additional security to your ssh file by encrypting it and putting it in a restricted directory. If you provide a passphrase you will have to enter it every time you use SSH to connect to target server.



// The above will generate private and public files i.e. testsshprofile and testsshprofile.pub

  • testsshprofile :  Its the private key file and should not be shared. Anyone with this file can access the sever.  Here is the sample contents of the testsshprofile:

  • testsshprofile.pub : this is the public key file that is shared with the remote server, so it can recognize your machine. The contents of this file needs to be copied on target server in ssh configuration. Here is the sample contents of the testsshprofile.ssh:


Copy the SSH key on Remote Server:

Once the ssh files are generated we need to copy over the ssh file on target server. I assume you have the access to the target server and have required permission to edit ssh configs.

You can use the following command to append the public key on server

cat ~/.ssh/testsshprofile.pub | ssh user@hostname 'cat >> .ssh/authorized_keys'

You can also edit this file manually if you have access to the target server and you are trying to provide access to this server to some other users.

1. On your target server go to the ssh directory, you should see authorized_keys file in ssh directory.
>>  cd ~/.ssh

authorization  authorized_keys  id_rsa  id_rsa.pub  known_hosts

>> Edit the authorized_keys file and append the contents of the your public key (i.e. "testsshprofile.pub") in this file.

2. Restart the ssh service :

>> sudo /etc/init.d/sshd restart

// For Ubuntu
>> sudo service ssh restart

// CentOS
>> sudo service sshd restart

Connecting to the Server :

Once we have generated the SSH key and copied the ssh file over to target server, we can use the following command to access the remote server.

>> ssh -i <<path to public key>> user@<<IP address>>

i.e.  ssh -i /test/location/testsshprofile.pub devuser@10.1.20.129

Make sure your ssh file has the correct permission or else you might get authentication error.

>> chmod 600 testsshprofile


Friday, July 17, 2015

Exception Ocured Spring MVC web application deployment : java.lang.NoClassDefFoundError: org/codehaus/jackson/map/ObjectMapper

Looking for solution to the following exception:

An error occurred during activation of changes, please see the log for details.
Message icon - Error [HTTP:101216]Servlet: "sysprop" failed to preload on startup in Web application: "sysprop". org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jsonHttpMessageConverter' defined in ServletContext resource [/WEB-INF/sysprop-servlet.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [org.springframework.http.converter.json.MappingJacksonHttpMessageConverter]: Constructor threw exception; nested exception is java.lang.NoClassDefFoundError: org/codehaus/jackson/map/ObjectMapper at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1076) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1021) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:504) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:700) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482) at org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:658) at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:624) at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:672) at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:543) at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:484) at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:136) at javax.servlet.GenericServlet.init(GenericServlet.java:241) at weblogic.servlet.internal.StubSecurityHelper$ServletInitAction.run(StubSecurityHelper.java:283) at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321) at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:120) at weblogic.servlet.internal.StubSecurityHelper.createServlet(StubSecurityHelper.java:64) at weblogic.servlet.internal.StubLifecycleHelper.createOneInstance(StubLifecycleHelper.java:58) at weblogic.servlet.internal.StubLifecycleHelper.<init>(StubLifecycleHelper.java:48) at weblogic.servlet.internal.ServletStubImpl.prepareServlet(ServletStubImpl.java:539) at weblogic.servlet.internal.WebAppServletContext.preloadServlet(WebAppServletContext.java:1981) at weblogic.servlet.internal.WebAppServletContext.loadServletsOnStartup(WebAppServletContext.java:1955) at weblogic.servlet.internal.WebAppServletContext.preloadResources(WebAppServletContext.java:1874) at weblogic.servlet.internal.WebAppServletContext.start(WebAppServletContext.java:3154) at weblogic.servlet.internal.WebAppModule.startContexts(WebAppModule.java:1518) at weblogic.servlet.internal.WebAppModule.start(WebAppModule.java:484) at weblogic.application.internal.flow.ModuleStateDriver$3.next(ModuleStateDriver.java:425) at weblogic.application.utils.StateMachineDriver.nextState(StateMachineDriver.java:52) at weblogic.application.internal.flow.ModuleStateDriver.start(ModuleStateDriver.java:119) at weblogic.application.internal.flow.ScopedModuleDriver.start(ScopedModuleDriver.java:200) at weblogic.application.internal.flow.ModuleListenerInvoker.start(ModuleListenerInvoker.java:247) at weblogic.application.internal.flow.ModuleStateDriver$3.next(ModuleStateDriver.java:425) at weblogic.application.utils.StateMachineDriver.nextState(StateMachineDriver.java:52) at weblogic.application.internal.flow.ModuleStateDriver.start(ModuleStateDriver.java:119) at weblogic.application.internal.flow.StartModulesFlow.activate(StartModulesFlow.java:27) at weblogic.application.internal.BaseDeployment$2.next(BaseDeployment.java:671) at weblogic.application.utils.StateMachineDriver.nextState(StateMachineDriver.java:52) at weblogic.application.internal.BaseDeployment.activate(BaseDeployment.java:212) at weblogic.application.internal.EarDeployment.activate(EarDeployment.java:59) at weblogic.application.internal.DeploymentStateChecker.activate(DeploymentStateChecker.java:161) at weblogic.deploy.internal.targetserver.AppContainerInvoker.activate(AppContainerInvoker.java:79) at weblogic.deploy.internal.targetserver.operations.AbstractOperation.activate(AbstractOperation.java:569) at weblogic.deploy.internal.targetserver.operations.ActivateOperation.activateDeployment(ActivateOperation.java:150) at weblogic.deploy.internal.targetserver.operations.ActivateOperation.doCommit(ActivateOperation.java:116) at weblogic.deploy.internal.targetserver.operations.AbstractOperation.commit(AbstractOperation.java:323) at weblogic.deploy.internal.targetserver.DeploymentManager.handleDeploymentCommit(DeploymentManager.java:844) at weblogic.deploy.internal.targetserver.DeploymentManager.activateDeploymentList(DeploymentManager.java:1253) at weblogic.deploy.internal.targetserver.DeploymentManager.handleCommit(DeploymentManager.java:440) at weblogic.deploy.internal.targetserver.DeploymentServiceDispatcher.commit(DeploymentServiceDispatcher.java:163) at weblogic.deploy.service.internal.targetserver.DeploymentReceiverCallbackDeliverer.doCommitCallback(DeploymentReceiverCallbackDeliverer.java:195) at weblogic.deploy.service.internal.targetserver.DeploymentReceiverCallbackDeliverer.access$100(DeploymentReceiverCallbackDeliverer.java:13) at weblogic.deploy.service.internal.targetserver.DeploymentReceiverCallbackDeliverer$2.run(DeploymentReceiverCallbackDeliverer.java:68) at weblogic.work.SelfTuningWorkManagerImpl$WorkAdapterImpl.run(SelfTuningWorkManagerImpl.java:545) at weblogic.work.ExecuteThread.execute(ExecuteThread.java:256) at weblogic.work.ExecuteThread.run(ExecuteThread.java:221) Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [org.springframework.http.converter.json.MappingJacksonHttpMessageConverter]: Constructor threw exception; nested exception is java.lang.NoClassDefFoundError: org/codehaus/jackson/map/ObjectMapper at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:164) at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:89) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1069) ... 59 more Caused by: java.lang.NoClassDefFoundError: org/codehaus/jackson/map/ObjectMapper at org.springframework.http.converter.json.MappingJacksonHttpMessageConverter.<init>(MappingJacksonHttpMessageConverter.java:63) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27) at java.lang.reflect.Constructor.newInstance(Constructor.java:513) at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:148) ... 61 more Caused by: java.lang.ClassNotFoundException: org.codehaus.jackson.map.ObjectMapper at weblogic.utils.classloaders.GenericClassLoader.findLocalClass(GenericClassLoader.java:297) at weblogic.utils.classloaders.GenericClassLoader.findClass(GenericClassLoader.java:270) at java.lang.ClassLoader.loadClass(ClassLoader.java:306) at java.lang.ClassLoader.loadClass(ClassLoader.java:247) at weblogic.utils.classloaders.GenericClassLoader.loadClass(GenericClassLoader.java:179) ... 67 more

Message icon - Error Substituted for missing class org.springframework.beans.BeanInstantiationException - Could not instantiate bean class [org.springframework.http.converter.json.MappingJacksonHttpMessageConverter]: Constructor threw exception; nested exception is java.lang.NoClassDefFoundError: org/codehaus/jackson/map/ObjectMapper