Jackson 通过删除“ is”来重命名原始布尔字段

这可能是一个副本。但我不能找到我的问题的解决方案。

我还有课

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,关键在于 ABc0。

我想要的关键作为 isSuccess本身。Jackson 在序列化时使用 setter 方法吗?如何使密钥成为字段名本身?

99925 次浏览

我最近碰到了这个问题,这是我发现的。Jackson 将检查传递给它的任何类的 getter 和 setter,并使用这些方法进行序列化和反序列化。这些方法中“ get”、“ is”和“ set”后面的内容将用作 JSON 字段的键(“ isValid”用于 getIsValid 和 setIsValid)。

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

这是一个有点晚的回答,但是对于其他访问这个页面的人可能有用。

改变 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元素

根据 Utkarsh 的回答. 。

使用 Getter 名称减去 得到[是]作为 JSON 名称。

public class Example{
private String radcliffe;


public getHarryPotter(){
return radcliffe;
}
}

存储为 {“哈利波特”: “无论你在这里”}


对于反序列化,Jackson 同时检查 setter 和字段名。 对于 JsonString{“ 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 考虑的反序列化顺序

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


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

我没有测试上述情况,但它将是有趣的,看到 单词1单词2的值..。

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

解决这个问题还有另一种方法。

只需定义一个新的子类来扩展 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;
}
});

您可以按以下方式配置您的 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);
}
});

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

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

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

这对我们奏效了:

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;


}

接受的答案对我的案子不起作用。

在我的情况下,类不属于我。有问题的类来自第三方依赖关系,因此我不能只在其中添加 @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属性。

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

当您使用 Kotlin 和数据类时:

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

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

编辑: 如果您正在使用 swagger-annotions 来生成文档,那么在使用 @get:JsonProperty时,该属性将被标记为 readOnly。为了解决这个问题,你可以这样做:

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

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

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


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


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

对我很有效。

如果你对处理不在你控制之下的第三方类感兴趣(就像@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”开头的方法名时浪费时间。诸如此类。