POJOAsArrayUpdateViewBypassTest.java
package tools.jackson.databind.views;
import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.annotation.JsonView;
import tools.jackson.databind.MapperFeature;
import tools.jackson.databind.ObjectMapper;
import tools.jackson.databind.testutil.DatabindTestUtil;
import static org.junit.jupiter.api.Assertions.*;
/**
* [databind#6096]: {@code @JsonView} filtering was applied on the create paths of
* {@link tools.jackson.databind.deser.bean.BeanAsArrayDeserializer} but not on its
* "update existing value" path ({@code readerForUpdating} / {@code withValueToUpdate}),
* so a {@code @JsonFormat(shape = ARRAY)} POJO let a view-hidden property be written
* during an update even when the active view excluded it.
*/
public class POJOAsArrayUpdateViewBypassTest extends DatabindTestUtil
{
static class Public {}
static class Internal {}
@JsonFormat(shape = JsonFormat.Shape.ARRAY)
@JsonPropertyOrder({ "email", "role" })
static class Account {
@JsonView(Public.class) public String email;
@JsonView(Internal.class) public String role; // admin-only
public Account() {}
public Account(String email, String role) {
this.email = email;
this.role = role;
}
}
private final ObjectMapper MAPPER = jsonMapperBuilder()
.configure(MapperFeature.DEFAULT_VIEW_INCLUSION, false)
.build();
// Update under the Public view must not overwrite the Internal-only property
@Test
public void updatePathHonorsView() throws Exception {
Account existing = new Account("orig@corp.test", "user");
Account updated = MAPPER.readerWithView(Public.class)
.forType(Account.class)
.withValueToUpdate(existing)
.readValue("[\"mallory@evil.test\",\"ADMIN\"]");
// email is visible in Public view -> updated
assertEquals("mallory@evil.test", updated.email);
// role is Internal-only -> must be left untouched under the Public view
assertEquals("user", updated.role,
"view-hidden 'role' should keep its original value but was: " + updated.role);
}
// Control: the create path already filters (matches update-path expectation)
@Test
public void createPathHonorsView() throws Exception {
Account created = MAPPER.readerWithView(Public.class)
.forType(Account.class)
.readValue("[\"mallory@evil.test\",\"ADMIN\"]");
assertEquals("mallory@evil.test", created.email);
assertNull(created.role);
}
// Without an active view every position updates as before
@Test
public void updateWithoutViewUpdatesAll() throws Exception {
Account existing = new Account("orig@corp.test", "user");
Account updated = MAPPER.readerForUpdating(existing)
.forType(Account.class)
.readValue("[\"mallory@evil.test\",\"ADMIN\"]");
assertEquals("mallory@evil.test", updated.email);
assertEquals("ADMIN", updated.role);
}
}