ジャクソンは「is」を削除してプリミティブブールフィールドの名前を変更します


96

これは重複している可能性があります。しかし、問題の解決策が見つかりません。

クラスがあります

public class MyResponse implements Serializable {

    private boolean isSuccess;

    public boolean isSuccess() {
        return isSuccess;
    }

    public void setSuccess(boolean isSuccess) {
        this.isSuccess = isSuccess;
    }
}

ゲッターとセッターはEclipseによって生成されます。

別のクラスでは、値をtrueに設定し、JSON文字列として記述します。

System.out.println(new ObjectMapper().writeValueAsString(myResponse));

JSONでは、キーはとして表示され{"success": true}ます。

キーisSuccess自体が欲しいです。ジャクソンはシリアル化中にセッターメソッドを使用していますか?キーをフィールド名自体にする方法は?


1
プロパティ名が嘘のisSuccess場合、メソッド名はisIsSuccess私が思うに違いありません
Jens

わかります。SetSuccess Eclipseで生成されているので良いと思いました。(標準に従う)
iCode 2015

回答:


120

これは少し遅い答えですが、このページにアクセスする他の人にとっては役立つかもしれません。

JSONにシリアル化するときにJacksonが使用する名前を変更する簡単な解決策は、@ JsonPropertyアノテーションを使用することです。したがって、例は次のようになります。

public class MyResponse implements Serializable {

    private boolean isSuccess;

    @JsonProperty(value="isSuccess")        
    public boolean isSuccess() {
        return isSuccess;
    }

    public void setSuccess(boolean isSuccess) {
        this.isSuccess = isSuccess;
    }
}

これは、としてJSONにシリアル化されますが{"isSuccess":true}、getterメソッド名を変更する必要がないという利点があります。

この場合@JsonProperty("isSuccess")、単一のvalue要素しかないため、注釈を書き込むこともできます。


クラスはサードパーティの依存関係からのものであるため、クラスは私が所有していないため、このメソッドは私の場合は機能しません。そのような場合は、以下の私の答えを参照してください。
edmundpie

5
イム・ジャクソンと春のブーツを使用してが、2つのフィールドを取得一つが「成功」であり、他は「isSuccess」であると私は唯一のフィールド「isSuccess」よりも、非プリミティブなブールを使用した場合
ヴィシャルSingla

@VishalSinglaまったく同じ問題があります。このソリューションでは、Spring Bootに2つのフィールドが生成されます
AronFiechter20年

GSONを使用したシリアル化は正常に機能します。
Nayeem

22

私は最近この問題に遭遇しました、そしてこれは私が見つけたものです。Jacksonは、渡されたクラスのゲッターとセッターを検査し、それらのメソッドをシリアル化と逆シリアル化に使用します。これらのメソッドの「get」、「is」、「set」に続くものは、JSONフィールドのキーとして使用されます(getIsValidおよびsetIsValidの場合は「isValid」)。

public class JacksonExample {   

    private boolean isValid = false;

    public boolean getIsValid() {
        return isValid;
    }

    public void setIsValid(boolean isValid) {
        this.isValid = isValid;
    }
} 

同様に、「isIsSuccess」または「getIsSuccess」に名前が変更されない限り、「isSuccess」は「success」になります。

詳細はこちら:http//www.citrine.io/blog/2015/5/20/jackson-json-processor


6
isValidは、Javaのブールデータ型の正しい命名規則ではありません。有効である必要があり、isValid()、setValid()
vels4j 2017

2
しかし、それはまさにそれであるはずではありませんか?コンベンション?存在する場合は、JSONフィールドとしてゲッター名を使用するというJacksonリファレンスにリンクできますか?それとも、それは悪いデザインの選択だと思いますか?
Abhinav Vishak 2017年

2
これについて警告があったらいいのにと思います
RyPope 2017

@ vels4j非常に具体的な実装を扱っている場合、命名規則はウィンドウの外に出ます。
ドラガス

13

以下の両方のアノテーションを使用して、出力JSONに以下を含めるように強制しますis_xxx

@get:JsonProperty("is_something")
@param:JsonProperty("is_something")

これがこの質問に対する最良の答えです。
dustinevan

2
それはJavaですか?多分それはコトリンですか?
spottedmahn

7

ObjectMapper次のように構成できます。

mapper.setPropertyNamingStrategy(new PropertyNamingStrategy() {
            @Override
            public String nameForGetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName)
            {
                if(method.hasReturnType() && (method.getRawReturnType() == Boolean.class || method.getRawReturnType() == boolean.class)
                        && method.getName().startsWith("is")) {
                    return method.getName();
                }
                return super.nameForGetterMethod(config, method, defaultName);
            }
        });

1
私はあなたが構成を介してこれを解決しようとしているのが好きです。ただし、これは、ブールフィールドとJSONプロパティの前に常に「is」を付ける場合にのみ機能します。単に「有効」という名前の別のブールフィールドがあり、そのようにシリアル化するとします。生成されたメソッドは「isEnabled()」であるため、上記のコードはそれを単に「有効」ではなく「isEnabled」にシリアル化します。最終的に、問題は、フィールド「x」と「isX」の両方について、Eclipseがメソッド「isX()」を生成することです。そのため、フィールドに一致するプロパティ名を推測することはできません。
DavidSiegal19年

@DavidSiegalはburakの回答に基づいていますこのような場合をサポートするために、以下の回答を拡張しました。
edmundpie

5

Kotlinとデータクラスを使用している場合:

