Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem deserializing ObservableObjects #42

Closed
octaviospain opened this issue Jun 21, 2015 · 4 comments
Closed

Problem deserializing ObservableObjects #42

octaviospain opened this issue Jun 21, 2015 · 4 comments
Labels

Comments

@octaviospain
Copy link

I'm coding a JavaFX application and I want to serialize/deserialize a list of objects that are observable cause they are used in a TableView. I tested that the serialization/deserialization with json-io of a List works well, but when I try to do the same thing with an ObservableList I get JsonIoException when calling readObject() from the JsonReader instance
This is the failure trace from JUnit

com.cedarsoftware.util.io.JsonIoException: null
Last read: afx.beans.property.SimpleObjectProperty","bean":null,"name":"","value":{"@type":"java.time.LocalDate","year":2015,"month":6,"day":21},"observable":null,"listener":null,"valid":true,"helper":null}}]}}v
line: 1, col: 3721
    at com.cedarsoftware.util.io.JsonReader.convertParsedMapsToJava(JsonReader.java:598)
    at com.cedarsoftware.util.io.JsonReader.readObject(JsonReader.java:540)
    at tests.unit.LibraryJsonSerializeTest.testObservableListToLibrary(LibraryJsonSerializeTest.java:69)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Caused by: java.lang.NullPointerException
    at com.sun.javafx.collections.ObservableListWrapper.size(ObservableListWrapper.java:94)
    at java.util.AbstractList.add(AbstractList.java:108)
    at com.cedarsoftware.util.io.ObjectResolver.traverseCollection(ObjectResolver.java:325)
    at com.cedarsoftware.util.io.Resolver.convertMapsToObjects(Resolver.java:122)
    at com.cedarsoftware.util.io.JsonReader.convertParsedMapsToJava(JsonReader.java:584)
    ... 25 more

Any ideas about the reason?

@jdereg
Copy link
Owner

jdereg commented Jun 21, 2015

If you notice near the end of the stack trace, the last 'Caused by:' entry, it says a NullPointerException occurred. It occurred inside the ObservableListWrapper.size() method. Taking a look at that method, you will see that all it does is call backingList.size(). The backingList member variable is obviously null, and calling size() on it causes the NPE.

This happens because during instantiation of the ObservableListWrapper, the backingList member variable is not getting set. json-io allows you to assign your own 'instantiator' class for situations like this. Use the JsonReader.assignInstantiator() method to assign your own JsonReader.ClassFactory class to be called when a new instance of ObservableListWrapper is needed:

JsonReader.assignInstantiator(ObservableListWrapper.class, myObservableListWrapperCreator);

This will associate a JsonReader.ClassFactory instance to be called which will create the ObservableListWrapper when needed.

public static class MyObservableListWrapperCreator implements JsonReader.ClassFactory
{
    Object newInstance(Class c)
    {
        // properly create an new ObservableListWrapper and return it here
    }
}

When the JsonReader encounters an ObservableListWrapper that needs to be created, it will call your factory class to get a new one. Since you are in charge of writing that class, you can properly create a new ObservalListWrapper and return it.

JsonReader does a lot of work to attempt to construct any class it encounters, including calling all constructors, private constructors, even using sun.misc.Unsafe if available. However, some classes still require their constructors to be called. This is why JsonReader has the ability to allow you to install your own 'constructors' as needed.

@octaviospain
Copy link
Author

Ok that is nice, I see now the power of json-io with that feature. I readed twice your explanation and I search in the api but I can't figure how to "properly create an new ObservableListWrapper and return it here", given a Class as parameter. I checked the code of JsonReader's CollectionFactory class and I infered that the naive approach would be something like

public class OberservableListWrapperCreator implements ClassFactory {

    @Override
    public Object newInstance(Class c) {
        if(ObservableListWrapper.class.isAssignableFrom(c))
                return new ObservableListWrapper(null);
        else
            throw new JsonIoException("CollectionFactory handed Class for which it was not expecting: " + c.getName());
    }
}

But obviously isn't. Sorry for my skills, can you tell me more about how I have to implement that? Thanks a lot

@jdereg
Copy link
Owner

jdereg commented Jun 21, 2015

First, you do not need an 'isAssignableFrom()' check. Your code will only be
called with a ObservableListWrapper.class. Pass whatever you need to
your ObservableListWrapperCreator in it's constructor that you would need
to create the class properly. Currently, your class does not have any constructor, so your 'newInstance(Class c)' method has no 'help' to create the class.

I am not familiar with this particular (ObservableListWrapper) class, but I am sure there is a
'normal' way to create an instance of ObservableListWrapper. Create the
instance in this method this 'normal' way [look at the JDK code if necessary], and then return it. If you need some external instances, those can be passed through your [missing] constructor, and then
used in the newInstance() method.

On Sun, Jun 21, 2015 at 7:18 PM, Otto notifications@github.com wrote:

Ok that is nice, I see now the power of json-io with that feature. I
readed twice your explanation and I search in the api but I can't figure
how to "properly create an new ObservableListWrapper and return it here",
given a Class as parameter. I checked the code of JsonReader's
CollectionFactory class and I infered that the naive approach would be
something like

public class OberservableListWrapperCreator implements ClassFactory {

@Override
public Object newInstance(Class c) {
    if(ObservableListWrapper.class.isAssignableFrom(c))
            return new ObservableListWrapper(null);
    else
        throw new JsonIoException("CollectionFactory handed Class for which it was not expecting: " + c.getName());
}

}

But obviously isn't. Sorry for my skills, can you tell me more about how I
have to implement that? Thanks a lot


Reply to this email directly or view it on GitHub
#42 (comment).

@octaviospain
Copy link
Author

Thank you a lot, I just did it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants