Android problem

79 views
Skip to first unread message

Rmac

unread,
Nov 30, 2011, 3:15:08 PM11/30/11
to json-io
Hi,

When I use json-io in my Android app I get lots of "newInstance
failed: no <init>()" messages on the Java console. It appears the
serialization/deserialization works properly, but the messages are a
concern. What could be the cause and resolution? Thanks.

-Ron


John

unread,
Nov 30, 2011, 3:22:29 PM11/30/11
to json-io
I assume these are happening during the 'reading' side of
serialization (not the 'writing' side). If so, I suggest adding some
'println debugging' to the 'newInstance(Class c)' method in
JsonReader.java to see what class's are causing this to happen.

When the JsonReader begins instantiating classes to reconstruct the
object graph on the destination side, it first attempts to use a
public constructor. If that fails to instantiate, it then goes
through the rest of the constructors (public or private) until one of
them gets the instance instantiated. Once instantiated, it then
copies the appropriate values to the appropriate fields.

There is a chance that one of the objects you are attempting to
instantiate print's out this message while it is going through this
process. I would locate which object is doing this, and see if that
behavior can be turned off.

I am interested in hearing about what you find.

- John

Ron

unread,
Nov 30, 2011, 7:28:26 PM11/30/11
to jso...@googlegroups.com
John,,

It fails when instantiating class "java.util.HashMap$HashMapEntry".  All the other elements in the object I am trying to reconstruct work fine, only the HashMap$HashMapEntry causes a problem.  Which is odd because instantiating HashMaps classes didn't throw an error.

I reworked the 'newInstance(Class c)' method to attempt the no-arg constructor after checking for the other constructors first.  This worked and the messages went away.  I attached the fix.  Let me know if you want me to do other testing.

-Ron
JsonReaderFix.txt

John DeRegnaucourt

unread,
Dec 2, 2011, 2:29:55 PM12/2/11
to jso...@googlegroups.com
Ron,

I am impressed with how quickly you fixed the issue for your situation.  The question I have, though, what exactly makes this work?  Once I understand that, then I think we could use your solution in the main library code.  

I am thinking that one of the classes your are attempting to instantiate has an very odd public constructor that is emitting this output when it is attempted to be created, as it the class designer wanted a more specific constructor called.  If we put in the fix you have, it will get around the class you have run into, however, there could just as well be a class where if you use a non-public constructor, it could emit this type of error message, but then not emit it if the public constructor is used.

I would really like to know how this "no <init>()" message is getting written out.  Is it via a System.out (god forbid)?  If so, we could temporarily re-direct stdout, do the instantiation, and then put back the System.out mapping. 

The fix I am suggesting, would hide System.out.println() output while the object is instantied, and then restore the ability for that stream to be used.  We'd have to think through the threading ramifications of such a fix.

Another thought is if I can instantiate all classes using some 'trickery' that by passes all constructor executions, and just gets the object space created, similar to a "malloc()" call from the C world.  In normal coding, this would be a bad thing as you want the constructor executed.  In the serialization case, however, all we are trying to do is recreate the exact same object state as it existed on the other end.  I will also looking a generic / generalized object instantiator that can be used for all objects.  That is what is truly desired here.

Thoughts, comments?

Regards,
John

Ron

unread,
Dec 2, 2011, 5:05:11 PM12/2/11
to jso...@googlegroups.com
John,

The Java object I am serializing/deserializing is a simple class with mostly primitive elements (String, boolean, int) and ArrayList/HashMap components that also have String elements in them.  The error messages showed it was trying to instantiate a "java.util.HashMap$HashMapEntry" class.  I've reviewed my code to see if one of the Collection objects is storing a HashMapEntry object instead of an intended String, but I could not locate it (but doesn't mean it isn't... just that I didn't see it).

There are no system.out statements for the error... I suspect Android's Dalvik VM is pushing those to the console because the newInstance method is trying to instantiate a no-arg constructor for a HashMapEntry and there is none in Android.  I am not sure what to do either because this is starting to get way beyond my expertise.

I'll keep looking at my code, but I wonder if your code could first validate there is a no-arg constructor using reflection before attempting to create the class... that seems to be the safest all around... or just do the no-arg constructor last like my solution.  Let me know if you'd like me to test any new code for you.

-Ron

John DeRegnaucourt

unread,
Dec 2, 2011, 6:31:18 PM12/2/11
to jso...@googlegroups.com
Ron,

I like the check-first for no-arg constructor, then use Constructor loop.  That should work (until I can implement the generic non-constructor calling 'new' operation.)

John

Ron

unread,
Dec 3, 2011, 10:36:12 AM12/3/11
to jso...@googlegroups.com
Will you be making the changes soon for the no-arg check?

John DeRegnaucourt

unread,
Dec 3, 2011, 10:39:59 AM12/3/11
to jso...@googlegroups.com
Sure, I will see if I can bang that out this weekend. 

John DeRegnaucourt

unread,
Dec 8, 2011, 6:56:46 AM12/8/11
to jso...@googlegroups.com
I've finished the changes to how classes are instantiated.  This change will eliminate the warning you are seeing and also make it faster, as it caches the constructors now.

In addition, I've changed it to serialize Calendar's much more compactly (I ran into a project where their transfer objects contained GregorianCalendar's and this caused the serialization stream to be extremely large.)

Finally, I've changed how 'Collections' and 'Maps' are written out by default.  They are written in a very simple format that does not expose the internals of the Collection class or Map class.  If you do not want this special treatment of Collection and Map, there is a boolean you can pass into the constructor of the JsonWriter that will tell it to adhere to strictly processing fields and arrays (that's all that really exist in Java, Collections and Maps are just built on top of these fundamental types).

I expect to check this code in over the weekend (2011 Dec 10-11).

Ron

unread,
Dec 9, 2011, 11:41:02 PM12/9/11
to jso...@googlegroups.com
John,

I have encountered another error... "java.lang.NoSuchMethodError: java.util.LinkedList.push" at line 240 in JsonReader.  It only occurs in Android 2.2 while 2.3 works fine.  Can you see if you can implement a fix in this new version?  Thanks.

-Ron

John DeRegnaucourt

unread,
Dec 9, 2011, 11:53:03 PM12/9/11
to jso...@googlegroups.com
Ron,

The attached files fix the 'push' problem you encountered.  In addition, they should fix the problem you had where the constructor was outputting a diagnostic (yet still instantiating the object).

These attached versions have a new optional format for Collections and Maps.  By default it is on, making the JSON output smaller and more readable.  It can be turned off, in which case there is no special treatment for Collections and Maps - they transfer fine, but you see all their 'inards' in the JSON stream.

Regards,
John
JsonWriter.java
JsonReader.java

Ron

unread,
Dec 12, 2011, 5:11:52 PM12/12/11
to jso...@googlegroups.com
John,

It all appears to be working fine now.  Thanks!

John DeRegnaucourt

unread,
Dec 12, 2011, 7:46:37 PM12/12/11
to jso...@googlegroups.com

Make sure you get the latest version, 1.0.4. Thanks for helping solve the issue.

Reply all
Reply to author
Forward
0 new messages