This is definitely not a duplicate of Only using @JsonIgnore during serialization, but not deserialization. The problem is the same but in the context of Immutables.
When a model(DTO/DAO) is decorated as an Immutable, I am not able to selectively @JsonIgnore one of the properties during serialization. Suppose that we have a UserDto which is defined as an Immutable as follow
@Value.Immutable
@Value.Style(defaults = @Value.Immutable(copy = false), init = "set*")
@JsonSerialize(as = ImmutableUserDto.class)
@JsonDeserialize(builder = ImmutableUserDto.Builder.class)
public abstract class UserDto {
@JsonProperty("id")
@Value.Default
public int getId() {
return 0;
}
@JsonProperty("username")
public abstract String getUsername();
@JsonProperty("email")
public abstract String getEmail();
@JsonProperty("password")
public abstract String getPassword();
}
I believe it is fair to expect that during serialization we would want to ignore the password
from the response of the service.
Without using Immutables if we were working with a simple class, then there are many ways to accomplish this. For example - annotate only the getter with @JsonIgnore
. Or if possible define a different accessor method (something that doesn't have the get prefix) and only define the regular setter method... and so on.
If I try the same on the Immutables accessor method for the password as shown below:
@Value.Immutable
@Value.Style(defaults = @Value.Immutable(copy = false), init = "set*")
@JsonSersonIgnoreialize(as = ImmutableUserDto.class)
@JsonDeserialize(builder = ImmutableUserDto.Builder.class)
public abstract class UserDto {
....
@JsonProperty("password")
@JsonIgnore
public abstract String getPassword();
}
then, the generated ImmutableUserDto adds the @JsonIgnore on both the getter and setter as shown below.
@Generated(from = "UserDto", generator = "Immutables")
@SuppressWarnings({"all"})
@ParametersAreNonnullByDefault
@javax.annotation.Generated("org.immutables.processor.ProxyProcessor")
@Immutable
@CheckReturnValue
public final class ImmutableUserDto extends UserDto {
...
...
private final String password;
...
...
/**
* @return The value of the {@code password} attribute
*/
@JsonProperty("password")
@JsonIgnore
@Override
public String getPassword() {
return password;
}
...
...
...
@Generated(from = "UserDto", generator = "Immutables")
@NotThreadSafe
public static final class Builder {
...
...
private String password;
@JsonProperty("password")
@JsonIgnore
public final Builder setPassword(String password) {
this.password = password;
return this;
}
}
}
Serialization will work as expected. The password
attribute will be excluded from the JSON. But when I try to de-serialize, I get the following error:
java.lang.IllegalStateException: Cannot build UserDto, some of the required attributes are not set [password]
Which is obvious as Immutables added the @JsonIgnore
to the setter as well.
The documentation isn't of much help. In their Things to be aware of section, it just mentions the following regarding @JsonIgnore
If using @JsonIgnore, you should explicitly make an attribute non-mandatory. In Immutables, an attribute can be declared as non-mandatory via @Nullable, Optional or @Value.Default which are all different in their effect and we do not derive anything automatically.
Using @Nullable
or Optional
or @Value.Default
is not of any use in case of fields like password
.
I have gone through the issue list on their GitHub page and there is a similar issue but the user was asking for a slightly different use case and using @Nullable could solve the problem which doesn't work in my case.
I have also tried to use one of the answers here. Still resulted in the same error.
It looked like this is not supported by Immutables library. I have created a new issue myself. Once I get some feedback from users on SOF, I will probably create a sscce.
I had to use the suggestion given by @benarena in this comment. However I had to explicitly specify the value attribute of the property along with the Access attribute.
@JsonProperty(value = "password", access = JsonProperty.Access.WRITE_ONLY)
solved the problem.
The Immutable class would look like:
@Value.Immutable
@Value.Style(defaults = @Value.Immutable(copy = false), init = "set*")
@JsonSersonIgnoreialize(as = ImmutableUserDto.class)
@JsonDeserialize(builder = ImmutableUserDto.Builder.class)
public abstract class UserDto {
....
@JsonProperty(value = "password", access = JsonProperty.Access.WRITE_ONLY)
public abstract String getPassword();
}