data class Dto(
    @get:JsonProperty("isSuccess") val isSuccess: Boolean
)

@param:JsonProperty("isSuccess")JSONも逆シリアル化する場合は、追加する必要があるかもしれません。


2

Utkarshの答えに基づいて構築します。

ゲッター名からget / isを引いたものJSON名として使用されます。

public class Example{
    private String radcliffe; 

    public getHarryPotter(){
        return radcliffe; 
    }
}

{"harryPotter": "whateverYouGaveHere"}として保存されます


デシリアライズの場合、Jacksonはセッターとフィールド名の両方をチェックします。Json String {"word1": "example"}の場合、以下の両方が有効です。

public class Example{
    private String word1; 

    public setword2( String pqr){
        this.word1 = pqr; 
    }
}

public class Example2{
    private String word2; 

    public setWord1(String pqr){
        this.word2 = pqr ; 
    }
}

さらに興味深い質問は、ジャクソンが逆シリアル化のためにどの順序を考慮するかです。{"word1": "myName"}をで逆シリアル化しようとすると

public class Example3{
    private String word1;
    private String word2; 

    public setWord1( String parameter){
        this.word2 = parameter ; 
    }
}

上記のケースはテストしていませんが、word1word2の値を確認するのは興味深いことです...

注:どのフィールドが同じである必要があるかを強調するために、大幅に異なる名前を使用しました。


2

いくつかのカスタム命名戦略を台無しにしたり、いくつかのアクセサーを再作成したりしたくありませんでした。
コードが少なければ少ないほど、私は幸せです。

これは私たちのためにトリックをしました:

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;

@JsonIgnoreProperties({"success", "deleted"}) // <- Prevents serialization duplicates 
public class MyResponse {

    private String id;
    private @JsonProperty("isSuccess") boolean isSuccess; // <- Forces field name
    private @JsonProperty("isDeleted") boolean isDeleted;

}

1

この問題には別の方法があります。

新しいサブクラスを定義してPropertyNamingStrategyを拡張し、それをObjectMapperインスタンスに渡すだけです。

ここにコードスニペットがもっと役立つかもしれません:

mapper.setPropertyNamingStrategy(new PropertyNamingStrategy() {
        @Override
        public String nameForGetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName) {
            String input = defaultName;
            if(method.getName().startsWith("is")){
                input = method.getName();
            }

            //copy from LowerCaseWithUnderscoresStrategy
            if (input == null) return input; // garbage in, garbage out
            int length = input.length();
            StringBuilder result = new StringBuilder(length * 2);
            int resultLength = 0;
            boolean wasPrevTranslated = false;
            for (int i = 0; i < length; i++)
            {
                char c = input.charAt(i);
                if (i > 0 || c != '_') // skip first starting underscore
                {
                    if (Character.isUpperCase(c))
                    {
                        if (!wasPrevTranslated && resultLength > 0 && result.charAt(resultLength - 1) != '_')
                        {
                            result.append('_');
                            resultLength++;
                        }
                        c = Character.toLowerCase(c);
                        wasPrevTranslated = true;
                    }
                    else
                    {
                        wasPrevTranslated = false;
                    }
                    result.append(c);
                    resultLength++;
                }
            }
            return resultLength > 0 ? result.toString() : input;
        }
    });

1

受け入れられた答えは私の場合には機能しません。

私の場合、クラスは私が所有していません。問題のあるクラスはサードパーティの依存関係に由来するため、@JsonPropertyアノテーションを追加することはできません。

それを解決するために、上記の@burakの回答に触発されて、PropertyNamingStrategy次のようにカスタムを作成しました。

mapper.setPropertyNamingStrategy(new PropertyNamingStrategy() {
  @Override
  public String nameForSetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName)
  {
    if (method.getParameterCount() == 1 &&
            (method.getRawParameterType(0) == Boolean.class || method.getRawParameterType(0) == boolean.class) &&
            method.getName().startsWith("set")) {

      Class<?> containingClass = method.getDeclaringClass();
      String potentialFieldName = "is" + method.getName().substring(3);

      try {
        containingClass.getDeclaredField(potentialFieldName);
        return potentialFieldName;
      } catch (NoSuchFieldException e) {
        // do nothing and fall through
      }
    }

    return super.nameForSetterMethod(config, method, defaultName);
  }

  @Override
  public String nameForGetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName)
  {
    if(method.hasReturnType() && (method.getRawReturnType() == Boolean.class || method.getRawReturnType() == boolean.class)
        && method.getName().startsWith("is")) {

      Class<?> containingClass = method.getDeclaringClass();
      String potentialFieldName = method.getName();

      try {
        containingClass.getDeclaredField(potentialFieldName);
        return potentialFieldName;
      } catch (NoSuchFieldException e) {
        // do nothing and fall through
      }
    }
    return super.nameForGetterMethod(config, method, defaultName);
  }
});

基本的に、これは、シリアル化および逆シリアル化する前に、ターゲット/ソースクラスで、クラスに存在するプロパティ名がプロパティであるisEnabledenabledプロパティであるかをチェックします。

これに基づいて、マッパーは存在するプロパティ名にシリアル化および逆シリアル化します。


0

プリミティブブール値をjava.lang.Booleanに変更できます(+ use @JsonPropery

@JsonProperty("isA")
private Boolean isA = false;

public Boolean getA() {
    return this.isA;
}

public void setA(Boolean a) {
    this.isA = a;
}

私にとっては素晴らしい仕事をしました。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.