409

I have a user object that is sent to and from the server. When I send out the user object, I don't want to send the hashed password to the client. So, I added @JsonIgnore on the password property, but this also blocks it from being deserialized into the password that makes it hard to sign up users when they don't have a password.

How can I only get @JsonIgnore to apply to serialization and not deserialization? I'm using Spring JSONView, so I don't have a ton of control over the ObjectMapper.

Things I've tried:

  1. Add @JsonIgnore to the property
  2. Add @JsonIgnore on the getter method only
rumdrums
  • 1,282
  • 2
  • 11
  • 23
chubbsondubs
  • 36,075
  • 24
  • 100
  • 134

9 Answers9

614

Exactly how to do this depends on the version of Jackson that you're using. This changed around version 1.9, before that, you could do this by adding @JsonIgnore to the getter.

Which you've tried:

Add @JsonIgnore on the getter method only

Do this, and also add a specific @JsonProperty annotation for your JSON "password" field name to the setter method for the password on your object.

More recent versions of Jackson have added READ_ONLY and WRITE_ONLY annotation arguments for JsonProperty. So you could also do something like:

@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private String password;

Docs can be found here.

Maifee Ul Asad
  • 2,815
  • 3
  • 25
  • 65
pb2q
  • 56,563
  • 18
  • 143
  • 144
  • 5
    https://gist.github.com/thurloat/2510887 for Jackson JSON ignore on **deserialize** only – Hadas Nov 26 '14 at 10:15
  • It works, but I don't want a setter. I can make it no-op, but that feels wrong too. Also, the requirement of a default constructor breaks encapsulation. I just get a lot of dead setters in my code. But I suppose there is no way around this. – Matt Broekhuis Dec 09 '14 at 05:16
  • @Matt : Cant you use "transient" then ? – Balaji Boggaram Ramanarayan Dec 09 '14 at 18:40
  • 1
    AFAIK you still have to implement the setter and annotate it. I just want the getter for serialization. What is the transient you speak of? That's a JPA annotation AFAIK – Matt Broekhuis Dec 10 '14 at 00:37
  • 3
    Also, make sure to remove @JsonProperty from the field itself otherwise it will override your getter/setter annotations – Anton Soradoi Mar 04 '15 at 15:14
  • 27
    `@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)` – Mikhail Batcer Mar 15 '16 at 07:55
  • 1
    Jackson-annotations 2.5 does not have the later feature. Jackson-annotations 2.6.3 does – radiantRazor Oct 21 '16 at 06:50
  • http://fasterxml.github.io/jackson-annotations/javadoc/2.6/com/fasterxml/jackson/annotation/JsonProperty.Access.html Yes the enum of Access in JsonProperty is since 2.6 – Xin Meng Nov 14 '16 at 14:09
  • 1
    Be careful, `JsonProperty` is `com.fasterxml.jackson.annotation.JsonProperty`, `Access` is `com.fasterxml.jackson.annotation.JsonProperty.Access` not `javax.persistence.Access`, If you wrote code like `import javax.persistence.*;` the Access may not what you want. – Donghua Liu May 28 '18 at 02:52
  • 1
    @MikhailBatcer you are a life saver – ancm Apr 10 '19 at 14:30
114

In order to accomplish this, all that we need is two annotations:

  1. @JsonIgnore
  2. @JsonProperty

Use @JsonIgnore on the class member and its getter, and @JsonProperty on its setter. A sample illustration would help to do this:

class User {

    // More fields here
    @JsonIgnore
    private String password;

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

    @JsonProperty
    public void setPassword(final String password) {
        this.password = password;
    }
}
Sae1962
  • 1,058
  • 14
  • 29
  • 3
    it's the only thing that worked for me with jackson 2.6.4. I tried my best to use @JsonProperty(access = Access.WRITE_ONLY) but it didn't work for me. – cirovladimir Feb 17 '17 at 21:37
98

Since version 2.6: a more intuitive way is to use the com.fasterxml.jackson.annotation.JsonProperty annotation on the field:

@JsonProperty(access = Access.WRITE_ONLY)
private String myField;

Even if a getter exists, the field value is excluded from serialization.

JavaDoc says:

/**
 * Access setting that means that the property may only be written (set)
 * for deserialization,
 * but will not be read (get) on serialization, that is, the value of the property
 * is not included in serialization.
 */
WRITE_ONLY

In case you need it the other way around, just use Access.READ_ONLY.

Aaron Kurtzhals
  • 2,018
  • 3
  • 18
  • 21
Daniel Beer
  • 1,559
  • 13
  • 13
  • 2
    I don't understand why there so few upvotes, this is elegant way to solve this problem, works like a charm. There is no need to annotate getter,setter and field. Only field. Thanks. – CROSP Dec 26 '15 at 16:22
  • This is available since version 2.6, see http://fasterxml.github.io/jackson-annotations/javadoc/2.6/com/fasterxml/jackson/annotation/JsonProperty.Access.html – Daniel Beer Dec 27 '15 at 22:56
  • Probably the best answer for 2.6+ users. – David Dossot Feb 17 '16 at 02:03
  • Make sure you are not using the **org.codehaus.jackson.annotate** import. @DanielBeer's solution works for Jackson 2.6.3. This should be the accepted answer now that Jackson has been updated. – Kent Bull Mar 11 '16 at 00:17
