1

I was working with a web application using the Spring framework version 3.0.2 along with Hibernate (NetBeans 6.9.1). Later I came to know that there was one of bugs that was causing problems in uploading multiple files as mentioned in my one of previous questions.

I have finished struggling to acquire the solution but couldn't succeed. Therefore, I upgraded the Spring version to 3.2.0.

With the earlier version (3.0.2), AJAX was working fine with Jackson 1.9.8 (its download page) but with the later version (3.2.0), everything works fine but AJAX calls alert an error everywhere in the JavaScript code.

There is a scenario at one place when one of the countries is selected in the country select box, the corresponding state list is retrieved from the Spring controller along with DAO. The method which is mapped with a URL in the Spring controller is as follows,

@RequestMapping(value="ajax/GetStateList", method=RequestMethod.GET)
public @ResponseBody List<Object[]> getStateSelectBox(HttpServletRequest request)
{
    return cityService.getStateSelectBox(request.getParameter("countryId"));
}   

This method is invoked when a country is selected in the country select box. The getStateSelectBox() method is defined in one of DAO classes as follows,

@Service
@Transactional(readOnly = true, propagation=Propagation.REQUIRES_NEW)
public final class CityDAO implements CityService
{
    private SessionFactory sessionFactory;

    public void setSessionFactory(SessionFactory sessionFactory)
    {
        this.sessionFactory = sessionFactory;
    }

    @SuppressWarnings("unchecked")
    public List<Object[]> getStateSelectBox(String id)
    {
        List<Object[]> list = sessionFactory.getCurrentSession()
                          .createQuery("select s.stateId, s.stateName from StateTable s where countryId.countryId=:id order by s.stateId")
                          .setParameter("id", Long.parseLong(id)).list();

       for(Object[]o:list)
       {
           System.out.println(o[0]+" : "+o[1]);
       }
       return list;
   }
}

The foreach loop is just for the sake of demonstration, it displays all the states along with their id that correspond to the countryId supplied by the AJAX request but the List is not returned to JSP.

The JavaScript code used to send this AJAX request alerts an error. It appears that there are some problems with JSON mapping. The same thing was working with the earlier version of the Spring framework (3.0.2). I'm not sure why does this cause problems with the higher version of Spring which is 3.2.0. Is there anything with the Spring version 3.2.0 which I might be missing?


If you needed to see the JavaScript code, the full JavaScript code to achieve this would be as follows.

function getStates(countryId)
{
    if(countryId==""||countryId==null||countryId==undefined||isNaN(countryId))
    {
        var str="<select id='cmbStates' name='cmbStates' onchange='errorMessage(this.value);' class='validate[required] text-input'><option value=''>Select</option></select>";
        $('#stateList').html(str);
        alert("Please select an appropriate option.");
        return;
    }

    var div=document.createElement("div");
    div.id="temp";
    document.body.appendChild(div);

    $.ajax({
        datatype:"json",
        type: "GET",
        contentType: "application/json",
        url: "/wagafashion/ajax/GetStateList.htm",
        data: "countryId=" + countryId+"&t="+new Date().getTime(),
        success: function(response)
        {
            if(typeof response==='object'&&response instanceof Array)
            {                            
                var str="<select id='cmbState' name='cmbState' onchange='errorMessage(this.value);' class='validate[required] text-input'><option value=''>Select</option>";
                var l=response.length;

                for(var i=0;i<l;i++)
                {
                    str+="<option value='"+response[i][0]+"'>"+$('#temp').text(response[i][1]).html()+"</option>";
                }
                str+="</select>";
                $('#stateList').html(str); // select box is written to #stateList div
                $('#temp').remove();
            }
        },
        error: function(e)
        {
            alert('Error: ' + e);
        }
    });
}            

To be sure, the Jackson library is on the classpath and I'm not getting any error or exception on the server side. The AJAX request succeeds and it goes to the DAO via Spring and the list of type List<Object[]> is retrieved from the database but it is not a response of JSON to JSP (which could/should be mapped to a JavaScript array). presumably, it appears that there is something missing with JSON mapping which was however not the case with the earlier version of Spring.


EDIT:

I have tried to parse List<Object[]> in both of the frameworks, 3.0.2 and 3.2.0 such as

List<Object[]> list = cityService.getStateSelectBox(request.getParameter("countryId"));
ObjectMapper objectMapper=new ObjectMapper();
try
{
    objectMapper.writeValue(new File("E:/Project/SpringHibernet/wagafashionLatest/temp.json"), list);
}
catch (IOException ex){}

The file temp.json contains the following string.

[[21,"Gujarat"],[22,"Maharashtra"],[23,"Kerala"],[24,"New Delhi"]]

In both the cases (with both frameworks). So, it appears that the JSON response should be same in both the cases.

The temp.json file can also be deserialized as follows.

try
{
    ObjectMapper mapper=new ObjectMapper();
    List<Object[]> list = mapper.readValue(new File("E:/Project/SpringHibernet/wagafashionLatest/temp.json"), new TypeReference<List<Object[]>>() {});

    for(Object[]o:list)
    {
        System.out.println(o[0]+" : "+o[1]);
    }
} 
catch (IOException ex) 
{

}

