9

I'm using XStream and JETTISON's Stax JSON serializer to send/receive messages to/from JSON javascripts clients and Java web applications.

I want to be able to create a list of objects to send to the server and be properly marshalled into Java but the format that XStream and JSON expect it in is very non-intuitive and requires our javascript libraries to jump through hoops.

[EDIT Update issues using GSON library] I attempted to use the GSON library but it cannot deserialize concrete objects when I only have it expect generic super classes (XStream and Jettison handles this because type information is baked into the serialization).

GSON FAQ states Collection Limitation:

Collections Limitations

Can serialize collection of arbitrary objects but can not deserialize from it

Because there is no way for the user to indicate the type of the resulting object

While deserializing, Collection must be of a specific generic type

Maybe I'm using bad java practices but how would I go about building a JSON to Java messaging framework that sent/received various concrete Message objects in JSON format?

For example this fails:

public static void main(String[] args) {
    Gson gson = new Gson();

    MockMessage mock1 = new MockMessage();
    MockMessage mock2 = new MockMessage();
    MockMessageOther mock3 = new MockMessageOther();

    List<MockMessage> messages = new ArrayList<MockMessage>();
    messages.add(mock1);
    messages.add(mock2);
    messages.add(mock3);

    String jsonString = gson.toJson(messages);

    //JSON list format is non-intuitive single element array with class name fields
    System.out.println(jsonString);
    List gsonJSONUnmarshalledMessages = (List)gson.fromJson(jsonString, List.class);
    //This will print 3 messages unmarshalled
    System.out.println("XStream format JSON Number of messages unmarshalled: " + gsonJSONUnmarshalledMessages.size());
}

[{"val":1},{"val":1},{"otherVal":1,"val":1}]
Exception in thread "main" com.google.gson.JsonParseException: The JsonDeserializer com.google.gson.DefaultTypeAdapters$CollectionTypeAdapter@638bd7f1 failed to deserialized json object [{"val":1},{"val":1},{"otherVal":1,"val":1}] given the type interface java.util.List

Here's an example, I want to send a list of 3 Message objects, 2 are of the same type and the 3rd is a different type.

import java.util.ArrayList;
import java.util.List;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.json.JettisonMappedXmlDriver;

class MockMessage {
    int val = 1;
}
class MockMessageOther {
    int otherVal = 1;
}

public class TestJSONXStream {


    public static void main(String[] args) {
        JettisonMappedXmlDriver xmlDriver = new JettisonMappedXmlDriver();        
        XStream xstream = new XStream(xmlDriver);

        MockMessage mock1 = new MockMessage();
        MockMessage mock2 = new MockMessage();
        MockMessageOther mock3 = new MockMessageOther();

        List messages = new ArrayList();
        messages.add(mock1);
        messages.add(mock2);
        messages.add(mock3);

        String jsonString = xstream.toXML(messages);

        //JSON list format is non-intuitive single element array with class name fields
        System.out.println(jsonString);
        List xstreamJSONUnmarshalledMessages = (List)xstream.fromXML(jsonString);
        //This will print 3 messages unmarshalled
        System.out.println("XStream format JSON Number of messages unmarshalled: " + xstreamJSONUnmarshalledMessages.size());

        //Attempt to deserialize a reasonable looking JSON string
        String jsonTest = 
              "{"+
                "\"list\" : ["+ 
                          "{"+
                          "\"MockMessage\" : {"+
                              "\"val\" : 1"+
                          "}"+
                      "}, {"+
                          "\"MockMessage\" : {"+
                              "\"val\" : 1"+
                          "}"+
                      "}, {"+
                          "\"MockMessageOther\" : {"+
                              "\"otherVal\" : 1"+
                          "}"+
                      "} ]"+
                  "};";

        List unmarshalledMessages = (List)xstream.fromXML(jsonTest);

        //We expect 3 messages but XStream only deserializes one
        System.out.println("Normal format JSON Number of messages unmarshalled: " + unmarshalledMessages.size());
    }

}

Intuitively I expect the XStream JSON to be serialized (and able to deserialize correctly) from the following format:

{
    "list" : [ 
        {
        "MockMessage" : {
            "val" : 1
        }
    }, {
        "MockMessage" : {
            "val" : 1
        }
    }, {
        "MockMessageOther" : {
            "otherVal" : 1
        }
    } ]
}

Instead XStream creates a single element list with fields that are named the classnames and nested arrays of Objects of the same type.

{
    "list" : [ {
        "MockMessage" : [ {
            "val" : 1
        }, {
            "val" : 1
        } ],
        "MockMessageOther" : {
            "otherVal" : 1
        }
    } ]
}

The trouble may be caused by it using the XStream XML CollectionConverter?

Does anyone have a suggestion for a good JSON Java object serialization that allows you to read/write arbitrary Java objects. I looked at the Jackson Java JSON Processor but when you were reading in objects from a stream you had to specify what type of object it was unlike XStream where it will read in any object (because the serialized XStream JSON contains class name information).


C# XMLDocument to DataTable?

I assume I have to do this via a DataSet, but it doesn't like my syntax.

I have an XMLDocument called "XmlDocument xmlAPDP".

I want it in a DataTable called "DataTable dtAPDP".

I also have a DataSet called "DataSet dsAPDP".

-

if I do DataSet dsAPDP.ReadXML(xmlAPDP) it doesn't like that because ReadXML wants a string, I assume a filename?

4

3 に答える 3

6

XStream は適切ではないという点で、他のポスターに同意します。これは OXM (オブジェクト/Xml マッパー) であり、JSON は XML 処理パスを使用して 2 次出力形式として処理されます。これが、(hierarchich xml モデルを json の object-graph モデルに、またはその逆に変換する方法の) "規則" が必要な理由です。そして、あなたの選択は、次善の選択の邪魔にならないものを使用することに要約されます。XML が主要なデータ形式であり、初歩的な JSON(-like) サポートが必要な場合は、これで問題ありません。

優れた JSON サポートを得るには、次のような実際の OJM マッピングを行う JSON 処理ライブラリを使用することを検討します (Svenson も行うと思いますが、さらに追加します)。

また、XML と JSON の両方をサポートする必要がある場合でも、これらのタスクに個別のライブラリを使用する方が IMO の方が適切です。サーバー側で使用するオブジェクト (Bean) は異なる必要はありません。変換するシリアライゼーション ライブラリだけです。 xml と json.

于 2009-05-11T18:50:09.007 に答える
0

完全なクラス名に基づく svenson 型マッパーは、次のようになります。

public class ClassNameBasedTypeMapper extends PropertyValueBasedTypeMapper
{
    protected Class getTypeHintFromTypeProperty(String value) throws IllegalStateException
    {
        try
        {
            return Class.forName(value);
        }
        catch (ClassNotFoundException e)
        {
            throw new IllegalStateException(value + " is no valid class", e);
        }
    }
}

これは、実際には必要とせずに PropertyValueBasedTypeMapper の構成を継承するため、理想的な実装ではありません。(svenson にクリーン バージョンを含める必要があります)

セットアップは上記と非常によく似ています

JSONParser parser = new JSONParser();
ClassNameBasedTypeMapper mapper = new ClassNameBasedTypeMapper();
mapper.setParsePathInfo("[]");
parser.setTypeMapper(mapper);

List foos = parser
    .parse( List.class, "[{\"type\":\"package.Foo\"},{\"type\":\"package.Bar\"}]");
于 2009-05-07T22:26:19.950 に答える