1 2 Previous Next 15 Replies Latest reply on Jun 17, 2012 5:26 PM by mcasperson

    NullPointerException when decoding generic list from JSON

    mcasperson

      When decoding a generic list, I get the following exception.

       

      java.lang.NullPointerException
                at org.jboss.errai.marshalling.client.api.json.impl.gwt.GWTJSONValue.isObject(GWTJSONValue.java:60)
                at org.jboss.errai.marshalling.client.marshallers.MapMarshaller.doDermashall(MapMarshaller.java:59)
                at org.jboss.errai.marshalling.client.marshallers.MapMarshaller.demarshall(MapMarshaller.java:55)
                at org.jboss.errai.marshalling.client.marshallers.MapMarshaller.demarshall(MapMarshaller.java:1)
                at org.jboss.errai.marshalling.client.marshallers.QualifyingMarshallerWrapper.doNotNullDemarshall(QualifyingMarshallerWrapper.java:51)
                at org.jboss.errai.marshalling.client.marshallers.AbstractNullableMarshaller.demarshall(AbstractNullableMarshaller.java:19)
                at org.jboss.errai.marshalling.client.marshallers.AbstractCollectionMarshaller.marshallToCollection(AbstractCollectionMarshaller.java:77)
                at org.jboss.errai.marshalling.client.marshallers.ListMarshaller.doDemarshall(ListMarshaller.java:43)
                at org.jboss.errai.marshalling.client.marshallers.ListMarshaller.doDemarshall(ListMarshaller.java:1)
                at org.jboss.errai.marshalling.client.marshallers.AbstractCollectionMarshaller.doDemarshall(AbstractCollectionMarshaller.java:47)
                at org.jboss.errai.marshalling.client.marshallers.AbstractCollectionMarshaller.doDemarshall(AbstractCollectionMarshaller.java:1)
                at org.jboss.errai.marshalling.client.marshallers.AbstractBackReferencingMarshaller.demarshall(AbstractBackReferencingMarshaller.java:67)
                at org.jboss.errai.marshalling.client.api.MarshallerFactoryImpl$3.demarshall(MarshallerFactoryImpl.java:333)
                at org.jboss.errai.marshalling.client.api.MarshallerFactoryImpl$3.demarshall(MarshallerFactoryImpl.java:1)
                at org.jboss.errai.marshalling.client.Marshalling.fromJSON(Marshalling.java:157)
                at org.jboss.errai.enterprise.client.jaxrs.MarshallingWrapper.fromJSON(MarshallingWrapper.java:56)
                at org.jboss.errai.enterprise.client.jaxrs.JaxrsProxyLoaderImpl$1RESTImpl$1.onResponseReceived(JaxrsProxyLoaderImpl.java:85)
                at com.google.gwt.http.client.Request.fireOnResponseReceived(Request.java:287)
                at com.google.gwt.http.client.RequestBuilder$1.onReadyStateChange(RequestBuilder.java:395)
                at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
                at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
                at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
                at java.lang.reflect.Method.invoke(Method.java:616)
                at com.google.gwt.dev.shell.MethodAdaptor.invoke(MethodAdaptor.java:103)
                at com.google.gwt.dev.shell.MethodDispatch.invoke(MethodDispatch.java:71)
                at com.google.gwt.dev.shell.OophmSessionHandler.invoke(OophmSessionHandler.java:172)
                at com.google.gwt.dev.shell.BrowserChannelServer.reactToMessagesWhileWaitingForReturn(BrowserChannelServer.java:337)
                at com.google.gwt.dev.shell.BrowserChannelServer.invokeJavascript(BrowserChannelServer.java:218)
                at com.google.gwt.dev.shell.ModuleSpaceOOPHM.doInvoke(ModuleSpaceOOPHM.java:136)
                at com.google.gwt.dev.shell.ModuleSpace.invokeNative(ModuleSpace.java:561)
                at com.google.gwt.dev.shell.ModuleSpace.invokeNativeObject(ModuleSpace.java:269)
                at com.google.gwt.dev.shell.JavaScriptHost.invokeNativeObject(JavaScriptHost.java:91)
                at com.google.gwt.core.client.impl.Impl.apply(Impl.java)
                at com.google.gwt.core.client.impl.Impl.entry0(Impl.java:213)
                at sun.reflect.GeneratedMethodAccessor33.invoke(Unknown Source)
                at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
                at java.lang.reflect.Method.invoke(Method.java:616)
                at com.google.gwt.dev.shell.MethodAdaptor.invoke(MethodAdaptor.java:103)
                at com.google.gwt.dev.shell.MethodDispatch.invoke(MethodDispatch.java:71)
                at com.google.gwt.dev.shell.OophmSessionHandler.invoke(OophmSessionHandler.java:172)
                at com.google.gwt.dev.shell.BrowserChannelServer.reactToMessages(BrowserChannelServer.java:292)
                at com.google.gwt.dev.shell.BrowserChannelServer.processConnection(BrowserChannelServer.java:546)
                at com.google.gwt.dev.shell.BrowserChannelServer.run(BrowserChannelServer.java:363)
                at java.lang.Thread.run(Thread.java:679)
      
      

       

      The List is held by a generic class.

       

      package com.test.restserver;
      
      import java.util.List;
      
      public class RESTObject<T>
      {
                private List<T> objects;
      
                public List<T> getObjects()
                {
                          return objects;
                }
      
                public void setObjects(List<T> objects)
                {
                          this.objects = objects;
                }
      }
      
      

       

      The objects being saved in the list are simple classes:

       

      package com.test.restserver;
      
      
      public class RESTChildObject
      {
                private Integer id;
      
                public Integer getId()
                {
                          return id;
                }
      
                public void setId(Integer id)
                {
                          this.id = id;
                }
      }
      
      

       

      Converting a RESTObject<RESTChildObject> returned from a REST service where there is at least 1 item in the generic list "objects" held by the RESTObject class results in the error above.

       

      A test case server that demonstrates the problem above can be found at https://github.com/mcasperson/TestCase-RESTServer, and a test case client can be found at https://github.com/mcasperson/TestCase-ErraiRESTClient.

        • 1. Re: NullPointerException when decoding generic list from JSON
          csa

          This will work now using the latest 2.1 snaphots. You have to mark your RESTObject and RESTChildObject as @Portable though to make them visible to Errai's marshaller.

          • 2. Re: NullPointerException when decoding generic list from JSON
            mcasperson

            That has fixed the issue. Thanks Christian.

            • 3. Re: NullPointerException when decoding generic list from JSON
              mcasperson

              A different issue has come up. When you have a generic list (lets call this "generic list 1") that holds objects that in turn hold another generic list (lets call this "generic list 2"), generic list 2 is populated with the object type held by generiic list 1 (even though the two lists are clearly constructed with different types).

              • 4. Re: NullPointerException when decoding generic list from JSON
                mcasperson

                I updated to the latest 2.1 snapshot, and also saw this error on startup. No code was changed, so do I have to import a new GWT module or something?

                 

                java.lang.NoSuchMethodError: org.jboss.errai.codegen.util.GenUtil.setPermissiveMode(Z)V
                    at org.jboss.errai.ioc.rebind.ioc.bootstrapper.QualiferEqualityFactoryGenerator.generate(QualiferEqualityFactoryGenerator.java:58)
                    at com.google.gwt.core.ext.GeneratorExtWrapper.generate(GeneratorExtWrapper.java:48)
                    at com.google.gwt.core.ext.GeneratorExtWrapper.generateIncrementally(GeneratorExtWrapper.java:60)
                    at com.google.gwt.dev.javac.StandardGeneratorContext.runGeneratorIncrementally(StandardGeneratorContext.java:647)
                    at com.google.gwt.dev.cfg.RuleGenerateWith.realize(RuleGenerateWith.java:41)
                    at com.google.gwt.dev.shell.StandardRebindOracle$Rebinder.rebind(StandardRebindOracle.java:78)
                    at com.google.gwt.dev.shell.StandardRebindOracle.rebind(StandardRebindOracle.java:268)
                    at com.google.gwt.dev.shell.ShellModuleSpaceHost.rebind(ShellModuleSpaceHost.java:141)
                    at com.google.gwt.dev.shell.ModuleSpace.rebind(ModuleSpace.java:585)
                    at com.google.gwt.dev.shell.ModuleSpace.rebindAndCreate(ModuleSpace.java:455)
                    at com.google.gwt.dev.shell.GWTBridgeImpl.create(GWTBridgeImpl.java:49)
                    at com.google.gwt.core.client.GWT.create(GWT.java:97)
                    at org.jboss.errai.ioc.client.QualifierUtil.<clinit>(QualifierUtil.java:16)
                    at org.jboss.errai.ioc.client.container.BeanRef$AnnotationHashWapper.<init>(BeanRef.java:101)
                    at org.jboss.errai.ioc.client.container.BeanRef$AnnotationHashWapper.<init>(BeanRef.java:96)
                    at org.jboss.errai.ioc.client.container.BeanRef.wrapAnnotations(BeanRef.java:68)
                    at org.jboss.errai.ioc.client.container.BeanRef.<init>(BeanRef.java:62)
                    at org.jboss.errai.ioc.client.container.CreationalContext.getBeanReference(CreationalContext.java:103)
                    at org.jboss.errai.ioc.client.BootstrapperImpl$1.getInstance(BootstrapperImpl.java:43)
                    at org.jboss.errai.ioc.client.BootstrapperImpl$1.getInstance(BootstrapperImpl.java:1)
                    at org.jboss.errai.ioc.client.BootstrapperImpl.bootstrapContainer(BootstrapperImpl.java:48)
                    at org.jboss.errai.ioc.client.Container.boostrapContainer(Container.java:49)
                    at org.jboss.errai.ioc.client.Container.onModuleLoad(Container.java:34)
                    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
                    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
                    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
                    at java.lang.reflect.Method.invoke(Method.java:601)
                    at com.google.gwt.dev.shell.ModuleSpace.onLoad(ModuleSpace.java:396)
                    at com.google.gwt.dev.shell.OophmSessionHandler.loadModule(OophmSessionHandler.java:200)
                    at com.google.gwt.dev.shell.BrowserChannelServer.processConnection(BrowserChannelServer.java:525)
                    at com.google.gwt.dev.shell.BrowserChannelServer.run(BrowserChannelServer.java:363)
                    at java.lang.Thread.run(Thread.java:722)
                java.lang.ExceptionInInitializerError
                    at org.jboss.errai.ioc.client.container.BeanRef$AnnotationHashWapper.<init>(BeanRef.java:101)
                    at org.jboss.errai.ioc.client.container.BeanRef$AnnotationHashWapper.<init>(BeanRef.java:96)
                    at org.jboss.errai.ioc.client.container.BeanRef.wrapAnnotations(BeanRef.java:68)
                    at org.jboss.errai.ioc.client.container.BeanRef.<init>(BeanRef.java:62)
                    at org.jboss.errai.ioc.client.container.CreationalContext.getBeanReference(CreationalContext.java:103)
                    at org.jboss.errai.ioc.client.BootstrapperImpl$1.getInstance(BootstrapperImpl.java:43)
                    at org.jboss.errai.ioc.client.BootstrapperImpl$1.getInstance(BootstrapperImpl.java:1)
                    at org.jboss.errai.ioc.client.BootstrapperImpl.bootstrapContainer(BootstrapperImpl.java:48)
                    at org.jboss.errai.ioc.client.Container.boostrapContainer(Container.java:49)
                    at org.jboss.errai.ioc.client.Container.onModuleLoad(Container.java:34)
                    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
                    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
                    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
                    at java.lang.reflect.Method.invoke(Method.java:601)
                    at com.google.gwt.dev.shell.ModuleSpace.onLoad(ModuleSpace.java:396)
                    at com.google.gwt.dev.shell.OophmSessionHandler.loadModule(OophmSessionHandler.java:200)
                    at com.google.gwt.dev.shell.BrowserChannelServer.processConnection(BrowserChannelServer.java:525)
                    at com.google.gwt.dev.shell.BrowserChannelServer.run(BrowserChannelServer.java:363)
                    at java.lang.Thread.run(Thread.java:722)
                Caused by: java.lang.RuntimeException: Deferred binding failed for 'org.jboss.errai.ioc.client.QualifierEqualityFactory' (did you forget to inherit a required module?)
                    at com.google.gwt.dev.shell.GWTBridgeImpl.create(GWTBridgeImpl.java:53)
                    at com.google.gwt.core.client.GWT.create(GWT.java:97)
                    at org.jboss.errai.ioc.client.QualifierUtil.<clinit>(QualifierUtil.java:16)
                    ... 19 more
                Caused by: com.google.gwt.core.ext.UnableToCompleteException: (see previous log entries)
                    at com.google.gwt.dev.shell.ModuleSpace.rebind(ModuleSpace.java:595)
                    at com.google.gwt.dev.shell.ModuleSpace.rebindAndCreate(ModuleSpace.java:455)
                    at com.google.gwt.dev.shell.GWTBridgeImpl.create(GWTBridgeImpl.java:49)
                    ... 21 more
                
                • 5. Re: NullPointerException when decoding generic list from JSON
                  csa

                  I just re-published all 2.1 snapshots. So, this error should be gone now.

                  • 6. Re: NullPointerException when decoding generic list from JSON
                    mcasperson

                    Thanks for the quick response Christian. The module bug has gone, and I have updated the test case at https://github.com/mcasperson/TestCase-RESTServer and https://github.com/mcasperson/TestCase-ErraiRESTClient to demonstrate the issue with the generic marshalling.

                     

                    As you will see, the server returns an object of type RESTObject<RESTChildObject<RESTGrandchildObject>>, but the marshalled response is of the type RESTObject<RESTChildObject<RESTChildObject>>.

                     

                    erraibug.png

                    • 7. Re: NullPointerException when decoding generic list from JSON
                      csa

                      Yes, you're hitting an edge case with our new JacksonTransformer (transforms between Errai's JSON and Jackson). This will not be a problem using Errai's native JSON format. In any case, I would not recommend nesting parameterized types like this.

                       

                      So, rather than having a List<List<T>>, I'd use a List<MyType> where MyType has a List<T>. This will also work using our JacksonTransfomer.

                      • 8. Re: NullPointerException when decoding generic list from JSON
                        mcasperson

                        So I can use List<MyType<T>> over List<T>, where MyType is something like

                         

                        public class MyType<T>
                        {
                             public List<T> list;
                        }
                        

                         

                        Is this correct?

                        • 9. Re: NullPointerException when decoding generic list from JSON
                          csa

                          Yes, the Jackson transformation should work in this case.

                          • 10. Re: NullPointerException when decoding generic list from JSON
                            mcasperson

                            I tried modifing the test case above with a wrapper class around the list, but the same problem appears to remain.

                             

                            You can see in the screenshot below the ListWrapper class is used instead of a standard List.

                             

                            erraibug2.png

                            • 11. Re: NullPointerException when decoding generic list from JSON
                              csa

                              Well, it seems you still have nested parameterized types here, or am I missing something? ListWrapper<T> defines a List<T> where T is RestChildObject<T> which results in a List<RestChildObject<T>>. So, that's basically the same problem as before.

                               

                              I can create a JIRA to investigate that for Jackson transformation (like I said in Errai JSON this will work). The workaround I am suggesting is to not nest parameterized types.

                              • 12. Re: NullPointerException when decoding generic list from JSON
                                mcasperson

                                So as it currently stands, in order to interoperate with a Jackson based REST server, you can have no more that one level of parameterized objects (i.e. no nesting) in the returned object?

                                • 13. Re: NullPointerException when decoding generic list from JSON
                                  csa

                                  Yes, here's the JIRA: https://issues.jboss.org/browse/ERRAI-319

                                   

                                  Errai's JSON marshaller is more powerful than Jackson. It adds type information to the payload which we don't get when consuming Jackson generated JSON. To use the same marshaller for both types of payload is not a straightforward process. This is one of the edge cases, another one are maps. Jackson support is a new feature which covers basic cases but isn't on par with Errai's default JSON marshalling.

                                  1 of 1 people found this helpful
                                  • 14. Re: NullPointerException when decoding generic list from JSON
                                    csa

                                    Hi Matthew,

                                     

                                    This issue has a low priority for us as a workaround exists that actually makes the code more readable (introducing a new type): So let's say you have List<List<User>>, depending on your use case, you could use a List<Group> (where Group has a List<User> field) or Table<User> instead.

                                     

                                    If you need the feature/fix right away we will happily accept a pull request ! In any case, we know how to implement it, it is just a matter of time....

                                     

                                    Cheers,

                                    Christian

                                    1 2 Previous Next