It works fine and the foreach loop iterates over the List of type List<Object[]>. So, the problem might be caused by the Spring framework itself. What else is required, I'm not sure. Why is it not mapped by Jackson?

Community
  • 1
  • 1
Tiny
  • 27,221
  • 105
  • 339
  • 599
  • A wise old programmer taught me, "Read the error, fix the error". Always include the actual error message in your questions, it makes everything easier. – digitaljoel Dec 27 '12 at 19:51
  • The error which issued and alerted by an alerbox as in the error section of jQuery is `Error: [object Object]`. I cannot see anything else. – Tiny Dec 27 '12 at 19:56
  • in chrome or firebug you should be able to set a breakpoint in the `error:` section where you perform the alert and then you can look at the `e` javascript variable. – digitaljoel Dec 27 '12 at 20:03
  • Google chrome shows this error - `Failed to load resource: the server responded with a status of 406 (Not Acceptable)`. – Tiny Dec 28 '12 at 04:33
  • To be sure enough, I have `` in the `dispatcher-servlet.xml` file. – Tiny Dec 28 '12 at 05:06

2 Answers2

2

I have the same post on the Spring forum. The solution from the replies to the question which ultimately worked for me was required to configure the dispatcher-servlet.xml file as follows.

<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager" />

<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
    <property name="favorPathExtension" value="false" />
    <property name="favorParameter" value="false" />
    <property name="ignoreAcceptHeader" value="false" />
    <property name="mediaTypes" >
        <value>
            atom=application/atom+xml
            html=text/html
            json=application/json
            *=*/*
        </value>
    </property>
</bean>

This led JSON to work with Jackson 1.9.8 and Spring 3.2.0. This is credited to all the replies to that question.


My entire dispatcher-servlet.xml file now looks like the following.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"

       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"

       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
       http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">


    <context:component-scan base-package="controller" />
    <context:component-scan base-package="validatorbeans" />

    <mvc:annotation-driven content-negotiation-manager="contentNegotiationManager" />
    <bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
        <property name="favorPathExtension" value="false" />
        <property name="favorParameter" value="false" />
        <property name="ignoreAcceptHeader" value="false" />
        <property name="mediaTypes" >
            <value>
                atom=application/atom+xml
                html=text/html
                json=application/json
                *=*/*
            </value>
        </property>
    </bean>


    <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
    <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props>
                <prop key="index.htm">indexController</prop>

            </props>
        </property>
    </bean>

    <bean id="viewResolver"
          class="org.springframework.web.servlet.view.InternalResourceViewResolver"
          p:prefix="/WEB-INF/jsp/"
          p:suffix=".jsp" />

    <bean name="indexController"
          class="org.springframework.web.servlet.mvc.ParameterizableViewController"
          p:viewName="index" />
</beans>
Tiny
  • 27,221
  • 105
  • 339
  • 599
1

I'm using Spring 3.1.3 and I've found that the Jackson mapping attempts to create a root object in the response. This is with the Jackson2 mapper. I haven't tried with the older Jackson mapper. If you also upgraded Jackson you may be seeing the same issue.

In the past, an object array would be mapped something like

[{name:'name1',id:4},{name:'name2',id:6}]

Now I find that they are providing an auto-generated object name for the object, so it is returned something like

{ objectArray: [{name:'name1',id:4},{name:'name2',id:6}]}

So you need to reference response.objectArray[0] instead of being able to directly reference response[0]

In any case, it's probable that the JSON response has changed format somewhat. You should look at the new response and see what changes need to occur in the javascript to make it map the new structure.

digitaljoel
  • 26,265
  • 15
  • 89
  • 115
  • When I attempt to change the success handler from `success: function(response)` to `success: function(response.objectArray[0])`, it reports a compiler error - `missing ) after formal parameters`. – Tiny Dec 27 '12 at 20:09
  • Google chrome shows this error - `Failed to load resource: the server responded with a status of 406 (Not Acceptable)`. – Tiny Dec 27 '12 at 20:14
  • `List` is parsed as `[[21,"Gujarat"],[22,"Maharashtra"],[23,"Kerala"],[24,"New Delhi"]]` in both the frameworks, 3.0.2 and 3.2.0 when I tried in both of them. – Tiny Dec 28 '12 at 02:46
  • Your answer opened up new ways to think of. Thank you very much for your useful answer. – Tiny Dec 31 '12 at 14:30
  • Glad you got it working. An upvote on my answer would be appreciated since it was helpful, but it would probably make more sense for you to accept your answer instead of mine since yours is the one that actually got you working. Thanks for updating with your working solution. – digitaljoel Dec 31 '12 at 19:27
  • When seeing something like `objectArray` with Jackson 2, I often just forgot to include `@ResponseBody` to my controller method. – Arjan Jan 29 '13 at 19:18
  • I recently found that wrapping the root value is configurable with the WRAP_ROOT_VALUE configuration parameter to the ObjectMapper. If you set it to false then it will remove the wrapper for the root value and the format will be like it was before. – digitaljoel Jan 29 '13 at 21:19