Announcement Announcement Module
Collapse
No announcement yet.
Problems serializing to JSON with Spring, Roo and FlexJson Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Problems serializing to JSON with Spring, Roo and FlexJson

    I am seeing this error when trying to deep serialize my object hierarchy to json. It appears to be related to trying to access a private member via reflection in commons-dbcp.

    There is no issue when doing a basic serialize. The error occurs if you try to deepSerialize or add flexjson includes for associated collections.

    Any thoughts? The full stacktrace follows.

    Code:
    2010-12-07 14:58:39,567 [tomcat-http--4] DEBUG org.springframework.web.servlet.DispatcherServlet - Handler execution resulted in exception - forwarding to resolved error view: ModelAndView: reference to view with name 'uncaughtException'; model is {exception=flexjson.JSONException: Error trying to deepSerialize}
    flexjson.JSONException: Error trying to deepSerialize
    	at flexjson.transformer.ObjectTransformer.transform(ObjectTransformer.java:97)
    	at flexjson.transformer.TransformerWrapper.transform(TransformerWrapper.java:22)
    	at flexjson.transformer.ObjectTransformer.transform(ObjectTransformer.java:57)
    	at flexjson.transformer.TransformerWrapper.transform(TransformerWrapper.java:22)
    	at flexjson.transformer.ObjectTransformer.transform(ObjectTransformer.java:57)
    	at flexjson.transformer.TransformerWrapper.transform(TransformerWrapper.java:22)
    	at flexjson.transformer.ObjectTransformer.transform(ObjectTransformer.java:57)
    	at flexjson.transformer.TransformerWrapper.transform(TransformerWrapper.java:22)
    	at flexjson.transformer.ObjectTransformer.transform(ObjectTransformer.java:57)
    	at flexjson.transformer.TransformerWrapper.transform(TransformerWrapper.java:22)
    	at flexjson.transformer.ObjectTransformer.transform(ObjectTransformer.java:57)
    	at flexjson.transformer.TransformerWrapper.transform(TransformerWrapper.java:22)
    	at flexjson.JSONContext.transform(JSONContext.java:75)
    	at flexjson.transformer.IterableTransformer.transform(IterableTransformer.java:29)
    	at flexjson.transformer.TransformerWrapper.transform(TransformerWrapper.java:22)
    	at flexjson.JSONContext.transform(JSONContext.java:75)
    	at flexjson.JSONSerializer.serialize(JSONSerializer.java:378)
    	at flexjson.JSONSerializer.deepSerialize(JSONSerializer.java:301)
    	at com.knoll.typicals.model.Typical.toJsonArray_aroundBody28(Typical.java:304)
    	at com.knoll.typicals.model.Typical.toJsonArray(Typical.java:1)
    	at com.knoll.typicals.web.admin.SearchController.searchTypicalEntriesJson(SearchController.java:57)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    	at java.lang.reflect.Method.invoke(Method.java:597)
    	at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:176)
    	at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:427)
    	at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:415)
    	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:788)
    	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:717)
    	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644)
    	at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:560)
    	at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
    	at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    	at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
    	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
    	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:343)
    	at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:109)
    	at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83)
    	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
    	at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:97)
    	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
    	at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:100)
    	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
    	at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:78)
    	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
    	at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:54)
    	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
    	at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:35)
    	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
    	at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilter(BasicAuthenticationFilter.java:177)
    	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
    	at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:188)
    	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
    	at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105)
    	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
    	at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:79)
    	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
    	at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:149)
    	at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:237)
    	at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167)
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    	at org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter.doFilterInternal(OpenEntityManagerInViewFilter.java:113)
    	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
    	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
    	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
    	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    	at com.springsource.insight.collection.tcserver.request.HttpRequestOperationCollectionValve.traceNextValve(HttpRequestOperationCollectionValve.java:92)
    	at com.springsource.insight.collection.tcserver.request.HttpRequestOperationCollectionValve.invoke(HttpRequestOperationCollectionValve.java:74)
    	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
    	at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:857)
    	at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
    	at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:409)
    	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    	at java.lang.Thread.run(Thread.java:662)
    Caused by: java.lang.IllegalAccessException: Class flexjson.transformer.ObjectTransformer can not access a member of class org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper with modifiers "public"
    	at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:65)
    	at java.lang.reflect.Method.invoke(Method.java:588)
    	at flexjson.transformer.ObjectTransformer.transform(ObjectTransformer.java:45)
    	... 88 more

  • #2
    It would be hard to give you an answer without seeing what exactly you are doing. Just a guess, but it seems you are referencing a persistence related field somewhere and it should be marked as either transient or it should be explicitly excluded from serialization by the Json parser. For details you would need to review the FlexJson docs or ask on their forum.

    Comment


    • #3
      Stefan,

      I am not doing anything really out of the ordinary here.

      I used roo to generate a model. It is hooked up with jpa. It has some finders in it, otherwise, roo manages everything about the class.

      To get the deepSerialize I need, I copied the toJson and toJsonArray from the _Roo_Json.aj and Roo removed them from that file. They are now pushed into my class and I changed the serialize method to deepSerialize because my app needs all associated entities.
      Code:
      public String toJson() {
          return new JSONSerializer().include( "assets" ).exclude( "*.class" ).deepSerialize( this );
      }
      
      public static String toJsonArray( Collection<Typical> collection ) {
          return new JSONSerializer().exclude( "*.class" ).deepSerialize( collection );
      }
      I created a controller to perform the action of looking up the objects. It performs a search and, optional, pagination calling the toJsonArray method in the object.
      Code:
      @RequestMapping( headers = "Accept=application/json" )
      @ResponseBody
      public String searchTypicalEntriesJson( @RequestParam String search, @RequestParam( value = "page", required = false ) Integer page, @RequestParam( value = "size", required = false ) Integer size ) {
          log.info( "searchTypicalEntriesJson : enter" );
      
          if( page != null || size != null ) {
              int sizeNo = size == null ? 10 : size.intValue();
      
              log.info( "searchTypicalEntriesJson : exit, no paging" );
              return Typical.toJsonArray( Typical.searchTypicalEntries( search, page == null ? 0 : ( page.intValue() - 1 ) * sizeNo, sizeNo ) );
          } else {
               log.info( "searchTypicalEntriesJson : exit" );
            	 return Typical.toJsonArray( Typical.searchTypicals( search ) );
          }
      }
      The stacktrace leads me to believe there is an issue accessing a member of class in apache commons-dbcp. However, nothing in my code directly interfaces with commons-dbcp. I believe this is most likely related to jpa and other annotations. I am not sure if excluding anything will work in the json serializer in this case as there is nothing in my class that directly contains the commons-dbcp.

      Any thoughts?

      Thanks for your help.

      Comment


      • #4
        I have not tried deep serializing (and you should be careful with this from an efficiency perspective). What you need to do is to dig (debug) a bit into the sources and see which fields FlexJson tries to serialize so you can exclude them explicitly.

        Comment


        • #5
          Was this issue ever resolved?

          Comment


          • #6
            I ended up implementing it myself.

            It seemed really odd to me that FlexJSON would try to inspect something in Commons DBCP and translate it to JSON. When I get some time, I will try to dive into that code to see what is going on.

            Comment


            • #7
              Originally posted by Stefan Schmidt View Post
              It would be hard to give you an answer without seeing what exactly you are doing. Just a guess, but it seems you are referencing a persistence related field somewhere and it should be marked as either transient or it should be explicitly excluded from serialization by the Json parser. For details you would need to review the FlexJson docs or ask on their forum.

              I have this issue as well, and I was wondering if there might be an incompatibility between Flexjson and Spring Roo. I basically reproduced the Flexjson example in Roo:

              Code:
              project --topLevelPackage com.springsource.issue
              
              persistence setup --provider HIBERNATE --database HYPERSONIC_IN_MEMORY
              
              // ZipCode
              entity --class ~.domain.ZipCode --testAutomatically
              field string zipcode
              
              // Address
              entity --class ~.domain.Address --testAutomatically
              field string --fieldName name
              field string --fieldName street
              field string --fieldName city
              field string --fieldName stateAbbreviation
              field reference --fieldName zipcode --type ~.domain.ZipCode
              
              // Phone
              entity --class ~.domain.Phone --testAutomatically
              field string name
              field string phoneNumber
              
              // Person
              entity --class ~.domain.Person --testAutomatically
              field string --fieldName name
              field date --fieldName birthDay --type java.util.Date --notNull
              field string --fieldName nickname
              field set --fieldName addresses --type ~.domain.Address
              field set --fieldName phoneNumbers --type ~.domain.Phone
              
              controller all --package ~.web
              logging setup --level DEBUG
              
              json all
              
              perform tests

              All works fine, ran a curl for the people:
              Code:
              curl -i -H "Accept: application/json" -X GET -H Accept:application/json -H Content-Type:application/json  http://localhost:8080/issue/people
              received a reasonable response:
              [{
              "birthDay":1293865200000
              ,"id":1
              ,"name":"Test Person"
              ,"nickname":"Test"
              ,"version":0
              }]

              Now the first example in FlexJson is to include the phone numbers:
              public String doSomething( Object arg1, ... ) {

              Person p = ...load a person...;

              return new JSONSerializer().include("phoneNumbers").serialize (p);
              }
              So Pulled in the toJsonArray, and modified Person.java
              Code:
                  public static String toJsonArray(Collection<Person> collection) {
                      return new JSONSerializer().exclude("*.class").include("phoneNumbers").serialize(collection);
                  }
              Started it up, typed in a couple phone numbers, couple addresses, couple zipcodes, added a Person. Tried the curl again, and received the deep serialization error:
              Caused by: java.lang.IllegalAccessException: Class flexjson.transformer.ObjectTr
              ansformer can not access a member of class org.apache.commons.dbcp.PoolingDataSource$PoolGuar dConnectionWrapper with modifiers "public"
              at sun.reflect.Reflection.ensureMemberAccess(Reflecti on.java:65)
              at java.lang.reflect.Method.invoke(Method.java:588)
              at flexjson.transformer.ObjectTransformer.transform(O bjectTransformer.java:45)

              As other's have said, I would think this is a very common activity, and something that Roo might benefit from having.

              Not sure if there is a bug in FlexJson, or just that FlexJson isn't compatible with a Roo/Spring/Hibernate project. I have posted this issue on the FlexJson forum as well.

              Comment


              • #8
                I was able to get it to work by creating a Transformer (using the instructions from the FlexJson site posting it here in case someone needs it:

                Code:
                public class PersonTransformer extends AbstractTransformer {
                
                    @Override
                    public Boolean isInline() {
                        return Boolean.TRUE;
                    }
                	@Override
                	public void transform(Object object) {
                		
                		// Start the object
                		TypeContext typeContext = getContext().writeOpenObject();
                		typeContext.setFirst(false);
                
                	    Person person = (Person) object;
                		
                		// Write out the fields
                	    getContext().writeName("id");
                	    getContext().transform(person.getId());
                	    getContext().writeComma();
                	    getContext().writeName("name");
                	    getContext().transform(person.getName());
                	    getContext().writeComma();
                	    getContext().writeName("birthday");
                	    getContext().transform(person.getBirthday());
                	    getContext().writeComma();
                	    getContext().writeName("nickname");
                	    getContext().transform(person.getNickname());
                	    getContext().writeComma();
                		
                		// Write out the phone numbers
                	    getContext().writeName("phoneNumbers");
                	    
                		// Open the Array of Phone Numbers
                	    TypeContext itemTypeContext = getContext().writeOpenArray();
                
                	    List<Phone> phoneNumbers = person.getPhoneNumbers();
                	    for(Phone phone : phoneNumbers){
                			// Add a comma after each phone number object is written
                            if (!itemTypeContext.isFirst()) getContext().writeComma();
                            itemTypeContext.setFirst(false);
                			// Open the phone object and write the fields
                			getContext().writeOpenObject();
                    	    getContext().writeName("id");
                    	    getContext().transform(phone.getId());
                    	    getContext().writeComma();
                    	    getContext().writeName("name");
                    	    getContext().transform(phone.getName());
                    	    getContext().writeComma();
                    	    getContext().writeName("phoneNumber");
                    	    getContext().transform(phone.getPhoneNumber());
                			// Close the phone object
                    	    getContext().writeCloseObject();
                        }
                		// Close the Array of Phone Numbers
                        getContext().writeCloseArray();
                
                		// Close the Person Object
                	    getContext().writeCloseObject();
                		
                	}
                
                }
                And then the toJsonArray becomes:
                Code:
                return new JSONSerializer().exclude("*.class").transform(new PersonTransformer(),Person.class).serialize(collection);
                It seems to me that should be almost the same as:
                Code:
                new JSONSerializer().exclude("*.class").include("phoneNumber").serialize(collection);
                With the main difference being FlexJson is using reflection to get the fields, and the Transformer is specifying them explicitly.
                Which makes me think their reflection process is not working correctly or is unable to work correctly with the Roo/Spring/Hibernate setup.

                Comment


                • #9
                  It turned out to be a bug in FlexJson 2.0: http://sourceforge.net/projects/flex.../topic/4032695

                  The bug should have been fixed in 2.1. You can also get around it by creating your own transformer (like btlife) or manually specifying the IterableTransformer as the proper transformer to be used:

                  Code:
                  .transform(new IterableTransformer(), Collection.class)

                  Comment


                  • #10
                    Originally posted by jjoyner View Post
                    It turned out to be a bug in FlexJson 2.0: http://sourceforge.net/projects/flex.../topic/4032695

                    The bug should have been fixed in 2.1. You can also get around it by creating your own transformer (like btlife) or manually specifying the IterableTransformer as the proper transformer to be used:

                    Code:
                    .transform(new IterableTransformer(), Collection.class)
                    Nice Find I created ROO-2017 to let them know they might want to upgrade the version in the next release. The new IterableTransformer() is A LOT easier than my solution lol, Thanks.

                    Comment


                    • #11
                      Thanks for the update. I am gonna upgrade to the newer version and replace my hard coded toJson methods with the roo generated ones and try it out.

                      Comment


                      • #12
                        In the latest version of Roo, I am still seeing this error. I checked the POM, and it seems to be pulling in FlexJSON 2.1. Can someone cofirm if its fixed yet? Reference to my posting is here. It's blowing up trying to deep serialize Calendar. It looks like the private "locale" is the cause, but I tried excluding "*.locale" and started getting the same error in java.util.SimpleTimeZone. It seems that FlexJSON should ignore the private members, but it is not.

                        Comment


                        • #13
                          I have a similar problem as well - are there any updates?

                          While it does not throw an exception, the returned json is some kind of array of chars.

                          [
                          {
                          "0": "<"
                          },
                          {
                          "0": "?"
                          },
                          {
                          "0": "x"

                          My context
                          - reverse engineered Roo app from database
                          - "web mvc json all"
                          - trying to make restful calls where the returned object has a field that was a mysql timestamp
                          - it works if the timestamp field is nulled before Roo code does the toJson()
                          Last edited by greg.soulsby; May 3rd, 2013, 04:25 AM.

                          Comment

                          Working...
                          X