JsonConverter failed with ObservableList

1,377 views
Skip to first unread message

Tai Hu

unread,
May 27, 2014, 5:07:41 PM5/27/14
to dataf...@googlegroups.com
Hi,
    I used RestSource to make RESTful call to my remote web service server. Since the return data is in JSON format, I created a JsonConverter as

JsonConverter<DataModel> jsonConverter = new JsonConverter<DataModel>(DataModel.class);

My DataModel contains a ObservableList<ChildModel>, after I run listDataProvider.retrieve(), an exception throw out from Worker thread

org.codehaus.jackson.map.JsonMappingException: Can not find a deserializer for non-concrete Collection type [collection type; class javafx.collections.ObservableList, contains [simple type, class com.test.model.ChildModel]]

I knew this is more of a Jackson API question. Just want to see if you have a quick solution about this. Since my data model object contains a lot of ObservableList.

Thanks,


Tai

Johan Vos

unread,
May 28, 2014, 3:37:48 PM5/28/14
to Tai Hu, dataf...@googlegroups.com
Hi,

Can you use a ListProperty instead?

- Johan


--
You received this message because you are subscribed to the Google Groups "DataFX" group.
To unsubscribe from this group and stop receiving emails from it, send an email to datafx-dev+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Tai Hu

unread,
May 28, 2014, 5:07:49 PM5/28/14
to dataf...@googlegroups.com, Tai Hu, jo...@lodgon.com
Johan,
     I just tried ListProperty and it has the same problem with ObservableList, since ListProperty is not a concrete class. If you use SimpleListProperty instead, then it will pass the non-concrete collection type error. However, it runs into a java.lang.UnsupportedOperationException. I looked into JavaFX 8 source code, it turns out that for SimpleListProperty, if you create an instance by using default constructor (no arg constructor), it creates a FXCollections.emptyObservableList(), which is unmodifiable. So for now, I just created my own deserializer then put @JsonDeserialize annotation on my model class to handle ObservableList

Thanks,

Tai

Hendrik Ebbers

unread,
May 28, 2014, 6:53:19 PM5/28/14
to dataf...@googlegroups.com
Hi,
can you share the code with us?

Tai Hu

unread,
May 28, 2014, 7:23:49 PM5/28/14
to dataf...@googlegroups.com
Sure, here is the code I used to handle ObservableList

Model Object

@JsonDeserializer(using=ParentObjectDeserializer.class)
public class ParentObject {
    private String name;
    ObservableList<ChildObject> children;

    // getter and setter
    ...
}

public class ChildObject {
      private String name;

      // getter and setter
      ...
}

Deserializer class

public class ParentObjectDeserializer extends JsonDeserializer<ParentObject> {
     public ParentObjectDeserializer() {
     }

     @Override
     public ParentObject deserialize(JsonParser parser, DeserializationContext ctx)
throws IOException, JsonProcessingException {
            ParentObject parentObject = new ParentObject();

            ObjectMapper objectMapper = (ObjectMapper) parser.getCodec();
            JsonNode node = objectMapper.readTree(parser);
            parent.setName(node.get("name").asText());
            JsonNode childNodes = node.get("children");

            ObservableList<ChildObject> children = FXCollections.observableArrayList();

            for (Iterator<JsonNode> i = childNodes.iterator(); i.hasNext();) {
                  JsonNode childNode = i.next();
                  ChildObject child = new ChildObject();
                  child.setName(childNode.get("name"));
                  children.add(child);
            }

            parentObject.setChildren(children);

            return parentObject;
     }
}

Once you put @JsonDeserializer annotation on your model object, DataFX's JsonConverter (Actually it is Jackson's ObjectMapper) will automatically use your customized deserializer instead of default standard one. I hope that there is a better solution to this issue. With this approach, you need to write a deserializer for every model object which contains a ObservableList.

Tai

Johan Vos

unread,
Jun 24, 2014, 7:09:43 AM6/24/14
to dataf...@googlegroups.com
Hi Tai,

We are changing the default implementation for the JsonConverter: we now use the javax.json API. This doesn't come with a mapper yet, so we use an own mapper for now (until there is a reference implementation). In the Mapper we are writing, we will make sure that list/arrays are automatically mapped to ObservableList fields. Stay tuned, this shouldn't take long...

- Johan

Op donderdag 29 mei 2014 01:23:49 UTC+2 schreef Tai Hu:

Johan Vos

unread,
Jun 24, 2014, 10:51:54 AM6/24/14
to dataf...@googlegroups.com
Tai,

I committed the new version of the JsonConverter, and added a sample in org.datafx.samples.NestedListSample.
Is this useful?

- Johan

Op dinsdag 24 juni 2014 13:09:43 UTC+2 schreef Johan Vos:

Turbo JV

unread,
Apr 28, 2015, 1:16:02 AM4/28/15
to dataf...@googlegroups.com
I did this working when JsonConverter was using jackson.  Now changed it trying to fix my code so works with new JsonConverter

Below is Converter being created
JsonConverter jsonConvert = new JsonConverter("jsonCase", CaseTable.class);

Below is the class trying to create in java
@XmlRootElement(name = "jsonCase")
public class CaseTable {
    
    private final StringProperty caseTitleProp = new SimpleStringProperty();
    private long caseID;
    private String caseTitle;

    public CaseTable() {
        this.caseID = -1;
        this.caseTitle = "";
        caseTitleProp.set("");        
    }    
    
    public CaseTable(long caseID, String caseTitle) {
        this.caseID = caseID;
        this.caseTitle = caseTitle;
        caseTitleProp.set(caseTitle);
    }
    
    public String getCaseTitleProp() {
        return caseTitleProp.get();
    }

    public void setCaseTitleProp(String value) {
        caseTitleProp.set(value);
    }

    public StringProperty caseTitlePropProperty() {
        return caseTitleProp;
    }

    
//    @JsonProperty("CaseID")
    @XmlElement(name = "CaseID")
    public long getCaseID() {
        return caseID;
    }

    public void setCaseID(long caseID) {
        this.caseID = caseID;
    }

//    @JsonProperty("CaseTitle")
    @XmlElement(name = "CaseTitle")
    public String getCaseTitle() {
        return caseTitle;
    }

    public void setCaseTitle(String caseTitle) {
        setCaseTitleProp(caseTitle);
        this.caseTitle = caseTitle;
    }
    
}

Here is json message
{"dsJson":{"jsonCase":[{"CaseID":1,"CaseTitle":"Case 1"},{"CaseID":2,"CaseTitle":"Case 2"}]}}

Can you see anything I am doing wrong.  Or is there bug is system?

Kind Regards,

TurboJV

Turbo JV

unread,
Apr 28, 2015, 7:18:46 PM4/28/15
to dataf...@googlegroups.com
I have change server so json message is as follows and now working.
{"jsonCase":[{"CaseID":1,"CaseTitle":"Case 1"},{"CaseID":2,"CaseTitle":"Case 2"}]}

Seems like there is bug where can not find nested json Arrays.  Was working with jackson converter.

Kind Regards,

TurboJV
Reply all
Reply to author
Forward
0 new messages