cincheo / jsweet

A Java to JavaScript transpiler.
http://www.jsweet.org
Other
1.46k stars 160 forks source link

Parse List from JSON #153

Closed mb720 closed 8 years ago

mb720 commented 8 years ago

Hi!

My server sends a List<Article> to the client where Article is a custom datatype of mine that contains the method getName().

Now, I convert those Articles to JSON on the server side using Gson:

String toJson(List<Article> articles) {
    Type type = new TypeToken<List<Article>>() {}.getType();

    return new Gson().toJson(articles, type);
}

On the client side, I get the Articles as a JSON string like this:

void get(String url, Consumer<String> onLoad) {
    XMLHttpRequest request = new XMLHttpRequest();

    // Get asynchronously
    request.open("GET", url, true);
    request.onload = e -> {
        onLoad.accept(request.responseText);
        return new Object();
    };
    request.send();
}

I call it to get the JSON and convert it to Article objects.

get(getArticlesUrl, response -> {
    List<Article> articles = toArticles(response);

    for (Article article : articles) {
        // TypeError: article.getName is not a function
        console.log("Article from server:" + article.getName());
    }
});

List<Article> toArticles(String response) {
    List<Article> articles = new ArrayList<>();
    Array<Object> arr = (Array<Object>) JSON.parse(response);
    for (Object articleHopefully: arr) {
        articles.add((Article) articleHopefully);
    }
    return articles;
}

Everything compiles just fine but unfortunately although toArticles type checks, it doesn't really return Articles since I get TypeError: article.getName is not a function when calling article.getName().

Any help is appreciated.

renaudpawlak commented 8 years ago

That's a typical JavaScript issue. When parsing the JSON, all you get are the data parts of the objects, not the actual instances. In order to get the instances, you need to "revive" your data objects. Here is a JSweet function to revive your objects to articles implemented with jQuery:

import static def.jquery.Globals.$;
[...]
    private Article revive(Object untypedDto) {
        return (Article) $.extend(new Article(), untypedDto);
    }

You need to call it on each article object after it has been parsed from JSON.

Note that it is possible to have a more transparent solution but it requires to have a type metadata in your objects.