杰克逊通过删除' is'来重命名原始布尔字段。

时间:2015-08-28 11:52:14

标签: java json jackson

这可能是重复的。但我无法找到解决问题的方法。

我有一个班级

public class MyResponse implements Serializable {

    private boolean isSuccess;

    public boolean isSuccess() {
        return isSuccess;
    }

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

Getter和setter由Eclipse生成。

在另一个类中,我将值设置为true,并将其写为JSON字符串。

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

在JSON中,密钥以{"success": true}开头。

我希望密钥为isSuccess本身。 Jackson是否在序列化时使用setter方法?如何使密钥成为字段名称本身?

11 个答案:

答案 0 :(得分:68)

这是一个稍晚的答案,但对于访问此页面的其他人可能会有用。

更改Jackson在序列化为JSON时使用的名称的简单解决方案是使用@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元素

答案 1 :(得分:17)

我最近碰到了这个问题,这就是我发现的。杰克逊将检查你传递给它的任何课程的getter和setter,并使用这些方法进行序列化和反序列化。这些方法中的“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;
    }
} 

同样“isSuccess”将成为“成功”,除非重命名为“isIsSuccess”或“getIsSuccess”

在此处阅读更多内容:http://www.citrine.io/blog/2015/5/20/jackson-json-processor

答案 2 :(得分:2)

以Utkarsh的答案为基础......

Getter名称减去 get / is 用作JSON名称。

public class Example{
    private String radcliffe; 

    public getHarryPotter(){
        return radcliffe; 
    }
}

存储为 {" harryPotter" :"无论你怎么样?" }

对于反序列化,Jackson会同时检查setter和字段名称。 对于Json String {" word1" :"示例" } ,以下两者都有效。

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 ; 
    }
}

我没有测试上面的情况,但看到 word1 &的价值会很有趣。 word2 ...

注意:我使用了截然不同的名称来强调哪些字段必须相同。

答案 3 :(得分:2)

您可以如下配置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);
            }
        });

答案 4 :(得分: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;
        }
    });

答案 5 :(得分:1)

使用Kotlin和数据类时:

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

如果还要反序列化JSON,则可能需要添加@param:JsonProperty("isSuccess")

答案 6 :(得分:0)

您应该将配置添加到Jakson对象映射器,例如:

var mostUsedCompanyId = _context ... 

答案 7 :(得分:0)

我不想弄乱某些自定义命名策略,也不想重新创建一些访问器。
代码越少,我越快乐。

这对我们有用:

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;

}

答案 8 :(得分:0)

接受的答案不适用于我的情况。

就我而言,该课程不是我所有的。有问题的类来自第三方的依赖关系,因此我不能只在其中添加@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);
  }
});

基本上,这是在序列化和反序列化之前,它检查目标/源类中该类中存在哪些属性名称,无论是isEnabled还是enabled属性。

基于此,映射器将序列化和反序列化为存在的属性名称。

答案 9 :(得分:0)

您可以将原始布尔值更改为java.lang.Boolean(+使用@JsonPropery

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

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

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

对我来说很棒。

答案 10 :(得分:0)

如果您有兴趣处理不受您控制的 3rd 方类(如评论中提到的 @edmundpie),那么您将 Mixin 类添加到您的 ObjectMapper 中,其中属性/字段名称应与您的 3rd 方类中的名称相匹配:< /p>

public class MyStack32270422 {

  public static void main(String[] args) {
    ObjectMapper om3rdParty = new ObjectMapper();
    om3rdParty .addMixIn(My3rdPartyResponse.class, MixinMyResponse.class);
    // add further mixins if required
    String jsonString = om3rdParty.writeValueAsString(new My3rdPartyResponse());
    System.out.println(jsonString);
  }
}

class MixinMyResponse {
  // add all jackson annotations here you want to be used when handling My3rdPartyResponse classes
  @JsonProperty("isSuccess")
  private boolean isSuccess;
}

class My3rdPartyResponse{
  private boolean isSuccess = true;
  // getter and setter here if desired
}

基本上,您将所有 Jackson 注释添加到 Mixin 类中,就好像您拥有该类一样。在我看来,这是一个很好的解决方案,因为您不必检查以“is..”开头的方法名称等等。