Skip to content

CsvMapper.typedSchemaForWithView() with DEFAULT_VIEW_INCLUSION #308

@mrpiggi

Description

@mrpiggi

Using CsvMapper.typedSchemaForWithView(Class<?> pojoType, Class<?> view) for a pojoType—which does not define a default view with @JsonView as type annotation—ignores fields without an @JsonView annotation during the creation of the schema. This behavior differs in comparison to JsonMapper. See the given test case.

package com.fasterxml.jackson.dataformat.csv;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonView;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;

import org.junit.Test;


public class SchemaDefaultView308Test extends ModuleTestBase {

	@Test
	public void testJsonVsCsv() throws JsonProcessingException {

		final ObjectMapper jsonMapperDisabled = JsonMapper.builder().disable(MapperFeature.DEFAULT_VIEW_INCLUSION).build();
		final CsvMapper csvMapperDisabled = CsvMapper.builder().disable(MapperFeature.DEFAULT_VIEW_INCLUSION).build();

		final ObjectMapper jsonMapperEnabled = JsonMapper.builder().enable(MapperFeature.DEFAULT_VIEW_INCLUSION).build();
		final CsvMapper csvMapperEnabled = CsvMapper.builder().enable(MapperFeature.DEFAULT_VIEW_INCLUSION).build();

		final ExplicitDefaultViewPojo explicit = new ExplicitDefaultViewPojo(true, "text", 1234);
		final ImplicitDefaultViewPojo implicit = new ImplicitDefaultViewPojo(true, "text", 1234);


		compareExpected(jsonMapperDisabled, csvMapperDisabled, explicit, null, "flag", "text", "number");
		compareExpected(jsonMapperDisabled, csvMapperDisabled, explicit, DefaultView.class, "flag");
		compareExpected(jsonMapperDisabled, csvMapperDisabled, explicit, BaseView.class, "flag", "text");
		compareExpected(jsonMapperDisabled, csvMapperDisabled, explicit, ExtendedView.class, "flag", "text", "number");

		compareExpected(jsonMapperDisabled, csvMapperDisabled, implicit, null, "flag", "text", "number");
		compareExpected(jsonMapperDisabled, csvMapperDisabled, implicit, DefaultView.class);
		compareExpected(jsonMapperDisabled, csvMapperDisabled, implicit, BaseView.class, "text");
		compareExpected(jsonMapperDisabled, csvMapperDisabled, implicit, ExtendedView.class, "text", "number");

		compareExpected(jsonMapperEnabled, csvMapperEnabled, explicit, null, "flag", "text", "number");
		compareExpected(jsonMapperEnabled, csvMapperEnabled, explicit, DefaultView.class, "flag");
		compareExpected(jsonMapperEnabled, csvMapperEnabled, explicit, BaseView.class, "flag", "text");
		compareExpected(jsonMapperEnabled, csvMapperEnabled, explicit, ExtendedView.class, "flag", "text", "number");

		System.err.println("serialization with 'DEFAULT_VIEW_INCLUSION' differs between JSON and CSV\n");
		compareExpected(jsonMapperEnabled, csvMapperEnabled, implicit, null, "flag", "text", "number");
		compareExpected(jsonMapperEnabled, csvMapperEnabled, implicit, DefaultView.class, "flag");
		compareExpected(jsonMapperEnabled, csvMapperEnabled, implicit, BaseView.class, "flag", "text");
		compareExpected(jsonMapperEnabled, csvMapperEnabled, implicit, ExtendedView.class, "flag", "text", "number");

	}


	private static void compareExpected(
			final ObjectMapper jsonMapper,
			final CsvMapper csvMapper,
			final Object pojo,
			final Class<?> view,
			final String... expectedNames
	) throws JsonProcessingException {

		final Set<String> actualJsonNames = new HashSet<>();
		final String json = jsonMapper.writerWithView(view).writeValueAsString(pojo);
		jsonMapper.readTree(json).fieldNames().forEachRemaining(actualJsonNames::add);
		assertEquals(Arrays.stream(expectedNames).collect(Collectors.toSet()), actualJsonNames);

		final Set<String> actualCsvNames = new HashSet<>();
		final CsvSchema schema = csvMapper.typedSchemaForWithView(pojo.getClass(), view);
		schema.rebuild().getColumns().forEachRemaining(c -> actualCsvNames.add(c.getName()));
		assertEquals(
				view == null ? "null" : view.getSimpleName() + " misses fields/columns",
				actualJsonNames,
				actualCsvNames
		);

	}


	interface DefaultView {}
	interface BaseView extends DefaultView {}
	interface ExtendedView extends BaseView {}

	
	@JsonView(DefaultView.class)
	class ExplicitDefaultViewPojo {

		@JsonProperty
		boolean flag;
		@JsonProperty
		@JsonView(BaseView.class)
		String text;
		@JsonProperty
		@JsonView(ExtendedView.class)
		Integer number;

		ExplicitDefaultViewPojo(
				final Boolean flag,
				final String text,
				final Integer number
		) {

			this.flag = flag;
			this.text = text;
			this.number = number;

		}

	}

	
	class ImplicitDefaultViewPojo {

		@JsonProperty
		boolean flag;
		@JsonProperty
		@JsonView(BaseView.class)
		String text;
		@JsonProperty
		@JsonView(ExtendedView.class)
		Integer number;

		ImplicitDefaultViewPojo(
				final Boolean flag,
				final String text,
				final Integer number
		) {

			this.flag = flag;
			this.text = text;
			this.number = number;

		}

	}

}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions