440

私は Gson を学ぼうとしていますが、フィールドの除外に苦労しています。ここに私のクラスがあります

public class Student {    
  private Long                id;
  private String              firstName        = "Philip";
  private String              middleName       = "J.";
  private String              initials         = "P.F";
  private String              lastName         = "Fry";
  private Country             country;
  private Country             countryOfBirth;
}

public class Country {    
  private Long                id;
  private String              name;
  private Object              other;
}

GsonBuilder を使用して、firstNameまたはのようなフィールド名に ExclusionStrategy を追加できますが、countryのような特定のフィールドのプロパティを除外することはできないようですcountry.name

メソッドを使用するpublic boolean shouldSkipField(FieldAttributes fa)と、FieldAttributes には、フィールドを のようなフィルタと一致させるのに十分な情報が含まれていませんcountry.name

PS:これを改善し、RegExを使用してフィールドを除外したいので、注釈を避けたいです。

編集: Struts2 JSONプラグインの動作をエミュレートできるかどうかを確認しようとしています

Gsonを使用して

<interceptor-ref name="json">
  <param name="enableSMD">true</param>
  <param name="excludeProperties">
    login.password,
    studentList.*\.sin
  </param>
</interceptor-ref>

編集: 次の追加で質問を再開しました:

この問題をさらに明確にするために、同じタイプの 2 番目のフィールドを追加しました。基本的には除外したいのですcountry.nameが、そうではありませんcountrOfBirth.name。また、国をタイプとして除外したくありません。したがって、型は同じです。オブジェクト グラフ内の実際の場所を特定して除外したいのです。

4

16 に答える 16

655

一般的にシリアライズしたくないフィールドは、「transient」修飾子を使用する必要があります。これは、json シリアライザーにも適用されます (少なくとも、gson を含む、私が使用したいくつかのフィールドには適用されます)。

シリアル化された json に名前を表示したくない場合は、次のように一時的なキーワードを指定します。

private transient String name;

詳細については、Gson のドキュメントを参照してください。

于 2011-05-04T20:40:31.683 に答える
325

Nishantは良い解決策を提供しましたが、もっと簡単な方法があります。次のように、目的のフィールドに@Exposeアノテーションを付けるだけです。

@Expose private Long id;

シリアル化したくないフィールドはすべて省略してください。次に、Gsonオブジェクトを次のように作成します。

Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
于 2011-10-18T17:26:56.753 に答える
247

したがって、 と を除外 firstNamecountry.nameます。これはあなたがどのExclusionStrategyように見えるべきかです

    public class TestExclStrat implements ExclusionStrategy {

        public boolean shouldSkipClass(Class<?> arg0) {
            return false;
        }

        public boolean shouldSkipField(FieldAttributes f) {

            return (f.getDeclaringClass() == Student.class && f.getName().equals("firstName"))||
            (f.getDeclaringClass() == Country.class && f.getName().equals("name"));
        }

    }

よく見るとtrueforStudent.firstNameとが返されますがCountry.name、これは除外したいものです。

ExclusionStrategyこれを次のように適用する必要があります。

    Gson gson = new GsonBuilder()
        .setExclusionStrategies(new TestExclStrat())
        //.serializeNulls() <-- uncomment to serialize NULL fields as well
        .create();
    Student src = new Student();
    String json = gson.toJson(src);
    System.out.println(json);

これは以下を返します:

{ "middleName": "J.", "initials": "P.F", "lastName": "Fry", "country": { "id": 91}}

国オブジェクトはid = 91L学生クラスで初期化されていると思います。


あなたは空想になるかもしれません。たとえば、名前に「name」文字列を含むフィールドをシリアル化する必要はありません。これを行う:

public boolean shouldSkipField(FieldAttributes f) {
    return f.getName().toLowerCase().contains("name"); 
}

これは以下を返します:

{ "initials": "P.F", "country": { "id": 91 }}

編集:要求に応じて詳細情報を追加しました。

これExclusionStrategyで問題はありませんが、「完全修飾フィールド名」を渡す必要があります。下記参照:

    public class TestExclStrat implements ExclusionStrategy {

        private Class<?> c;
        private String fieldName;
        public TestExclStrat(String fqfn) throws SecurityException, NoSuchFieldException, ClassNotFoundException
        {
            this.c = Class.forName(fqfn.substring(0, fqfn.lastIndexOf(".")));
            this.fieldName = fqfn.substring(fqfn.lastIndexOf(".")+1);
        }
        public boolean shouldSkipClass(Class<?> arg0) {
            return false;
        }

        public boolean shouldSkipField(FieldAttributes f) {

            return (f.getDeclaringClass() == c && f.getName().equals(fieldName));
        }

    }

これを一般的に使用する方法を次に示します。

    Gson gson = new GsonBuilder()
        .setExclusionStrategies(new TestExclStrat("in.naishe.test.Country.name"))
        //.serializeNulls()
        .create();
    Student src = new Student();
    String json = gson.toJson(src);
    System.out.println(json); 

戻り値:

{ "firstName": "Philip" , "middleName": "J.", "initials": "P.F", "lastName": "Fry", "country": { "id": 91 }}
于 2011-01-26T10:13:08.323 に答える
85

シリアライゼーションからのみ除外したい少数のフィールドがあったこの問題に遭遇したため@Expose、カスタム除外戦略で Gson の注釈を使用するかなり単純なソリューションを開発しました。

