1

この JSON を逆シリアル化した結果の Java データ構造があります。

{
  'level1 value1': {
    'level2 value1': {
      'level3 value1': [ "25", "45", "78" ],
      // ...
      'level3 valueN': [ "59", "17", "42" ]
    },
    // ...
    'level2 valueN': {
      'level3 value1': [ "34", "89", "54" ],
      // ...
      'level3 valueN': [ "45", "23", "23" ]
    },
  },
  // ...
  'level1 valueN': {
    // ...
  }
}

Java では、これは次のようになります。

Map<String, Map<String, Map<String, List<String>>>> data;

もちろん、レベルの数は任意なので、変数宣言でコレクションをネストすることはできません。私が代わりにやっていることはこれです:

void traverse(Map<String, ?> children) {
  for (Map.Entry<String, ?> node : data.entrySet()) {
    if (node.getValue() instanceof Map) {
      doSomethingWithNonLeafNode((Map<String, Map<String, ?>>) node);
    } else if (node.getValue() instanceof List) {
      doSomethingWithLeafNode((Map <String, List<String>>) node);
    }
  }
}


void doSomethingWithNonLeafNode(Map <String, Map<String ?>> node) {
  // do stuff
}


void doSomethingWithLeafNode(Map <String, List<String>> node) {
  // do stuff
}

これは明らかに a) いくつかのチェックされていないキャストを使用しており、b) 醜いです。これを回避するために、新しい型を定義しようとしました。

private interface Node extends Map<String, Map<String, ?>> {
}

private interface LeafNode extends Map<String, List<String>> {
}

// ...

    if (node.getValue() instanceof Map) {
      doSomethingWithNonLeafNode((Node) node);
    } else if (node.getValue() instanceof List) {
      doSomethingWithLeafNode((LeafNode) node);
    }

ただし、これにより実行時例外が発生します。

java.lang.ClassCastException: java.util.HashMap cannot be cast to com.foo.ReportDataProcessor$Node

クリーンで警告のない方法でこれを行うにはどうすればよいですか?

4

3 に答える 3

1

よりクリーンなソリューションとして、コンテナとしての Map を忘れて、ツリーを表すオブジェクトを作成することをお勧めします。

public class Node{
   String text;
   List<String> data;
   List<Node> children; 
}

また、Map を使用してツリーを作成する現在の方法を、このツリー構造を使用するように実装できます。ノードの子が空でない場合、データについて考える必要はありません。

void traverse(Node node) {
  if(node.getChildren()!=null){
      doSomethingWithNonLeafNode(node);
      // Or for recursion if you need
      // List<Node> children=node.getChildren();
      // for(Node c:children){
      //    traverse(c);
      // }
  }else{
      doSomethingWithLeafNode(node);
  }
}
于 2012-03-14T10:24:01.870 に答える
1

JSON デシリアライザーは Node および LeafNode インターフェースを認識しないため、新しいタイプを定義しても役に立ちません。したがって、生成される具体的なコレクション オブジェクトはそれらを実装できません。

事前にマップの要素の型を実際に把握していないため、強制するコンパイル時の型の安全性はありません。依存できるのは実行時の型チェックのみです。したがって、ジェネリックは生活を複雑にし、コードを醜くしますが、何のメリットもありません。

したがって、ここでの最悪の解決策は、コードで非ジェネリックMapList型を使用して、ジェネリックを削除することだと思います。

于 2012-03-14T10:08:21.107 に答える
1

ユニオン型がないとうまくやれないと思います。

考えてみると、Map扱っている には実際には 2 種類のオブジェクトが含まれている可能性があります。下のレベルの別のマップか、リーフ ノードの文字列のリストです。したがって、このマップのジェネリック パラメータは、マップとリストの両方の共通のスーパータイプである必要があります。最終的に、リーフ ノードがあり、リストを処理していることを検出したら、キャストする必要があります。

于 2012-03-14T10:09:10.013 に答える