jackson-dataformats-text icon indicating copy to clipboard operation
jackson-dataformats-text copied to clipboard

CSV generator does not support Object values for properties (nested Objects)

Open KevinDougan opened this issue 7 months ago • 3 comments
trafficstars

I have written a short test class to identify a problem I am encountering when attempting to convert a POJO to a JSON String.

NOTE that in my Java code I tried to configure the CsvMapper v2.18.3 to ignore certain types of problems but the Exception is still thrown.

Dependency:

		<dependency>
			<groupId>com.fasterxml.jackson.dataformat</groupId>
			<artifactId>jackson-dataformat-csv</artifactId>
			<version>2.18.3</version>
		</dependency>

The Java code is:

package ca.cdr.admin.web.controller;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.dataformat.csv.CsvMapper;
import com.fasterxml.jackson.dataformat.csv.CsvParser;
import com.fasterxml.jackson.dataformat.csv.CsvSchema;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;

public class JacksonCsvSerializationTest {

	@JsonIgnoreProperties(ignoreUnknown=true)
	private static class Name {
		private String firstName;
		private String lastName;

		public Name(String firstName, String lastName) {
				this.firstName = firstName;
				this.lastName = lastName;
		}

		@JsonProperty("name")
		public String getName() {
			return this.firstName + " " + this.lastName;
		}
	}

	@JsonIgnoreProperties(ignoreUnknown=true)
	private static class Person {
		@JsonProperty("id")
		private int id = 1;

		@JsonProperty("names")
		private Collection<Name> names = new HashSet<Name>();

		public Person(Name name) {
			this.names.add(name);
		}
	}

	public static void main(String args[]) throws IOException {
		Name name = new Name("first", "last");
		Person person = new Person(name);
		CsvSchema.Builder csvBuilder = new CsvSchema.Builder();
		CsvMapper csvMapper = (CsvMapper) new CsvMapper()
			.configure(CsvParser.Feature.FAIL_ON_MISSING_COLUMNS, false)
			.configure(CsvParser.Feature.FAIL_ON_MISSING_HEADER_COLUMNS, false)
			.configure(JsonParser.Feature.IGNORE_UNDEFINED, true)
			.configure(JsonGenerator.Feature.IGNORE_UNKNOWN, true);
		csvBuilder.addColumn(new CsvSchema.Column(1, "id"));
		csvBuilder.addColumn(new CsvSchema.Column(2, "names"));
		CsvSchema csvSchema = csvBuilder.build().withStrictHeaders(false);
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		csvMapper.writer(csvSchema).writeValue(baos, person);
		System.out.println("-->" + baos.toString() + "<--");
	}
}

The ERROR I get is:

Exception in thread "main" com.fasterxml.jackson.dataformat.csv.CsvWriteException: CSV generator does not support Object values for properties (nested Objects) (through reference chain: ca.cdr.admin.web.controller.JacksonCsvSerializationTest$Person["names"]->java.util.HashSet[0])
	at com.fasterxml.jackson.dataformat.csv.CsvWriteException.from(CsvWriteException.java:25)
	at com.fasterxml.jackson.dataformat.csv.CsvGenerator._reportMappingError(CsvGenerator.java:1108)
	at com.fasterxml.jackson.dataformat.csv.CsvGenerator.writeStartObject(CsvGenerator.java:648)
	at com.fasterxml.jackson.core.base.GeneratorBase.writeStartObject(GeneratorBase.java:328)
	at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:179)
	at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serializeContents(CollectionSerializer.java:145)
	at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:107)
	at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:25)
	at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:732)
	at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:770)
	at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:183)
	at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:502)
	at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:341)
	at com.fasterxml.jackson.databind.ObjectWriter$Prefetch.serialize(ObjectWriter.java:1574)
	at com.fasterxml.jackson.databind.ObjectWriter._writeValueAndClose(ObjectWriter.java:1275)
	at com.fasterxml.jackson.databind.ObjectWriter.writeValue(ObjectWriter.java:1098)
	at ca.cdr.admin.web.controller.JacksonCsvSerializationTest.main(JacksonCsvSerializationTest.java:62)

Any assistance would be appreciated!

KevinDougan avatar Apr 08 '25 16:04 KevinDougan

Well, what do you want your CSV to look like? Both the list and the object are not straight-forward to map.

yawkat avatar Apr 08 '25 17:04 yawkat

Quick note: usually it's a Bad Idea to use this for any tests:

@JsonIgnoreProperties(ignoreUnknown=true)

since it tends to mask all kinds of problems.

Aside from that, yeah, nested POJOs are not supported. List/arrays with simple Scalar types (Numbers, Strings, Booleans) are. As per exception:

"CSV generator does not support Object values for properties (nested Objects) "

this is current limitation and someone would need to work on adding support -- probably first specifying what kind of convention would be used. For List/arrays/Collections, support is in a way that the whole value is encoded within a single cell. For POJOs this approach would be more difficult.

cowtowncoder avatar Apr 08 '25 17:04 cowtowncoder

Thanks for the quick response! Maybe this code I provided can be used to test that future feature. Let me know if you want to add it somewhere as a @Disabled Test. Thanks again, Kevin

KevinDougan avatar Apr 08 '25 18:04 KevinDougan