2

json ドキュメント内の文字列要素の単純な配列を、genson を使用して Bean 内にある Java リストに変換しようとしています。これが自動的に行われることを期待していましたが、機能していません。何か不足していますか?

これが私のJson-Stringです:

{"id":12345,"permissions":["READ_XX","WRITE_XX"]}

そして、これが私のオブジェクトの出力であり、私のアクセス許可リストが入力されていないことを示しています:

DefaultRole [id=12345, name=null, permissions=[]]

私の DefaultRole クラスは次のようになります。

public class DefaultRole implements Role
{
  public Id id = null;

  @XmlElementWrapper(name = "permissions")
  @XmlElement(name = "permission")
  private List<String> permissions = Lists.newArrayList();

  @Inject
  public DefaultRole()
  {

  }
  [...]

JAXB アノテーションは XML 変換専用です。彼らはここで役割を果たすべきではありません。

次のような Genson オブジェクトを作成しています。

Genson genson = new Genson.Builder()
  .setWithClassMetadata(false)
  .setWithBeanViewConverter(true)
  .setWithDebugInfoPropertyNameResolver(true)
  .setSkipNull(true)
  .create();

私の逆シリアル化呼び出し:

genson().deserialize(jsonString, DefaultRole.class)

JSON文字列配列をBean内にあるJava Listオブジェクトに逆シリアル化する方法についてのヒントはありますか?

編集 [部分的に解決 - まだ 1 つの質問が未解決]

私は今、さらに一歩を踏み出しました。ルーツに戻り、単純に文字列のリストを持つ基本的な Bean から始めました。そして、初めて期待どおり、これは機能します。前のオブジェクトとの主な違いは、これが Bean 仕様に従っていることです。もう 1 つのオブジェクト (DefaultRole) は fluid-object-pattern に従います (それが正しい定義かどうかはわかりません)。基本的に、setter メソッドが void である代わりに、オブジェクトを返すので、次の値を流動的な方法で簡単に設定できます。

したがって、これは機能します:

public void setPermissions(List<String> permissions)
{
  this.permissions = permissions;
}

これは動作しません:

public Role setPermissions(List<String> permissions)
{
  this.permissions = permissions;
  return this;
}

他の誰かがこれに遭遇しましたか?すべてのBeanをBean仕様に準拠するように切り替える代替手段は何ですか? セッターメソッドを使用する代わりに、純粋なフィールドレベルの人口を使用する唯一のオプションはありますか?

編集 [ほぼ解決済み]

こんにちは、私が行ったことを理解するためにコードが必要な質問にどのように答えるのが最善かわかりません。

とにかく、あなたの助けをどうもありがとう。私は、私が探していたタイプのものである 3 番目のオプションが本当に気に入っています。残念ながら、「型クラス xxx.DefaultRole のコンストラクターが見つかりませんでした」というエラーが表示されます。あなたの答えであなたが言ったことによると、これは Trilean.UNKNOWN を返すときに検索が続行されるときに発生しないはずです。

次のコードを genson-builder に追加しています。

        .set(new BeanMutatorAccessorResolver.BaseResolver()
        {
            @Override
            public Trilean isMutator(Method method, Class<?> fromClass)
            {
                if (Reflect.isSetter(method))
                    return Trilean.TRUE;

                else
                    return Trilean.UNKNOWN;
            }
        })

私の Reflect.isSetter(method) は次のようになります (コードはここから適応: http://www.asgteach.com/blog/?p=559 ):

public static boolean isSetter(Method method)
{
    return Modifier.isPublic(method.getModifiers()) &&
        (method.getReturnType().equals(void.class) || method.getReturnType().equals(method.getDeclaringClass())) &&
        method.getParameterTypes().length == 1 &&
        method.getName().matches("^set[A-Z].*");
}

BaseResolver は、実装されていないすべてのものに対して Trilean.UNKNOWN を返します。したがって、標準ロジックを使用してコンストラクターを見つける必要があります。

編集 [解決済み]

完全を期すために、実際に機能するコードを投稿します。

public static final Genson genson()
{
    Genson genson = new Genson.Builder()
        .setSkipNull(true)
        .setWithClassMetadata(false)
        .setWithDebugInfoPropertyNameResolver(true)
        .setWithBeanViewConverter(true)
        .with(new BeanMutatorAccessorResolver.BaseResolver()
        {
            @Override
            public Trilean isMutator(Method method, Class<?> fromClass)
            {
                if (Reflect.isSetter(method))
                    return Trilean.TRUE;

                else
                    return Trilean.UNKNOWN;
            }
        })
        .create();

    return genson;
}

ここで、「.set(new BeanMutatorAccessorResolver.BaseResolver()」を「.with(new BeanMutatorAccessorResolver.BaseResolver()」) に置き換える必要があることに注意することが重要です (「set」ではなく「with」に注意してください)。それ以外の場合、標準のリゾルバーは使用されなくなり、コンストラクターが見つからなくなったというエラーが発生します。

isSetter メソッドは次のようになります。

public static boolean isSetter(Method method)
{
    return Modifier.isPublic(method.getModifiers())
        && (method.getReturnType().equals(void.class) || method.getReturnType().isAssignableFrom(method.getDeclaringClass()))
        && method.getParameterTypes().length == 1
        && method.getName().matches("^set[A-Z].*");
}

ここで、return-type と declaring-class を比較するときに、もともと「isAssignableFrom」ではなく「equals」を使用していたことに注意することが重要です。これは、戻り値の型が宣言されているクラスとまったく同じクラスである場合にのみ機能します。ただし、戻り値としてインターフェイスを使用する場合は機能しなくなります。代わりに "method.getReturnType().isAssignableFrom(method.getDeclaringClass())" を使用すると、これはインターフェイス (スーパー インターフェイスを含む) でも機能します。

ありがとう、マイケル

4

1 に答える 1

1

実際、Genson は (他のほとんどのライブラリと同様に) Java Bean 規則を使用してセッター/ゲッターを検出するため、setPermissions をセッターとして検出しません。

2 つの簡単な解決策:

1) @JsonProperty で注釈を付けることができます (名前を定義する必要はありません)。これは、genson にそれをセッターとして使用するように指示します (ただし、genson は返されたオブジェクトを再利用しません。つまり、あなたの場合は機能しますが、ビルダーのようなものはそのようにサポートされています)。

2) genson にフィールドのみを使用させ、メソッドを使用させないようにすることができます (これにより、get/set を呼び出さずにフィールド値が直接設定されます)。

Genson.Builder()
        .setUseFields(true)
        .setFieldFilter(VisibilityFilter.DEFAULT)
        .setUseGettersAndSetters(false)
      .create();

より一般的な:

3)特定のケースを処理するカスタム BeanMutatorAccessorResolver をチェーンに追加します

Genson genson = Genson.Builder().with(new BeanMutatorAccessorResolver.BaseResolver() {
        @Override
        public Trilean isMutator(Method method, Class<?> fromClass) {
            // if method starts with setXXX and return type same as method.getDeclaringClass
            return Trilean.TRUE;
            // else return Tilean.UNKNOWN genson will use its built-in resolvers
        }
    }).create();

編集

ビルダーでwithメソッドの代わりにsetを使用していたことがわかったはずです。genson API で setXXX が表示される場合、これは通常、何らかのメカニズムをオーバーライド/強制する (値を設定する) ことを意味しますが、動作を追加するために使用されます。

于 2014-02-23T11:21:45.927 に答える