組み込みで使用する唯一の方法@Exposeは を設定することですGsonBuilder.excludeFieldsWithoutExposeAnnotation()が、その名前が示すように、明示的でないフィールド@Exposeは無視されます。除外したいフィールドがいくつかあったため、すべてのフィールドに注釈を追加するのは非常に面倒でした。

私は事実上、明示的@Exposeに除外しない限りすべてが含まれる逆を望んでいました。これを達成するために、次の除外戦略を使用しました。

new GsonBuilder()
        .addSerializationExclusionStrategy(new ExclusionStrategy() {
            @Override
            public boolean shouldSkipField(FieldAttributes fieldAttributes) {
                final Expose expose = fieldAttributes.getAnnotation(Expose.class);
                return expose != null && !expose.serialize();
            }

            @Override
            public boolean shouldSkipClass(Class<?> aClass) {
                return false;
            }
        })
        .addDeserializationExclusionStrategy(new ExclusionStrategy() {
            @Override
            public boolean shouldSkipField(FieldAttributes fieldAttributes) {
                final Expose expose = fieldAttributes.getAnnotation(Expose.class);
                return expose != null && !expose.deserialize();
            }

            @Override
            public boolean shouldSkipClass(Class<?> aClass) {
                return false;
            }
        })
        .create();

@Expose(serialize = false)これで、または@Expose(deserialize = false)注釈を使用していくつかのフィールドを簡単に除外できます(両方の@Expose属性のデフォルト値が であることに注意してくださいtrue)。もちろん を使用できますが、代わり@Expose(serialize = false, deserialize = false)にフィールドを宣言することでより簡潔に実現できtransientます (これらのカスタム除外戦略でも有効です)。

于 2013-07-18T20:46:19.813 に答える
16

この機能をサポートするクラス ファクトリを考え出しました。除外するフィールドまたはクラスの任意の組み合わせを渡します。

public class GsonFactory {

    public static Gson build(final List<String> fieldExclusions, final List<Class<?>> classExclusions) {
        GsonBuilder b = new GsonBuilder();
        b.addSerializationExclusionStrategy(new ExclusionStrategy() {
            @Override
            public boolean shouldSkipField(FieldAttributes f) {
                return fieldExclusions == null ? false : fieldExclusions.contains(f.getName());
            }

            @Override
            public boolean shouldSkipClass(Class<?> clazz) {
                return classExclusions == null ? false : classExclusions.contains(clazz);
            }
        });
        return b.create();

    }
}

使用するには、2 つのリスト (それぞれオプション) を作成し、GSON オブジェクトを作成します。

static {
 List<String> fieldExclusions = new ArrayList<String>();
 fieldExclusions.add("id");
 fieldExclusions.add("provider");
 fieldExclusions.add("products");

 List<Class<?>> classExclusions = new ArrayList<Class<?>>();
 classExclusions.add(Product.class);
 GSON = GsonFactory.build(null, classExclusions);
}

private static final Gson GSON;

public String getSomeJson(){
    List<Provider> list = getEntitiesFromDatabase();
    return GSON.toJson(list);
}
于 2012-04-26T18:03:23.400 に答える
15

カスタム注釈でこの問題を解決しました。これは私の「SkipSerialisation」注釈クラスです。

@Target (ElementType.FIELD)
public @interface SkipSerialisation {

}

これは私のGsonBuilderです:

gsonBuilder.addSerializationExclusionStrategy(new ExclusionStrategy() {

  @Override public boolean shouldSkipField (FieldAttributes f) {

    return f.getAnnotation(SkipSerialisation.class) != null;

  }

  @Override public boolean shouldSkipClass (Class<?> clazz) {

    return false;
  }
});

例 :

public class User implements Serializable {

  public String firstName;

  public String lastName;

  @SkipSerialisation
  public String email;
}
于 2016-09-12T09:35:18.160 に答える
9

私はこの戦略を使用しました: @SerializedNameアノテーションでマークされていないすべてのフィールドを除外しました。

public class Dummy {

    @SerializedName("VisibleValue")
    final String visibleValue;
    final String hiddenValue;

    public Dummy(String visibleValue, String hiddenValue) {
        this.visibleValue = visibleValue;
        this.hiddenValue = hiddenValue;
    }
}


public class SerializedNameOnlyStrategy implements ExclusionStrategy {

    @Override
    public boolean shouldSkipField(FieldAttributes f) {
        return f.getAnnotation(SerializedName.class) == null;
    }

    @Override
    public boolean shouldSkipClass(Class<?> clazz) {
        return false;
    }
}


Gson gson = new GsonBuilder()
                .setExclusionStrategies(new SerializedNameOnlyStrategy())
                .create();

Dummy dummy = new Dummy("I will see this","I will not see this");
String json = gson.toJson(dummy);

戻る

{"VisibleValue":"これを見る"}

于 2016-07-20T12:15:49.643 に答える
1

私は@Expose注釈を入れるだけで作業しています。ここに私が使用しているバージョンがあります

compile 'com.squareup.retrofit2:retrofit:2.0.2'
compile 'com.squareup.retrofit2:converter-gson:2.0.2'

Modelクラスで:

@Expose
int number;

public class AdapterRestApi {

Adapterクラスで:

public EndPointsApi connectRestApi() {
    OkHttpClient client = new OkHttpClient.Builder()
            .connectTimeout(90000, TimeUnit.SECONDS)
            .readTimeout(90000,TimeUnit.SECONDS).build();

    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(ConstantRestApi.ROOT_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .client(client)
            .build();

    return retrofit.create  (EndPointsApi.class);
}
于 2017-03-31T16:26:54.050 に答える