Skip to content

FilteringGeneratorDelegate bug when filtering arrays (in 2.10.1) #582

@alarribeau

Description

@alarribeau

Since 2.10.1, it is not possible to filter out object arrays anymore.

The regression has been introduced by this (jackson-databind) commit which changed the array serialization implementation (more specifically the writeStartArray methods used):
FasterXML/jackson-databind@ca1867e

So it seems that the root cause is that the FilteringGeneratorDelegate (jackson-core) should override all JsonGenerator::writeStartArray methods.

Here is a maven project with 1 test class that reproduces the bug and offers a workaround :
filterGeneratorBug.zip

Test class :

package test;

import java.io.IOException;
import java.io.StringWriter;

import org.junit.Assert;
import org.junit.Test;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.filter.FilteringGeneratorDelegate;
import com.fasterxml.jackson.core.filter.JsonPointerBasedFilter;
import com.fasterxml.jackson.core.filter.TokenFilter;
import com.fasterxml.jackson.databind.ObjectMapper;

public class ArrayFilteringBugTest {
	
	private static final ArrayWrapper ARRAY_WRAPPER = new ArrayWrapper(new String[] { "foo", "bar" });
	
	static class ArrayWrapper {
		@JsonProperty
		private final String[] stringArray;
		
		ArrayWrapper(String[] stringArray) {
			this.stringArray = stringArray;
		}
	}
	
	@Test
	public void arrayFilterOut_failing() throws IOException {
		StringWriter output = new StringWriter();
		JsonGenerator jg = new JsonFactory().createGenerator(output);
		
		FilteringGeneratorDelegate filteringGeneratorDelegate = new FilteringGeneratorDelegate(jg, new JsonPointerBasedFilter("/noMatch"), true, true);
		
		new ObjectMapper().writeValue(filteringGeneratorDelegate, ARRAY_WRAPPER);
		
		Assert.assertEquals("", output.toString());
	}
	
	@Test
	public void arrayFilterOut_workaroundFix() throws IOException {
		
		StringWriter output = new StringWriter();
		JsonGenerator jg = new JsonFactory().createGenerator(output);
		
		FilteringGeneratorDelegate filteringGeneratorDelegate = new FixedFilteringGeneratorDelegate(jg, new JsonPointerBasedFilter("/noMatch"), true, true);
		
		new ObjectMapper().writeValue(filteringGeneratorDelegate, ARRAY_WRAPPER);
		
		Assert.assertEquals("", output.toString());
	}
	
	static class FixedFilteringGeneratorDelegate extends FilteringGeneratorDelegate {
		
		public FixedFilteringGeneratorDelegate(JsonGenerator d, TokenFilter f, boolean includePath, boolean allowMultipleMatches) {
			super(d, f, includePath, allowMultipleMatches);
		}
		
//		!! This method may also need overriding when called by other binders !!
//		@Override
//		public void writeStartArray(Object forValue) throws IOException;
		
		
		@Override
		public void writeStartArray(Object forValue, int size) throws IOException
		{
			// First things first: whole-sale skipping easy
			if (_itemFilter == null) {
				_filterContext = _filterContext.createChildArrayContext(null, false);
				return;
			}
			if (_itemFilter == TokenFilter.INCLUDE_ALL) { // include the whole sub-tree?
				_filterContext = _filterContext.createChildArrayContext(_itemFilter, true);
				delegate.writeStartArray(forValue, size);
				return;
			}
			// Ok; regular checking state then
			_itemFilter = _filterContext.checkValue(_itemFilter);
			if (_itemFilter == null) {
				_filterContext = _filterContext.createChildArrayContext(null, false);
				return;
			}
			if (_itemFilter != TokenFilter.INCLUDE_ALL) {
				_itemFilter = _itemFilter.filterStartArray();
			}
			if (_itemFilter == TokenFilter.INCLUDE_ALL) {
				_checkParentPath();
				_filterContext = _filterContext.createChildArrayContext(_itemFilter, true);
				delegate.writeStartArray(forValue, size);
			} else {
				_filterContext = _filterContext.createChildArrayContext(_itemFilter, false);
			}
		}
	}
	
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions