DefaultViewConfigTest.java
package tools.jackson.databind.views;
import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.annotation.*;
import tools.jackson.databind.*;
import tools.jackson.databind.testutil.DatabindTestUtil;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* Tests for configuring default serialization and deserialization views
* at the mapper level (via builder).
* Addresses [databind#5575].
*
* @since 3.1
*/
public class DefaultViewConfigTest extends DatabindTestUtil
{
// Classes that represent views
static class ViewPublic { }
static class ViewInternal { }
@JsonPropertyOrder({ "id", "name", "internalData" })
static class Bean {
@JsonView(ViewPublic.class)
public int id = 1;
@JsonView(ViewPublic.class)
public String name = "Bob";
@JsonView(ViewInternal.class)
public String internalData = "secret";
}
/*
/**********************************************************
/* Tests: default serialization view
/**********************************************************
*/
@Test
public void testDefaultSerializationView() throws Exception
{
// Configure mapper with default serialization view
ObjectMapper mapper = jsonMapperBuilder()
.defaultSerializationView(ViewPublic.class)
.build();
Bean bean = new Bean();
// Should use ViewPublic by default
String json = mapper.writeValueAsString(bean);
assertEquals(a2q("{'id':1,'name':'Bob'}"), json);
}
@Test
public void testDefaultSerializationViewOverride() throws Exception
{
// Configure mapper with default serialization view
ObjectMapper mapper = jsonMapperBuilder()
.defaultSerializationView(ViewPublic.class)
.build();
Bean bean = new Bean();
// Override default view with writer
String json = mapper.writerWithView(ViewInternal.class)
.writeValueAsString(bean);
assertEquals(a2q("{'internalData':'secret'}"), json);
// No view on writer should use default
json = mapper.writer().writeValueAsString(bean);
assertEquals(a2q("{'id':1,'name':'Bob'}"), json);
}
/*
/**********************************************************
/* Tests: default deserialization view
/**********************************************************
*/
@Test
public void testDefaultDeserializationView() throws Exception
{
// Configure mapper with default deserialization view
ObjectMapper mapper = jsonMapperBuilder()
.defaultDeserializationView(ViewPublic.class)
.disable(DeserializationFeature.FAIL_ON_UNEXPECTED_VIEW_PROPERTIES)
.build();
String json = a2q("{'id':99,'name':'Alice','internalData':'hacked'}");
// Should use ViewPublic by default (internal data not set)
Bean bean = mapper.readerFor(Bean.class).readValue(json);
assertEquals(99, bean.id);
assertEquals("Alice", bean.name);
assertEquals("secret", bean.internalData); // default value, not from JSON
}
@Test
public void testDefaultDeserializationViewOverride() throws Exception
{
// Configure mapper with default deserialization view
ObjectMapper mapper = jsonMapperBuilder()
.defaultDeserializationView(ViewPublic.class)
.disable(DeserializationFeature.FAIL_ON_UNEXPECTED_VIEW_PROPERTIES)
.build();
String json = a2q("{'id':99,'name':'Alice','internalData':'hacked'}");
// Override default view with reader
Bean bean = mapper.readerFor(Bean.class)
.withView(ViewInternal.class)
.readValue(json);
assertEquals(1, bean.id); // default value, not from JSON
assertEquals("Bob", bean.name); // default value, not from JSON
assertEquals("hacked", bean.internalData);
// No view on reader should use default
bean = mapper.readerFor(Bean.class).readValue(json);
assertEquals(99, bean.id);
assertEquals("Alice", bean.name);
assertEquals("secret", bean.internalData); // default value
}
/*
/**********************************************************
/* Tests: convenience method for both ser and deser
/**********************************************************
*/
@Test
public void testDefaultViewBothSerAndDeser() throws Exception
{
// Configure mapper with default view for both serialization and deserialization
ObjectMapper mapper = jsonMapperBuilder()
.defaultView(ViewPublic.class)
.disable(DeserializationFeature.FAIL_ON_UNEXPECTED_VIEW_PROPERTIES)
.build();
Bean bean = new Bean();
// Serialization should use ViewPublic
String json = mapper.writeValueAsString(bean);
assertEquals(a2q("{'id':1,'name':'Bob'}"), json);
// Deserialization should use ViewPublic
String inputJson = a2q("{'id':99,'name':'Alice','internalData':'hacked'}");
Bean result = mapper.readerFor(Bean.class).readValue(inputJson);
assertEquals(99, result.id);
assertEquals("Alice", result.name);
assertEquals("secret", result.internalData); // default value
}
/*
/**********************************************************
/* Tests: separate ser/deser views
/**********************************************************
*/
@Test
public void testSeparateSerializationAndDeserializationViews() throws Exception
{
// Configure different default views for serialization and deserialization
ObjectMapper mapper = jsonMapperBuilder()
.defaultSerializationView(ViewPublic.class)
.defaultDeserializationView(ViewInternal.class)
.disable(DeserializationFeature.FAIL_ON_UNEXPECTED_VIEW_PROPERTIES)
.build();
Bean bean = new Bean();
// Serialization should use ViewPublic
String json = mapper.writeValueAsString(bean);
assertEquals(a2q("{'id':1,'name':'Bob'}"), json);
// Deserialization should use ViewInternal
String inputJson = a2q("{'id':99,'name':'Alice','internalData':'hacked'}");
Bean result = mapper.readerFor(Bean.class).readValue(inputJson);
assertEquals(1, result.id); // default value
assertEquals("Bob", result.name); // default value
assertEquals("hacked", result.internalData);
}
/*
/**********************************************************
/* Tests: no default view (null)
/**********************************************************
*/
@Test
public void testNoDefaultView() throws Exception
{
// Mapper with no default view
ObjectMapper mapper = jsonMapperBuilder().build();
Bean bean = new Bean();
// Without view, all properties should be serialized
String json = mapper.writeValueAsString(bean);
assertEquals(a2q("{'id':1,'name':'Bob','internalData':'secret'}"), json);
// Without view, all properties should be deserialized
String inputJson = a2q("{'id':99,'name':'Alice','internalData':'hacked'}");
Bean result = mapper.readerFor(Bean.class).readValue(inputJson);
assertEquals(99, result.id);
assertEquals("Alice", result.name);
assertEquals("hacked", result.internalData);
}
/*
/**********************************************************
/* Tests: rebuild preserves default views
/**********************************************************
*/
@Test
public void testRebuildPreservesDefaultViews() throws Exception
{
// Configure mapper with default views
ObjectMapper mapper1 = jsonMapperBuilder()
.defaultSerializationView(ViewPublic.class)
.defaultDeserializationView(ViewInternal.class)
.disable(DeserializationFeature.FAIL_ON_UNEXPECTED_VIEW_PROPERTIES)
.build();
// Rebuild mapper
ObjectMapper mapper2 = mapper1.rebuild().build();
Bean bean = new Bean();
// Rebuilt mapper should preserve default serialization view
String json = mapper2.writeValueAsString(bean);
assertEquals(a2q("{'id':1,'name':'Bob'}"), json);
// Rebuilt mapper should preserve default deserialization view
String inputJson = a2q("{'id':99,'name':'Alice','internalData':'hacked'}");
Bean result = mapper2.readerFor(Bean.class).readValue(inputJson);
assertEquals(1, result.id); // default value
assertEquals("Bob", result.name); // default value
assertEquals("hacked", result.internalData);
}
/*
/**********************************************************
/* Tests: setting null view clears previous value
/**********************************************************
*/
@Test
public void testNullViewClearsPrevious() throws Exception
{
// Configure mapper with default views, then clear them
ObjectMapper mapper = jsonMapperBuilder()
.defaultView(ViewPublic.class)
.defaultView(null) // clear the default view
.build();
Bean bean = new Bean();
// Without view, all properties should be serialized
String json = mapper.writeValueAsString(bean);
assertEquals(a2q("{'id':1,'name':'Bob','internalData':'secret'}"), json);
}
}