杰克逊:如何防止现场序列化


163

我有一个带有密码字段的实体类:

class User {
    private String password;

    //setter, getter..
}

我希望在序列化过程中跳过此字段。但是它仍然应该能够反序列化。这是必需的,以便客户端可以向我发送一个新密码,但无法读取当前密码。

我如何与杰克逊做到这一点?


1
您不想序列化它,但是想对它进行反序列化?我要说那是不可能的。如果您没有在一个盒子里放一个cookie,那么您将无法从这个盒子里取回它。
亚历克西斯·杜弗洛尼

1
@Traroth:但是我可以放一个新的cookie。我只是在寻找一个方便的注释,但这可以手工完成。
周末2012年

8
快速评论:从技术上讲,完全有可能使用一个setter(甚至会自动检测到私有的setter),而只是省略访问器(没有公共字段或getter)。也可以@JsonIgnore在getter @JsonProperty上添加,但在setter 上添加,在这种情况下,事情不会序列化,而是可以反序列化。
StaxMan

4
您介意接受这个问题的答案吗?(您的其他几个人已经几岁了,但仍然不被接受...请考虑查看!)
巴雷特2016年

Answers:


187

您可以将其标记为@JsonIgnore

在1.9中,您可以添加@JsonIgnoregetter,@JsonPropertysetter,以使其反序列化而不是序列化。


6
@JsonIgnore也可以防止反序列化。对于瞬态-我会检查一下。
Weekens

98
在1.9中,您可以添加@JsonIgnoregetter,@JsonPropertysetter,以使其反序列化而不是序列化。
StaxMan

StaxMan的评论应该是答案,不是吗?那为什么还留下评论...!..?
Saravanabalagi Ramachandran,2015年

瞬态似乎对我不起作用,我将字段“瞬态”标记为我不希望对其进行序列化/反序列化。
rohith

以前建议使用此答案transient(如所述private transient String password;),但除非启用了MapperFeature.PROPAGATE_TRANSIENT_MARKER,否则将使用公共getter的瞬态字段将被忽略
汤姆(Tom)

96

说明StaxMan所说的内容,这对我有用

private String password;

@JsonIgnore
public String getPassword() {
    return password;
}

@JsonProperty
public void setPassword(String password) {
    this.password = password;
}

12
您使用哪个Json依赖项?不适用于com.fasterxml.jackson
Alexander Burakevych 2014年

3
谢谢!@JsonIgnore看来,在现场没有必要。
Ferran Maylinch 2014年

com.fasterxml.jackson.annotation.JsonIgnore from jackson-annotations- <version> .jar
mvmn

我已经尝试过了,但是它对我不起作用。我使用v2.8。有什么帮助吗?
Maz

36

最简单的方法是为您的获取器和设置器添加注释。

这是修改后的原始示例,以排除纯文本密码,然后注释一个新方法,该方法仅将密码字段作为加密文本返回。

class User {

    private String password;

    public void setPassword(String password) {
        this.password = password;
    }

    @JsonIgnore
    public String getPassword() {
        return password;
    }

    @JsonProperty("password")
    public String getEncryptedPassword() {
        // encryption logic
    }
}

21

Jackson 2.6开始,可以将属性标记为只读或只写。这比修改两个访问器上的注释更简单,并将所有信息都放在一个位置:

public class User {
    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
    private String password;
}

这是一个很棒的解决方案,简单有效。谢谢。
dhqvinh

17

除了@JsonIgnore,还有其他两种可能性:

  • 使用JSON视图有条件地过滤掉字段(默认情况下,不用于反序列化;在2.0中可用,但您可以对序列化,反序列化使用不同的视图)
  • @JsonIgnoreProperties 上课可能有用

10

transient是我的解决方案。谢谢!它是Java固有的,避免您添加其他特定于框架的注释。


2
如果您的属性确实是临时属性,而不涉及ORM,那么该方法就可以工作,例如....发现@JsonIgnore对我来说更有趣,尽管我会被锁定在杰克逊身上,但这是一个很好的权衡
Joao Pereira

3
如果您创建自己的注释并由JsonIgnore和JacksonAnnotationsInside对其进行注释,则不必锁定杰克逊。这样,如果您更改序列化程序,则只需更改自己的注释。
DavidA 2014年

4

人们应该问为什么要使用公用的获取方法作为密码。Hibernate或任何其他ORM框架都将使用私有的getter方法。要检查密码是否正确,可以使用

public boolean checkPassword(String password){
  return this.password.equals(anyHashingMethod(password));
}

我实际上认为这是考虑解决方案的最佳方法。将您需要的东西设为私有并从对象本身进行控制更为有意义。
arcynum

2

杰克逊有一个名为SimpleBeanPropertyFilter的类,该类有助于在序列化和反序列化期间过滤字段。不在全球范围内。我想那就是你想要的。

@JsonFilter("custom_serializer")
class User {
    private String password;

    //setter, getter..
}

然后在您的代码中:

String[] fieldsToSkip = new String[] { "password" };

ObjectMapper mapper = new ObjectMapper();

final SimpleFilterProvider filter = new SimpleFilterProvider();
filter.addFilter("custom_serializer",
            SimpleBeanPropertyFilter.serializeAllExcept(fieldsToSkip));

mapper.setFilters(filter);

String jsonStr = mapper.writeValueAsString(currentUser);

这将防止password字段被序列化。您也可以照password原样反序列化字段。只要确保没有在ObjectMapper对象上应用任何过滤器即可。

ObjectMapper mapper = new ObjectMapper();
User user = mapper.readValue(yourJsonStr, User.class);    // user object does have non-null password field

0

将变量设置为

@JsonIgnore

这允许变量被json序列化程序跳过

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.