1

JSON を常に次の形式で送信する RESTful サードパーティ API を使用しています。

{
    "response": {
        ...
    }
}

...Java POJO にマップし直す必要がある応答オブジェクトはどこにありますか。たとえば、JSON には、FruitPOJOにマップし直すべきデータが含まれていることがあります。

{
    "response": {
        "type": "orange",
        "shape": "round"
    }
}

Employee...また、JSON には、 POJOにマップし直すべきデータが含まれている場合があります。

{
    "response": {
        "name": "John Smith",
        "employee_ID": "12345",
        "isSupervisor": "true",
        "jobTitle": "Chief Burninator"
    }
}

したがって、RESTful API 呼び出しに応じて、次の 2 つの JSON 結果を 2 つのうちの 1 つにマップする必要があります。

public class Fruit {
    private String type;
    private String shape;

    // Getters & setters for all properties
}

public class Employee {
    private String name;
    private Integer employeeId;
    private Boolean isSupervisor;
    private String jobTitle;

    // Getters & setters for all properties
}

残念ながら、このサード パーティの REST サービスが常に{ "response": { ... } }JSON の結果を返すという事実を変えることはできません。しかし、そのようなresponseバックを aFruitまたはEmployee.

最初に、Jacksonを試してみましたが、あまりうまくいきませんでしたが、私が望んでいたほどには構成可能ではありませんでした。そのため、JSONをPOJOにマッピングするためにXStreamを使用しようとしています。JettisonMappedXmlDriverこれが私が持っているプロトタイプコードです:

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

    xs.alias("response", Fruit.class);
    xs.alias("response", Employee.class);

    // When XStream sees "employee_ID" in the JSON, replace it with
    // "employeeID" to match the field on the POJO.
    xs.aliasField("employeeID", Employee.class, "employee_ID");

    // Hits 3rd party RESTful API and returns the "*fruit version*" of the JSON.
    String json = externalService.getFruit();

    Fruit fruit = (Fruit)xs.fromXML(json);
}

残念ながら、これを実行すると例外が発生します。これは、2 つの異なる Java オブジェクトにxs.alias("response", ...)マッピングしているためです。response

Caused by: com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter$UnknownFieldException: No such field me.myorg.myapp.domain.Employee.type
---- Debugging information ----
field               : type
class               : me.myorg.myapp.domain.Employee
required-type       : me.myorg.myapp.domain.Employee
converter-type      : com.thoughtworks.xstream.converters.reflection.ReflectionConverter
path                : /response/type
line number         : -1
version             : null
-------------------------------

API が常に同じ「ラッパー」 JSON オブジェクトを送り返すという事実を回避するにはどうすればよいresponseでしょうか? 私が考えることができる唯一のことは、最初に次のように文字列置換を行うことです。

String json = externalService.getFruit();
json = json.replaceAll("response", "fruit");
...

しかし、これは醜いハックのようです。XStream (または別のマッピング フレームワーク) は、この特定のケースで私を助ける何かを提供しますか? 事前に感謝します。

4

2 に答える 2

0

実際のタイプを知っている場合は、Jackson を使用すると比較的単純なはずです。次のような一般的なラッパー タイプを使用する必要があります。

public class Wrapper<T> {
  public T response;
}

唯一のトリックは、型オブジェクトを構築して、Jackson に何があるかを知らせることTです。静的に利用可能な場合は、次のようにします。

Wrapper<Fruit> wrapped = mapper.readValue(input, new TypeReference<Wrapper<Fruit>>() { });
Fruit fruit = wrapped.response;

ただし、より動的に生成される場合は、次のようになります。

Class<?> rawType = ... ; // determined using whatever logic is needed
JavaType actualType = mapper.getTypeFactory().constructGenericType(Wrapper.class, rawType);
Wrapper<?> wrapper = mapper.readValue(input, actualType);
Object value = wrapper.response;

しかし、どちらにしても「うまくいくはずです」。後者の場合、基本型 ("? extends MyBaseType") を使用できる場合がありますが、一般に動的型は指定できないことに注意してください。

于 2013-01-03T18:52:31.560 に答える
0

Jackson には 2 つの方法があります。

  • 必要なキーがそこにあることを手動でテストします(JsonNode必要なメソッドがあります)。
  • JSON スキーマを使用します。Java には 1 つの API があります。Jackson を使用するjson-schema-validator (私のものです) です。

最初のオブジェクト タイプに一致するスキーマを記述します。

{
    "type": "object",
    "properties": {
        "type": {
            "type": "string",
            "required": true
        },
        "shape": {
            "type": "string",
            "required": true
        }
    },
    "additionalProperties": false
}

これをスキーマとしてロードし、それに対して入力を検証します。検証された場合は、果物クラスに対して逆シリアル化する必要があることがわかります。それ以外の場合は、2 番目のアイテム タイプのスキーマを作成し、セキュリティ対策としてそれに対して検証し、他のクラスを使用して逆シリアル化します。

API のコード例もあります (バージョン 1.4.x)

于 2013-01-02T14:07:19.023 に答える