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


97

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

我有一堂课

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本身。杰克逊在序列化时是否使用setter方法?如何使关键字成为字段名称本身?


1
如果您的属性名称是liek,则isSuccess您的方法名称必须是isIsSuccess我认为的
Jens 2015年

我明白。我认为它是SetSuccess 由Eclipse生成的更好。(遵循标准)
iCode

Answers:


121

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

更改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

5
我使用带有杰克逊的弹簧靴,但得到两个字段,一个是“成功”,另一个是“ isSuccess”,当我使用非基本布尔型时,只有一个字段是“ isSuccess”
Vishal Singla

@VishalSingla我有一个确切的问题,此解决方案在Spring Boot中产生了两个字段
Aron Fiechter

使用GSON进行序列化工作正常。
Nayeem '20年

23

我最近遇到了这个问题,这就是我所发现的。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


6
isValid不是Java中布尔数据类型的命名约定。应该是有效的,并且isValid(),
setValid

2
难道不应该是那样吗?约定?如果存在,是否可以链接到Jackson引用,该引用说它使用getter名称作为JSON字段?还是您认为这是一个糟糕的设计选择?
Abhinav Vishak

2
我希望对此有一个警告
RyPope

@ vels4j在处理高度特定的实现时,命名约定不可用。
Dragas

13

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

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

这是对这个问题的最佳答案。
dustinevan '19

2
那是Java吗?也许是科特林?
spottedmahn'5

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”的情况下才有效。假设您有另一个布尔字段,简称为“ enabled”,您希望以此进行序列化。因为生成的方法是“ isEnabled()”,所以上面的代码会将其序列化为“ isEnabled”,而不仅仅是“ enabled”。最终,问题在于,对于两个字段“ x”和“ isX”,Eclipse都会生成方法“ isX()”。因此您无法推断出与该字段匹配的属性名称。
David Siegal

@DavidSiegal基于burak答案我已经扩展了下面的答案以支持这种情况。
edmundpie

5

使用Kotlin和数据类时:

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

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


2

以乌特喀什的答案为基础。

Getter名称减去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 ; 
    }
}

一个更有趣的问题是杰克逊考虑进行反序列化的顺序。如果我尝试反序列化{“字1”:“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);
  }
});

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

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


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

对我来说很棒。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.