16

In my case, I have Jackson automatically (de)serializing objects that I return from a Spring MVC controller (I am using @RestController with Spring 4.1.6). I had to use com.fasterxml.jackson.annotation.JsonIgnore instead of org.codehaus.jackson.annotate.JsonIgnore, as otherwise, it simply did nothing.

Sae1962
  • 1,058
  • 14
  • 29
Alex Beardsley
  • 20,560
  • 14
  • 50
  • 67
  • 1
    this is an extremely useful answer that really helped me find the source of why @JsonIgnore was not being honored by Jackson... thanks! – Clint Eastwood Jun 14 '17 at 21:13
4

Another easy way to handle this is to use the argument allowSetters=truein the annotation. This will allow the password to be deserialized into your dto but it will not serialize it into a response body that uses contains object.

example:

@JsonIgnoreProperties(allowSetters = true, value = {"bar"})
class Pojo{
    String foo;
    String bar;
}

Both foo and bar are populated in the object, but only foo is written into a response body.

dkb
  • 3,846
  • 4
  • 33
  • 50
Dhandley
  • 41
  • 1
  • That was my mistake, I didn't realize you had already corrected the snippet. Looking at your changes, it appears my years of writing in Groovy got me and my translation to Java was a bit rough. Sorry! – Dhandley Dec 25 '19 at 22:58
3
"user": {
        "firstName": "Musa",
        "lastName": "Aliyev",
        "email": "klaudi2012@gmail.com",
        "passwordIn": "98989898", (or encoded version in front if we not using https)
        "country": "Azeribaijan",
        "phone": "+994707702747"
    }

@CrossOrigin(methods=RequestMethod.POST)
@RequestMapping("/public/register")
public @ResponseBody MsgKit registerNewUsert(@RequestBody User u){

        root.registerUser(u);

    return new MsgKit("registered");
}  

@Service
@Transactional
public class RootBsn {

    @Autowired UserRepository userRepo;

    public void registerUser(User u) throws Exception{

        u.setPassword(u.getPasswordIn());
        //Generate some salt and  setPassword (encoded -  salt+password)
        User u=userRepo.save(u);

        System.out.println("Registration information saved");
    }

}

    @Entity        
@JsonIgnoreProperties({"recordDate","modificationDate","status","createdBy","modifiedBy","salt","password"})
                    public class User implements Serializable {
                        private static final long serialVersionUID = 1L;

                        @Id
                        @GeneratedValue(strategy=GenerationType.AUTO)
                        private Long id;

                        private String country;

                        @Column(name="CREATED_BY")
                        private String createdBy;

                        private String email;

                        @Column(name="FIRST_NAME")
                        private String firstName;

                        @Column(name="LAST_LOGIN_DATE")
                        private Timestamp lastLoginDate;

                        @Column(name="LAST_NAME")
                        private String lastName;

                        @Column(name="MODIFICATION_DATE")
                        private Timestamp modificationDate;

                        @Column(name="MODIFIED_BY")
                        private String modifiedBy;

                        private String password;

                        @Transient
                        private String passwordIn;

                        private String phone;

                        @Column(name="RECORD_DATE")
                        private Timestamp recordDate;

                        private String salt;

                        private String status;

                        @Column(name="USER_STATUS")
                        private String userStatus;

                        public User() {
                        }
                // getters and setters
                }
Musa
  • 2,480
  • 25
  • 23
2

You can use @JsonIgnoreProperties at class level and put variables you want to igonre in json in "value" parameter.Worked for me fine.

@JsonIgnoreProperties(value = { "myVariable1","myVariable2" })
public class MyClass {
      private int myVariable1;,
      private int myVariable2;
}
2

You can also do like:

@JsonIgnore
@JsonProperty(access = Access.WRITE_ONLY)
private String password;

It's worked for me

  • It will completely ignore. This is not what asked in question. JsonIgnore has precedence over JsonProperty. – Mubasher Dec 24 '21 at 10:17
0

I was looking for something similar. I still wanted my property serialized but wanted to alter the value using a different getter. In the below example, I'm deserializing the real password but serializing to a masked password. Here's how to do it:

public class User() {

    private static final String PASSWORD_MASK = "*********";

    @JsonIgnore
    private String password;

    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
    public String setPassword(String password) {
        if (!password.equals(PASSWORD_MASK) {
            this.password = password;
        }
    }

    public String getPassword() {
        return password;
    }

    @JsonProperty("password")
    public String getPasswordMasked() {
        return PASSWORD_MASK;
    }
}
Collin Krawll
  • 1,672
  • 14
  • 15