杰克逊通过去掉“is”来重命名原始布尔字段。

183

这可能是一个重复的问题,但我找不到解决方法。

我有一个类。

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方法?如何使键名为字段名称本身?


3
如果你的属性名是isSuccess,那么你的方法名必须是isIsSuccess - Jens
我明白。我认为使用由Eclipse生成的“SetSuccess”更好,因为它遵循了标准。 - iCode
1
杰克逊库开发人员删除隐式的 is,这是一个奇怪的想法... - Boris Mitioglov
12个回答

205

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

更改 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元素。


这种方法对我的情况不起作用,因为这个类不是我拥有的,而是来自第三方依赖。对于这种情况,请看下面的答案。 - edmundpie
17
我正在使用Spring Boot和Jackson,但是得到了两个字段,一个是"success",另一个是"isSuccess"。当我使用非原始类型的布尔值时,只有一个字段"isSuccess"。 - Vishal Singla
@VishalSingla 我们完全有同样的问题,这个解决方案在Spring Boot中生成了两个字段。 - Aron Fiechter
@VishalSingla 在 getter 上使用 JsonProperty 注解。 - Vikash Kumar Verma
这似乎是正确的答案 https://dev59.com/_mEh5IYBdhLWcg3w32xG#55567974 - Arun Gowda
在 Kotlin 中,@JsonProperty 需要放在 getter 上,因此应该是 @get:JsonProperty("isSuccess") - Nick Sherrill

38

我最近遇到了这个问题,以下是我的发现。Jackson会检查您传递给它的任何类的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”将变成“success”,除非重命名为“isIsSuccess”或“getIsSuccess”。

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


9
isValid不是Java中布尔数据类型的正确命名规范。应该使用valid作为属性名,并使用isValid()和setValid()方法。 - vels4j
4
但它不应该正是一个惯例吗?一种公约?如果确实存在,你能否提供杰克逊参考文献,表明它使用getter名称作为JSON字段?或者你认为这是一个糟糕的设计选择? - Abhinav Vishak
2
我希望有一个警告来提醒这个。 - RyPope
1
当你处理高度特定的实现时,命名约定就不再适用了。 - Dragas

31

使用下面两个注释,可以强制输出的JSON包含is_xxx

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

1
这是对这个问题最好的答案。 - dustinevan
3
那是Java吗?也许是Kotlin? - spottedmahn
1
@spottedmahn 那是 Kotlin(两年后 :)) - Fabio
即使没有为我工作,@param:JsonProperty("is_something") 也可以。 - Демьян Бельский
1
@get:JsonProperty("isSomething") 对我有用(Kotlin)。 - Brian Crider

20

当您使用 Kotlin 和数据类时:

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

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

编辑:如果您正在使用swagger注释生成文档,则在使用@get:JsonProperty时,该属性将被标记为readOnly。为了解决这个问题,您可以执行以下操作:

@JsonAutoDetect(isGetterVisibility = JsonAutoDetect.Visibility.NONE)
data class Dto(
    @field:JsonProperty(value = "isSuccess") val isSuccess: Boolean
)

9
你可以按照以下方式配置你的 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”时,才能实现此目标。假设您有另一个布尔字段仅命名为“enabled”,您希望将其序列化为这样。由于生成的方法是“isEnabled()”,上面的代码将把它序列化为“isEnabled”而不是“enabled”。最终,问题在于对于字段“x”和“isX”,Eclipse生成方法“isX()”;因此,您无法推断出与字段匹配的属性名称。 - David Siegal
@DavidSiegal 基于Burak的答案,我已经扩展了下面的答案以支持这种情况。 - edmundpie

7

我不想深入研究一些自定义命名策略,也不想重新创建一些访问器。
代码越少,我就越开心。

这对我们很有用:

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;

}

3
在Utkarsh的回答基础上进行补充,JSON名称使用Getter方法名减去“get/is”。
public class Example{
    private String radcliffe; 

    public getHarryPotter(){
        return radcliffe; 
    }
}

存储为{"harryPotter": "whateverYouGaveHere"}


对于反序列化,Jackson检查setter和字段名称。 对于Json字符串{"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 ; 
    }
}

一个更有趣的问题是Jackson在反序列化时考虑的顺序。如果我尝试使用以下代码对{ "word1" : "myName" } 进行反序列化:

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

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

我没有测试上面的情况,但是看到word1word2的值会很有趣...

注意:我使用了截然不同的名称来强调需要相同的字段。


3

如果您有兴趣处理不在您控制范围内的第三方类(如@edmundpie在评论中提到的),则可以将Mixin类添加到ObjectMapper中,其中属性/字段名称应与第三方类中的名称匹配:

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…”开头的方法名称等等。


2
你可以将原始布尔值更改为java.lang.Boolean(+使用@JsonPropery)。
@JsonProperty("isA")
private Boolean isA = false;

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

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

这对我非常有帮助。


这个没问题。然而,对我来说,使用boolean而不是Boolean也完全可以。+1 - shamiul97

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接