GeneratorInitializerTest.java
package tools.jackson.databind.ser;
import java.io.*;
import java.nio.file.Path;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import tools.jackson.core.JsonEncoding;
import tools.jackson.core.JsonGenerator;
import tools.jackson.databind.JsonNode;
import tools.jackson.databind.ObjectMapper;
import tools.jackson.databind.ObjectWriter;
import tools.jackson.databind.SequenceWriter;
import tools.jackson.databind.cfg.GeneratorInitializer;
import tools.jackson.databind.json.JsonMapper;
import tools.jackson.databind.testutil.DatabindTestUtil;
import static org.junit.jupiter.api.Assertions.*;
/**
* Tests for {@link GeneratorInitializer} support (issue #5860).
* Verifies that the initializer is called exactly once per internally-created
* generator and never for externally-provided generators.
*/
public class GeneratorInitializerTest extends DatabindTestUtil
{
// Helper to build a mapper with a counting initializer
private ObjectMapper _mapperWith(AtomicInteger count) {
return JsonMapper.builder()
.generatorInitializer((config, gen) -> count.incrementAndGet())
.build();
}
// Helper to build an ObjectWriter with a counting initializer
private ObjectWriter _writerWith(AtomicInteger count) {
return _mapperWith(count).writer();
}
/*
/**********************************************************************
/* Basic configuration tests
/**********************************************************************
*/
@Test
public void testNoInitializerByDefault() throws Exception
{
ObjectMapper mapper = new JsonMapper();
assertNull(mapper.serializationConfig().getGeneratorInitializer());
assertEquals("42", mapper.writeValueAsString(42));
}
@Test
public void testInitializerOverrideOnObjectWriter() throws Exception
{
final AtomicInteger count1 = new AtomicInteger();
final AtomicInteger count2 = new AtomicInteger();
ObjectWriter writer = _mapperWith(count1).writer()
.with((config, gen) -> count2.incrementAndGet());
writer.writeValueAsString(42);
assertEquals(0, count1.get(), "Original initializer should NOT be called");
assertEquals(1, count2.get(), "Override initializer should be called once");
}
@Test
public void testInitializerClearedWithNull() throws Exception
{
final AtomicInteger count = new AtomicInteger();
ObjectWriter writer = _mapperWith(count).writer()
.with((GeneratorInitializer) null);
writer.writeValueAsString(42);
assertEquals(0, count.get(), "No initializer should be called after clearing");
}
/*
/**********************************************************************
/* ObjectMapper.createGenerator(): exactly once
/**********************************************************************
*/
@Test
public void testMapperCreateGeneratorOutputStream() throws Exception
{
final AtomicInteger count = new AtomicInteger();
ObjectMapper mapper = _mapperWith(count);
try (JsonGenerator g = mapper.createGenerator(new ByteArrayOutputStream())) {
assertEquals(1, count.get());
g.writeNumber(1);
}
assertEquals(1, count.get());
}
@Test
public void testMapperCreateGeneratorOutputStreamEncoding() throws Exception
{
final AtomicInteger count = new AtomicInteger();
ObjectMapper mapper = _mapperWith(count);
try (JsonGenerator g = mapper.createGenerator(new ByteArrayOutputStream(), JsonEncoding.UTF8)) {
assertEquals(1, count.get());
g.writeNumber(1);
}
assertEquals(1, count.get());
}
@Test
public void testMapperCreateGeneratorWriter() throws Exception
{
final AtomicInteger count = new AtomicInteger();
ObjectMapper mapper = _mapperWith(count);
try (JsonGenerator g = mapper.createGenerator(new StringWriter())) {
assertEquals(1, count.get());
g.writeNumber(1);
}
assertEquals(1, count.get());
}
@Test
public void testMapperCreateGeneratorFile(@TempDir Path tempDir) throws Exception
{
final AtomicInteger count = new AtomicInteger();
ObjectMapper mapper = _mapperWith(count);
File f = tempDir.resolve("test.json").toFile();
try (JsonGenerator g = mapper.createGenerator(f, JsonEncoding.UTF8)) {
assertEquals(1, count.get());
g.writeNumber(1);
}
assertEquals(1, count.get());
}
@Test
public void testMapperCreateGeneratorPath(@TempDir Path tempDir) throws Exception
{
final AtomicInteger count = new AtomicInteger();
ObjectMapper mapper = _mapperWith(count);
Path p = tempDir.resolve("test.json");
try (JsonGenerator g = mapper.createGenerator(p, JsonEncoding.UTF8)) {
assertEquals(1, count.get());
g.writeNumber(1);
}
assertEquals(1, count.get());
}
@Test
public void testMapperCreateGeneratorDataOutput() throws Exception
{
final AtomicInteger count = new AtomicInteger();
ObjectMapper mapper = _mapperWith(count);
try (JsonGenerator g = mapper.createGenerator((DataOutput) new DataOutputStream(new ByteArrayOutputStream()))) {
assertEquals(1, count.get());
g.writeNumber(1);
}
assertEquals(1, count.get());
}
/*
/**********************************************************************
/* ObjectMapper.writeValue*(): exactly once
/**********************************************************************
*/
@Test
public void testMapperWriteValueAsString() throws Exception
{
final AtomicInteger count = new AtomicInteger();
ObjectMapper mapper = _mapperWith(count);
assertEquals("42", mapper.writeValueAsString(42));
assertEquals(1, count.get());
}
@Test
public void testMapperWriteValueAsBytes() throws Exception
{
final AtomicInteger count = new AtomicInteger();
ObjectMapper mapper = _mapperWith(count);
byte[] bytes = mapper.writeValueAsBytes(42);
assertEquals("42", new String(bytes, "UTF-8"));
assertEquals(1, count.get());
}
@Test
public void testMapperWriteValueOutputStream() throws Exception
{
final AtomicInteger count = new AtomicInteger();
ObjectMapper mapper = _mapperWith(count);
ByteArrayOutputStream out = new ByteArrayOutputStream();
mapper.writeValue(out, "test");
assertEquals(1, count.get());
}
@Test
public void testMapperWriteValueWriter() throws Exception
{
final AtomicInteger count = new AtomicInteger();
ObjectMapper mapper = _mapperWith(count);
mapper.writeValue(new StringWriter(), "test");
assertEquals(1, count.get());
}
@Test
public void testMapperWriteValueFile(@TempDir Path tempDir) throws Exception
{
final AtomicInteger count = new AtomicInteger();
ObjectMapper mapper = _mapperWith(count);
mapper.writeValue(tempDir.resolve("test.json").toFile(), "test");
assertEquals(1, count.get());
}
@Test
public void testMapperWriteValuePath(@TempDir Path tempDir) throws Exception
{
final AtomicInteger count = new AtomicInteger();
ObjectMapper mapper = _mapperWith(count);
mapper.writeValue(tempDir.resolve("test.json"), "test");
assertEquals(1, count.get());
}
@Test
public void testMapperWriteValueDataOutput() throws Exception
{
final AtomicInteger count = new AtomicInteger();
ObjectMapper mapper = _mapperWith(count);
mapper.writeValue((DataOutput) new DataOutputStream(new ByteArrayOutputStream()), "test");
assertEquals(1, count.get());
}
/*
/**********************************************************************
/* ObjectMapper: NOT called for user-provided generators
/**********************************************************************
*/
@Test
public void testMapperWriteValueWithProvidedGenerator() throws Exception
{
final AtomicInteger count = new AtomicInteger();
ObjectMapper mapper = _mapperWith(count);
ByteArrayOutputStream out = new ByteArrayOutputStream();
// createGenerator fires once
try (JsonGenerator g = mapper.createGenerator(out)) {
assertEquals(1, count.get());
// writeValue(gen, ...) must NOT fire again
mapper.writeValue(g, 42);
assertEquals(1, count.get());
}
}
/*
/**********************************************************************
/* ObjectWriter.createGenerator(): exactly once
/**********************************************************************
*/
@Test
public void testWriterCreateGeneratorOutputStream() throws Exception
{
final AtomicInteger count = new AtomicInteger();
ObjectWriter w = _writerWith(count);
try (JsonGenerator g = w.createGenerator(new ByteArrayOutputStream())) {
assertEquals(1, count.get());
g.writeNumber(1);
}
assertEquals(1, count.get());
}
@Test
public void testWriterCreateGeneratorOutputStreamEncoding() throws Exception
{
final AtomicInteger count = new AtomicInteger();
ObjectWriter w = _writerWith(count);
try (JsonGenerator g = w.createGenerator(new ByteArrayOutputStream(), JsonEncoding.UTF8)) {
assertEquals(1, count.get());
g.writeNumber(1);
}
assertEquals(1, count.get());
}
@Test
public void testWriterCreateGeneratorWriter() throws Exception
{
final AtomicInteger count = new AtomicInteger();
ObjectWriter w = _writerWith(count);
try (JsonGenerator g = w.createGenerator(new StringWriter())) {
assertEquals(1, count.get());
g.writeNumber(1);
}
assertEquals(1, count.get());
}
@Test
public void testWriterCreateGeneratorFile(@TempDir Path tempDir) throws Exception
{
final AtomicInteger count = new AtomicInteger();
ObjectWriter w = _writerWith(count);
File f = tempDir.resolve("test.json").toFile();
try (JsonGenerator g = w.createGenerator(f, JsonEncoding.UTF8)) {
assertEquals(1, count.get());
g.writeNumber(1);
}
assertEquals(1, count.get());
}
@Test
public void testWriterCreateGeneratorPath(@TempDir Path tempDir) throws Exception
{
final AtomicInteger count = new AtomicInteger();
ObjectWriter w = _writerWith(count);
Path p = tempDir.resolve("test.json");
try (JsonGenerator g = w.createGenerator(p, JsonEncoding.UTF8)) {
assertEquals(1, count.get());
g.writeNumber(1);
}
assertEquals(1, count.get());
}
@Test
public void testWriterCreateGeneratorDataOutput() throws Exception
{
final AtomicInteger count = new AtomicInteger();
ObjectWriter w = _writerWith(count);
try (JsonGenerator g = w.createGenerator((DataOutput) new DataOutputStream(new ByteArrayOutputStream()))) {
assertEquals(1, count.get());
g.writeNumber(1);
}
assertEquals(1, count.get());
}
/*
/**********************************************************************
/* ObjectWriter.writeValue*(): exactly once
/**********************************************************************
*/
@Test
public void testWriterWriteValueAsString() throws Exception
{
final AtomicInteger count = new AtomicInteger();
ObjectWriter w = _writerWith(count);
assertEquals("42", w.writeValueAsString(42));
assertEquals(1, count.get());
}
@Test
public void testWriterWriteValueAsBytes() throws Exception
{
final AtomicInteger count = new AtomicInteger();
ObjectWriter w = _writerWith(count);
byte[] bytes = w.writeValueAsBytes(42);
assertEquals("42", new String(bytes, "UTF-8"));
assertEquals(1, count.get());
}
@Test
public void testWriterWriteValueOutputStream() throws Exception
{
final AtomicInteger count = new AtomicInteger();
ObjectWriter w = _writerWith(count);
w.writeValue(new ByteArrayOutputStream(), "test");
assertEquals(1, count.get());
}
@Test
public void testWriterWriteValueWriter() throws Exception
{
final AtomicInteger count = new AtomicInteger();
ObjectWriter w = _writerWith(count);
w.writeValue(new StringWriter(), "test");
assertEquals(1, count.get());
}
@Test
public void testWriterWriteValueFile(@TempDir Path tempDir) throws Exception
{
final AtomicInteger count = new AtomicInteger();
ObjectWriter w = _writerWith(count);
w.writeValue(tempDir.resolve("test.json").toFile(), "test");
assertEquals(1, count.get());
}
@Test
public void testWriterWriteValuePath(@TempDir Path tempDir) throws Exception
{
final AtomicInteger count = new AtomicInteger();
ObjectWriter w = _writerWith(count);
w.writeValue(tempDir.resolve("test.json"), "test");
assertEquals(1, count.get());
}
@Test
public void testWriterWriteValueDataOutput() throws Exception
{
final AtomicInteger count = new AtomicInteger();
ObjectWriter w = _writerWith(count);
w.writeValue((DataOutput) new DataOutputStream(new ByteArrayOutputStream()), "test");
assertEquals(1, count.get());
}
/*
/**********************************************************************
/* ObjectWriter: NOT called for user-provided generators
/**********************************************************************
*/
@Test
public void testWriterWriteValueWithProvidedGenerator() throws Exception
{
final AtomicInteger count = new AtomicInteger();
ObjectMapper mapper = _mapperWith(count);
ObjectWriter w = mapper.writer();
ByteArrayOutputStream out = new ByteArrayOutputStream();
try (JsonGenerator g = mapper.createGenerator(out)) {
assertEquals(1, count.get()); // once from createGenerator
w.writeValue(g, 42);
assertEquals(1, count.get()); // NOT again for writeValue
}
}
/*
/**********************************************************************
/* ObjectWriter.writeValues(): exactly once per sequence writer
/**********************************************************************
*/
@Test
public void testWriterWriteValuesOutputStream() throws Exception
{
final AtomicInteger count = new AtomicInteger();
ObjectWriter w = _writerWith(count);
try (SequenceWriter seq = w.writeValues(new ByteArrayOutputStream())) {
assertEquals(1, count.get());
seq.write(1);
seq.write(2);
assertEquals(1, count.get());
}
}
@Test
public void testWriterWriteValuesWriter() throws Exception
{
final AtomicInteger count = new AtomicInteger();
ObjectWriter w = _writerWith(count);
try (SequenceWriter seq = w.writeValues(new StringWriter())) {
assertEquals(1, count.get());
seq.write(1);
assertEquals(1, count.get());
}
}
@Test
public void testWriterWriteValuesFile(@TempDir Path tempDir) throws Exception
{
final AtomicInteger count = new AtomicInteger();
ObjectWriter w = _writerWith(count);
try (SequenceWriter seq = w.writeValues(tempDir.resolve("test.json").toFile())) {
assertEquals(1, count.get());
seq.write(1);
assertEquals(1, count.get());
}
}
@Test
public void testWriterWriteValuesPath(@TempDir Path tempDir) throws Exception
{
final AtomicInteger count = new AtomicInteger();
ObjectWriter w = _writerWith(count);
try (SequenceWriter seq = w.writeValues(tempDir.resolve("test.json"))) {
assertEquals(1, count.get());
seq.write(1);
assertEquals(1, count.get());
}
}
@Test
public void testWriterWriteValuesDataOutput() throws Exception
{
final AtomicInteger count = new AtomicInteger();
ObjectWriter w = _writerWith(count);
try (SequenceWriter seq = w.writeValues((DataOutput) new DataOutputStream(new ByteArrayOutputStream()))) {
assertEquals(1, count.get());
seq.write(1);
assertEquals(1, count.get());
}
}
@Test
public void testWriterWriteValuesWithProvidedGenerator() throws Exception
{
final AtomicInteger count = new AtomicInteger();
ObjectMapper mapper = _mapperWith(count);
ObjectWriter w = mapper.writer();
ByteArrayOutputStream out = new ByteArrayOutputStream();
try (JsonGenerator g = mapper.createGenerator(out)) {
assertEquals(1, count.get());
try (SequenceWriter seq = w.writeValues(g)) {
seq.write(1);
}
assertEquals(1, count.get()); // NOT again
}
}
/*
/**********************************************************************
/* ObjectWriter.writeValuesAsArray(): exactly once per sequence writer
/**********************************************************************
*/
@Test
public void testWriterWriteValuesAsArrayOutputStream() throws Exception
{
final AtomicInteger count = new AtomicInteger();
ObjectWriter w = _writerWith(count);
try (SequenceWriter seq = w.writeValuesAsArray(new ByteArrayOutputStream())) {
assertEquals(1, count.get());
seq.write(1);
seq.write(2);
assertEquals(1, count.get());
}
}
@Test
public void testWriterWriteValuesAsArrayWriter() throws Exception
{
final AtomicInteger count = new AtomicInteger();
ObjectWriter w = _writerWith(count);
try (SequenceWriter seq = w.writeValuesAsArray(new StringWriter())) {
assertEquals(1, count.get());
seq.write(1);
assertEquals(1, count.get());
}
}
@Test
public void testWriterWriteValuesAsArrayFile(@TempDir Path tempDir) throws Exception
{
final AtomicInteger count = new AtomicInteger();
ObjectWriter w = _writerWith(count);
try (SequenceWriter seq = w.writeValuesAsArray(tempDir.resolve("test.json").toFile())) {
assertEquals(1, count.get());
seq.write(1);
assertEquals(1, count.get());
}
}
@Test
public void testWriterWriteValuesAsArrayPath(@TempDir Path tempDir) throws Exception
{
final AtomicInteger count = new AtomicInteger();
ObjectWriter w = _writerWith(count);
try (SequenceWriter seq = w.writeValuesAsArray(tempDir.resolve("test.json"))) {
assertEquals(1, count.get());
seq.write(1);
assertEquals(1, count.get());
}
}
@Test
public void testWriterWriteValuesAsArrayDataOutput() throws Exception
{
final AtomicInteger count = new AtomicInteger();
ObjectWriter w = _writerWith(count);
try (SequenceWriter seq = w.writeValuesAsArray((DataOutput) new DataOutputStream(new ByteArrayOutputStream()))) {
assertEquals(1, count.get());
seq.write(1);
assertEquals(1, count.get());
}
}
@Test
public void testWriterWriteValuesAsArrayWithProvidedGenerator() throws Exception
{
final AtomicInteger count = new AtomicInteger();
ObjectMapper mapper = _mapperWith(count);
ObjectWriter w = mapper.writer();
ByteArrayOutputStream out = new ByteArrayOutputStream();
try (JsonGenerator g = mapper.createGenerator(out)) {
assertEquals(1, count.get());
try (SequenceWriter seq = w.writeValuesAsArray(g)) {
seq.write(1);
}
assertEquals(1, count.get()); // NOT again
}
}
/*
/**********************************************************************
/* ObjectWriter.valueToTree(): exactly once (uses internal generator)
/**********************************************************************
*/
@Test
public void testWriterValueToTree() throws Exception
{
final AtomicInteger count = new AtomicInteger();
ObjectWriter w = _writerWith(count);
JsonNode node = w.valueToTree(Map.of("a", 1));
assertNotNull(node);
assertTrue(node.isObject());
assertEquals(1, count.get());
}
/*
/**********************************************************************
/* Multiple independent writes: count increments once per call
/**********************************************************************
*/
@Test
public void testMultipleWritesIncrementCount() throws Exception
{
final AtomicInteger count = new AtomicInteger();
ObjectMapper mapper = _mapperWith(count);
mapper.writeValueAsString(1);
assertEquals(1, count.get());
mapper.writeValueAsString(2);
assertEquals(2, count.get());
mapper.writeValueAsString(3);
assertEquals(3, count.get());
}
@Test
public void testMultipleWriterWritesIncrementCount() throws Exception
{
final AtomicInteger count = new AtomicInteger();
ObjectWriter w = _writerWith(count);
w.writeValueAsString(1);
assertEquals(1, count.get());
w.writeValueAsString(2);
assertEquals(2, count.get());
w.writeValueAsString(3);
assertEquals(3, count.get());
}
}