├── .gitattributes ├── .gitignore ├── .travis.yml ├── README.md ├── pom.xml ├── profile-perf.sh ├── release-notes ├── CREDITS └── VERSION ├── run-perf.sh ├── samples └── f_5500_2010_first9999.csv └── src ├── main ├── java │ └── com │ │ └── fasterxml │ │ └── jackson │ │ └── dataformat │ │ └── csv │ │ ├── CsvFactory.java │ │ ├── CsvGenerator.java │ │ ├── CsvMapper.java │ │ ├── CsvMappingException.java │ │ ├── CsvParser.java │ │ ├── CsvSchema.java │ │ ├── PackageVersion.java.in │ │ └── impl │ │ ├── BufferedValue.java │ │ ├── CsvDecoder.java │ │ ├── CsvEncoder.java │ │ ├── CsvIOContext.java │ │ ├── CsvParserBootstrapper.java │ │ ├── LRUMap.java │ │ ├── NumberInput.java │ │ ├── NumberOutput.java │ │ ├── TextBuffer.java │ │ ├── UTF8Reader.java │ │ └── UTF8Writer.java └── resources │ └── META-INF │ ├── LICENSE │ └── services │ └── com.fasterxml.jackson.core.JsonFactory └── test └── java ├── com └── fasterxml │ └── jackson │ └── dataformat │ └── csv │ ├── FeaturesTest.java │ ├── ModuleTestBase.java │ ├── TestVersions.java │ ├── deser │ ├── AnySetterTest.java │ ├── ArrayReadTest.java │ ├── BasicParserTest.java │ ├── BrokenEncodingTest.java │ ├── CommentsTest.java │ ├── FormatDetectionTest.java │ ├── IgnoreUnmappableTest.java │ ├── MissingColumnsTest.java │ ├── NullReadTest.java │ ├── ParserTrimSpacesTest.java │ ├── ReadSequencesTest.java │ ├── SequenceRecoveryTest.java │ ├── StreamingReadTest.java │ ├── TestFiltering.java │ ├── TestParserEscapes.java │ ├── TestParserNoSchema.java │ ├── TestParserQuotes.java │ ├── TestParserStrictQuoting.java │ ├── TestParserWithHeader.java │ ├── TestParserWorkarounds.java │ ├── TrailingCommaTest.java │ └── UnwrappingWithCSVTest.java │ ├── failing │ ├── MappingIteratorEnd119Test.java │ ├── NullWriting116Test.java │ └── ParserQuotes19Test.java │ ├── schema │ ├── PropertyOrder74Test.java │ └── SchemaTest.java │ └── ser │ ├── ArrayWriteTest.java │ ├── FilteringTest.java │ ├── GeneratorIgnoreUnknownTest.java │ ├── HeaderWriteTest.java │ ├── JDKSerializationTest.java │ ├── MultipleWritesTest.java │ ├── NullWritingTest.java │ ├── SchemaReorderTest.java │ ├── TestGenerator.java │ ├── TestGeneratorNoSchema.java │ ├── TestGeneratorWithCustomSeparators.java │ ├── TestGeneratorWithSequences.java │ ├── TestWriterWithMissingValues.java │ ├── TestWriterWithSomeMoreMissingValues.java │ ├── UnicodeWritingTest.java │ └── UnwrappedWriteTest.java └── perf ├── BogusOutputStream.java ├── F5500Entry.java ├── F5500Reader.java ├── ManualPerfComparison.java └── RequestEntry.java /.gitattributes: -------------------------------------------------------------------------------- 1 | # Do not merge `pom.xml` from older version, as it will typically conflict 2 | 3 | pom.xml merge=ours 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # use glob syntax. 2 | syntax: glob 3 | *.class 4 | *~ 5 | *.bak 6 | *.off 7 | *.old 8 | .DS_Store 9 | 10 | # building 11 | target 12 | 13 | # Eclipse 14 | .classpath 15 | .project 16 | .settings 17 | 18 | # IDEA 19 | *.iml 20 | *.ipr 21 | *.iws 22 | .idea 23 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | 3 | jdk: 4 | - oraclejdk7 5 | - oraclejdk8 6 | 7 | branches: 8 | only: 9 | - master 10 | - "2.8" 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **NOTE**: This module has become part of 2 | [Jackson Text Dataformats](../../../jackson-dataformats-text) 3 | as of Jackson 2.9 4 | 5 | This repo still exists to allow release of patch versions of older versions; it will be 6 | hidden (made private) in near future. 7 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | com.fasterxml.jackson 6 | jackson-bom 7 | 2.9.0.pr2-SNAPSHOT 8 | 9 | com.fasterxml.jackson.dataformat 10 | jackson-dataformat-csv 11 | Jackson-dataformat-CSV 12 | 2.9.0.pr2-SNAPSHOT 13 | bundle 14 | Support for reading and writing CSV-encoded data via Jackson 15 | abstractions. 16 | 17 | https://github.com/FasterXML/jackson-dataformat-csv 18 | 19 | scm:git:git@github.com:FasterXML/jackson-dataformat-csv.git 20 | scm:git:git@github.com:FasterXML/jackson-dataformat-csv.git 21 | http://github.com/FasterXML/jackson-dataformat-csv 22 | HEAD 23 | 24 | 25 | 26 | 27 | com/fasterxml/jackson/dataformat/csv 28 | ${project.groupId}.csv 29 | com.fasterxml.jackson.dataformat.csv.impl 30 | 31 | 32 | 33 | 34 | 35 | 36 | com.fasterxml.jackson.core 37 | jackson-core 38 | 39 | 40 | com.fasterxml.jackson.core 41 | jackson-databind 42 | 43 | 47 | 48 | com.fasterxml.jackson.core 49 | jackson-annotations 50 | 51 | 52 | 53 | 54 | junit 55 | junit 56 | test 57 | 58 | 59 | com.google.guava 60 | guava 61 | 16.0.1 62 | test 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | com.google.code.maven-replacer-plugin 71 | replacer 72 | 73 | 74 | process-packageVersion 75 | generate-sources 76 | 77 | 78 | 79 | 80 | 81 | 82 | org.apache.maven.plugins 83 | maven-surefire-plugin 84 | ${version.plugin.surefire} 85 | 86 | 87 | com/fasterxml/jackson/**/failing/*.java 88 | 89 | 90 | **/*Test.java 91 | **/Test*.java 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /profile-perf.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | java -Xmx64m -server \ 4 | -cp target/classes:target/test-classes:lib/\* \ 5 | -Xrunhprof:cpu=samples,depth=10,verbose=n,interval=2 \ 6 | $* 7 | -------------------------------------------------------------------------------- /release-notes/CREDITS: -------------------------------------------------------------------------------- 1 | Project: jackson-dataformat-csv 2 | 3 | Here are people who have contributed to development of this project: 4 | (version numbers in parenthesis indicate release in which the problem was fixed) 5 | 6 | Tatu Saloranta, tatu.saloranta@iki.fi: author 7 | 8 | Lior Lipshitz (from zazma.com) 9 | 10 | * Reported #14: Incorrect quoting of double-quotes for long String values that 11 | cross buffer boundary 12 | (2.1.5 / 2.2.0) 13 | 14 | Paul Magrath (Magrath@github) 15 | 16 | * Reported #33: CSV is written without column separators if first column is null 17 | (2.3.3) 18 | * Reported #38: Extra column delimiter added when column is escaped and follows empty column 19 | (2.3.4) 20 | 21 | Jason Dunkelberger (dirkraft@github) 22 | 23 | * Suggested #32: Allow disabling of quoteChar 24 | (2.4.0) 25 | 26 | Wei Li (wli600@github) 27 | 28 | * Contributed fix for 54: Encounter ArrayIndexOutOfBoundsException in the corner case delimiter 29 | or end-of-line happened to be the leading character of a segment buffer 30 | (2.4.4) 31 | 32 | Luke Nezda (nezda@github) 33 | 34 | * Suggested #56: Support comments (either via `CsvSchema`, or using std 35 | `JsonParser.Feature.ALLOW_YAML_COMMENTS. 36 | (requested by nezda@github) 37 | (2.5.0) 38 | 39 | David Navas (davidnavas@github) 40 | 41 | * Contributed #75: Support escapes at beginning of the file 42 | (2.5.3) 43 | 44 | sothmann@github) 45 | 46 | * Reported #83: Serializing List with null values leads to corrupt CSV 47 | (2.6.0) 48 | 49 | Jonathan Cheseaux (cheseaux@github) 50 | 51 | * Reported #90: Unexpected output with arrays starting with a null/empty element 52 | (2.6.4) 53 | 54 | Oliver Röss (cloudyday@github) 55 | 56 | * Reported #98: Escape char is not being escaped during serialization 57 | (2.6.4) 58 | 59 | Justo Ruiz Ferrer (jrferrer@github) 60 | 61 | * Contributed #89: Allow choice of using header-line declaration to reorder columns 62 | of explicit schema, with `CsvSchema.setReorderColumns` 63 | (2.7.0) 64 | 65 | Rob Baily (rob-baily@github) 66 | 67 | * Contributed fix for #93: CSV mapper does not support Views or filtering correctly 68 | for serialization 69 | (2.6.5) 70 | 71 | dharaburda@github) 72 | 73 | * Contributed fix for #100: trim spaces: don't trim/strip separator character 74 | (2.6.5) 75 | 76 | Nick Babcock (nickbabcock@github) 77 | 78 | * Contributed #97: Verify CSV headers are in the order as expected (added `strictHeaders` 79 | property in `CsvSchema`) 80 | (2.7.0) 81 | * Constributed #139: Add `CsvParser.Feature.ALLOW_TRAILING_COMMA` to allow enforcing 82 | strict handling 83 | (2.9.0) 84 | 85 | Brian Moriarty (morbrian@github) 86 | 87 | * Contributed #106: Null fields are always ignored when serializing list of objects 88 | (2.7.0) 89 | 90 | Peter Ansell (ansell@github) 91 | 92 | * Contributed fix for #128: Write out headers even if no data rows written 93 | (2.7.7) 94 | 95 | George Fraser (georgewfraser@github) 96 | 97 | * Contributed #127: Add `CsvGenerator.Feature.ALWAYS_QUOTE_EMPTY_STRINGS` to allow forced 98 | quoting of empty Strings. 99 | (2.9.0) 100 | 101 | Austin Sharp (sharpau@github) 102 | 103 | * Suggested #142: Add methods for appending columns of a `CsvSchema` into another 104 | (2.9.0) 105 | -------------------------------------------------------------------------------- /release-notes/VERSION: -------------------------------------------------------------------------------- 1 | Project: jackson-dataformat-csv 2 | 3 | ------------------------------------------------------------------------ 4 | === Releases === 5 | ------------------------------------------------------------------------ 6 | 7 | 2.9.0 (not yet released) 8 | 9 | #127: Add `CsvGenerator.Feature.ALWAYS_QUOTE_EMPTY_STRINGS` to allow forced 10 | quoting of empty Strings. 11 | (contributed by georgewfraser@github) 12 | #130: Add fluent addColumns operation to CsvSchema.Builder 13 | (contributed by Peter A) 14 | #137: Inject "missing" trailing columns as `null`s 15 | (`JsonParser.Feature.INSERT_NULLS_FOR_MISSING_COLUMNS`) 16 | #139: Add `CsvParser.Feature.ALLOW_TRAILING_COMMA` to allow enforcing strict handling 17 | (contributed by Nick B) 18 | #140: Fail for missing column values (`JsonParser.Feature.FAIL_ON_MISSING_COLUMNS`) 19 | (suggested by jwilmoth@github) 20 | #142: Add methods for appending columns of a `CsvSchema` into another 21 | (suggested by Austin S) 22 | - Add new exception type `CsvMappingException` to indicate CSV-mapping issues (and 23 | give access to effective Schema) 24 | 25 | 2.8.6 (12-Jan-2017) 26 | 2.8.5 (14-Nov-2016) 27 | 2.8.4 (14-Oct-2016) 28 | 2.8.3 (17-Sep-2016) 29 | 2.8.2 (30-Aug-2016) 30 | 2.8.1 (20-Jul-2016) 31 | 32 | No changes since 2.8.0. 33 | 34 | 2.8.0 (04-Jul-2016) 35 | 36 | - Removed unused `CsvEncoding` class. 37 | 38 | 2.7.7 (not yet released) 39 | 40 | #128: Write out headers even if no data rows written 41 | (contributed by Peter A) 42 | #132: Invalid UTF8-character in non-UTF8 file is detected too early, 43 | so parsing can not be continued 44 | (reported by flappingeagle@github) 45 | 46 | 2.7.6 (23-Jul-2016) 47 | 2.7.5 (11-Jun-2016) 48 | 49 | #124: jackson-annotations are not included as a dependency within jackson-dataformat-csv 50 | (reported by zauberjoe@github) 51 | 52 | 2.7.4 (29-Apr-2016) 53 | 54 | #??: Implement basic format detection 55 | - Minor fixes to `parser.getIntValue()` (and related) implementations 56 | 57 | 2.7.3 (16-Mar-2016) 58 | 59 | No changes since 2.7.2 60 | 61 | 2.7.2 (27-Feb-2016) 62 | 63 | - Change build to produce JDK6-compatible jar, to allow use on JDK6 runtime 64 | 65 | 2.7.1 (02-Feb-2016) 66 | 67 | No changes since 2.7.0 68 | 69 | 2.7.0 (10-Jan-2016) 70 | 71 | #81: Add alternative way to configure 'wrap-as-array', as `CsvParser` feature 72 | #89: Allow choice of using header-line declaration to reorder columns of explicit schema, 73 | with `CsvSchema.setReorderColumns` 74 | (contributed by Justo-Ruiz F) 75 | #92: Allow multi-character separator values 76 | (contributed by dharaburda@github) 77 | #94: Change schema/mapping related `JsonParseException`s to proper `JsonMappingException`s 78 | #95: Add `CsvParser.Feature.IGNORE_TRAILING_UNMAPPABLE` to allow skipping of 79 | all extra, unmappable columns 80 | #97: Verify CSV headers are in the order as expected (added `strictHeaders` property in `CsvSchema`) 81 | (contributed by Nick B) 82 | #103: `JsonGenerator.Feature.IGNORE_UNKNOWN` does not prevent error when writing structured values 83 | #106: Null fields are always ignored when serializing list of objects 84 | (reported, fix contributed by Brian M) 85 | #109: Allow specifying (via `CsvSchema`) a way to map "extra" columns into specific 86 | key (to use via any setter) 87 | 88 | 2.6.6 (05-Apr-2016) 89 | 90 | No changes since 2.6.5. 91 | 92 | 2.6.5 (18-Jan-2016) 93 | 94 | #93: CSV mapper does not support Views or filtering correctly for serialization 95 | (reported by triviski@github; fix contributed by Rob B) 96 | #96: SortedBy only apply to headers and actual data 97 | (reported by ShijunK@github) 98 | 99 | 2.6.4 (07-Dec-2015) 100 | 101 | #90: Unexpected output with arrays starting with a null/empty element 102 | (reported by Jonathan C) 103 | #98: Escape char is not being escaped during serialization 104 | (reported by Oliver R) 105 | 106 | 2.6.3 (12-Oct-2015) 107 | 108 | #91: Ensure that "too many columns" is recoverable 109 | 110 | 2.6.2 (15-Sep-2015) 111 | 112 | No changes since 2.6.1. 113 | 114 | 2.6.1 (09-Aug-2015) 115 | 116 | #87: Serialization of single Float or Double value leads to incorrect CSV when schema is used 117 | (reported by sothmann@github) 118 | 119 | 2.6.0 (20-Jul-2015) 120 | 121 | #72: Recognize the configured "null value" (String) also in reader-infrastructure. 122 | (requested by flappingeagle@github) 123 | #74: Problems with ordering, `@JsonPropertyOrder` losing alphabetic ordering 124 | #83: Serializing List with null values leads to corrupt CSV 125 | (reported by sothmann@github) 126 | - Removed type `CsvObjectReader`, sub-classing not needed at this point, 127 | just complicates handling (for now) 128 | 129 | 2.5.4 (09-Jun-2015) 130 | 131 | - Fixes to potential ArrayIndexOutOfBoundsException on `CsvEncoder`, bounds check 132 | 133 | 2.5.3 (24-Apr-2015) 134 | 135 | #75: Support escapes at beginning of the file 136 | (contributed by David N) 137 | 138 | 2.5.2 (29-Mar-2015) 139 | 140 | #66: Deserializing an empty string as an array field return a non-empty list of one empty String 141 | (reported by aksh3ll@github) 142 | #69: SequenceWriter#write(null) writes a single null, not an entire row of nulls 143 | (reported by georgewfraser@github) 144 | 145 | 2.5.1 (06-Feb-2015) 146 | 147 | #65: Buffer recycling not always working 148 | 149 | 2.5.0 (01-Jan-2015) 150 | 151 | #50: Support `JsonGenerator.Feature.IGNORE_KNOWN` for CSV, to ignoring extra columns 152 | #53: Add a way to specify "null value" (String) for `CsvGenerator` to use when writing `null`s 153 | (part of `CsvSchema`; method `withNullValue()`) 154 | #56: Support comments (either via `CsvSchema`, or using std `JsonParser.Feature.ALLOW_YAML_COMMENTS. 155 | (requested by nezda@github) 156 | #57: Support simple array types 157 | #61: Add a feature to always quote non-numeric values: `CsvGenerator.Feature.ALWAYS_QUOTE_STRINGS` 158 | 159 | 2.4.6 (23-Apr-2015) 160 | 2.4.5 (13-Jan-2015) 161 | 2.4.4 (24-Nov-2014) 162 | 163 | #54: Encounter ArrayIndexOutOfBoundsException in the corner case delimiter or end-of-line 164 | happened to be the leading character of a segment buffer 165 | (contributed by wli600@github) 166 | 167 | 2.4.3 (04-Oct-2014) 168 | 169 | - Support JDK serializability of CsvMapper 170 | - Add `CsvMapper.copy()` 171 | 172 | 2.4.2 (15-Aug-2014) 173 | 174 | * [#47](../../jackson-dataformat-csv/issues/47): UTF-8 BOM handling not working 175 | (reported by andrealexandre@github) 176 | 177 | 2.4.1 (17-Jun-2014) 178 | 179 | No changes since 2.4.0 180 | 181 | 2.4.0 (02-Jun-2014) 182 | 183 | #26: Inconsistent quoting of headers, values; add 184 | `CsvGenerator.Feature.STRICT_CHECK_FOR_QUOTING` to allow more optimal checks. 185 | #32: Allow disabling of quoteChar 186 | (suggested by Jason D) 187 | #40: Allow (re)ordering of columns of Schema, using `CsvSchema.sortedBy(...)` 188 | #45: Change outputting behavior to include final commas even if values are 189 | missing; also add `CsvGenerator.OMIT_MISSING_TAIL_COLUMNS` 190 | 191 | 2.3.3 (10-Apr-2014) 192 | 193 | #33: CSV is written without column separators if first column is null 194 | (reported by Paul M) 195 | #36 Fix a minor problem with `CsvSchema` defaults: was setting default 196 | escape char to be same as default quote (i.e. double-quote) 197 | 198 | 2.3.2 (01-Mar-2014) 199 | 200 | No functional changes 201 | 202 | 2.3.1 (28-Dec-2013) 203 | 204 | #28: Missing override for `createGenerator()` 205 | 206 | 2.3.0 (14-Nov-2013) 207 | 208 | #11: Default `CsvMapper` to use alphabetic sorting of properties (since 209 | alternative is basically undefined; and with JDK 1.7+, unstable too) 210 | #12: Support coercion from String "null", in addition 211 | #20: Support filtering (`@JsonView`, `@JsonFilter`) with CSV 212 | (requested by mablaev@github) 213 | - Add support for `JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN` 214 | 215 | 2.2.2 (27-May-2013) 216 | 217 | No functional changes 218 | 219 | 2.2.1 (03-May-2013) 220 | 221 | - Fixed `CsvFactory.copy()` 222 | 223 | 2.2.0 (22-Apr-2013) 224 | 225 | #15: Ensure that `@JsonUnwrapper` works, even with auto-schema 226 | 227 | 2.1.4 (26-Feb-2013) 228 | 229 | No functional changes 230 | 231 | 2.1.2 (04-Dec-2012) 232 | 233 | * [Issue#10]: Embedded linefeeds not properly handled 234 | 235 | 2.1.1 (12-Nov-2012) 236 | 237 | No functional changes 238 | 239 | 2.1.0 (08-Oct-2012) 240 | 241 | Changes: 242 | 243 | * Due to core changes, `readValues()` method of `CsvMapper` and `ObjectReader` 244 | instances will work slightly differently, for specific case of "unwrapped" 245 | Object[] binding: see unit tests for correct usage. 246 | 247 | 2.0.4 (26-Jun-2012) 248 | 249 | No fixes or changes, released along with other core components 250 | 251 | 2.0.2 (16-May-2012) 252 | 253 | Fixes: 254 | 255 | * Issue-5: Writing of double values failing 256 | * Issue-6: Generator not doubling up double-quotes as expected 257 | 258 | 2.0.1 (23-Apr-2012) 259 | Maintenance release to keep version numbers in sync with other components 260 | (depend on 2.0.1 core etc) 261 | 262 | 2.0.0 (25-Mar-2012) 263 | The official 2.0 release of Jackson. 264 | No new features; upgraded to work with core 2.0.0. 265 | 266 | [entries for versions 1.x and earlier not retained; refer to earlier releases) 267 | -------------------------------------------------------------------------------- /run-perf.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | java -Xmx64m -server \ 4 | -cp target/classes:target/test-classes:lib/\* \ 5 | $* 6 | -------------------------------------------------------------------------------- /src/main/java/com/fasterxml/jackson/dataformat/csv/CsvMappingException.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv; 2 | 3 | import com.fasterxml.jackson.databind.JsonMappingException; 4 | 5 | /** 6 | * Format-specific exception used to indicate problems regarding handling of CSV 7 | * content above minimal decoding, based on {@link CsvSchema}. 8 | * 9 | * @since 2.9 10 | */ 11 | public class CsvMappingException extends JsonMappingException 12 | { 13 | protected final CsvSchema _schema; 14 | 15 | public CsvMappingException(CsvParser p, String msg, CsvSchema schema) { 16 | super(p, msg); 17 | _schema = schema; 18 | } 19 | 20 | public static CsvMappingException from(CsvParser p, String msg, CsvSchema schema) { 21 | return new CsvMappingException(p, msg, schema); 22 | } 23 | 24 | public CsvSchema getSchema() { 25 | return _schema; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/fasterxml/jackson/dataformat/csv/PackageVersion.java.in: -------------------------------------------------------------------------------- 1 | package @package@; 2 | 3 | import com.fasterxml.jackson.core.Version; 4 | import com.fasterxml.jackson.core.Versioned; 5 | import com.fasterxml.jackson.core.util.VersionUtil; 6 | 7 | /** 8 | * Automatically generated from PackageVersion.java.in during 9 | * packageVersion-generate execution of maven-replacer-plugin in 10 | * pom.xml. 11 | */ 12 | public final class PackageVersion implements Versioned { 13 | public final static Version VERSION = VersionUtil.parseVersion( 14 | "@projectversion@", "@projectgroupid@", "@projectartifactid@"); 15 | 16 | @Override 17 | public Version version() { 18 | return VERSION; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/fasterxml/jackson/dataformat/csv/impl/BufferedValue.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.impl; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * Helper class used for holding values for a while until output 7 | * can proceed in expected order. 8 | */ 9 | public abstract class BufferedValue 10 | { 11 | protected BufferedValue() { } 12 | 13 | public abstract void write(CsvEncoder w) throws IOException; 14 | 15 | public static BufferedValue buffered(String v) { return new TextValue(v); } 16 | public static BufferedValue bufferedRaw(String v) { return new RawValue(v); } 17 | public static BufferedValue buffered(int v) { return new IntValue(v); } 18 | public static BufferedValue buffered(long v) { return new LongValue(v); } 19 | public static BufferedValue buffered(double v) { return new DoubleValue(v); } 20 | public static BufferedValue buffered(boolean v) { 21 | return v ? BooleanValue.TRUE : BooleanValue.FALSE; 22 | } 23 | 24 | public static BufferedValue bufferedNull() { 25 | return NullValue.std; 26 | } 27 | 28 | protected final static class TextValue extends BufferedValue 29 | { 30 | private final String _value; 31 | 32 | public TextValue(String v) { _value = v; } 33 | 34 | @Override 35 | public void write(CsvEncoder w) throws IOException { 36 | w.appendValue(_value); 37 | } 38 | } 39 | 40 | /** 41 | * @since 2.5 42 | */ 43 | protected final static class RawValue extends BufferedValue 44 | { 45 | private final String _value; 46 | 47 | public RawValue(String v) { _value = v; } 48 | 49 | @Override 50 | public void write(CsvEncoder w) throws IOException { 51 | w.appendRawValue(_value); 52 | } 53 | } 54 | 55 | protected final static class IntValue extends BufferedValue 56 | { 57 | private final int _value; 58 | 59 | public IntValue(int v) { _value = v; } 60 | 61 | @Override 62 | public void write(CsvEncoder w) throws IOException { 63 | w.appendValue(_value); 64 | } 65 | } 66 | 67 | protected final static class LongValue extends BufferedValue 68 | { 69 | private final long _value; 70 | 71 | public LongValue(long v) { _value = v; } 72 | 73 | @Override 74 | public void write(CsvEncoder w) throws IOException { 75 | w.appendValue(_value); 76 | } 77 | } 78 | 79 | protected final static class DoubleValue extends BufferedValue 80 | { 81 | private final double _value; 82 | 83 | public DoubleValue(double v) { _value = v; } 84 | 85 | @Override 86 | public void write(CsvEncoder w) throws IOException { 87 | w.appendValue(_value); 88 | } 89 | } 90 | 91 | protected final static class BooleanValue extends BufferedValue 92 | { 93 | public final static BooleanValue FALSE = new BooleanValue(false); 94 | public final static BooleanValue TRUE = new BooleanValue(true); 95 | 96 | private final boolean _value; 97 | 98 | public BooleanValue(boolean v) { _value = v; } 99 | 100 | @Override 101 | public void write(CsvEncoder w) throws IOException { 102 | w.appendValue(_value); 103 | } 104 | } 105 | 106 | protected final static class NullValue extends BufferedValue { 107 | public final static NullValue std = new NullValue(); 108 | 109 | private NullValue() { } 110 | 111 | @Override 112 | public void write(CsvEncoder w) throws IOException { 113 | w.appendNull(); 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/main/java/com/fasterxml/jackson/dataformat/csv/impl/CsvIOContext.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.impl; 2 | 3 | import com.fasterxml.jackson.core.io.IOContext; 4 | import com.fasterxml.jackson.core.util.BufferRecycler; 5 | 6 | public class CsvIOContext extends IOContext 7 | { 8 | public CsvIOContext(BufferRecycler br, Object sourceRef, boolean managedResource) { 9 | super(br, sourceRef, managedResource); 10 | } 11 | 12 | public TextBuffer csvTextBuffer() { 13 | return new TextBuffer(_bufferRecycler); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/fasterxml/jackson/dataformat/csv/impl/LRUMap.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.impl; 2 | 3 | import java.util.LinkedHashMap; 4 | import java.util.Map; 5 | 6 | /** 7 | * Helper for simple bounded LRU maps used for reusing lookup values. 8 | */ 9 | @SuppressWarnings("serial") 10 | public class LRUMap extends LinkedHashMap 11 | { 12 | protected final int _maxEntries; 13 | 14 | public LRUMap(int initialEntries, int maxEntries) 15 | { 16 | super(initialEntries, 0.8f, true); 17 | _maxEntries = maxEntries; 18 | } 19 | 20 | @Override 21 | protected boolean removeEldestEntry(Map.Entry eldest) 22 | { 23 | return size() > _maxEntries; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/fasterxml/jackson/dataformat/csv/impl/NumberInput.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.impl; 2 | 3 | /* NOTE: copied from Jackson core, to reduce coupling 4 | */ 5 | public final class NumberInput 6 | { 7 | /** 8 | * Textual representation of a double constant that can cause nasty problems 9 | * with JDK (see http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308). 10 | */ 11 | public final static String NASTY_SMALL_DOUBLE = "2.2250738585072012e-308"; 12 | 13 | /** 14 | * Constants needed for parsing longs from basic int parsing methods 15 | */ 16 | final static long L_BILLION = 1000000000; 17 | 18 | final static String MIN_LONG_STR_NO_SIGN = String.valueOf(Long.MIN_VALUE).substring(1); 19 | final static String MAX_LONG_STR = String.valueOf(Long.MAX_VALUE); 20 | 21 | /** 22 | * Fast method for parsing integers that are known to fit into 23 | * regular 32-bit signed int type. This means that length is 24 | * between 1 and 9 digits (inclusive) 25 | *

26 | * Note: public to let unit tests call it 27 | */ 28 | public final static int parseInt(char[] digitChars, int offset, int len) 29 | { 30 | int num = digitChars[offset] - '0'; 31 | len += offset; 32 | // This looks ugly, but appears the fastest way (as per measurements) 33 | if (++offset < len) { 34 | num = (num * 10) + (digitChars[offset] - '0'); 35 | if (++offset < len) { 36 | num = (num * 10) + (digitChars[offset] - '0'); 37 | if (++offset < len) { 38 | num = (num * 10) + (digitChars[offset] - '0'); 39 | if (++offset < len) { 40 | num = (num * 10) + (digitChars[offset] - '0'); 41 | if (++offset < len) { 42 | num = (num * 10) + (digitChars[offset] - '0'); 43 | if (++offset < len) { 44 | num = (num * 10) + (digitChars[offset] - '0'); 45 | if (++offset < len) { 46 | num = (num * 10) + (digitChars[offset] - '0'); 47 | if (++offset < len) { 48 | num = (num * 10) + (digitChars[offset] - '0'); 49 | } 50 | } 51 | } 52 | } 53 | } 54 | } 55 | } 56 | } 57 | return num; 58 | } 59 | 60 | public final static long parseLong(char[] digitChars, int offset, int len) 61 | { 62 | // Note: caller must ensure length is [10, 18] 63 | int len1 = len-9; 64 | long val = parseInt(digitChars, offset, len1) * L_BILLION; 65 | return val + parseInt(digitChars, offset+len1, 9); 66 | } 67 | 68 | /** 69 | * Helper method for determining if given String representation of 70 | * an integral number would fit in 64-bit Java long or not. 71 | * Note that input String must NOT contain leading minus sign (even 72 | * if 'negative' is set to true). 73 | * 74 | * @param negative Whether original number had a minus sign (which is 75 | * NOT passed to this method) or not 76 | */ 77 | public final static boolean inLongRange(char[] digitChars, int offset, int len, 78 | boolean negative) 79 | { 80 | String cmpStr = negative ? MIN_LONG_STR_NO_SIGN : MAX_LONG_STR; 81 | int cmpLen = cmpStr.length(); 82 | if (len < cmpLen) return true; 83 | if (len > cmpLen) return false; 84 | 85 | for (int i = 0; i < cmpLen; ++i) { 86 | int diff = digitChars[offset+i] - cmpStr.charAt(i); 87 | if (diff != 0) { 88 | return (diff < 0); 89 | } 90 | } 91 | return true; 92 | } 93 | 94 | public final static double parseDouble(String numStr) throws NumberFormatException 95 | { 96 | // [JACKSON-486]: avoid some nasty float representations... but should it be MIN_NORMAL or MIN_VALUE? 97 | if (NASTY_SMALL_DOUBLE.equals(numStr)) { 98 | return Double.MIN_VALUE; 99 | } 100 | return Double.parseDouble(numStr); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/com/fasterxml/jackson/dataformat/csv/impl/NumberOutput.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.impl; 2 | 3 | /** 4 | * Helper class for efficient writing of numeric values 5 | *

6 | * NOTE: modified from Jackson Core's similar functionality 7 | */ 8 | public final class NumberOutput 9 | { 10 | private final static char NULL_CHAR = (char) 0; 11 | 12 | private static int MILLION = 1000000; 13 | private static int BILLION = 1000000000; 14 | private static long TEN_BILLION_L = 10000000000L; 15 | private static long THOUSAND_L = 1000L; 16 | 17 | private static long MIN_INT_AS_LONG = Integer.MIN_VALUE; 18 | private static long MAX_INT_AS_LONG = Integer.MAX_VALUE; 19 | 20 | private final static String SMALLEST_LONG = String.valueOf(Long.MIN_VALUE); 21 | 22 | private final static char[] LEADING_TRIPLETS = new char[4000]; 23 | private final static char[] FULL_TRIPLETS = new char[4000]; 24 | static { 25 | /* Let's fill it with NULLs for ignorable leading digits, 26 | * and digit chars for others 27 | */ 28 | int ix = 0; 29 | for (int i1 = 0; i1 < 10; ++i1) { 30 | char f1 = (char) ('0' + i1); 31 | char l1 = (i1 == 0) ? NULL_CHAR : f1; 32 | for (int i2 = 0; i2 < 10; ++i2) { 33 | char f2 = (char) ('0' + i2); 34 | char l2 = (i1 == 0 && i2 == 0) ? NULL_CHAR : f2; 35 | for (int i3 = 0; i3 < 10; ++i3) { 36 | // Last is never to be empty 37 | char f3 = (char) ('0' + i3); 38 | LEADING_TRIPLETS[ix] = l1; 39 | LEADING_TRIPLETS[ix+1] = l2; 40 | LEADING_TRIPLETS[ix+2] = f3; 41 | FULL_TRIPLETS[ix] = f1; 42 | FULL_TRIPLETS[ix+1] = f2; 43 | FULL_TRIPLETS[ix+2] = f3; 44 | ix += 4; 45 | } 46 | } 47 | } 48 | } 49 | 50 | private final static byte[] FULL_TRIPLETS_B = new byte[4000]; 51 | static { 52 | for (int i = 0; i < 4000; ++i) { 53 | FULL_TRIPLETS_B[i] = (byte) FULL_TRIPLETS[i]; 54 | } 55 | } 56 | 57 | /* 58 | /********************************************************** 59 | /* Efficient serialization methods using raw buffers 60 | /********************************************************** 61 | */ 62 | 63 | /** 64 | * @return Offset within buffer after outputting int 65 | */ 66 | public static int outputInt(int value, char[] buffer, int offset) 67 | { 68 | if (value < 0) { 69 | if (value == Integer.MIN_VALUE) { 70 | /* Special case: no matching positive value within range; 71 | * let's then "upgrade" to long and output as such. 72 | */ 73 | return outputLong(value, buffer, offset); 74 | } 75 | buffer[offset++] = '-'; 76 | value = -value; 77 | } 78 | 79 | if (value < MILLION) { // at most 2 triplets... 80 | if (value < 1000) { 81 | if (value < 10) { 82 | buffer[offset++] = (char) ('0' + value); 83 | } else { 84 | offset = outputLeadingTriplet(value, buffer, offset); 85 | } 86 | } else { 87 | int thousands = value / 1000; 88 | value -= (thousands * 1000); // == value % 1000 89 | offset = outputLeadingTriplet(thousands, buffer, offset); 90 | offset = outputFullTriplet(value, buffer, offset); 91 | } 92 | return offset; 93 | } 94 | 95 | // ok, all 3 triplets included 96 | /* Let's first hand possible billions separately before 97 | * handling 3 triplets. This is possible since we know we 98 | * can have at most '2' as billion count. 99 | */ 100 | boolean hasBillions = (value >= BILLION); 101 | if (hasBillions) { 102 | value -= BILLION; 103 | if (value >= BILLION) { 104 | value -= BILLION; 105 | buffer[offset++] = '2'; 106 | } else { 107 | buffer[offset++] = '1'; 108 | } 109 | } 110 | int newValue = value / 1000; 111 | int ones = (value - (newValue * 1000)); // == value % 1000 112 | value = newValue; 113 | newValue /= 1000; 114 | int thousands = (value - (newValue * 1000)); 115 | 116 | // value now has millions, which have 1, 2 or 3 digits 117 | if (hasBillions) { 118 | offset = outputFullTriplet(newValue, buffer, offset); 119 | } else { 120 | offset = outputLeadingTriplet(newValue, buffer, offset); 121 | } 122 | offset = outputFullTriplet(thousands, buffer, offset); 123 | offset = outputFullTriplet(ones, buffer, offset); 124 | return offset; 125 | } 126 | 127 | /** 128 | * @return Offset within buffer after outputting int 129 | */ 130 | public static int outputLong(long value, char[] buffer, int offset) 131 | { 132 | // First: does it actually fit in an int? 133 | if (value < 0L) { 134 | /* MIN_INT is actually printed as long, just because its 135 | * negation is not an int but long 136 | */ 137 | if (value > MIN_INT_AS_LONG) { 138 | return outputInt((int) value, buffer, offset); 139 | } 140 | if (value == Long.MIN_VALUE) { 141 | // Special case: no matching positive value within range 142 | int len = SMALLEST_LONG.length(); 143 | SMALLEST_LONG.getChars(0, len, buffer, offset); 144 | return (offset + len); 145 | } 146 | buffer[offset++] = '-'; 147 | value = -value; 148 | } else { 149 | if (value <= MAX_INT_AS_LONG) { 150 | return outputInt((int) value, buffer, offset); 151 | } 152 | } 153 | 154 | /* Ok: real long print. Need to first figure out length 155 | * in characters, and then print in from end to beginning 156 | */ 157 | int origOffset = offset; 158 | offset += calcLongStrLength(value); 159 | int ptr = offset; 160 | 161 | // First, with long arithmetics: 162 | while (value > MAX_INT_AS_LONG) { // full triplet 163 | ptr -= 3; 164 | long newValue = value / THOUSAND_L; 165 | int triplet = (int) (value - newValue * THOUSAND_L); 166 | outputFullTriplet(triplet, buffer, ptr); 167 | value = newValue; 168 | } 169 | // Then with int arithmetics: 170 | int ivalue = (int) value; 171 | while (ivalue >= 1000) { // still full triplet 172 | ptr -= 3; 173 | int newValue = ivalue / 1000; 174 | int triplet = ivalue - (newValue * 1000); 175 | outputFullTriplet(triplet, buffer, ptr); 176 | ivalue = newValue; 177 | } 178 | // And finally, if anything remains, partial triplet 179 | outputLeadingTriplet(ivalue, buffer, origOffset); 180 | 181 | return offset; 182 | } 183 | 184 | /* 185 | /********************************************************** 186 | /* Secondary convenience serialization methods 187 | /********************************************************** 188 | */ 189 | /* 190 | final static String[] sSmallIntStrs = new String[] { 191 | "0","1","2","3","4","5","6","7","8","9","10" 192 | }; 193 | final static String[] sSmallIntStrs2 = new String[] { 194 | "-1","-2","-3","-4","-5","-6","-7","-8","-9","-10" 195 | }; 196 | 197 | 198 | public static String toString(int value) 199 | { 200 | // Lookup table for small values 201 | if (value < sSmallIntStrs.length) { 202 | if (value >= 0) { 203 | return sSmallIntStrs[value]; 204 | } 205 | int v2 = -value - 1; 206 | if (v2 < sSmallIntStrs2.length) { 207 | return sSmallIntStrs2[v2]; 208 | } 209 | } 210 | return Integer.toString(value); 211 | } 212 | 213 | public static String toString(long value) 214 | { 215 | if (value <= Integer.MAX_VALUE && 216 | value >= Integer.MIN_VALUE) { 217 | return toString((int) value); 218 | } 219 | return Long.toString(value); 220 | } 221 | */ 222 | 223 | public static String toString(double value) 224 | { 225 | return Double.toString(value); 226 | } 227 | 228 | public static String toString(float value) 229 | { 230 | return Float.toString(value); 231 | } 232 | 233 | /* 234 | /********************************************************** 235 | /* Internal methods 236 | /********************************************************** 237 | */ 238 | 239 | private static int outputLeadingTriplet(int triplet, char[] buffer, int offset) 240 | { 241 | int digitOffset = (triplet << 2); 242 | char c = LEADING_TRIPLETS[digitOffset++]; 243 | if (c != NULL_CHAR) { 244 | buffer[offset++] = c; 245 | } 246 | c = LEADING_TRIPLETS[digitOffset++]; 247 | if (c != NULL_CHAR) { 248 | buffer[offset++] = c; 249 | } 250 | // Last is required to be non-empty 251 | buffer[offset++] = LEADING_TRIPLETS[digitOffset]; 252 | return offset; 253 | } 254 | 255 | private static int outputFullTriplet(int triplet, char[] buffer, int offset) 256 | { 257 | int digitOffset = (triplet << 2); 258 | buffer[offset++] = FULL_TRIPLETS[digitOffset++]; 259 | buffer[offset++] = FULL_TRIPLETS[digitOffset++]; 260 | buffer[offset++] = FULL_TRIPLETS[digitOffset]; 261 | return offset; 262 | } 263 | 264 | /** 265 | *

266 | * Pre-conditions: posValue is positive, and larger than 267 | * Integer.MAX_VALUE (about 2 billions). 268 | */ 269 | private static int calcLongStrLength(long posValue) 270 | { 271 | int len = 10; 272 | long comp = TEN_BILLION_L; 273 | 274 | // 19 is longest, need to worry about overflow 275 | while (posValue >= comp) { 276 | if (len == 19) { 277 | break; 278 | } 279 | ++len; 280 | comp = (comp << 3) + (comp << 1); // 10x 281 | } 282 | return len; 283 | } 284 | } 285 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/LICENSE: -------------------------------------------------------------------------------- 1 | This copy of Jackson JSON processor databind module is licensed under the 2 | Apache (Software) License, version 2.0 ("the License"). 3 | See the License for details about distribution rights, and the 4 | specific rights regarding derivate works. 5 | 6 | You may obtain a copy of the License at: 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/services/com.fasterxml.jackson.core.JsonFactory: -------------------------------------------------------------------------------- 1 | com.fasterxml.jackson.dataformat.csv.CsvFactory 2 | -------------------------------------------------------------------------------- /src/test/java/com/fasterxml/jackson/dataformat/csv/FeaturesTest.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv; 2 | 3 | import java.io.StringWriter; 4 | 5 | public class FeaturesTest extends ModuleTestBase 6 | { 7 | public void testFactoryFeatures() throws Exception 8 | { 9 | CsvFactory f = new CsvFactory(); 10 | assertFalse(f.canHandleBinaryNatively()); 11 | assertFalse(f.canUseCharArrays()); 12 | assertTrue(f.canUseSchema(CsvSchema.emptySchema())); 13 | 14 | CsvParser p = f.createParser(""); 15 | assertFalse(p.canReadObjectId()); 16 | assertFalse(p.canReadTypeId()); 17 | assertTrue(p.canUseSchema(CsvSchema.emptySchema())); 18 | p.close(); 19 | 20 | CsvGenerator g = f.createGenerator(new StringWriter()); 21 | assertFalse(g.canOmitFields()); 22 | assertFalse(g.canWriteBinaryNatively()); 23 | assertFalse(g.canWriteObjectId()); 24 | assertFalse(g.canWriteTypeId()); 25 | assertTrue(g.canWriteFormattedNumbers()); 26 | assertTrue(g.canUseSchema(CsvSchema.emptySchema())); 27 | g.close(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/com/fasterxml/jackson/dataformat/csv/ModuleTestBase.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv; 2 | 3 | import java.io.IOException; 4 | import java.util.Arrays; 5 | 6 | import com.fasterxml.jackson.core.*; 7 | import com.fasterxml.jackson.annotation.JsonPropertyOrder; 8 | 9 | public abstract class ModuleTestBase extends junit.framework.TestCase 10 | { 11 | public enum Gender { MALE, FEMALE }; 12 | 13 | /** 14 | * Slightly modified sample class from Jackson tutorial ("JacksonInFiveMinutes") 15 | */ 16 | @JsonPropertyOrder({"firstName", "lastName", "gender" ,"verified", "userImage"}) 17 | protected static class FiveMinuteUser { 18 | 19 | private Gender _gender; 20 | 21 | public String firstName, lastName; 22 | 23 | private boolean _isVerified; 24 | private byte[] _userImage; 25 | 26 | public FiveMinuteUser() { } 27 | 28 | public FiveMinuteUser(String first, String last, boolean verified, Gender g, byte[] data) 29 | { 30 | firstName = first; 31 | lastName = last; 32 | _isVerified = verified; 33 | _gender = g; 34 | _userImage = data; 35 | } 36 | 37 | public boolean isVerified() { return _isVerified; } 38 | public Gender getGender() { return _gender; } 39 | public byte[] getUserImage() { return _userImage; } 40 | 41 | public void setVerified(boolean b) { _isVerified = b; } 42 | public void setGender(Gender g) { _gender = g; } 43 | public void setUserImage(byte[] b) { _userImage = b; } 44 | 45 | @Override 46 | public boolean equals(Object o) 47 | { 48 | if (o == this) return true; 49 | if (o == null || o.getClass() != getClass()) return false; 50 | FiveMinuteUser other = (FiveMinuteUser) o; 51 | if (_isVerified != other._isVerified) return false; 52 | if (_gender != other._gender) return false; 53 | if (!firstName.equals(other.firstName)) return false; 54 | if (!lastName.equals(other.lastName)) return false; 55 | byte[] otherImage = other._userImage; 56 | if (otherImage.length != _userImage.length) return false; 57 | for (int i = 0, len = _userImage.length; i < len; ++i) { 58 | if (_userImage[i] != otherImage[i]) { 59 | return false; 60 | } 61 | } 62 | return true; 63 | } 64 | 65 | @Override 66 | public int hashCode() { 67 | // not really good but whatever: 68 | return firstName.hashCode(); 69 | } 70 | } 71 | 72 | @JsonPropertyOrder({"id", "desc"}) 73 | protected static class IdDesc { 74 | public String id, desc; 75 | 76 | protected IdDesc() { } 77 | public IdDesc(String id, String desc) { 78 | this.id = id; 79 | this.desc = desc; 80 | } 81 | } 82 | 83 | protected ModuleTestBase() { } 84 | 85 | /* 86 | /********************************************************************** 87 | /* Helper methods, setup 88 | /********************************************************************** 89 | */ 90 | 91 | protected CsvMapper mapperForCsv() 92 | { 93 | return new CsvMapper(); 94 | } 95 | 96 | /* 97 | /********************************************************** 98 | /* Helper methods; low-level 99 | /********************************************************** 100 | */ 101 | 102 | public String quote(String str) { 103 | return '"'+str+'"'; 104 | } 105 | 106 | protected String aposToQuotes(String json) { 107 | return json.replace("'", "\""); 108 | } 109 | 110 | protected void assertToken(JsonToken expToken, JsonToken actToken) { 111 | if (actToken != expToken) { 112 | fail("Expected token "+expToken+", current token "+actToken); 113 | } 114 | } 115 | 116 | protected void assertToken(JsonToken expToken, JsonParser jp) { 117 | assertToken(expToken, jp.getCurrentToken()); 118 | } 119 | 120 | protected void assertType(Object ob, Class expType) 121 | { 122 | if (ob == null) { 123 | fail("Expected an object of type "+expType.getName()+", got null"); 124 | } 125 | Class cls = ob.getClass(); 126 | if (!expType.isAssignableFrom(cls)) { 127 | fail("Expected type "+expType.getName()+", got "+cls.getName()); 128 | } 129 | } 130 | 131 | /** 132 | * Method that gets textual contents of the current token using 133 | * available methods, and ensures results are consistent, before 134 | * returning them 135 | */ 136 | protected String getAndVerifyText(JsonParser jp) 137 | throws IOException, JsonParseException 138 | { 139 | // Ok, let's verify other accessors 140 | int actLen = jp.getTextLength(); 141 | char[] ch = jp.getTextCharacters(); 142 | String str2 = new String(ch, jp.getTextOffset(), actLen); 143 | String str = jp.getText(); 144 | 145 | if (str.length() != actLen) { 146 | fail("Internal problem (jp.token == "+jp.getCurrentToken()+"): jp.getText().length() ['"+str+"'] == "+str.length()+"; jp.getTextLength() == "+actLen); 147 | } 148 | assertEquals("String access via getText(), getTextXxx() must be the same", str, str2); 149 | 150 | return str; 151 | } 152 | 153 | protected void verifyFieldName(JsonParser jp, String expName) 154 | throws IOException 155 | { 156 | assertEquals(expName, jp.getText()); 157 | assertEquals(expName, jp.getCurrentName()); 158 | } 159 | 160 | protected void verifyIntValue(JsonParser jp, long expValue) 161 | throws IOException 162 | { 163 | // First, via textual 164 | assertEquals(String.valueOf(expValue), jp.getText()); 165 | } 166 | 167 | protected void verifyException(Throwable e, String... matches) 168 | { 169 | String msg = e.getMessage(); 170 | String lmsg = (msg == null) ? "" : msg.toLowerCase(); 171 | for (String match : matches) { 172 | String lmatch = match.toLowerCase(); 173 | if (lmsg.indexOf(lmatch) >= 0) { 174 | return; 175 | } 176 | } 177 | fail("Expected an exception with one of substrings ("+Arrays.asList(matches)+"): got one with message \""+msg+"\""); 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /src/test/java/com/fasterxml/jackson/dataformat/csv/TestVersions.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv; 2 | 3 | import java.io.*; 4 | 5 | import com.fasterxml.jackson.core.*; 6 | import com.fasterxml.jackson.databind.MapperFeature; 7 | 8 | public class TestVersions extends ModuleTestBase 9 | { 10 | public void testMapperVersions() throws IOException 11 | { 12 | CsvFactory f = new CsvFactory(); 13 | assertVersion(f); 14 | CsvParser jp = (CsvParser) f.createParser("abc"); 15 | assertVersion(jp); 16 | CsvGenerator jgen = f.createGenerator(new ByteArrayOutputStream()); 17 | assertVersion(jgen); 18 | jp.close(); 19 | jgen.close(); 20 | } 21 | 22 | // Mostly to verify #11 23 | public void testMapperDefaults() 24 | { 25 | CsvMapper mapper = new CsvMapper(); 26 | assertTrue(mapper.isEnabled(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY)); 27 | } 28 | 29 | // Also, not strictly related to version but... 30 | 31 | public void testMapperCopy() 32 | { 33 | CsvMapper mapper = new CsvMapper(); 34 | CsvMapper copy = mapper.copy(); 35 | // for now, not throwing exception is a happy-enough case 36 | assertNotNull(copy); 37 | } 38 | 39 | /* 40 | /********************************************************** 41 | /* Helper methods 42 | /********************************************************** 43 | */ 44 | 45 | private void assertVersion(Versioned vers) 46 | { 47 | assertEquals(PackageVersion.VERSION, vers.version()); 48 | } 49 | } 50 | 51 | -------------------------------------------------------------------------------- /src/test/java/com/fasterxml/jackson/dataformat/csv/deser/AnySetterTest.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.deser; 2 | 3 | import java.util.*; 4 | 5 | import com.fasterxml.jackson.annotation.JsonAnySetter; 6 | import com.fasterxml.jackson.dataformat.csv.*; 7 | 8 | public class AnySetterTest extends ModuleTestBase 9 | { 10 | static class Entry { 11 | Map stuff = new LinkedHashMap(); 12 | 13 | public int age; 14 | public String name; 15 | 16 | @JsonAnySetter 17 | public void set(String key, Object value) { 18 | // for secondary test, where name remains empty: 19 | if (key.isEmpty()) { 20 | key = String.valueOf(stuff.size()); 21 | } 22 | stuff.put(key, value); 23 | } 24 | } 25 | 26 | /* 27 | /********************************************************************** 28 | /* Test methods 29 | /********************************************************************** 30 | */ 31 | 32 | public void testSimpleHeader() throws Exception 33 | { 34 | CsvMapper mapper = mapperForCsv(); 35 | CsvSchema schema = CsvSchema.emptySchema().withHeader(); 36 | Entry entry = mapper.readerFor(Entry.class).with(schema).readValue( 37 | "name,age,gender,extra\nBarbara,35,F,1246\n"); 38 | assertEquals(35, entry.age); 39 | assertEquals("F", entry.stuff.get("gender")); 40 | assertEquals("1246", entry.stuff.get("extra")); 41 | assertEquals(2, entry.stuff.size()); 42 | } 43 | 44 | // [dataformat-csv@109]: allow "any-setter-like" 45 | public void testWithMapToAny() throws Exception 46 | { 47 | CsvMapper mapper = mapperForCsv(); 48 | CsvSchema schema = CsvSchema.emptySchema().withHeader() 49 | .withAnyPropertyName(""); 50 | Entry entry = mapper.readerFor(Entry.class).with(schema) 51 | .readValue("name,age\nJoe,28,first,second\n"); 52 | assertEquals("Joe", entry.name); 53 | assertEquals(28, entry.age); 54 | assertEquals("first", entry.stuff.get("0")); 55 | assertEquals("second", entry.stuff.get("1")); 56 | assertEquals(2, entry.stuff.size()); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/test/java/com/fasterxml/jackson/dataformat/csv/deser/ArrayReadTest.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.deser; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import com.fasterxml.jackson.annotation.JsonPropertyOrder; 6 | import com.fasterxml.jackson.dataformat.csv.*; 7 | 8 | // for [dataformat-csv#57] 9 | public class ArrayReadTest extends ModuleTestBase 10 | { 11 | @JsonPropertyOrder({"id", "values", "extra"}) 12 | static class ValueEntry { 13 | public String id, extra; 14 | public int[] values; 15 | 16 | @JsonCreator 17 | public ValueEntry(@JsonProperty("id") String id, 18 | @JsonProperty("extra") String extra, 19 | @JsonProperty("values") int[] values) { 20 | this.id = id; 21 | this.extra = extra; 22 | this.values = values; 23 | } 24 | } 25 | 26 | /* 27 | /********************************************************************** 28 | /* Test methods 29 | /********************************************************************** 30 | */ 31 | 32 | private final CsvMapper MAPPER = mapperForCsv(); 33 | 34 | public void testSimpleExplicitLooseTyping() throws Exception 35 | { 36 | ValueEntry value = MAPPER.readerWithSchemaFor(ValueEntry.class) 37 | .readValue("foo,1;2;3,stuff"); 38 | assertNotNull(value); 39 | assertEquals("foo", value.id); 40 | assertEquals("stuff", value.extra); 41 | int[] v = value.values; 42 | assertNotNull(v); 43 | assertEquals(3, v.length); 44 | assertEquals(1, v[0]); 45 | assertEquals(2, v[1]); 46 | assertEquals(3, v[2]); 47 | } 48 | 49 | public void testSimpleExplicitStrictTyping() throws Exception 50 | { 51 | ValueEntry value = MAPPER.readerWithTypedSchemaFor(ValueEntry.class) 52 | .readValue("foo,1;2;3,stuff"); 53 | assertNotNull(value); 54 | assertEquals("foo", value.id); 55 | assertEquals("stuff", value.extra); 56 | int[] v = value.values; 57 | assertNotNull(v); 58 | assertEquals(3, v.length); 59 | assertEquals(1, v[0]); 60 | assertEquals(2, v[1]); 61 | assertEquals(3, v[2]); 62 | 63 | // one more thing: for [dataformat-csv#66]: 64 | value = MAPPER.readerWithTypedSchemaFor(ValueEntry.class) 65 | .readValue("foo,,stuff"); 66 | assertNotNull(value); 67 | assertEquals("foo", value.id); 68 | assertEquals("stuff", value.extra); 69 | v = value.values; 70 | assertNotNull(v); 71 | assertEquals(0, v.length); 72 | } 73 | 74 | public void testSeparatorOverrideSpace() throws Exception 75 | { 76 | ValueEntry input = new ValueEntry("foo", "stuff", new int[] {1, 2, 3}); 77 | String csv = MAPPER.writer(CsvSchema.builder() 78 | .addColumn("id") 79 | .addArrayColumn("values", " ") 80 | .addColumn("extra") 81 | .build()) 82 | .writeValueAsString(input) 83 | .trim(); 84 | // gets quoted due to white space 85 | assertEquals("foo,\"1 2 3\",stuff", csv); 86 | 87 | ValueEntry value = MAPPER.reader(MAPPER.schemaFor(ValueEntry.class).withArrayElementSeparator(" ")).forType(ValueEntry.class) 88 | .readValue(csv); 89 | assertEquals("foo", value.id); 90 | assertEquals("stuff", value.extra); 91 | int[] v = value.values; 92 | assertNotNull(v); 93 | assertEquals(3, v.length); 94 | assertEquals(1, v[0]); 95 | assertEquals(2, v[1]); 96 | assertEquals(3, v[2]); 97 | } 98 | 99 | public void testSeparatorOverrideMulti() throws Exception 100 | { 101 | ValueEntry input = new ValueEntry("foo", "stuff", new int[] {1, 2, 3}); 102 | String csv = MAPPER.writer(CsvSchema.builder() 103 | .addColumn("id") 104 | .addArrayColumn("values", "::") 105 | .addColumn("extra") 106 | .build()) 107 | .writeValueAsString(input) 108 | .trim(); 109 | assertEquals("foo,1::2::3,stuff", csv); 110 | 111 | ValueEntry value = MAPPER.reader(MAPPER.schemaFor(ValueEntry.class).withArrayElementSeparator("::")).forType(ValueEntry.class) 112 | .readValue(csv); 113 | assertEquals("foo", value.id); 114 | assertEquals("stuff", value.extra); 115 | int[] v = value.values; 116 | assertNotNull(v); 117 | assertEquals(3, v.length); 118 | assertEquals(1, v[0]); 119 | assertEquals(2, v[1]); 120 | assertEquals(3, v[2]); 121 | } 122 | 123 | 124 | } 125 | -------------------------------------------------------------------------------- /src/test/java/com/fasterxml/jackson/dataformat/csv/deser/BrokenEncodingTest.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.deser; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.CharConversionException; 5 | 6 | import com.fasterxml.jackson.core.JsonToken; 7 | import com.fasterxml.jackson.dataformat.csv.*; 8 | 9 | public class BrokenEncodingTest extends ModuleTestBase 10 | { 11 | /* 12 | /********************************************************************** 13 | /* Test methods 14 | /********************************************************************** 15 | */ 16 | 17 | // Simple test where a Latin-1 character is encountered; first byte wrong 18 | public void testLatin1AsUTF8() throws Exception 19 | { 20 | CsvFactory factory = new CsvFactory(); 21 | String CSV = "1,2\nabc,\u00A0\n"; 22 | 23 | CsvSchema schema = CsvSchema.builder() 24 | .addColumn("a") 25 | .addColumn("b") 26 | .build(); 27 | // So: take Latin-1 bytes, but construct without specifying to lead to UTF-8 handling 28 | CsvParser parser = factory.createParser(CSV.getBytes("ISO-8859-1")); 29 | parser.setSchema(schema); 30 | 31 | assertToken(JsonToken.START_OBJECT, parser.nextToken()); 32 | assertToken(JsonToken.FIELD_NAME, parser.nextToken()); 33 | assertEquals("a", parser.getCurrentName()); 34 | assertToken(JsonToken.VALUE_STRING, parser.nextToken()); 35 | assertToken(JsonToken.FIELD_NAME, parser.nextToken()); 36 | assertToken(JsonToken.VALUE_STRING, parser.nextToken()); 37 | assertEquals("2", parser.getText()); 38 | assertToken(JsonToken.END_OBJECT, parser.nextToken()); 39 | 40 | // problem should only be triggered now 41 | assertToken(JsonToken.START_OBJECT, parser.nextToken()); 42 | assertToken(JsonToken.FIELD_NAME, parser.nextToken()); 43 | assertEquals("a", parser.getCurrentName()); 44 | assertToken(JsonToken.VALUE_STRING, parser.nextToken()); 45 | assertEquals("abc", parser.getText()); 46 | try { 47 | parser.nextToken(); 48 | fail("Should trigger exception for invalid UTF-8 char"); 49 | } catch (CharConversionException e) { 50 | verifyException(e, "Invalid UTF-8 start byte"); 51 | verifyException(e, "0xA0"); 52 | } 53 | parser.close(); 54 | } 55 | 56 | // Then a test with "middle" byte broken 57 | public void testBrokenUTF8MiddleByte() throws Exception 58 | { 59 | CsvFactory factory = new CsvFactory(); 60 | ByteArrayOutputStream bytes = new ByteArrayOutputStream(); 61 | bytes.write('1'); 62 | bytes.write(','); 63 | bytes.write(0xD7); // this is fine 64 | bytes.write(0x41); // this not 65 | bytes.write('\n'); 66 | CsvSchema schema = CsvSchema.builder() 67 | .addColumn("a") 68 | .addColumn("b") 69 | .build(); 70 | // So: take Latin-1 bytes, but construct without specifying to lead to UTF-8 handling 71 | CsvParser parser = factory.createParser(bytes.toByteArray()); 72 | parser.setSchema(schema); 73 | 74 | assertToken(JsonToken.START_OBJECT, parser.nextToken()); 75 | assertToken(JsonToken.FIELD_NAME, parser.nextToken()); 76 | assertEquals("a", parser.getCurrentName()); 77 | assertToken(JsonToken.VALUE_STRING, parser.nextToken()); 78 | assertEquals("1", parser.getText()); 79 | try { 80 | assertToken(JsonToken.FIELD_NAME, parser.nextToken()); 81 | assertEquals("b", parser.getCurrentName()); 82 | parser.nextToken(); 83 | fail("Should trigger exception for invalid UTF-8 char"); 84 | } catch (CharConversionException e) { 85 | verifyException(e, "Invalid UTF-8 middle byte"); 86 | verifyException(e, "0x41"); 87 | } 88 | parser.close(); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/test/java/com/fasterxml/jackson/dataformat/csv/deser/CommentsTest.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.deser; 2 | 3 | import java.util.Map; 4 | 5 | import com.fasterxml.jackson.core.JsonParser; 6 | import com.fasterxml.jackson.databind.MappingIterator; 7 | import com.fasterxml.jackson.dataformat.csv.*; 8 | 9 | // Tests for [csv#56] 10 | public class CommentsTest extends ModuleTestBase 11 | { 12 | final String CSV_WITH_COMMENTS = "x,y\n# comment!\na,b\n# another...\n"; 13 | 14 | public void testWithoutComments() throws Exception 15 | { 16 | CsvMapper mapper = mapperForCsv(); 17 | 18 | // to handle comments that follow leading spaces 19 | mapper.enable(CsvParser.Feature.TRIM_SPACES); 20 | // should not be needed but seems to be... 21 | mapper.enable(CsvParser.Feature.WRAP_AS_ARRAY); 22 | 23 | String[] row; 24 | 25 | // First, with comments disabled: 26 | 27 | MappingIterator it = mapper.readerFor(String[].class) 28 | .with(mapper.schema().withoutComments()).readValues(CSV_WITH_COMMENTS); 29 | 30 | row = it.nextValue(); 31 | assertEquals(2, row.length); 32 | assertEquals("x", row[0]); 33 | assertEquals("y", row[1]); 34 | 35 | // next, comment visible 36 | assertTrue(it.hasNext()); 37 | row = it.nextValue(); 38 | assertEquals("# comment!", row[0]); 39 | assertEquals(1, row.length); 40 | 41 | assertTrue(it.hasNext()); 42 | row = it.nextValue(); 43 | assertEquals(2, row.length); 44 | assertEquals("a", row[0]); 45 | assertEquals("b", row[1]); 46 | 47 | assertTrue(it.hasNext()); 48 | row = it.nextValue(); 49 | assertEquals("# another...", row[0]); 50 | assertEquals(1, row.length); 51 | 52 | assertFalse(it.hasNext()); 53 | it.close(); 54 | } 55 | 56 | public void testSimpleComments() throws Exception 57 | { 58 | CsvMapper mapper = mapperForCsv(); 59 | // to handle comments that follow leading spaces 60 | mapper.enable(CsvParser.Feature.TRIM_SPACES); 61 | // should not be needed but seems to be... 62 | mapper.enable(CsvParser.Feature.WRAP_AS_ARRAY); 63 | 64 | MappingIterator it = mapper.readerFor(String[].class) 65 | .with(mapper.schema().withComments()).readValues(CSV_WITH_COMMENTS); 66 | 67 | // first row the same 68 | String[] row = it.nextValue(); 69 | assertEquals(2, row.length); 70 | assertEquals("x", row[0]); 71 | assertEquals("y", row[1]); 72 | 73 | // next, comment NOT visible 74 | assertTrue(it.hasNext()); 75 | row = it.nextValue(); 76 | assertEquals("a", row[0]); 77 | assertEquals(2, row.length); 78 | assertEquals("b", row[1]); 79 | 80 | // and ditto for second comment 81 | assertFalse(it.hasNext()); 82 | it.close(); 83 | } 84 | 85 | public void testLeadingComments() throws Exception 86 | { 87 | CsvMapper mapper = mapperForCsv(); 88 | // should not be needed but seems to be... 89 | mapper.enable(CsvParser.Feature.WRAP_AS_ARRAY); 90 | 91 | MappingIterator it = mapper.readerFor(String[].class) 92 | .with(mapper.schema().withComments()).readValues("# first\n#second\n1,2\n"); 93 | 94 | // first row the same 95 | String[] row = it.nextValue(); 96 | assertEquals("1", row[0]); 97 | assertEquals(2, row.length); 98 | assertEquals("2", row[1]); 99 | 100 | assertFalse(it.hasNextValue()); 101 | 102 | it.close(); 103 | } 104 | 105 | public void testCommentsWithHeaderRow() throws Exception 106 | { 107 | CsvMapper mapper = mapperForCsv(); 108 | MappingIterator> it = mapper.readerFor(Map.class) 109 | .with(mapper.schema().withComments().withHeader()) 110 | .readValues("# headers:\nid,value\n# values:\nab#c,#13\n"); 111 | 112 | // first row the same 113 | Map row = it.nextValue(); 114 | assertEquals("ab#c", row.get("id")); 115 | assertEquals("#13", row.get("value")); 116 | assertEquals(2, row.size()); 117 | 118 | assertFalse(it.hasNextValue()); 119 | 120 | it.close(); 121 | } 122 | 123 | // Alternate test to ensure comments may be enabled 124 | public void testSimpleCommentsWithDefaultProp() throws Exception 125 | { 126 | CsvMapper mapper = mapperForCsv(); 127 | mapper.enable(JsonParser.Feature.ALLOW_YAML_COMMENTS); 128 | mapper.enable(CsvParser.Feature.WRAP_AS_ARRAY); 129 | final String CSV = "# comment!\na,b\n"; 130 | 131 | MappingIterator it = mapper.readerFor(String[].class) 132 | .readValues(CSV); 133 | String[] row = it.nextValue(); 134 | // assertEquals(2, row.length); 135 | assertEquals("a", row[0]); 136 | assertEquals("b", row[1]); 137 | assertFalse(it.hasNext()); 138 | it.close(); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/test/java/com/fasterxml/jackson/dataformat/csv/deser/FormatDetectionTest.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.deser; 2 | 3 | import java.io.IOException; 4 | 5 | import com.fasterxml.jackson.core.format.DataFormatDetector; 6 | import com.fasterxml.jackson.core.format.DataFormatMatcher; 7 | import com.fasterxml.jackson.core.format.MatchStrength; 8 | import com.fasterxml.jackson.dataformat.csv.CsvFactory; 9 | import com.fasterxml.jackson.dataformat.csv.ModuleTestBase; 10 | 11 | public class FormatDetectionTest extends ModuleTestBase 12 | { 13 | public void testSimpleObjectWithHeader() throws IOException 14 | { 15 | CsvFactory f = new CsvFactory(); 16 | DataFormatDetector detector = new DataFormatDetector(f); 17 | byte[] doc = "name,place,town\nBob,home,Denver\n".getBytes("UTF-8"); 18 | DataFormatMatcher matcher = detector.findFormat(doc); 19 | // should have match 20 | assertTrue(matcher.hasMatch()); 21 | assertEquals("CSV", matcher.getMatchedFormatName()); 22 | assertEquals(MatchStrength.SOLID_MATCH, matcher.getMatchStrength()); 23 | assertSame(f, matcher.getMatch()); 24 | 25 | // and also something that does NOT look like CSV 26 | doc = "{\"a\":3}".getBytes("UTF-8"); 27 | matcher = detector.findFormat(doc); 28 | assertFalse(matcher.hasMatch()); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/test/java/com/fasterxml/jackson/dataformat/csv/deser/IgnoreUnmappableTest.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.deser; 2 | 3 | import com.fasterxml.jackson.annotation.JsonPropertyOrder; 4 | 5 | import com.fasterxml.jackson.databind.JsonMappingException; 6 | import com.fasterxml.jackson.databind.MappingIterator; 7 | 8 | import com.fasterxml.jackson.dataformat.csv.*; 9 | 10 | /** 11 | * Test(s) for [dataformat-csv#95] 12 | */ 13 | public class IgnoreUnmappableTest extends ModuleTestBase 14 | { 15 | final CsvMapper MAPPER = mapperForCsv(); 16 | 17 | @JsonPropertyOrder({ "first", "second" }) 18 | static class StringPair { 19 | public String first, second; 20 | } 21 | 22 | public void testSimpleIgnoral() throws Exception 23 | { 24 | final String INPUT = "a,b,c,foo\nd,e\nf,g,h,i\n"; 25 | final CsvSchema schema = MAPPER.schemaFor(StringPair.class); 26 | 27 | // first: throw exception(s) with default settings 28 | MappingIterator it = MAPPER.readerFor(StringPair.class) 29 | .with(schema) 30 | .without(CsvParser.Feature.IGNORE_TRAILING_UNMAPPABLE) 31 | .readValues(INPUT); 32 | 33 | try { 34 | it.nextValue(); 35 | fail("Should not have passed"); 36 | } catch (JsonMappingException e) { 37 | verifyException(e, "Too many entries"); 38 | } 39 | 40 | // yet second one ought to work 41 | StringPair pair = it.nextValue(); 42 | assertEquals("d", pair.first); 43 | assertEquals("e", pair.second); 44 | 45 | // and not third, again 46 | try { 47 | it.nextValue(); 48 | fail("Should not have passed"); 49 | } catch (JsonMappingException e) { 50 | verifyException(e, "Too many entries"); 51 | } 52 | it.close(); 53 | 54 | // But with settings... 55 | it = MAPPER.readerFor(StringPair.class) 56 | .with(schema) 57 | .with(CsvParser.Feature.IGNORE_TRAILING_UNMAPPABLE) 58 | .readValues(INPUT); 59 | 60 | pair = it.nextValue(); 61 | assertEquals("a", pair.first); 62 | assertEquals("b", pair.second); 63 | 64 | pair = it.nextValue(); 65 | assertEquals("d", pair.first); 66 | assertEquals("e", pair.second); 67 | 68 | pair = it.nextValue(); 69 | assertEquals("f", pair.first); 70 | assertEquals("g", pair.second); 71 | 72 | assertFalse(it.hasNextValue()); 73 | 74 | it.close(); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/test/java/com/fasterxml/jackson/dataformat/csv/deser/MissingColumnsTest.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.deser; 2 | 3 | import com.fasterxml.jackson.annotation.JsonPropertyOrder; 4 | import com.fasterxml.jackson.databind.MappingIterator; 5 | import com.fasterxml.jackson.databind.ObjectReader; 6 | import com.fasterxml.jackson.dataformat.csv.CsvMapper; 7 | import com.fasterxml.jackson.dataformat.csv.CsvMappingException; 8 | import com.fasterxml.jackson.dataformat.csv.CsvParser; 9 | import com.fasterxml.jackson.dataformat.csv.CsvSchema; 10 | import com.fasterxml.jackson.dataformat.csv.ModuleTestBase; 11 | 12 | /** 13 | * Tests for cases where one more of schema-declared columns is 14 | * missing; various handling choices include "null-injection" 15 | * as well as failure (throw exception) and just skipping (default). 16 | */ 17 | public class MissingColumnsTest extends ModuleTestBase 18 | { 19 | @JsonPropertyOrder({ "a", "b", "c" }) 20 | static class ABC { 21 | public String a = "a"; 22 | public String b = "b"; 23 | public String c = "c"; 24 | } 25 | 26 | /* 27 | /********************************************************************** 28 | /* Test methods 29 | /********************************************************************** 30 | */ 31 | 32 | final CsvMapper MAPPER = mapperForCsv(); 33 | 34 | final CsvSchema SCHEMA = MAPPER.schemaFor(ABC.class); 35 | 36 | // by default, just... ignore 37 | public void testDefaultMissingHandling() throws Exception 38 | { 39 | ObjectReader r = MAPPER.readerFor(ABC.class).with(SCHEMA); 40 | final ABC DEFAULT = new ABC(); 41 | 42 | ABC result = r.readValue("first,second,third\n"); 43 | assertEquals("first", result.a); 44 | assertEquals("second", result.b); 45 | assertEquals("third", result.c); 46 | 47 | // then with one missing 48 | result = r.readValue("first,second\n"); 49 | assertEquals("second", result.b); 50 | assertEquals(DEFAULT.c, result.c); 51 | 52 | // etc 53 | result = r.readValue("first\n"); 54 | assertEquals("first", result.a); 55 | assertEquals(DEFAULT.b, result.b); 56 | assertEquals(DEFAULT.c, result.c); 57 | 58 | result = r.readValue("\n"); 59 | // 16-Mar-2017, tatu: Actually first value is just empty, not null... since 60 | // logical "empty String" does exist no matter what. 61 | assertEquals("", result.a); 62 | assertEquals(DEFAULT.b, result.b); 63 | assertEquals(DEFAULT.c, result.c); 64 | } 65 | 66 | // [dataformat-csv#137]: inject `null`s in place of missing 67 | public void testInjectMissingAsNulls() throws Exception 68 | { 69 | ObjectReader r = MAPPER.readerFor(ABC.class) 70 | .with(SCHEMA) 71 | .with(CsvParser.Feature.INSERT_NULLS_FOR_MISSING_COLUMNS); 72 | 73 | // check with various number of missing; but first with no missing 74 | ABC result = r.readValue("first,second,third\n"); 75 | assertEquals("third", result.c); 76 | 77 | // then with one missing 78 | result = r.readValue("first,second\n"); 79 | assertEquals("second", result.b); 80 | assertNull(result.c); 81 | 82 | // etc 83 | result = r.readValue("first\n"); 84 | assertEquals("first", result.a); 85 | assertNull(result.b); 86 | assertNull(result.c); 87 | 88 | result = r.readValue("\n"); 89 | // 16-Mar-2017, tatu: Actually first value is just empty, not null... since 90 | // logical "empty String" does exist no matter what. 91 | assertEquals("", result.a); 92 | assertNull(result.b); 93 | assertNull(result.c); 94 | } 95 | 96 | // [dataformat-csv#140]: report error for missing columns 97 | public void testFailOnMissingColumns() throws Exception 98 | { 99 | ObjectReader r = MAPPER.readerFor(ABC.class) 100 | .with(SCHEMA) 101 | .with(CsvParser.Feature.FAIL_ON_MISSING_COLUMNS); 102 | 103 | // check with various number of missing, as well as recovery 104 | MappingIterator it = r.readValues( 105 | // First line, one misses one column 106 | "first,second\n" 107 | // second has it all 108 | +"1,2,3\n" 109 | // third only has one 110 | +"one\n" 111 | ); 112 | 113 | try { 114 | it.nextValue(); 115 | fail("Should not pass"); 116 | } catch (CsvMappingException e) { 117 | verifyException(e, "Not enough column values"); 118 | verifyException(e, "expected 3, found 2"); 119 | } 120 | // next value ok 121 | ABC value = it.nextValue(); 122 | assertEquals("1", value.a); 123 | assertEquals("2", value.b); 124 | assertEquals("3", value.c); 125 | // then another miss 126 | try { 127 | it.nextValue(); 128 | fail("Should not pass"); 129 | } catch (CsvMappingException e) { 130 | verifyException(e, "Not enough column values"); 131 | verifyException(e, "expected 3, found 1"); 132 | } 133 | assertFalse(it.hasNextValue()); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/test/java/com/fasterxml/jackson/dataformat/csv/deser/NullReadTest.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.deser; 2 | 3 | import java.util.*; 4 | 5 | import com.fasterxml.jackson.annotation.JsonPropertyOrder; 6 | import com.fasterxml.jackson.databind.*; 7 | import com.fasterxml.jackson.dataformat.csv.*; 8 | 9 | public class NullReadTest extends ModuleTestBase 10 | { 11 | final CsvMapper MAPPER = mapperForCsv(); 12 | 13 | @JsonPropertyOrder({ "prop1", "prop2", "prop3" }) 14 | static class Pojo83 { 15 | public String prop1; 16 | public String prop2; 17 | public int prop3; 18 | 19 | protected Pojo83() { } 20 | public Pojo83(String a, String b, int c) { 21 | prop1 = a; 22 | prop2 = b; 23 | prop3 = c; 24 | } 25 | } 26 | 27 | /* 28 | /********************************************************************** 29 | /* Test methods 30 | /********************************************************************** 31 | */ 32 | 33 | public void testNullIssue83() throws Exception 34 | { 35 | CsvMapper mapper = new CsvMapper(); 36 | CsvSchema schema = mapper.schemaFor(Pojo83.class); 37 | final ObjectWriter writer = mapper.writer(schema); 38 | 39 | List list = Arrays.asList( 40 | new Pojo83("foo", "bar", 123), 41 | null, 42 | new Pojo83("test", "abc", 42)); 43 | 44 | String expectedCsv = "foo,bar,123\ntest,abc,42\n"; 45 | String actualCsv = writer.writeValueAsString(list); 46 | 47 | assertEquals(expectedCsv, actualCsv); 48 | } 49 | 50 | // For [dataformat-csv#72]: recognize "null value" for reading too 51 | public void testReadNullValue72() throws Exception 52 | { 53 | CsvSchema schema = CsvSchema.builder() 54 | .setNullValue("n/a") 55 | .addColumn("id") 56 | .addColumn("desc") 57 | .build(); 58 | 59 | // start by writing, first 60 | String csv = MAPPER.writer(schema).writeValueAsString(new IdDesc("id", null)); 61 | // MUST use doubling for quotes! 62 | assertEquals("id,n/a\n", csv); 63 | 64 | // but read back 65 | 66 | ObjectReader r = MAPPER.readerFor(IdDesc.class) 67 | .with(schema); 68 | 69 | IdDesc result = r.readValue(csv); 70 | assertNotNull(result); 71 | assertEquals("id", result.id); 72 | assertNull(result.desc); 73 | 74 | // also try the other combination 75 | result = r.readValue("n/a,Whatevs\n"); 76 | assertNotNull(result); 77 | assertNull(result.id); 78 | assertEquals("Whatevs", result.desc); 79 | } 80 | 81 | public void testReadNullValueFromEmptyString() throws Exception 82 | { 83 | // first: empty String should work as default 84 | CsvSchema schemaWithDefault = CsvSchema.builder() 85 | .addColumn("id") 86 | .addColumn("desc") 87 | .build(); 88 | 89 | // start by writing, first 90 | String csv = MAPPER.writer(schemaWithDefault).writeValueAsString(new IdDesc("id", null)); 91 | assertEquals("id,\n", csv); 92 | 93 | // but read back. Note: no null coercion unless explicitly defined 94 | 95 | ObjectReader r = MAPPER.readerFor(IdDesc.class).with(schemaWithDefault); 96 | 97 | IdDesc result = r.readValue(csv); 98 | assertNotNull(result); 99 | assertEquals("id", result.id); 100 | assertEquals("", result.desc); 101 | 102 | // also try the other combination 103 | result = r.readValue(",Whatevs\n"); 104 | assertNotNull(result); 105 | assertEquals("", result.id); 106 | assertEquals("Whatevs", result.desc); 107 | 108 | // And then with explicit Empty String 109 | CsvSchema schemaWithExplicitEmpty = CsvSchema.builder() 110 | .setNullValue("") 111 | .addColumn("id") 112 | .addColumn("desc") 113 | .build(); 114 | 115 | csv = MAPPER.writer(schemaWithExplicitEmpty).writeValueAsString(new IdDesc("id", null)); 116 | assertEquals("id,\n", csv); 117 | r = MAPPER.readerFor(IdDesc.class).with(schemaWithExplicitEmpty); 118 | result = r.readValue(csv); 119 | assertNotNull(result); 120 | assertEquals("id", result.id); 121 | assertNull(result.desc); 122 | 123 | // and finally with explicit `null`, which once again disables coercion 124 | CsvSchema schemaWithExplicitNull = CsvSchema.builder() 125 | .setNullValue((String) null) 126 | .addColumn("id") 127 | .addColumn("desc") 128 | .build(); 129 | 130 | csv = MAPPER.writer(schemaWithExplicitNull).writeValueAsString(new IdDesc("id", null)); 131 | assertEquals("id,\n", csv); 132 | r = MAPPER.readerFor(IdDesc.class).with(schemaWithExplicitNull); 133 | result = r.readValue(csv); 134 | assertNotNull(result); 135 | assertEquals("id", result.id); 136 | assertEquals("", result.desc); 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/test/java/com/fasterxml/jackson/dataformat/csv/deser/ParserTrimSpacesTest.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.deser; 2 | 3 | import com.fasterxml.jackson.annotation.JsonPropertyOrder; 4 | 5 | import com.fasterxml.jackson.databind.MappingIterator; 6 | import com.fasterxml.jackson.dataformat.csv.*; 7 | 8 | public class ParserTrimSpacesTest extends ModuleTestBase 9 | { 10 | /* 11 | /********************************************************************** 12 | /* Helper types 13 | /********************************************************************** 14 | */ 15 | 16 | @JsonPropertyOrder({"a", "b", "c"}) 17 | protected static class Entry { 18 | public String a, b, c; 19 | } 20 | 21 | /* 22 | /********************************************************************** 23 | /* Test methods 24 | /********************************************************************** 25 | */ 26 | 27 | // Test to verify default behavior of not trimming spaces 28 | public void testNonTrimming() throws Exception 29 | { 30 | CsvMapper mapper = mapperForCsv(); 31 | mapper.disable(CsvParser.Feature.TRIM_SPACES); 32 | MappingIterator it = mapper.readerWithSchemaFor(Entry.class).readValues( 33 | "a, b, c \n 1,2,\"3 \"\n" 34 | ); 35 | Entry entry; 36 | 37 | assertTrue(it.hasNext()); 38 | assertNotNull(entry = it.nextValue()); 39 | assertEquals("a", entry.a); 40 | assertEquals(" b", entry.b); 41 | assertEquals(" c ", entry.c); 42 | 43 | assertTrue(it.hasNext()); 44 | assertNotNull(entry = it.nextValue()); 45 | assertEquals(" 1", entry.a); 46 | assertEquals("2", entry.b); 47 | assertEquals("3 ", entry.c); 48 | 49 | assertFalse(it.hasNext()); 50 | it.close(); 51 | 52 | // [dataformat-csv#81]: also need to be able to re-enable 53 | it = mapper.readerWithSchemaFor(Entry.class) 54 | .with(CsvParser.Feature.TRIM_SPACES) 55 | .readValues("a, b, c \n"); 56 | assertTrue(it.hasNext()); 57 | assertNotNull(entry = it.nextValue()); 58 | assertEquals("a", entry.a); 59 | assertEquals("b", entry.b); 60 | assertEquals("c", entry.c); 61 | 62 | it.close(); 63 | } 64 | 65 | public void testTrimming() throws Exception 66 | { 67 | CsvMapper mapper = mapperForCsv(); 68 | mapper.enable(CsvParser.Feature.TRIM_SPACES); 69 | MappingIterator it = mapper.readerWithSchemaFor(Entry.class).readValues( 70 | "a, b, c\t\n 1,2,\" 3\" \n\"ab\t\" ,\"c\", \n" 71 | ); 72 | Entry entry; 73 | 74 | assertTrue(it.hasNext()); 75 | assertNotNull(entry = it.nextValue()); 76 | assertEquals("a", entry.a); 77 | assertEquals("b", entry.b); 78 | assertEquals("c", entry.c); 79 | 80 | assertTrue(it.hasNext()); 81 | assertNotNull(entry = it.nextValue()); 82 | assertEquals("1", entry.a); 83 | assertEquals("2", entry.b); 84 | assertEquals(" 3", entry.c); // note: space within quotes is preserved 85 | 86 | assertTrue(it.hasNext()); 87 | assertNotNull(entry = it.nextValue()); 88 | assertEquals("ab\t", entry.a); 89 | assertEquals("c", entry.b); 90 | assertEquals("", entry.c); 91 | 92 | assertFalse(it.hasNext()); 93 | it.close(); 94 | } 95 | 96 | // for [dataformat-csv#100]: Do not eat tabs when trimming space 97 | public void testTrimmingTabSeparated() throws Exception 98 | { 99 | CsvMapper mapper = mapperForCsv(); 100 | mapper.enable(CsvParser.Feature.TRIM_SPACES); 101 | CsvSchema schema = mapper.schemaFor(Entry.class).withColumnSeparator('\t'); 102 | MappingIterator it = mapper.readerFor(Entry.class).with(schema). 103 | readValues( 104 | "a\t\t c\n 1\t2\t\" 3\" \n\"ab\" \t\"c \t\"\t \n" 105 | ); 106 | Entry entry; 107 | 108 | assertTrue(it.hasNext()); 109 | assertNotNull(entry = it.nextValue()); 110 | assertEquals("a", entry.a); 111 | assertEquals("", entry.b); 112 | assertEquals("c", entry.c); 113 | 114 | assertTrue(it.hasNext()); 115 | assertNotNull(entry = it.nextValue()); 116 | assertEquals("1", entry.a); 117 | assertEquals("2", entry.b); 118 | assertEquals(" 3", entry.c); // note: space within quotes is preserved 119 | 120 | assertTrue(it.hasNext()); 121 | assertNotNull(entry = it.nextValue()); 122 | assertEquals("ab", entry.a); 123 | assertEquals("c \t", entry.b); 124 | assertEquals("", entry.c); 125 | 126 | assertFalse(it.hasNext()); 127 | it.close(); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/test/java/com/fasterxml/jackson/dataformat/csv/deser/ReadSequencesTest.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.deser; 2 | 3 | import java.io.*; 4 | import java.util.*; 5 | 6 | import com.fasterxml.jackson.annotation.JsonPropertyOrder; 7 | 8 | import com.fasterxml.jackson.databind.MappingIterator; 9 | import com.fasterxml.jackson.databind.ObjectWriter; 10 | import com.fasterxml.jackson.dataformat.csv.*; 11 | 12 | /** 13 | * Tests for verifying behavior of enclosing input stream as 14 | * a logical array. 15 | */ 16 | public class ReadSequencesTest extends ModuleTestBase 17 | { 18 | @JsonPropertyOrder({"x", "y"}) 19 | protected static class Entry { 20 | public int x, y; 21 | 22 | public Entry() { } 23 | public Entry(int x, int y) { 24 | this.x = x; 25 | this.y = y; 26 | } 27 | 28 | public boolean equals(Entry e) { // simplified just for testing 29 | return e.x == this.x && e.y == this.y; 30 | } 31 | 32 | @Override 33 | public String toString() { 34 | return "["+x+","+y+"]"; 35 | } 36 | } 37 | 38 | /* 39 | /********************************************************************** 40 | /* Test methods 41 | /********************************************************************** 42 | */ 43 | 44 | // Test using non-wrapped sequence of entries 45 | public void testAsSequence() throws Exception 46 | { 47 | CsvMapper mapper = mapperForCsv(); 48 | mapper.disable(CsvParser.Feature.WRAP_AS_ARRAY); 49 | MappingIterator it = mapper.readerWithSchemaFor(Entry.class).readValues( 50 | "1,2\n-3,0\n5,6\n"); 51 | Entry entry; 52 | 53 | assertTrue(it.hasNext()); 54 | assertNotNull(entry = it.next()); 55 | assertEquals(1, entry.x); 56 | assertEquals(2, entry.y); 57 | assertTrue(it.hasNext()); 58 | assertNotNull(entry = it.next()); 59 | assertEquals(-3, entry.x); 60 | assertEquals(0, entry.y); 61 | assertTrue(it.hasNext()); 62 | assertNotNull(entry = it.next()); 63 | assertEquals(5, entry.x); 64 | assertEquals(6, entry.y); 65 | assertFalse(it.hasNext()); 66 | it.close(); 67 | } 68 | 69 | // Test using sequence of entries wrapped in a logical array. 70 | public void testAsWrappedArray() throws Exception 71 | { 72 | CsvMapper mapper = mapperForCsv(); 73 | mapper.enable(CsvParser.Feature.WRAP_AS_ARRAY); 74 | Entry[] entries = mapper.readerWithSchemaFor(Entry.class).forType(Entry[].class) 75 | .readValue("1,2\n0,0\n123,123456789\n"); 76 | assertEquals(3, entries.length); 77 | assertEquals(1, entries[0].x); 78 | assertEquals(2, entries[0].y); 79 | assertEquals(0, entries[1].x); 80 | assertEquals(0, entries[1].y); 81 | assertEquals(123, entries[2].x); 82 | assertEquals(123456789, entries[2].y); 83 | } 84 | 85 | // Test for teasing out buffer-edge conditions... 86 | public void testLongerUnwrapped() throws Exception 87 | { 88 | // how many? about 10-20 bytes per entry, so try to get at ~100k -> about 10k entries 89 | List entries = generateEntries(9999); 90 | CsvMapper mapper = mapperForCsv(); 91 | CsvSchema schema = mapper.schemaFor(Entry.class); 92 | ObjectWriter writer = mapper.writer(schema); 93 | mapper.disable(CsvParser.Feature.WRAP_AS_ARRAY); 94 | 95 | // First, using bytes; note 96 | byte[] bytes = writer.writeValueAsBytes(entries); 97 | // ... we just happen to know this is expected length... 98 | final int EXPECTED_BYTES = 97640; 99 | assertEquals(EXPECTED_BYTES, bytes.length); 100 | 101 | MappingIterator it = mapper.readerFor(Entry.class).with(schema).readValues(bytes, 0, bytes.length); 102 | verifySame(it, entries); 103 | bytes = null; 104 | 105 | // and then chars: NOTE: ASCII, so bytes == chars 106 | String text = writer.writeValueAsString(entries); 107 | assertEquals(EXPECTED_BYTES, text.length()); 108 | it.close(); 109 | 110 | it = mapper.readerFor(Entry.class).with(schema).readValues(text); 111 | verifySame(it, entries); 112 | it.close(); 113 | 114 | } 115 | 116 | // Verify that code sample from the page works: 117 | public void testRawObjectArrays() throws Exception 118 | { 119 | CsvMapper mapper = new CsvMapper(); 120 | mapper.enable(CsvParser.Feature.WRAP_AS_ARRAY); 121 | final String CSV = "a,b\nc,d\ne,f\n"; 122 | MappingIterator it = mapper.readerFor(Object[].class).readValues(CSV); 123 | 124 | assertTrue(it.hasNext()); 125 | Object[] row = it.next(); 126 | assertEquals(2, row.length); 127 | assertEquals("a", row[0]); 128 | assertEquals("b", row[1]); 129 | assertTrue(it.hasNext()); 130 | it.next(); 131 | assertTrue(it.hasNext()); 132 | row = it.next(); 133 | assertEquals(2, row.length); 134 | assertEquals("e", row[0]); 135 | assertEquals("f", row[1]); 136 | assertFalse(it.hasNext()); 137 | it.close(); 138 | } 139 | 140 | /* 141 | /********************************************************************** 142 | /* Helper methods 143 | /********************************************************************** 144 | */ 145 | 146 | private List generateEntries(int count) throws IOException 147 | { 148 | Random rnd = new Random(count); 149 | ArrayList entries = new ArrayList(count); 150 | while (--count >= 0) { 151 | entries.add(new Entry(rnd.nextInt() % 9876, 50 - (rnd.nextInt() % 987))); 152 | } 153 | return entries; 154 | } 155 | 156 | private void verifySame(Iterator it, List exp) 157 | { 158 | Iterator expIt = exp.iterator(); 159 | int count = 0; 160 | 161 | while (it.hasNext()) { 162 | if (!expIt.hasNext()) { 163 | fail("Expected "+exp.size()+" entries; got more"); 164 | } 165 | Entry expEntry = expIt.next(); 166 | Entry actualEntry = it.next(); 167 | if (!expEntry.equals(actualEntry)) { 168 | fail("Entry at "+count+" (of "+exp.size()+") differs: exp = "+expEntry+", actual = "+actualEntry); 169 | } 170 | ++count; 171 | } 172 | 173 | if (expIt.hasNext()) { 174 | fail("Expected "+exp.size()+" entries; got only "+count); 175 | } 176 | } 177 | } 178 | 179 | -------------------------------------------------------------------------------- /src/test/java/com/fasterxml/jackson/dataformat/csv/deser/SequenceRecoveryTest.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.deser; 2 | 3 | import com.fasterxml.jackson.annotation.JsonPropertyOrder; 4 | import com.fasterxml.jackson.core.JsonProcessingException; 5 | import com.fasterxml.jackson.databind.JsonMappingException; 6 | import com.fasterxml.jackson.databind.MappingIterator; 7 | 8 | import com.fasterxml.jackson.dataformat.csv.*; 9 | 10 | public class SequenceRecoveryTest extends ModuleTestBase 11 | { 12 | @JsonPropertyOrder({"x", "y"}) 13 | protected static class Entry { 14 | public int x, y; 15 | 16 | public Entry() { } 17 | public Entry(int x, int y) { 18 | this.x = x; 19 | this.y = y; 20 | } 21 | 22 | public boolean equals(Entry e) { // simplified just for testing 23 | return e.x == this.x && e.y == this.y; 24 | } 25 | 26 | @Override 27 | public String toString() { 28 | return "["+x+","+y+"]"; 29 | } 30 | } 31 | 32 | /* 33 | /********************************************************************** 34 | /* Test methods 35 | /********************************************************************** 36 | */ 37 | 38 | private final CsvMapper MAPPER = new CsvMapper(); 39 | 40 | public void testSequenceRecovery() throws Exception 41 | { 42 | // can not reuse shared instance because we need: 43 | CsvMapper mapper = mapperForCsv(); 44 | mapper.disable(CsvParser.Feature.WRAP_AS_ARRAY); 45 | MappingIterator it = mapper.readerWithSchemaFor(Entry.class).readValues( 46 | "1,2\n3,invalid\n5,6\n1,2,3,5\n13,-4\ngarbage\n"); 47 | Entry entry; 48 | 49 | assertTrue(it.hasNext()); 50 | assertNotNull(entry = it.nextValue()); 51 | assertEquals(1, entry.x); 52 | assertEquals(2, entry.y); 53 | assertTrue(it.hasNext()); 54 | 55 | // second row, invalid: 56 | try { 57 | it.nextValue(); 58 | fail("Shouldn't have passed"); 59 | } catch (JsonMappingException e) { 60 | verifyException(e, "not a valid Integer value"); 61 | verifyException(e, "\"invalid\""); 62 | } 63 | 64 | // but third is fine again 65 | assertNotNull(entry = it.nextValue()); 66 | assertEquals(5, entry.x); 67 | assertEquals(6, entry.y); 68 | 69 | // fourth not 70 | assertTrue(it.hasNext()); 71 | try { 72 | it.nextValue(); 73 | fail("Shouldn't have passed"); 74 | } catch (JsonProcessingException e) { 75 | // !!! TODO, maybe: Would be nicer to get a JsonMappingException? 76 | verifyException(e, "Too many entries"); 77 | } 78 | 79 | // fifth ok 80 | assertTrue(it.hasNext()); 81 | assertNotNull(entry = it.nextValue()); 82 | assertEquals(13, entry.x); 83 | assertEquals(-4, entry.y); 84 | 85 | // and sixth busted again 86 | assertTrue(it.hasNext()); 87 | try { 88 | it.nextValue(); 89 | fail("Shouldn't have passed"); 90 | } catch (JsonMappingException e) { 91 | verifyException(e, "not a valid Integer value"); 92 | verifyException(e, "\"garbage\""); 93 | } 94 | assertFalse(it.hasNext()); 95 | it.close(); 96 | } 97 | 98 | // for [dataformat-csv#91]: ensure recovery works for extra columns 99 | public void testRecoverFromExtraColumns91() throws Exception 100 | { 101 | CsvSchema schema = MAPPER.schemaFor(Entry.class); 102 | final String CSV = "1,2\n3,4,\n5,6\n7,8,,foo,\n9,10\n"; 103 | MappingIterator it = MAPPER.readerFor(Entry.class) 104 | .with(schema) 105 | .readValues(CSV); 106 | Entry entry; 107 | 108 | assertTrue(it.hasNext()); 109 | entry = it.nextValue(); 110 | assertNotNull(entry); 111 | assertEquals(1, entry.x); 112 | assertEquals(2, entry.y); 113 | 114 | // one extra empty column always allowed 115 | assertTrue(it.hasNext()); 116 | entry = it.nextValue(); 117 | assertEquals(3, entry.x); 118 | assertEquals(4, entry.y); 119 | 120 | assertTrue(it.hasNext()); 121 | entry = it.nextValue(); 122 | assertEquals(5, entry.x); 123 | assertEquals(6, entry.y); 124 | 125 | assertTrue(it.hasNext()); 126 | try { 127 | entry = it.nextValue(); 128 | fail("Should fail"); 129 | } catch (JsonProcessingException e) { 130 | verifyException(e, "Too many entries"); 131 | } 132 | // this SHOULD skip 7,8,, entry 133 | 134 | assertTrue(it.hasNext()); 135 | entry = it.nextValue(); 136 | assertEquals(9, entry.x); 137 | assertEquals(10, entry.y); 138 | 139 | assertFalse(it.hasNext()); 140 | 141 | it.close(); 142 | } 143 | 144 | // for [dataformat-csv#91]: ensure recovery works for extra columns 145 | public void testRecoveryFromMissingQuote91() throws Exception 146 | { 147 | CsvSchema schema = MAPPER.schemaFor(IdDesc.class); 148 | final String CSV = "a,\"desc\"\nb,\"Broken\nc,\"good\"\nd,foo"; 149 | MappingIterator it = MAPPER.readerFor(IdDesc.class) 150 | .with(schema) 151 | .readValues(CSV); 152 | IdDesc value; 153 | 154 | assertTrue(it.hasNext()); 155 | value = it.nextValue(); 156 | assertEquals("a", value.id); 157 | assertEquals("desc", value.desc); 158 | 159 | 160 | // Should choke on 'g', because it's not a separator after what parser 161 | // thinks is closing quote (but user probably meant as opening) 162 | assertTrue(it.hasNext()); 163 | try { 164 | value = it.nextValue(); 165 | fail("Should fail"); 166 | } catch (JsonProcessingException e) { 167 | verifyException(e, "Expected separator"); 168 | } 169 | 170 | // and because of this, synchronization skips the rest of 3rd line... 171 | assertTrue(it.hasNext()); 172 | value = it.nextValue(); 173 | assertEquals("d", value.id); 174 | assertEquals("foo", value.desc); 175 | 176 | it.close(); 177 | } 178 | 179 | @JsonPropertyOrder({"s1", "s2", "s3"}) 180 | protected static class ThreeString { 181 | public String s1, s2, s3; 182 | } 183 | 184 | // Additional test for [dataformat-csv#91]: should skip only line with error 185 | // and do not fail on next line 186 | public void testRecoveryFromUnclosedQuotes() throws Exception 187 | { 188 | String toParse = aposToQuotes( 189 | "'value1','value2','value3'\n" + 190 | "'value4','value5','value6\n" + // missing closing quote 191 | "'value7','value8','value9'\n"+ 192 | "'value10','value11','value12'\n" 193 | ); 194 | CsvSchema schema = MAPPER.schemaFor(ThreeString.class); 195 | MappingIterator it = MAPPER.reader(schema).forType(ThreeString.class).readValues(toParse); 196 | 197 | ThreeString value; 198 | 199 | assertTrue(it.hasNext()); 200 | value = it.nextValue(); 201 | 202 | assertEquals("value1", value.s1); 203 | assertEquals("value2", value.s2); 204 | assertEquals("value3", value.s3); 205 | 206 | // second row has the problem, missing closing quote 207 | assertTrue(it.hasNext()); 208 | try { 209 | value = it.nextValue(); 210 | fail("Should fail"); 211 | } catch (JsonProcessingException e) { 212 | verifyException(e, "Expected separator"); 213 | } 214 | 215 | // and this means that since error was encountered on 3rd row, that gets 216 | // skipped and we'll see the 4th row next. 217 | 218 | assertTrue(it.hasNext()); 219 | value = it.nextValue(); 220 | 221 | assertEquals("value10", value.s1); 222 | assertEquals("value11", value.s2); 223 | assertEquals("value12", value.s3); 224 | 225 | assertFalse(it.hasNext()); 226 | 227 | it.close(); 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /src/test/java/com/fasterxml/jackson/dataformat/csv/deser/StreamingReadTest.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.deser; 2 | 3 | import java.io.ByteArrayInputStream; 4 | import java.io.IOException; 5 | import java.io.StringWriter; 6 | 7 | import com.fasterxml.jackson.core.*; 8 | import com.fasterxml.jackson.core.io.SerializedString; 9 | import com.fasterxml.jackson.dataformat.csv.*; 10 | 11 | /** 12 | * Container for some low-level tests that use parser directly; 13 | * needed for exercising certain methods that are difficult to 14 | * trigger via data-binding 15 | */ 16 | public class StreamingReadTest extends ModuleTestBase 17 | { 18 | private final CsvFactory CSV_F = new CsvFactory(); 19 | 20 | private final CsvSchema ABC_SCHEMA = CsvSchema.builder() 21 | .addColumn("a") 22 | .addColumn("b") 23 | .addColumn("c") 24 | .setUseHeader(false) 25 | .build(); 26 | 27 | public void testIntRead() throws Exception 28 | { 29 | _testInts(1, 59, -8); 30 | _testInts(10093525, -123456789, 123456789); 31 | _testInts(-123451, 0, -829); 32 | _testInts(Integer.MAX_VALUE, Integer.MIN_VALUE, 3); 33 | } 34 | 35 | public void testLongRead() throws Exception 36 | { 37 | _testLongs(1L, -3L); 38 | _testLongs(1234567890L, -9876543212345679L); 39 | _testLongs(Long.MIN_VALUE, Long.MAX_VALUE); 40 | } 41 | 42 | public void testFloatRead() throws Exception 43 | { 44 | _testDoubles(1.0, 125.375, -900.5); 45 | _testDoubles(10093525.125, -123456789.5, 123456789.0); 46 | _testDoubles(-123451.75, 0.0625, -829.5); 47 | } 48 | 49 | private void _testInts(int a, int b, int c) throws Exception { 50 | _testInts(false, a, b, c); 51 | _testInts(true, a, b, c); 52 | } 53 | 54 | private void _testLongs(long a, long b) throws Exception { 55 | _testLongs(false, a, b); 56 | _testLongs(true, a, b); 57 | } 58 | 59 | private void _testDoubles(double a, double b, double c) throws Exception { 60 | _testDoubles(false, a, b, c); 61 | _testDoubles(true, a, b, c); 62 | } 63 | 64 | private void _testInts(boolean useBytes, int a, int b, int c) throws Exception { 65 | CsvParser parser = _parser(String.format("%d,%d,%d\n", a, b, c), useBytes, ABC_SCHEMA); 66 | 67 | assertToken(JsonToken.START_OBJECT, parser.nextToken()); 68 | 69 | assertToken(JsonToken.FIELD_NAME, parser.nextToken()); 70 | assertEquals("a", parser.getCurrentName()); 71 | 72 | StringWriter w = new StringWriter(); 73 | assertEquals(1, parser.getText(w)); 74 | assertEquals("a", w.toString()); 75 | 76 | String numStr = String.valueOf(a); 77 | assertEquals(numStr, parser.nextTextValue()); 78 | char[] ch = parser.getTextCharacters(); 79 | String str2 = new String(ch, parser.getTextOffset(), parser.getTextLength()); 80 | assertEquals(numStr, str2); 81 | w = new StringWriter(); 82 | assertEquals(numStr.length(), parser.getText(w)); 83 | assertEquals(numStr, w.toString()); 84 | 85 | assertEquals(a, parser.getIntValue()); 86 | assertEquals((long) a, parser.getLongValue()); 87 | 88 | assertEquals("b", parser.nextFieldName()); 89 | assertEquals(""+b, parser.nextTextValue()); 90 | assertEquals((long) b, parser.getLongValue()); 91 | assertEquals(b, parser.getIntValue()); 92 | 93 | assertTrue(parser.nextFieldName(new SerializedString("c"))); 94 | 95 | assertToken(JsonToken.VALUE_STRING, parser.nextToken()); 96 | assertEquals(c, parser.getIntValue()); 97 | assertEquals((long) c, parser.getLongValue()); 98 | 99 | assertToken(JsonToken.END_OBJECT, parser.nextToken()); 100 | assertNull(parser.nextToken()); 101 | 102 | parser.close(); 103 | } 104 | 105 | private void _testLongs(boolean useBytes, long a, long b) throws Exception 106 | { 107 | CsvParser parser = _parser(String.format("%d,%d\n", a, b), useBytes, ABC_SCHEMA); 108 | 109 | assertToken(JsonToken.START_OBJECT, parser.nextToken()); 110 | 111 | assertToken(JsonToken.FIELD_NAME, parser.nextToken()); 112 | assertEquals("a", parser.getCurrentName()); 113 | assertEquals(""+a, parser.nextTextValue()); 114 | assertEquals(a, parser.getLongValue()); 115 | 116 | assertEquals("b", parser.nextFieldName()); 117 | assertEquals(""+b, parser.nextTextValue()); 118 | assertEquals(b, parser.getLongValue()); 119 | 120 | assertToken(JsonToken.END_OBJECT, parser.nextToken()); 121 | assertNull(parser.nextToken()); 122 | 123 | parser.close(); 124 | } 125 | 126 | private void _testDoubles(boolean useBytes, double a, double b, double c) 127 | throws Exception 128 | { 129 | CsvParser parser = _parser(String.format("%s,%s,%s\n", a, b, c), useBytes, ABC_SCHEMA); 130 | 131 | assertToken(JsonToken.START_OBJECT, parser.nextToken()); 132 | 133 | assertToken(JsonToken.FIELD_NAME, parser.nextToken()); 134 | assertEquals("a", parser.getCurrentName()); 135 | assertEquals(""+a, parser.nextTextValue()); 136 | assertEquals(a, parser.getDoubleValue()); 137 | assertEquals((float) a, parser.getFloatValue()); 138 | 139 | assertEquals("b", parser.nextFieldName()); 140 | assertEquals(""+b, parser.nextTextValue()); 141 | assertEquals((float) b, parser.getFloatValue()); 142 | assertEquals(b, parser.getDoubleValue()); 143 | 144 | assertTrue(parser.nextFieldName(new SerializedString("c"))); 145 | 146 | assertToken(JsonToken.VALUE_STRING, parser.nextToken()); 147 | assertEquals(c, parser.getDoubleValue()); 148 | assertEquals((float) c, parser.getFloatValue()); 149 | 150 | assertToken(JsonToken.END_OBJECT, parser.nextToken()); 151 | assertNull(parser.nextToken()); 152 | 153 | parser.close(); 154 | } 155 | 156 | private CsvParser _parser(String csv, boolean useBytes, CsvSchema schema) 157 | throws IOException 158 | { 159 | CsvParser p; 160 | if (useBytes) { 161 | p = CSV_F.createParser(new ByteArrayInputStream(csv.getBytes("UTF-8"))); 162 | } else { 163 | p = CSV_F.createParser(csv); 164 | } 165 | p.setSchema(schema); 166 | return p; 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /src/test/java/com/fasterxml/jackson/dataformat/csv/deser/TestFiltering.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.deser; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.StringReader; 5 | import java.util.*; 6 | 7 | import com.fasterxml.jackson.annotation.*; 8 | import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter.FilterExceptFilter; 9 | import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider; 10 | import com.fasterxml.jackson.dataformat.csv.CsvMapper; 11 | import com.fasterxml.jackson.dataformat.csv.CsvSchema; 12 | import com.fasterxml.jackson.dataformat.csv.ModuleTestBase; 13 | 14 | public class TestFiltering extends ModuleTestBase 15 | { 16 | // Classes that represent views 17 | static class ViewA { } 18 | static class ViewAA extends ViewA { } 19 | static class ViewB { } 20 | static class ViewBB extends ViewB { } 21 | 22 | @JsonPropertyOrder({ "a", "aa", "b" }) 23 | static class Bean 24 | { 25 | @JsonView({ ViewA.class, ViewB.class }) 26 | public String a = "1"; 27 | 28 | @JsonView({ViewAA.class }) 29 | public String aa = "2"; 30 | 31 | @JsonView(ViewB.class) 32 | public String b = "3"; 33 | } 34 | 35 | static final String COMPANY_FILTER = "COMPANY_FILTER"; 36 | 37 | @JsonPropertyOrder({ "id", "name", "ticker" }) 38 | @JsonFilter(COMPANY_FILTER) 39 | public static class Company { 40 | public int id; 41 | public String name; 42 | public String ticker; 43 | 44 | Company() { } 45 | Company(int id, String name, String ticker) { 46 | this.id = id; 47 | this.name = name; 48 | this.ticker = ticker; 49 | } 50 | } 51 | 52 | /* 53 | /********************************************************** 54 | /* Test methods 55 | /********************************************************** 56 | */ 57 | 58 | private final CsvMapper MAPPER = mapperForCsv(); 59 | 60 | public void testWithJsonView() throws Exception 61 | { 62 | CsvSchema schema = MAPPER.schemaFor(Bean.class).withLineSeparator("\n").withHeader(); 63 | String actual = MAPPER.writer(schema).withView(ViewB.class).writeValueAsString(new Bean()); 64 | // System.out.println(actual); 65 | 66 | BufferedReader br = new BufferedReader(new StringReader(actual.trim())); 67 | assertEquals("a,aa,b", br.readLine()); 68 | assertEquals("1,,3", br.readLine()); 69 | assertNull(br.readLine()); 70 | 71 | // plus read back? 72 | final String INPUT = "a,aa,b\n5,6,7\n"; 73 | Bean result = MAPPER.readerFor(Bean.class).with(schema).withView(ViewB.class).readValue(INPUT); 74 | assertEquals("5", result.a); 75 | // due to filtering, ought to use default 76 | assertEquals("2", result.aa); 77 | assertEquals("7", result.b); 78 | } 79 | 80 | public void testWithJsonFilter() throws Exception 81 | { 82 | CsvSchema schema = MAPPER.schemaFor(Company.class).withLineSeparator("\n").withHeader(); 83 | 84 | SimpleFilterProvider filterProvider = new SimpleFilterProvider() 85 | .addFilter(COMPANY_FILTER, FilterExceptFilter.filterOutAllExcept("name", "ticker")); 86 | 87 | List companies = Arrays.asList( 88 | new Company(1, "name1", "ticker1") 89 | , new Company(2, "name2", "ticker2") 90 | , new Company(3, "name3", "ticker3")); 91 | String actual = MAPPER.writer(filterProvider).with(schema).writeValueAsString(companies); 92 | // System.out.println(actual); 93 | 94 | BufferedReader br = new BufferedReader(new StringReader(actual.trim())); 95 | assertEquals("id,name,ticker", br.readLine()); 96 | assertEquals(",name1,ticker1", br.readLine()); 97 | assertEquals(",name2,ticker2", br.readLine()); 98 | assertEquals(",name3,ticker3", br.readLine()); 99 | assertNull(br.readLine()); 100 | } 101 | 102 | public void testWithJsonFilterFieldSuppressed() throws Exception 103 | { 104 | final CsvSchema schema = new CsvSchema.Builder() 105 | .addColumn("name") 106 | .addColumn("ticker") 107 | .setLineSeparator("\n").setUseHeader(true) 108 | .build(); 109 | 110 | SimpleFilterProvider filterProvider = new SimpleFilterProvider() 111 | .addFilter(COMPANY_FILTER, FilterExceptFilter.filterOutAllExcept("name", "ticker")); 112 | 113 | List companies = Arrays.asList( 114 | new Company(1, "name1", "ticker1") 115 | , new Company(2, "name2", "ticker2") 116 | , new Company(3, "name3", "ticker3")); 117 | String actual = MAPPER.writer(filterProvider).with(schema).writeValueAsString(companies); 118 | 119 | BufferedReader br = new BufferedReader(new StringReader(actual.trim())); 120 | assertEquals("name,ticker", br.readLine()); 121 | assertEquals("name1,ticker1", br.readLine()); 122 | assertEquals("name2,ticker2", br.readLine()); 123 | assertEquals("name3,ticker3", br.readLine()); 124 | assertNull(br.readLine()); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/test/java/com/fasterxml/jackson/dataformat/csv/deser/TestParserEscapes.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.deser; 2 | 3 | import com.fasterxml.jackson.annotation.JsonPropertyOrder; 4 | import com.fasterxml.jackson.dataformat.csv.CsvMapper; 5 | import com.fasterxml.jackson.dataformat.csv.CsvSchema; 6 | import com.fasterxml.jackson.dataformat.csv.ModuleTestBase; 7 | 8 | public class TestParserEscapes extends ModuleTestBase 9 | { 10 | @JsonPropertyOrder({"id", "description"}) 11 | protected static class Desc { 12 | public String id, desc; 13 | } 14 | 15 | /* 16 | /********************************************************************** 17 | /* Test methods 18 | /********************************************************************** 19 | */ 20 | 21 | public void testSimpleEscapesInQuotes() throws Exception 22 | { 23 | CsvMapper mapper = mapperForCsv(); 24 | CsvSchema schema = mapper.schemaFor(Desc.class).withColumnSeparator('|').withEscapeChar('\\'); 25 | final String id = "abc\\\\def"; // doubled for javac 26 | final String desc = "Desc with\\\nlinefeed"; 27 | String input = quote(id)+"|"+quote(desc)+"\n"; 28 | Desc result = mapper.reader(schema).forType(Desc.class).readValue(input); 29 | assertEquals("abc\\def", result.id); 30 | assertEquals("Desc with\nlinefeed", result.desc); 31 | } 32 | 33 | /* Specs are unclear as to whether escapes should work in unquoted values; 34 | * but since escape themselves are not officially supported, let's allow 35 | * them for now (can add a config setting if need be) 36 | */ 37 | public void testSimpleEscapesInUnquoted() throws Exception 38 | { 39 | CsvMapper mapper = mapperForCsv(); 40 | CsvSchema schema = mapper.schemaFor(Desc.class).withColumnSeparator('|').withEscapeChar('\\'); 41 | final String id = "abc\\\\def"; // doubled for javac 42 | final String desc = "Desc with\\\nlinefeed"; 43 | String input = id+"|"+desc+"\n"; 44 | Desc result = mapper.reader(schema).forType(Desc.class).readValue(input); 45 | assertEquals("abc\\def", result.id); 46 | assertEquals("Desc with\nlinefeed", result.desc); 47 | } 48 | 49 | public void testEscapesAtStartInUnquoted() throws Exception 50 | { 51 | CsvMapper mapper = mapperForCsv(); 52 | CsvSchema schema = mapper.schemaFor(Desc.class).withColumnSeparator('|').withEscapeChar('\\'); 53 | final String id = "\\|abcdef"; // doubled for javac 54 | final String desc = "Desc with\\\nlinefeed"; 55 | String input = id+"|"+desc+"\n"; 56 | Desc result = mapper.reader(schema).forType(Desc.class).readValue(input); 57 | assertEquals("|abcdef", result.id); 58 | assertEquals("Desc with\nlinefeed", result.desc); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/test/java/com/fasterxml/jackson/dataformat/csv/deser/TestParserNoSchema.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.deser; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | 6 | import com.fasterxml.jackson.databind.MappingIterator; 7 | import com.fasterxml.jackson.dataformat.csv.*; 8 | 9 | /** 10 | * Test to verify that CSV content can be parsed without schema 11 | * (or more precisely: using Schema that does not define any columns); 12 | * if so, content will be exposed as a sequence of JSON Arrays, instead 13 | * of JSON Objects. 14 | */ 15 | public class TestParserNoSchema extends ModuleTestBase 16 | { 17 | /* 18 | /********************************************************************** 19 | /* Test methods 20 | /********************************************************************** 21 | */ 22 | 23 | public void testUntypedAsSequence() throws Exception 24 | { 25 | CsvMapper mapper = mapperForCsv(); 26 | mapper.disable(CsvParser.Feature.WRAP_AS_ARRAY); 27 | 28 | /* 04-Oct-2012, tatu: Due to changes to 2.1, this is the one case 29 | * that does NOT work automatically via ObjectMapper/-Reader, but 30 | * instead we must manually create the reader 31 | */ 32 | final String CSV = "1,null\nfoobar\n7,true\n"; 33 | CsvParser cp = mapper.getFactory().createParser(CSV); 34 | 35 | MappingIterator it = mapper.readerFor(Object[].class).readValues(cp); 36 | 37 | Object[] row; 38 | assertTrue(it.hasNext()); 39 | row = it.next(); 40 | assertEquals(2, row.length); 41 | assertEquals("1", row[0]); 42 | assertEquals("null", row[1]); 43 | 44 | assertTrue(it.hasNext()); 45 | row = it.next(); 46 | assertEquals(1, row.length); 47 | assertEquals("foobar", row[0]); 48 | 49 | assertTrue(it.hasNext()); 50 | row = it.next(); 51 | assertEquals(2, row.length); 52 | assertEquals("7", row[0]); 53 | assertEquals("true", row[1]); 54 | 55 | assertFalse(it.hasNext()); 56 | 57 | cp.close(); 58 | it.close(); 59 | } 60 | 61 | public void testUntypedAsObjectArray() throws Exception 62 | { 63 | CsvMapper mapper = mapperForCsv(); 64 | mapper.enable(CsvParser.Feature.WRAP_AS_ARRAY); 65 | // when wrapped as an array, we'll get array of Lists: 66 | Object[] rows = mapper.readerFor(Object[].class).readValue( 67 | "1,\"xyz\"\n\ntrue,\n" 68 | ); 69 | assertEquals(3, rows.length); 70 | List row; 71 | 72 | row = (List) rows[0]; 73 | assertEquals(2, row.size()); 74 | assertEquals("1", row.get(0)); 75 | assertEquals("xyz", row.get(1)); 76 | 77 | row = (List) rows[1]; 78 | assertEquals(1, row.size()); 79 | assertEquals("", row.get(0)); 80 | 81 | row = (List) rows[2]; 82 | assertEquals(2, row.size()); 83 | assertEquals("true", row.get(0)); 84 | assertEquals("", row.get(1)); 85 | } 86 | 87 | public void testUntypedAsStringArray() throws Exception 88 | { 89 | CsvMapper mapper = mapperForCsv(); 90 | mapper.enable(CsvParser.Feature.WRAP_AS_ARRAY); 91 | // when wrapped as an array, we'll get array of Lists: 92 | String[][] rows = mapper.readValue("1,\"xyz\"\n\ntrue,\n", String[][].class); 93 | assertEquals(3, rows.length); 94 | String[] row; 95 | 96 | row = (String[]) rows[0]; 97 | assertEquals(2, row.length); 98 | assertEquals("1",row[0]); 99 | assertEquals("xyz", row[1]); 100 | 101 | row =(String[]) rows[1]; 102 | assertEquals(1, row.length); 103 | assertEquals("", row[0]); 104 | 105 | row = (String[])rows[2]; 106 | assertEquals(2, row.length); 107 | assertEquals("true", row[0]); 108 | assertEquals("", row[1]); 109 | } 110 | 111 | public void testUntypedViaReadValues() throws Exception 112 | { 113 | CsvMapper mapper = mapperForCsv(); 114 | mapper.enable(CsvParser.Feature.WRAP_AS_ARRAY); 115 | MappingIterator it = mapper.readerFor(String[].class) 116 | .readValues("1,\"xyz\"\n\ntrue,\n"); 117 | assertTrue(it.hasNextValue()); 118 | String[] row = it.nextValue(); 119 | assertEquals(2, row.length); 120 | assertEquals("1",row[0]); 121 | assertEquals("xyz", row[1]); 122 | 123 | assertTrue(it.hasNextValue()); 124 | row = it.nextValue(); 125 | assertEquals(1, row.length); 126 | assertEquals("", row[0]); 127 | 128 | assertTrue(it.hasNextValue()); 129 | row = it.nextValue(); 130 | assertEquals(2, row.length); 131 | assertEquals("true", row[0]); 132 | assertEquals("", row[1]); 133 | 134 | assertFalse(it.hasNextValue()); 135 | it.close(); 136 | } 137 | 138 | public void testUntypedWithHeaderAsMap() throws Exception 139 | { 140 | CsvMapper mapper = mapperForCsv(); 141 | MappingIterator> it = mapper 142 | .readerFor(Map.class) 143 | .with(mapper.schemaWithHeader()) 144 | .readValues("a,b\n1,2\n3,4\n"); 145 | 146 | Map first = it.nextValue(); 147 | assertNotNull(first); 148 | assertEquals("1", first.get("a")); 149 | assertEquals("2", first.get("b")); 150 | 151 | Map second = it.nextValue(); 152 | assertNotNull(first); 153 | assertEquals("3", second.get("a")); 154 | assertEquals("4", second.get("b")); 155 | 156 | assertFalse(it.hasNextValue()); 157 | it.close(); 158 | } 159 | 160 | /* Let's also allow varying number of columns, if no 161 | * schema has been defined. 162 | */ 163 | public void testUntypedAsSequenceVarLengths() throws Exception 164 | { 165 | CsvMapper mapper = mapperForCsv(); 166 | mapper.disable(CsvParser.Feature.WRAP_AS_ARRAY); 167 | 168 | /* 04-Oct-2012, tatu: Due to changes to 2.1, this is the one case 169 | * that does NOT work automatically via ObjectMapper/-Reader, but 170 | * instead we must manually create the reader 171 | */ 172 | final String CSV = "1,2\n1,2,3,4\n"; 173 | CsvParser cp = mapper.getFactory().createParser(CSV); 174 | 175 | MappingIterator it = mapper.readerFor(String[].class).readValues(cp); 176 | 177 | Object[] row; 178 | assertTrue(it.hasNext()); 179 | row = it.next(); 180 | assertEquals(2, row.length); 181 | assertEquals("1", row[0]); 182 | assertEquals("2", row[1]); 183 | 184 | assertTrue(it.hasNext()); 185 | row = it.next(); 186 | assertEquals(4, row.length); 187 | assertEquals("1", row[0]); 188 | assertEquals("2", row[1]); 189 | assertEquals("3", row[2]); 190 | assertEquals("4", row[3]); 191 | 192 | assertFalse(it.hasNext()); 193 | 194 | cp.close(); 195 | it.close(); 196 | } 197 | 198 | // [Issue#54] 199 | public void testDelimiterAtBufferBoundary() throws Exception 200 | { 201 | CsvMapper mapper = mapperForCsv(); 202 | mapper.enable(CsvParser.Feature.TRIM_SPACES); 203 | 204 | final String col1 = "hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh" + 205 | "hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh" + 206 | "hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh" + 207 | "hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh"; 208 | final String col2 = "H"; 209 | 210 | CsvParser cp = mapper.getFactory().createParser(col1 + " ," + col2 +"\n" + col2 + "," + col1 + "\n"); 211 | MappingIterator it = mapper.readerFor(Object[].class).readValues(cp); 212 | 213 | Object[] row; 214 | 215 | assertTrue(it.hasNext()); 216 | row = it.next(); 217 | assertEquals(2, row.length); 218 | assertEquals(col1, row[0]); 219 | assertEquals(col2, row[1]); 220 | 221 | assertTrue(it.hasNext()); 222 | row = it.next(); 223 | assertEquals(2, row.length); 224 | assertEquals(col2, row[0]); 225 | assertEquals(col1, row[1]); 226 | 227 | cp.close(); 228 | it.close(); 229 | } 230 | 231 | } 232 | -------------------------------------------------------------------------------- /src/test/java/com/fasterxml/jackson/dataformat/csv/deser/TestParserQuotes.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.deser; 2 | 3 | import com.fasterxml.jackson.annotation.JsonPropertyOrder; 4 | import com.fasterxml.jackson.databind.*; 5 | import com.fasterxml.jackson.dataformat.csv.*; 6 | 7 | public class TestParserQuotes extends ModuleTestBase 8 | { 9 | @JsonPropertyOrder({"age", "name"}) 10 | protected static class AgeName { 11 | public int age; 12 | public String name; 13 | 14 | public AgeName() { } 15 | public AgeName(int age, String name) { 16 | this.age = age; 17 | this.name = name; 18 | } 19 | } 20 | 21 | @JsonPropertyOrder({"s1", "s2", "s3"}) 22 | protected static class ThreeString { 23 | public String s1, s2, s3; 24 | } 25 | 26 | /* 27 | /********************************************************************** 28 | /* Test methods 29 | /********************************************************************** 30 | */ 31 | 32 | public void testSimpleQuotes() throws Exception 33 | { 34 | CsvMapper mapper = mapperForCsv(); 35 | CsvSchema schema = mapper.schemaFor(AgeName.class); 36 | AgeName user = mapper.reader(schema).forType(AgeName.class).readValue(" 13 ,\"Joe \"\"Sixpack\"\" Paxson\""); 37 | assertEquals(13, user.age); 38 | assertEquals("Joe \"Sixpack\" Paxson", user.name); 39 | } 40 | 41 | public void testSimpleMultiLine() throws Exception 42 | { 43 | CsvMapper mapper = mapperForCsv(); 44 | mapper.disable(CsvParser.Feature.WRAP_AS_ARRAY); 45 | CsvSchema schema = mapper.schemaFor(AgeName.class); 46 | MappingIterator it = mapper.reader(schema).forType(AgeName.class).readValues( 47 | "-3,\"\"\"Unknown\"\"\"\n\"13\" ,\"Joe \"\"Sixpack\"\" Paxson\""); 48 | assertTrue(it.hasNext()); 49 | AgeName user = it.nextValue(); 50 | assertEquals(-3, user.age); 51 | assertEquals("\"Unknown\"", user.name); 52 | assertTrue(it.hasNext()); 53 | user = it.nextValue(); 54 | assertEquals(13, user.age); 55 | assertEquals("Joe \"Sixpack\" Paxson", user.name); 56 | assertFalse(it.hasNext()); 57 | it.close(); 58 | } 59 | 60 | // [dataformat-csv#32] 61 | public void testDisablingQuotes() throws Exception 62 | { 63 | CsvMapper mapper = mapperForCsv(); 64 | mapper.disable(CsvParser.Feature.WRAP_AS_ARRAY); 65 | CsvSchema schema = mapper.schemaFor(AgeName.class) 66 | .withoutQuoteChar() 67 | ; 68 | 69 | // First, read something and expect quotes to be retained 70 | 71 | final String RAW_NAME = "\"UNKNOWN\""; 72 | final String RAW_NAME2 = "a\"b"; 73 | 74 | MappingIterator it = mapper.reader(schema).forType(AgeName.class) 75 | .readValues("38,"+RAW_NAME+"\n" 76 | +"27,"+RAW_NAME2+"\n"); 77 | assertTrue(it.hasNext()); 78 | AgeName user = it.nextValue(); 79 | assertEquals(38, user.age); 80 | assertEquals(RAW_NAME, user.name); 81 | 82 | AgeName user2 = it.nextValue(); 83 | assertEquals(27, user2.age); 84 | assertEquals(RAW_NAME2, user2.name); 85 | assertFalse(it.hasNext()); 86 | it.close(); 87 | 88 | String csv = mapper.writer(schema).writeValueAsString(user).trim(); 89 | assertEquals("38,"+RAW_NAME, csv); 90 | } 91 | 92 | // for [dataformat-csv#117] 93 | public void testDefaultSimpleQuotes() throws Exception 94 | { 95 | CsvMapper mapper = mapperForCsv(); 96 | 97 | // first without array wrapping: 98 | mapper.disable(CsvParser.Feature.WRAP_AS_ARRAY); 99 | MappingIterator it = mapper.readerFor(String[].class) 100 | .readValues("\"te,st\""); 101 | assertTrue(it.hasNextValue()); 102 | String[] row = it.nextValue(); 103 | assertEquals(1, row.length); 104 | assertEquals("te,st", row[0]); 105 | 106 | // 21-Feb-2016, tatu: Surprisingly this fails; not directly related to 107 | // reported problem, so covered by a separate unit test, left commented out here 108 | // assertFalse(it.hasNextValue()); 109 | it.close(); 110 | 111 | // then with array wrapping 112 | mapper = mapperForCsv(); 113 | mapper.enable(CsvParser.Feature.WRAP_AS_ARRAY); 114 | it = mapper.readerFor(String[].class) 115 | .readValues("\"te,st\""); 116 | assertTrue(it.hasNextValue()); 117 | row = it.nextValue(); 118 | assertEquals(1, row.length); 119 | assertEquals("te,st", row[0]); 120 | 121 | it.close(); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/test/java/com/fasterxml/jackson/dataformat/csv/deser/TestParserStrictQuoting.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.deser; 2 | 3 | import com.fasterxml.jackson.annotation.JsonPropertyOrder; 4 | import com.fasterxml.jackson.dataformat.csv.*; 5 | 6 | // Tests for [dataformat-csv#26] 7 | public class TestParserStrictQuoting extends ModuleTestBase 8 | { 9 | @JsonPropertyOrder({"a", "b"}) 10 | protected static class AB { 11 | public String a, b; 12 | 13 | public AB() { } 14 | public AB(String a, String b) { 15 | this.a = a; 16 | this.b = b; 17 | } 18 | } 19 | 20 | /* 21 | /********************************************************************** 22 | /* Test methods 23 | /********************************************************************** 24 | */ 25 | 26 | public void testStrictQuoting() throws Exception 27 | { 28 | final String NUMS = "12345 6789"; 29 | final String LONG = NUMS + NUMS + NUMS + NUMS; // 40 chars should do it 30 | 31 | CsvMapper mapper = mapperForCsv(); 32 | 33 | assertFalse(mapper.getFactory().isEnabled(CsvGenerator.Feature.STRICT_CHECK_FOR_QUOTING)); 34 | CsvSchema schema = mapper.schemaFor(AB.class).withoutHeader(); 35 | 36 | final AB input = new AB("x", LONG); 37 | 38 | // with non-strict, should quote 39 | String csv = mapper.writer(schema).writeValueAsString(input); 40 | assertEquals(aposToQuotes("x,'"+LONG+"'"), csv.trim()); 41 | 42 | // should be possible to hot-swap 43 | // and with strict/optimal, no quoting 44 | mapper.configure(CsvGenerator.Feature.STRICT_CHECK_FOR_QUOTING, true); 45 | csv = mapper.writer(schema).writeValueAsString(input); 46 | assertEquals(aposToQuotes("x,"+LONG), csv.trim()); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/test/java/com/fasterxml/jackson/dataformat/csv/deser/TestParserWithHeader.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.deser; 2 | 3 | import java.util.*; 4 | 5 | import com.fasterxml.jackson.annotation.JsonPropertyOrder; 6 | import com.fasterxml.jackson.core.JsonToken; 7 | import com.fasterxml.jackson.databind.MappingIterator; 8 | import com.fasterxml.jackson.dataformat.csv.*; 9 | 10 | public class TestParserWithHeader extends ModuleTestBase 11 | { 12 | @JsonPropertyOrder({ "age", "name", "cute" }) 13 | protected static class Entry { 14 | public int age; 15 | public String name; 16 | public boolean cute; 17 | } 18 | 19 | /* 20 | /********************************************************************** 21 | /* Test methods, success 22 | /********************************************************************** 23 | */ 24 | 25 | public void testSimpleHeader() throws Exception 26 | { 27 | CsvParser parser = (CsvParser) new CsvFactory().createParser( 28 | "name, age, other\nfoo,2,xyz\n"); 29 | // need to enable first-line-as-schema handling: 30 | parser.setSchema(CsvSchema.emptySchema().withHeader()); 31 | assertToken(JsonToken.START_OBJECT, parser.nextToken()); 32 | CsvSchema schema = parser.getSchema(); 33 | assertEquals(3, schema.size()); 34 | 35 | // verify that names from first line are trimmed: 36 | assertEquals("name", schema.columnName(0)); 37 | assertEquals("age", schema.columnName(1)); 38 | assertEquals("other", schema.columnName(2)); 39 | parser.close(); 40 | } 41 | 42 | public void testSimpleQuotes() throws Exception 43 | { 44 | CsvMapper mapper = mapperForCsv(); 45 | mapper.disable(CsvParser.Feature.WRAP_AS_ARRAY); 46 | CsvSchema schema = CsvSchema.emptySchema().withHeader(); 47 | Entry entry = mapper.readerFor(Entry.class).with(schema).readValue( 48 | "name,age,\"cute\" \nLeo,4,true\n"); 49 | assertEquals("Leo", entry.name); 50 | assertEquals(4, entry.age); 51 | assertTrue(entry.cute); 52 | } 53 | 54 | public void testSkipFirstDataLine() throws Exception 55 | { 56 | CsvMapper mapper = mapperForCsv(); 57 | mapper.disable(CsvParser.Feature.WRAP_AS_ARRAY); 58 | CsvSchema schema = mapper.schemaFor(Entry.class).withSkipFirstDataRow(true); 59 | MappingIterator it = mapper.readerFor(Entry.class).with(schema).readValues( 60 | "12354\n6,Lila,true"); 61 | Entry entry; 62 | 63 | assertTrue(it.hasNext()); 64 | assertNotNull(entry = it.next()); 65 | assertEquals(6, entry.age); 66 | assertEquals("Lila", entry.name); 67 | assertFalse(it.hasNext()); 68 | it.close(); 69 | } 70 | 71 | public void testLongHeader() throws Exception 72 | { 73 | StringBuilder sb = new StringBuilder(650); 74 | ArrayList names = new ArrayList(); 75 | 76 | do { 77 | if (sb.length() > 0) { 78 | sb.append(','); 79 | } 80 | String name = "COLUMN"+names.size(); 81 | names.add(name); 82 | sb.append(name); 83 | } while (sb.length() < 600); 84 | sb.append("\nabc\n"); 85 | final String CSV = sb.toString(); 86 | 87 | 88 | // Ok, then, first let's try reading columns: 89 | 90 | CsvMapper mapper = mapperForCsv(); 91 | mapper.disable(CsvParser.Feature.WRAP_AS_ARRAY); 92 | CsvSchema schema = CsvSchema.emptySchema().withHeader(); 93 | CsvParser p = (CsvParser) mapper.getFactory().createParser(CSV); 94 | p.setSchema(schema); 95 | // need to read something to ensure header line is processed 96 | assertEquals(JsonToken.START_OBJECT, p.nextToken()); 97 | CsvSchema actual = p.getSchema(); 98 | 99 | assertEquals(names.size(), actual.size()); 100 | for (int i = 0, len = names.size(); i < len; ++i) { 101 | CsvSchema.Column col = actual.column(i); 102 | assertEquals(names.get(i), col.getName()); 103 | } 104 | p.close(); 105 | } 106 | 107 | public void testLongColumnName() throws Exception 108 | { 109 | StringBuilder sb = new StringBuilder(650); 110 | 111 | sb.append("COLUMN"); 112 | 113 | for (int i = 0; i < 600; ++i) { 114 | sb.append((char) ('0' + i%10)); 115 | } 116 | final String COLUMN = sb.toString(); 117 | sb.append("\nabc\n"); 118 | final String CSV = sb.toString(); 119 | 120 | // Ok, then, first let's try reading columns: 121 | 122 | CsvMapper mapper = mapperForCsv(); 123 | mapper.disable(CsvParser.Feature.WRAP_AS_ARRAY); 124 | CsvSchema schema = CsvSchema.emptySchema().withHeader(); 125 | CsvParser p = (CsvParser) mapper.getFactory().createParser(CSV); 126 | p.setSchema(schema); 127 | // need to read something to ensure header line is processed 128 | assertEquals(JsonToken.START_OBJECT, p.nextToken()); 129 | CsvSchema actual = p.getSchema(); 130 | 131 | assertEquals(1, actual.size()); 132 | assertEquals(COLUMN, actual.columnName(0)); 133 | p.close(); 134 | } 135 | 136 | /* 137 | /********************************************************************** 138 | /* Test methods, fail 139 | /********************************************************************** 140 | */ 141 | 142 | public void testInvalidMissingHeader() throws Exception 143 | { 144 | CsvMapper mapper = mapperForCsv(); 145 | try { 146 | mapper.readerFor(Entry.class).with(CsvSchema.emptySchema().withHeader()).readValue(" \nJoseph,57,false"); 147 | fail("Should have failed with exception"); 148 | } catch (Exception e) { 149 | verifyException(e, "Empty header line"); 150 | } 151 | } 152 | 153 | } 154 | -------------------------------------------------------------------------------- /src/test/java/com/fasterxml/jackson/dataformat/csv/deser/TestParserWorkarounds.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.deser; 2 | 3 | import java.util.Map; 4 | 5 | import com.fasterxml.jackson.core.*; 6 | 7 | import com.fasterxml.jackson.databind.*; 8 | 9 | import com.fasterxml.jackson.dataformat.csv.CsvSchema; 10 | import com.fasterxml.jackson.dataformat.csv.ModuleTestBase; 11 | 12 | /** 13 | * Tests that verify that various minor workarounds 14 | * work as expected. 15 | */ 16 | public class TestParserWorkarounds extends ModuleTestBase 17 | { 18 | /** 19 | * Test for [#1]; in case we get an extra empty element, 20 | * we can just ignore it. 21 | */ 22 | public void testIgnoringOptionalTrailing() throws Exception 23 | { 24 | ObjectMapper mapper = mapperForCsv(); 25 | CsvSchema schema = CsvSchema.builder() 26 | .addColumn("first") 27 | .addColumn("second") 28 | .build(); 29 | 30 | MappingIterator> it = mapper.reader(schema).forType(Map.class).readValues( 31 | "a,b\nc,d,\ne,f, \nfoo,bar,x\n"); 32 | assertTrue(it.hasNext()); 33 | 34 | // first should have no problems anyway: 35 | Map result = it.nextValue(); 36 | assertEquals(2, result.size()); 37 | assertEquals("a", result.get("first")); 38 | assertEquals("b", result.get("second")); 39 | 40 | // but second and third should skip empty trailing values 41 | assertTrue(it.hasNextValue()); 42 | result = it.nextValue(); 43 | assertEquals(2, result.size()); 44 | assertEquals("c", result.get("first")); 45 | assertEquals("d", result.get("second")); 46 | 47 | assertTrue(it.hasNextValue()); 48 | result = it.nextValue(); 49 | assertEquals(2, result.size()); 50 | assertEquals("e", result.get("first")); 51 | assertEquals("f", result.get("second")); 52 | 53 | // but then the fourth row should give an error; last entry not empty 54 | assertTrue(it.hasNextValue()); 55 | try { 56 | result = it.nextValue(); 57 | fail("Expected an error"); 58 | } catch (JsonMappingException e) { 59 | verifyException(e, "Too many entries"); 60 | } 61 | it.close(); 62 | } 63 | 64 | // also ensure [databind-csv#1] also works appropriately for failing case 65 | public void testOptionalTrailFailing() throws Exception 66 | { 67 | ObjectMapper mapper = mapperForCsv(); 68 | CsvSchema schema = CsvSchema.builder() 69 | .addColumn("first") 70 | .addColumn("second") 71 | .build(); 72 | 73 | MappingIterator> it = mapper.reader(schema).forType(Map.class).readValues( 74 | "a,b,\nc,d,,,\n"); 75 | assertTrue(it.hasNext()); 76 | 77 | // first should have no problems with extra entry 78 | Map result = it.nextValue(); 79 | assertEquals(2, result.size()); 80 | assertEquals("a", result.get("first")); 81 | assertEquals("b", result.get("second")); 82 | 83 | // but second is problematic 84 | try { 85 | result = it.nextValue(); 86 | fail("Should have failed"); 87 | } catch (JsonProcessingException e) { 88 | verifyException(e, "Too many entries: expected at most 2"); 89 | } 90 | it.close(); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/test/java/com/fasterxml/jackson/dataformat/csv/deser/TrailingCommaTest.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.deser; 2 | 3 | import com.fasterxml.jackson.annotation.JsonPropertyOrder; 4 | import com.fasterxml.jackson.databind.JsonMappingException; 5 | import com.fasterxml.jackson.databind.MappingIterator; 6 | import com.fasterxml.jackson.dataformat.csv.CsvMapper; 7 | import com.fasterxml.jackson.dataformat.csv.CsvParser; 8 | import com.fasterxml.jackson.dataformat.csv.CsvSchema; 9 | import com.fasterxml.jackson.dataformat.csv.ModuleTestBase; 10 | 11 | public class TrailingCommaTest extends ModuleTestBase { 12 | final CsvMapper MAPPER = mapperForCsv(); 13 | 14 | @JsonPropertyOrder({ "a", "b" }) 15 | static class StringPair { 16 | public String a, b; 17 | } 18 | 19 | public void testDisallowTrailingComma() throws Exception 20 | { 21 | final String INPUT = "s,t\nd,e,\n"; 22 | final CsvSchema schema = MAPPER.schemaFor(StringPair.class); 23 | 24 | MappingIterator it = MAPPER.readerFor(StringPair.class) 25 | .with(schema) 26 | .without(CsvParser.Feature.ALLOW_TRAILING_COMMA) 27 | .readValues(INPUT); 28 | 29 | it.nextValue(); 30 | try { 31 | it.nextValue(); 32 | fail("Should not have passed"); 33 | } catch (JsonMappingException e) { 34 | verifyException(e, "Too many entries: expected at most 2 (value #2 (0 chars) \"\")"); 35 | } 36 | 37 | it.close(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/test/java/com/fasterxml/jackson/dataformat/csv/deser/UnwrappingWithCSVTest.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.deser; 2 | 3 | import com.fasterxml.jackson.annotation.JsonPropertyOrder; 4 | import com.fasterxml.jackson.annotation.JsonUnwrapped; 5 | import com.fasterxml.jackson.databind.ObjectMapper; 6 | import com.fasterxml.jackson.dataformat.csv.CsvMapper; 7 | import com.fasterxml.jackson.dataformat.csv.CsvSchema; 8 | import com.fasterxml.jackson.dataformat.csv.ModuleTestBase; 9 | 10 | // for #12 11 | public class UnwrappingWithCSVTest extends ModuleTestBase 12 | { 13 | @JsonPropertyOrder({"x", "y"}) 14 | final static class Location { 15 | public int x; 16 | public int y; 17 | 18 | public Location() { } 19 | public Location(int x, int y) { 20 | this.x = x; 21 | this.y = y; 22 | } 23 | } 24 | 25 | // IMPORTANT: ordering DOES matter here 26 | @JsonPropertyOrder({ "name", "location" }) 27 | static class Unwrapping { 28 | public String name; 29 | @JsonUnwrapped(prefix="loc.") 30 | public Location location; 31 | 32 | public Unwrapping() { } 33 | public Unwrapping(String str, int x, int y) { 34 | name = str; 35 | location = new Location(x, y); 36 | } 37 | } 38 | 39 | /* 40 | /********************************************************** 41 | /* Tests 42 | /********************************************************** 43 | */ 44 | 45 | /** 46 | * Simple test to verify that explicit schema mapping works fine 47 | * with unwrapped entities 48 | */ 49 | public void testSimpleUnwrappingRoundtrip() throws Exception 50 | { 51 | final String CSV = "Joe,15,27\n"; 52 | ObjectMapper mapper = mapperForCsv(); 53 | CsvSchema schema = CsvSchema.builder() 54 | .addColumn("name") 55 | .addColumn("loc.x") 56 | .addColumn("loc.y") 57 | .build(); 58 | Unwrapping wrapper = mapper.reader(schema).forType(Unwrapping.class).readValue(CSV); 59 | assertNotNull(wrapper); 60 | assertNotNull(wrapper.location); 61 | assertEquals(15, wrapper.location.x); 62 | assertEquals(27, wrapper.location.y); 63 | 64 | // should also write out the same way 65 | assertEquals(CSV, mapper.writer(schema).writeValueAsString(wrapper)); 66 | } 67 | 68 | 69 | /** 70 | * Another simple test, but this time auto-generating Schema from 71 | * POJO. 72 | */ 73 | /* NOTE: the problem here is that Unwrapped properties should be further 74 | * detected to find sub-properties -- but that information is not yet 75 | * available via BeanProperty/POJOPropertyBuilder. But it needs to be 76 | * made; and when this occurs, we can handle this case reasonably well. 77 | */ 78 | public void testSimpleWithAutoSchema() throws Exception 79 | { 80 | final String CSV = "Henry,28,12\n"; 81 | CsvMapper mapper = mapperForCsv(); 82 | CsvSchema schema = mapper.schemaFor(Unwrapping.class); 83 | 84 | Unwrapping wrapper = mapper.reader(schema).forType(Unwrapping.class).readValue(CSV); 85 | assertNotNull(wrapper); 86 | assertNotNull(wrapper.location); 87 | assertEquals(28, wrapper.location.x); 88 | assertEquals(12, wrapper.location.y); 89 | 90 | // should also write out the same way 91 | assertEquals(CSV, mapper.writer(schema).writeValueAsString(wrapper)); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/test/java/com/fasterxml/jackson/dataformat/csv/failing/MappingIteratorEnd119Test.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.failing; 2 | 3 | import com.fasterxml.jackson.databind.*; 4 | import com.fasterxml.jackson.dataformat.csv.*; 5 | 6 | public class MappingIteratorEnd119Test extends ModuleTestBase 7 | { 8 | // for [dataformat-csv#119] 9 | public void testDefaultSimpleQuotes() throws Exception 10 | { 11 | CsvMapper mapper = mapperForCsv(); 12 | mapper.disable(CsvParser.Feature.WRAP_AS_ARRAY); 13 | MappingIterator it = mapper.readerFor(String[].class) 14 | .readValues("\"te,st\""); 15 | assertTrue(it.hasNextValue()); 16 | String[] row = it.nextValue(); 17 | assertEquals(1, row.length); 18 | assertEquals("te,st", row[0]); 19 | 20 | assertFalse(it.hasNextValue()); 21 | assertFalse(it.hasNext()); 22 | 23 | it.close(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/test/java/com/fasterxml/jackson/dataformat/csv/failing/NullWriting116Test.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.failing; 2 | 3 | import java.io.StringWriter; 4 | 5 | import com.fasterxml.jackson.databind.*; 6 | 7 | import com.fasterxml.jackson.dataformat.csv.*; 8 | 9 | public class NullWriting116Test extends ModuleTestBase 10 | { 11 | private final CsvMapper csv = new CsvMapper(); 12 | 13 | // [dataformat#116] 14 | public void testWithObjectArray() throws Exception 15 | { 16 | CsvSchema schema = CsvSchema.builder() 17 | .addColumn("a", CsvSchema.ColumnType.NUMBER) 18 | .addColumn("b", CsvSchema.ColumnType.NUMBER) 19 | .setUseHeader(true) 20 | .build(); 21 | ObjectWriter writer = csv.writer(schema); 22 | StringWriter out = new StringWriter(); 23 | SequenceWriter sequence = writer.writeValues(out); 24 | 25 | sequence.write(new Object[]{ 1, 2 }); 26 | // sequence.write(new Object[]{ null, 2 }); 27 | sequence.write(new Object[]{ null, null }); 28 | sequence.write(new Object[]{ 1, null }); 29 | 30 | sequence.close(); 31 | 32 | //System.err.println("CSV:\n"+out); 33 | assertEquals("a,b\n" + 34 | "1,2\n" + 35 | // ",2\n" + 36 | ",\n" + 37 | "1,\n", out.toString()); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/test/java/com/fasterxml/jackson/dataformat/csv/failing/ParserQuotes19Test.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.failing; 2 | 3 | import com.fasterxml.jackson.annotation.JsonPropertyOrder; 4 | 5 | import com.fasterxml.jackson.dataformat.csv.*; 6 | 7 | // for [dataformat-csv#19] 8 | public class ParserQuotes19Test extends ModuleTestBase 9 | { 10 | @JsonPropertyOrder({"s1", "s2", "s3"}) 11 | protected static class ThreeString { 12 | public String s1, s2, s3; 13 | } 14 | 15 | /* 16 | /********************************************************************** 17 | /* Test methods 18 | /********************************************************************** 19 | */ 20 | 21 | // For #19: need to handle spaces outside quotes, even if not trimming? 22 | public void testSimpleQuotesWithSpaces() throws Exception 23 | { 24 | CsvMapper mapper = mapperForCsv(); 25 | CsvSchema schema = mapper.schemaFor(ThreeString.class); 26 | ThreeString result = mapper.reader(schema).forType(ThreeString.class).readValue( 27 | "\"abc\" , \"def\", \"gh\" \n"); 28 | 29 | // start by trailing space trimming (easiest one to work) 30 | assertEquals("abc", result.s1); 31 | // follow by leading space trimming 32 | assertEquals("def", result.s2); 33 | // and then both 34 | assertEquals("gh", result.s3); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/test/java/com/fasterxml/jackson/dataformat/csv/schema/PropertyOrder74Test.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.schema; 2 | 3 | import com.fasterxml.jackson.annotation.JsonPropertyOrder; 4 | 5 | import com.fasterxml.jackson.dataformat.csv.CsvMapper; 6 | import com.fasterxml.jackson.dataformat.csv.CsvSchema; 7 | import com.fasterxml.jackson.dataformat.csv.ModuleTestBase; 8 | 9 | // For [dataformat-csv#74]: problems applying default do-sort handling 10 | public class PropertyOrder74Test extends ModuleTestBase 11 | { 12 | static class Point { 13 | public int y; 14 | public int x; 15 | } 16 | 17 | @JsonPropertyOrder() 18 | public static class PointWithAnnotation extends Point {} 19 | 20 | private final CsvMapper MAPPER = new CsvMapper(); 21 | 22 | public void testSchemaWithOrdering() throws Exception 23 | { 24 | CsvSchema schema1 = MAPPER.schemaFor(Point.class); 25 | CsvSchema schema2 = MAPPER.schemaFor(PointWithAnnotation.class); 26 | 27 | assertEquals(schema1.size(), schema2.size()); 28 | assertEquals(schema1.column(0).getName(), schema2.column(0).getName()); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/test/java/com/fasterxml/jackson/dataformat/csv/schema/SchemaTest.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.schema; 2 | 3 | import java.util.*; 4 | 5 | import com.fasterxml.jackson.annotation.JsonPropertyOrder; 6 | import com.fasterxml.jackson.dataformat.csv.CsvMapper; 7 | import com.fasterxml.jackson.dataformat.csv.CsvSchema; 8 | import com.fasterxml.jackson.dataformat.csv.ModuleTestBase; 9 | import com.fasterxml.jackson.dataformat.csv.CsvSchema.Column; 10 | 11 | public class SchemaTest extends ModuleTestBase 12 | { 13 | @JsonPropertyOrder({ "a", "b", "c", "d" }) 14 | static class Mixed { 15 | public int a, b, c, d; 16 | } 17 | 18 | @JsonPropertyOrder({ "a", "b", "c" }) 19 | static class ArrayWrapper { 20 | public int[] a; 21 | public int b; 22 | public List c; 23 | } 24 | 25 | // for [dataformat-csv#74] 26 | static class Point { 27 | public int y; 28 | public int x; 29 | } 30 | 31 | @JsonPropertyOrder() 32 | public static class PointWithAnnotation extends Point {} 33 | 34 | // for [dataformat-csv#142] 35 | interface Named { 36 | public String getFirstName(); 37 | public String getLastName(); 38 | } 39 | 40 | static abstract class YZ { 41 | public abstract int getY(); 42 | public abstract int getZ(); 43 | } 44 | 45 | /* 46 | /********************************************************************** 47 | /* Test methods 48 | /********************************************************************** 49 | */ 50 | 51 | final CsvMapper MAPPER = mapperForCsv(); 52 | 53 | public void testUserWithTypedAutoSchema() throws Exception 54 | { 55 | CsvSchema schema = MAPPER.typedSchemaFor(FiveMinuteUser.class); 56 | assertEquals("[\"firstName\",\"lastName\",\"gender\",\"verified\",\"userImage\"]", 57 | schema.getColumnDesc()); 58 | assertEquals(5, schema.size()); 59 | Iterator it = schema.iterator(); 60 | CsvSchema.Column col; 61 | 62 | col = it.next(); 63 | assertEquals("firstName", col.getName()); 64 | assertEquals(CsvSchema.ColumnType.STRING, col.getType()); 65 | 66 | col = it.next(); 67 | assertEquals("lastName", col.getName()); 68 | assertEquals(CsvSchema.ColumnType.STRING, col.getType()); 69 | 70 | col = it.next(); 71 | assertEquals("gender", col.getName()); 72 | assertEquals(CsvSchema.ColumnType.NUMBER_OR_STRING, col.getType()); 73 | 74 | col = it.next(); 75 | assertEquals("verified", col.getName()); 76 | assertEquals(CsvSchema.ColumnType.BOOLEAN, col.getType()); 77 | 78 | col = it.next(); 79 | assertEquals("userImage", col.getName()); 80 | assertEquals(CsvSchema.ColumnType.STRING, col.getType()); 81 | assertFalse(it.hasNext()); 82 | 83 | // Then verify linkage 84 | _verifyLinks(schema); 85 | } 86 | 87 | public void testArrayWithTypedAutoSchema() throws Exception 88 | { 89 | CsvSchema schema = MAPPER.typedSchemaFor(ArrayWrapper.class); 90 | assertEquals("[\"a\",\"b\",\"c\"]", 91 | schema.getColumnDesc()); 92 | assertEquals(3, schema.size()); 93 | Iterator it = schema.iterator(); 94 | CsvSchema.Column col; 95 | 96 | col = it.next(); 97 | assertEquals("a", col.getName()); 98 | assertEquals(CsvSchema.ColumnType.ARRAY, col.getType()); 99 | col = it.next(); 100 | assertEquals("b", col.getName()); 101 | assertEquals(CsvSchema.ColumnType.NUMBER, col.getType()); 102 | col = it.next(); 103 | assertEquals("c", col.getName()); 104 | // List: 105 | assertEquals(CsvSchema.ColumnType.ARRAY, col.getType()); 106 | assertFalse(it.hasNext()); 107 | 108 | _verifyLinks(schema); 109 | } 110 | 111 | // for [dataformat-csv#42] 112 | public void testReorderByName() throws Exception 113 | { 114 | CsvMapper mapper = mapperForCsv(); 115 | CsvSchema schema = mapper.schemaFor(Mixed.class); 116 | assertEquals(aposToQuotes("['a','b','c','d']"), schema.getColumnDesc()); 117 | schema = schema.sortedBy("b", "c"); 118 | assertEquals(aposToQuotes("['b','c','a','d']"), schema.getColumnDesc()); 119 | 120 | _verifyLinks(schema); 121 | } 122 | 123 | // for [dataformat-csv#42] 124 | public void testReorderWithComparator() throws Exception 125 | { 126 | CsvSchema schema = MAPPER.schemaFor(Mixed.class); 127 | schema = schema.sortedBy(Collections.reverseOrder()); 128 | assertEquals(aposToQuotes("['d','c','b','a']"), schema.getColumnDesc()); 129 | 130 | _verifyLinks(schema); 131 | } 132 | 133 | private void _verifyLinks(CsvSchema schema) 134 | { 135 | List all = new ArrayList(); 136 | for (Column col : schema) { 137 | all.add(col); 138 | } 139 | 140 | Column prev = null; 141 | for (int i = all.size(); --i >= 0; ) { 142 | Column curr = all.get(i); 143 | assertSame(prev, curr.getNext()); 144 | prev = curr; 145 | } 146 | } 147 | 148 | // For [dataformat-csv#74]: problems applying default do-sort handling 149 | public void testSchemaWithOrdering() throws Exception 150 | { 151 | CsvSchema schema1 = MAPPER.schemaFor(Point.class); 152 | CsvSchema schema2 = MAPPER.schemaFor(PointWithAnnotation.class); 153 | 154 | assertEquals(schema1.size(), schema2.size()); 155 | assertEquals(schema1.column(0).getName(), schema2.column(0).getName()); 156 | } 157 | 158 | // For pull request 89 159 | public void testSchemaWithReordering() 160 | { 161 | // Checks flags are handled properly through builder, getters 162 | // and with* functions 163 | CsvSchema schemaWithReordering = CsvSchema.builder() 164 | .setUseHeader(true) 165 | .setReorderColumns(true) 166 | .build(); 167 | 168 | assertTrue(schemaWithReordering.reordersColumns()); 169 | CsvSchema schemaWithoutReordering = schemaWithReordering.withColumnReordering(false); 170 | assertFalse(schemaWithoutReordering.reordersColumns()); 171 | } 172 | 173 | // For [dataformat-csv#142]: append columns from POJOs 174 | public void testSchemaComposition() throws Exception 175 | { 176 | CsvSchema pointSchema = MAPPER.typedSchemaFor(Point.class); 177 | CsvSchema yzSchema = MAPPER.typedSchemaFor(YZ.class); 178 | CsvSchema namedSchema = MAPPER.typedSchemaFor(Named.class); 179 | 180 | // should only add `z` since there's already `y` 181 | CsvSchema schema = pointSchema; 182 | schema = schema.withColumnsFrom(yzSchema); 183 | // but then two name properties 184 | schema = schema.withColumnsFrom(namedSchema); 185 | 186 | assertEquals(5, schema.size()); 187 | Iterator it = schema.iterator(); 188 | assertEquals("x", it.next().getName()); 189 | assertEquals("y", it.next().getName()); 190 | assertEquals("z", it.next().getName()); 191 | assertEquals("firstName", it.next().getName()); 192 | assertEquals("lastName", it.next().getName()); 193 | 194 | // and try alternate way as well. 195 | CsvSchema.Builder builder = CsvSchema.builder(); 196 | builder.addColumnsFrom(yzSchema) 197 | .addColumnsFrom(namedSchema) 198 | .addColumnsFrom(pointSchema); 199 | schema = builder.build(); 200 | 201 | assertEquals(5, schema.size()); 202 | it = schema.iterator(); 203 | assertEquals("y", it.next().getName()); 204 | assertEquals("z", it.next().getName()); 205 | assertEquals("firstName", it.next().getName()); 206 | assertEquals("lastName", it.next().getName()); 207 | assertEquals("x", it.next().getName()); 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /src/test/java/com/fasterxml/jackson/dataformat/csv/ser/ArrayWriteTest.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.ser; 2 | 3 | import com.fasterxml.jackson.annotation.JsonPropertyOrder; 4 | 5 | import com.fasterxml.jackson.dataformat.csv.*; 6 | 7 | // Tests for verifying that it is possible to write "simple" arrays 8 | // (ones with scalar serializations) as CSV 9 | public class ArrayWriteTest extends ModuleTestBase 10 | { 11 | @JsonPropertyOrder({"id", "values", "extra"}) 12 | static class ValueEntry { 13 | public String id, extra; 14 | public int[] values; 15 | 16 | public ValueEntry(String id, String extra, int... v) { 17 | this.id = id; 18 | this.extra = extra; 19 | values = v; 20 | } 21 | } 22 | 23 | @JsonPropertyOrder({"a", "b", "c"}) 24 | static class Pojo90 { 25 | 26 | public String[] a = new String[]{"", "foo"}; 27 | 28 | public String[] b = new String[]{null, "bar"}; 29 | 30 | public String[] c = new String[]{"baz",null}; 31 | } 32 | 33 | /* 34 | /********************************************************************** 35 | /* Test methods 36 | /********************************************************************** 37 | */ 38 | 39 | private final CsvMapper MAPPER = mapperForCsv(); 40 | 41 | public void testSimpleExplicit() throws Exception 42 | { 43 | ValueEntry input = new ValueEntry("foo", "stuff", 1, 2, 3); 44 | String csv = MAPPER.writerWithSchemaFor(ValueEntry.class) 45 | .writeValueAsString(input) 46 | .trim(); 47 | assertEquals("foo,1;2;3,stuff", csv); 48 | } 49 | 50 | public void testSeparatorOverride() throws Exception 51 | { 52 | ValueEntry input = new ValueEntry("foo", "stuff", 1, 2, 3); 53 | String csv = MAPPER.writer(CsvSchema.builder() 54 | .addColumn("id") 55 | .addArrayColumn("values", " ") 56 | .addColumn("extra") 57 | .build()) 58 | .writeValueAsString(input) 59 | .trim(); 60 | // gets quoted due to white space 61 | assertEquals("foo,\"1 2 3\",stuff", csv); 62 | } 63 | 64 | public void testArraysWithNulls() throws Exception 65 | { 66 | Pojo90 value = new Pojo90(); 67 | String csvContent = MAPPER.writer(MAPPER.schemaFor(Pojo90.class) 68 | .withHeader()) 69 | .writeValueAsString(value); 70 | String[] lines = csvContent.split("\\n"); 71 | assertEquals(2, lines.length); 72 | assertEquals("a,b,c", lines[0]); 73 | assertEquals(";foo,;bar,baz;", lines[1]); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/test/java/com/fasterxml/jackson/dataformat/csv/ser/FilteringTest.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.ser; 2 | 3 | import java.io.*; 4 | import java.util.ArrayList; 5 | import java.util.HashSet; 6 | import java.util.List; 7 | 8 | import com.fasterxml.jackson.databind.*; 9 | import com.fasterxml.jackson.databind.introspect.Annotated; 10 | import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector; 11 | import com.fasterxml.jackson.databind.ser.FilterProvider; 12 | import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter; 13 | import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider; 14 | import com.fasterxml.jackson.dataformat.csv.*; 15 | 16 | @SuppressWarnings("serial") 17 | public class FilteringTest extends ModuleTestBase 18 | { 19 | static class Entity { 20 | public String name; 21 | public String unusedFieldBetween; 22 | public String description; 23 | public String unusedField; 24 | 25 | public Entity(String name, String description, String unusedField) { 26 | this.name = name; 27 | this.description = description; 28 | this.unusedField = unusedField; 29 | } 30 | } 31 | 32 | private final static String CSV_FILTER_NAME = "csvFilter"; 33 | 34 | static class CsvJacksonWriter { 35 | public void writeObjects(OutputStream outputStream, 36 | List objects, CsvSchema csvSchema ) throws IOException 37 | { 38 | HashSet columnNames = new HashSet(); 39 | for (CsvSchema.Column column : csvSchema) { 40 | columnNames.add( column.getName() ); 41 | } 42 | 43 | SimpleBeanPropertyFilter csvReponseFilter = 44 | new SimpleBeanPropertyFilter.FilterExceptFilter(columnNames); 45 | FilterProvider filterProvider = new SimpleFilterProvider().addFilter( CSV_FILTER_NAME, csvReponseFilter ); 46 | 47 | CsvMapper csvMapper = new CsvMapper(); 48 | csvMapper.setFilterProvider( filterProvider ); 49 | csvMapper.setAnnotationIntrospector(new CsvAnnotationIntrospector()); 50 | 51 | ObjectWriter objectWriter = csvMapper.writer(csvSchema); 52 | objectWriter.writeValue( outputStream, objects); 53 | } 54 | } 55 | 56 | static class CsvAnnotationIntrospector extends JacksonAnnotationIntrospector { 57 | @Override 58 | public Object findFilterId(Annotated a) { 59 | return CSV_FILTER_NAME; 60 | } 61 | } 62 | 63 | public void testWriteObjects() throws Exception { 64 | List entities = new ArrayList(); 65 | entities.add( new Entity("Test entity 1", "Test description 1", "Test unused field")); 66 | entities.add(new Entity("Test entity 2", "Test description 2", "Test unused field")); 67 | 68 | CsvSchema csvSchema = CsvSchema.builder() 69 | .addColumn("name") 70 | .addColumn("description") 71 | .setUseHeader( true ) 72 | .build() 73 | .withLineSeparator("\r\n"); 74 | 75 | CsvJacksonWriter csvWriter = new CsvJacksonWriter(); 76 | ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 77 | csvWriter.writeObjects(outputStream, entities, csvSchema); 78 | 79 | StringBuffer expectedResults = new StringBuffer(); 80 | expectedResults.append( "name,description\r\n" ); 81 | expectedResults.append( "\"Test entity 1\",\"Test description 1\"\r\n" ); 82 | expectedResults.append( "\"Test entity 2\",\"Test description 2\"\r\n"); 83 | 84 | assertEquals( expectedResults.toString(), outputStream.toString() ); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/test/java/com/fasterxml/jackson/dataformat/csv/ser/GeneratorIgnoreUnknownTest.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.ser; 2 | 3 | import java.util.*; 4 | 5 | import com.fasterxml.jackson.annotation.JsonPropertyOrder; 6 | import com.fasterxml.jackson.core.JsonGenerator; 7 | import com.fasterxml.jackson.databind.*; 8 | import com.fasterxml.jackson.dataformat.csv.CsvSchema; 9 | import com.fasterxml.jackson.dataformat.csv.ModuleTestBase; 10 | 11 | public class GeneratorIgnoreUnknownTest extends ModuleTestBase 12 | { 13 | @JsonPropertyOrder({ "x", "y", "z" }) 14 | public static class Point { 15 | public int x; 16 | public Integer y; 17 | public Integer z = 8; 18 | } 19 | 20 | @JsonPropertyOrder({ "x", "extra", "y" }) 21 | public static class PointAndExtra { 22 | public int x = 1, y = 2; 23 | public Point extra = new Point(); 24 | } 25 | 26 | @JsonPropertyOrder({ "x", "stuff", "y" }) 27 | public static class PointAndStuff { 28 | public int x = 1, y = 2; 29 | public Object stuff; 30 | 31 | public PointAndStuff(Object s) { stuff = s; } 32 | } 33 | 34 | // for [dataformat-csv#104] 35 | @JsonPropertyOrder({ "x", "points", "y" }) 36 | public static class PointAndArray { 37 | public int x = 1, y = 2; 38 | 39 | public List points = new ArrayList(); 40 | { 41 | points.add(new Point()); 42 | points.add(new Point()); 43 | } 44 | 45 | protected PointAndArray() { } 46 | protected PointAndArray(int x, int y) { 47 | this.x = x; 48 | this.y = y; 49 | } 50 | } 51 | 52 | /* 53 | /********************************************************** 54 | /* Test methods 55 | /********************************************************** 56 | */ 57 | 58 | public void testSimpleIgnore() throws Exception 59 | { 60 | ObjectMapper mapper = mapperForCsv(); 61 | final CsvSchema schema = CsvSchema.builder() 62 | .addColumn("x") 63 | .addColumn("z") 64 | .build(); 65 | ObjectWriter writer = mapper.writerFor(Point.class) 66 | .with(schema) 67 | .with(JsonGenerator.Feature.IGNORE_UNKNOWN); 68 | String csv = writer.writeValueAsString(new Point()); 69 | assertNotNull(csv); 70 | } 71 | 72 | // Also verify that it is possible to ignore more complex object output too 73 | public void testIgnorePOJO() throws Exception 74 | { 75 | ObjectMapper mapper = mapperForCsv(); 76 | final CsvSchema schema = CsvSchema.builder() 77 | .addColumn("x") 78 | .addColumn("y") 79 | .build(); 80 | ObjectWriter writer = mapper.writerFor(PointAndExtra.class) 81 | .with(schema) 82 | .with(JsonGenerator.Feature.IGNORE_UNKNOWN); 83 | String csv = writer.writeValueAsString(new PointAndExtra()); 84 | assertNotNull(csv); 85 | assertEquals("1,2\n", csv); 86 | } 87 | 88 | public void testIgnoreObject() throws Exception 89 | { 90 | ObjectMapper mapper = mapperForCsv(); 91 | final CsvSchema schema = CsvSchema.builder() 92 | .addColumn("x") 93 | .addColumn("y") 94 | .build(); 95 | ObjectWriter writer = mapper.writerFor(PointAndStuff.class) 96 | .with(schema) 97 | .with(JsonGenerator.Feature.IGNORE_UNKNOWN); 98 | 99 | List l = Arrays.asList("a", "b"); 100 | String csv = writer.writeValueAsString(new PointAndStuff(l)); 101 | assertNotNull(csv); 102 | assertEquals("1,2\n", csv); 103 | 104 | Map m = new HashMap(); 105 | m.put("foo", "bar"); 106 | csv = writer.writeValueAsString(new PointAndStuff(m)); 107 | assertNotNull(csv); 108 | assertEquals("1,2\n", csv); 109 | } 110 | 111 | // for [dataformat-csv#104] 112 | public void testIgnoreNested() throws Exception 113 | { 114 | ObjectMapper mapper = mapperForCsv(); 115 | final CsvSchema schema = CsvSchema.builder() 116 | .addColumn("x") 117 | .addColumn("y") 118 | .build(); 119 | ObjectWriter writer = mapper.writerFor(PointAndArray.class) 120 | .with(schema) 121 | .with(JsonGenerator.Feature.IGNORE_UNKNOWN); 122 | 123 | String csv = writer.writeValueAsString(new PointAndArray(3,5)); 124 | 125 | //System.err. println("CSV:\n"+csv); 126 | 127 | assertNotNull(csv); 128 | assertEquals("3,5\n", csv); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/test/java/com/fasterxml/jackson/dataformat/csv/ser/HeaderWriteTest.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.ser; 2 | 3 | import java.io.IOException; 4 | import java.io.StringWriter; 5 | import java.util.Arrays; 6 | import java.util.List; 7 | 8 | import com.fasterxml.jackson.databind.SequenceWriter; 9 | import com.fasterxml.jackson.dataformat.csv.*; 10 | 11 | // Tests for verifying that headers are emitted 12 | public class HeaderWriteTest extends ModuleTestBase 13 | { 14 | /* 15 | /********************************************************************** 16 | /* Test methods 17 | /********************************************************************** 18 | */ 19 | 20 | private final CsvMapper MAPPER = mapperForCsv(); 21 | 22 | public void testNoLines() throws Exception 23 | { 24 | List headers = Arrays.asList("TestHeader1", "TestHeader2"); 25 | List> dataSource = Arrays.asList(); 26 | String result = runTest(headers, dataSource); 27 | 28 | assertEquals("Headers should have been written even with no other data", "TestHeader1,TestHeader2\n", result); 29 | } 30 | 31 | public void testOneLine() throws Exception 32 | { 33 | List headers = Arrays.asList("TestHeader1", "TestHeader2"); 34 | List> dataSource = Arrays.asList(Arrays.asList("TestValue1", "TestValue2")); 35 | String result = runTest(headers, dataSource); 36 | 37 | assertEquals("Headers should have been written before line", "TestHeader1,TestHeader2\nTestValue1,TestValue2\n", result); 38 | } 39 | 40 | private String runTest(List headers, List> dataSource) throws IOException 41 | { 42 | StringWriter writer = new StringWriter(); 43 | 44 | CsvSchema.Builder builder = CsvSchema.builder(); 45 | for (String nextHeader : headers) { 46 | builder = builder.addColumn(nextHeader); 47 | } 48 | 49 | CsvSchema schema = builder.setUseHeader(true).build(); 50 | try (SequenceWriter csvWriter = MAPPER.writerWithDefaultPrettyPrinter() 51 | .with(schema) 52 | .forType(List.class) 53 | .writeValues(writer);) { 54 | for(List nextRow : dataSource) { 55 | csvWriter.write(nextRow); 56 | } 57 | } 58 | 59 | return writer.toString(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/test/java/com/fasterxml/jackson/dataformat/csv/ser/JDKSerializationTest.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.ser; 2 | 3 | import java.io.*; 4 | 5 | import com.fasterxml.jackson.annotation.JsonPropertyOrder; 6 | import com.fasterxml.jackson.dataformat.csv.CsvMapper; 7 | import com.fasterxml.jackson.dataformat.csv.CsvSchema; 8 | import com.fasterxml.jackson.dataformat.csv.ModuleTestBase; 9 | 10 | /** 11 | * Tests to verify that most core Jackson components can be serialized 12 | * using default JDK serialization: this feature is useful for some 13 | * platforms, such as Android, where memory management is handled 14 | * much more aggressively. 15 | */ 16 | public class JDKSerializationTest extends ModuleTestBase 17 | { 18 | @JsonPropertyOrder({ "x", "y" }) 19 | static class MyPojo { 20 | public int x; 21 | protected int y; 22 | 23 | public MyPojo() { } 24 | public MyPojo(int x0, int y0) { 25 | x = x0; 26 | y = y0; 27 | } 28 | 29 | public int getY() { return y; } 30 | public void setY(int y) { this.y = y; } 31 | } 32 | 33 | static class MyPojo2 extends MyPojo { } 34 | 35 | /* 36 | /********************************************************** 37 | /* Tests for individual objects 38 | /********************************************************** 39 | */ 40 | 41 | // Let's not use the shared instance, but local one here. 42 | private final CsvMapper MAPPER = mapperForCsv(); 43 | 44 | private final CsvSchema SCHEMA_POJO = MAPPER.schemaFor(MyPojo.class); 45 | 46 | public void testSchema() throws IOException 47 | { 48 | byte[] ser = jdkSerialize(SCHEMA_POJO); 49 | CsvSchema out = (CsvSchema) jdkDeserialize(ser); 50 | assertNotNull(out); 51 | } 52 | 53 | public void testObjectMapper() throws IOException 54 | { 55 | final String EXP_CSV = "2,3"; 56 | final MyPojo p = new MyPojo(2, 3); 57 | assertEquals(EXP_CSV, MAPPER.writerFor(MyPojo.class) 58 | .with(SCHEMA_POJO).writeValueAsString(p).trim()); 59 | 60 | byte[] bytes = jdkSerialize(MAPPER); 61 | CsvMapper mapper2 = jdkDeserialize(bytes); 62 | 63 | assertEquals(EXP_CSV, mapper2.writerFor(MyPojo.class) 64 | .with(SCHEMA_POJO).writeValueAsString(p).trim()); 65 | MyPojo p2 = mapper2.readerFor(MyPojo.class).with(SCHEMA_POJO).readValue(EXP_CSV); 66 | assertEquals(p.x, p2.x); 67 | assertEquals(p.y, p2.y); 68 | 69 | // and just to be sure, try something different... 70 | String csv = mapper2.writerFor(MyPojo2.class) 71 | .with(mapper2.schemaFor(MyPojo2.class)) 72 | .writeValueAsString(new MyPojo2()); 73 | assertNotNull(csv); 74 | } 75 | 76 | /* 77 | /********************************************************** 78 | /* Helper methods 79 | /********************************************************** 80 | */ 81 | 82 | protected byte[] jdkSerialize(Object o) throws IOException 83 | { 84 | ByteArrayOutputStream bytes = new ByteArrayOutputStream(1000); 85 | ObjectOutputStream obOut = new ObjectOutputStream(bytes); 86 | obOut.writeObject(o); 87 | obOut.close(); 88 | return bytes.toByteArray(); 89 | } 90 | 91 | @SuppressWarnings("unchecked") 92 | protected T jdkDeserialize(byte[] raw) throws IOException 93 | { 94 | ObjectInputStream objIn = new ObjectInputStream(new ByteArrayInputStream(raw)); 95 | try { 96 | return (T) objIn.readObject(); 97 | } catch (ClassNotFoundException e) { 98 | fail("Missing class: "+e.getMessage()); 99 | return null; 100 | } finally { 101 | objIn.close(); 102 | } 103 | } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /src/test/java/com/fasterxml/jackson/dataformat/csv/ser/MultipleWritesTest.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.ser; 2 | 3 | import java.io.*; 4 | import java.util.*; 5 | 6 | import com.fasterxml.jackson.core.JsonGenerator; 7 | import com.fasterxml.jackson.databind.*; 8 | import com.fasterxml.jackson.dataformat.csv.CsvMapper; 9 | import com.fasterxml.jackson.dataformat.csv.CsvSchema; 10 | import com.fasterxml.jackson.dataformat.csv.ModuleTestBase; 11 | 12 | public class MultipleWritesTest extends ModuleTestBase 13 | { 14 | private final CsvMapper MAPPER = mapperForCsv(); 15 | 16 | /** 17 | * To reproduce [dataformat-csv#71]: Although ideally one uses 18 | * `ObjectWriter.writeValues()` for sequences, we should not 19 | * write headers more than once regardless, as long as target 20 | * is CsvGenerator which tracks state. 21 | */ 22 | public void testMultipleListWrites() throws Exception 23 | { 24 | StringWriter sw = new StringWriter(); 25 | 26 | CsvSchema.Builder builder = CsvSchema.builder(); 27 | builder.addColumn("col1"); 28 | builder.addColumn("col2"); 29 | 30 | CsvSchema csvSchema = builder.build().withHeader(); 31 | 32 | JsonGenerator gen = MAPPER.getFactory().createGenerator(sw); 33 | 34 | ObjectWriter csvWriter = MAPPER.writer(csvSchema); 35 | 36 | List line1 = new ArrayList(); 37 | line1.add("line1-val1"); 38 | line1.add("line1-val2"); 39 | 40 | csvWriter.writeValue(gen, line1); 41 | 42 | List line2 = new ArrayList(); 43 | line2.add("line2-val1"); 44 | line2.add("line2-val2"); 45 | 46 | csvWriter.writeValue(gen, line2); 47 | 48 | gen.close(); 49 | 50 | String csv = sw.toString().trim(); 51 | // may get different linefeed on different OSes? 52 | csv = csv.replaceAll("[\\r\\n]", "/"); 53 | 54 | assertEquals("col1,col2/line1-val1,line1-val2/line2-val1,line2-val2", csv); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/test/java/com/fasterxml/jackson/dataformat/csv/ser/NullWritingTest.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.ser; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.StringWriter; 5 | import java.util.Arrays; 6 | import java.util.List; 7 | 8 | import com.fasterxml.jackson.databind.*; 9 | import com.fasterxml.jackson.dataformat.csv.*; 10 | 11 | // for [dataformat-csv#69], other null value serialization 12 | public class NullWritingTest extends ModuleTestBase 13 | { 14 | public static class Nullable { 15 | public String a, b, c, d; 16 | } 17 | 18 | private final CsvMapper csv = new CsvMapper(); 19 | 20 | public void testObjectWithNullMembersToString() throws Exception { 21 | CsvSchema schema = csv.schemaFor(Nullable.class).withUseHeader(true); 22 | ObjectWriter writer = csv.writer(schema); 23 | String nullMembers = writer.writeValueAsString(new Nullable()); 24 | assertEquals("a,b,c,d\n,,,\n", nullMembers); 25 | } 26 | 27 | public void testNullToString() throws Exception { 28 | CsvSchema schema = csv.schemaFor(Nullable.class).withUseHeader(true); 29 | ObjectWriter writer = csv.writer(schema); 30 | String nullObject = writer.writeValueAsString(null); 31 | assertEquals("a,b,c,d\n", nullObject); 32 | } 33 | 34 | public void testObjectWithNullMembersToStream() throws Exception { 35 | CsvSchema schema = csv.schemaFor(Nullable.class).withUseHeader(true); 36 | ObjectWriter writer = csv.writer(schema); 37 | 38 | // Write an object with null members 39 | ByteArrayOutputStream stream = new ByteArrayOutputStream(); 40 | SequenceWriter writeValues = writer.writeValues(stream); 41 | writeValues.write(new Nullable()); 42 | writeValues.write(new Nullable()); 43 | writeValues.flush(); 44 | String nullMembers = stream.toString("UTF-8"); 45 | assertEquals("a,b,c,d\n,,,\n,,,\n", nullMembers); 46 | writeValues.close(); 47 | } 48 | 49 | public void testNullToStream() throws Exception { 50 | CsvSchema schema = csv.schemaFor(Nullable.class).withUseHeader(true); 51 | ObjectWriter writer = csv.writer(schema); 52 | 53 | // Write a null value 54 | StringWriter sw = new StringWriter(); 55 | SequenceWriter writeValues = writer.writeValues(sw); 56 | writeValues.write(null); 57 | writeValues.write(null); 58 | writeValues.flush(); 59 | String nullObject = sw.toString(); 60 | /* 11-Feb-2015, tatu: Two ways to go; either nulls get ignored, or they trigger serialization of 61 | * empty Object. For now, former occurs: 62 | */ 63 | 64 | assertEquals("a,b,c,d\n", nullObject); 65 | // assertEquals("a,b,c,d\n\n\n", nullObject); 66 | writeValues.close(); 67 | } 68 | 69 | // [dataformat-csv#53] 70 | public void testCustomNullValue() throws Exception 71 | { 72 | ObjectMapper mapper = mapperForCsv(); 73 | CsvSchema schema = CsvSchema.builder() 74 | .setNullValue("n/a") 75 | .addColumn("id") 76 | .addColumn("desc") 77 | .build(); 78 | 79 | String result = mapper.writer(schema).writeValueAsString(new IdDesc("id", null)); 80 | // MUST use doubling for quotes! 81 | assertEquals("id,n/a\n", result); 82 | } 83 | 84 | public void testNullFieldsOfListsContainedByMainLevelListIssue106() throws Exception 85 | { 86 | CsvMapper mapper = mapperForCsv(); 87 | CsvSchema schema = CsvSchema.builder().build(); 88 | 89 | List row1 = Arrays.asList("d0", null, "d2"); 90 | List row2 = Arrays.asList(null, "d1", "d2"); 91 | List row3 = Arrays.asList("d0", "d1", null); 92 | 93 | List> dataList = Arrays.asList(row1, row2, row3); 94 | 95 | String result = mapper.writer(schema).writeValueAsString(dataList); 96 | assertEquals("d0,,d2\n,d1,d2\nd0,d1,\n", result); 97 | 98 | schema = schema.withNullValue("n/a"); 99 | result = mapper.writer(schema).writeValueAsString(dataList); 100 | assertEquals("d0,n/a,d2\nn/a,d1,d2\nd0,d1,n/a\n", result); 101 | } 102 | 103 | public void testNullElementsOfMainLevelListIssue106() throws Exception 104 | { 105 | CsvMapper mapper = mapperForCsv(); 106 | CsvSchema schema = CsvSchema.builder().build(); 107 | 108 | List row1 = Arrays.asList("d0", null, "d2"); 109 | List row2 = Arrays.asList(null, "d1", "d2"); 110 | List row3 = Arrays.asList("d0", "d1", null); 111 | 112 | // when serialized, the added root level nulls at index 1 and 3 113 | // should be absent from the output 114 | List> dataList = Arrays.asList(row1, null, row2, null, row3); 115 | 116 | String result = mapper.writer(schema).writeValueAsString(dataList); 117 | assertEquals("d0,,d2\n,d1,d2\nd0,d1,\n", result); 118 | 119 | schema = schema.withNullValue("n/a"); 120 | result = mapper.writer(schema).writeValueAsString(dataList); 121 | assertEquals("d0,n/a,d2\nn/a,d1,d2\nd0,d1,n/a\n", result); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/test/java/com/fasterxml/jackson/dataformat/csv/ser/SchemaReorderTest.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.ser; 2 | 3 | import java.util.Arrays; 4 | 5 | import com.fasterxml.jackson.dataformat.csv.CsvMapper; 6 | import com.fasterxml.jackson.dataformat.csv.CsvSchema; 7 | import com.fasterxml.jackson.dataformat.csv.ModuleTestBase; 8 | 9 | public class SchemaReorderTest extends ModuleTestBase 10 | { 11 | // should work ok since CsvMapper forces alphabetic ordering as default: 12 | static class Reordered { 13 | public int a, b, c, d; 14 | } 15 | 16 | private final CsvMapper MAPPER = new CsvMapper(); 17 | 18 | public void testSchemaWithOrdering() throws Exception 19 | { 20 | CsvSchema schema = MAPPER.schemaFor(Reordered.class); 21 | assertEquals(aposToQuotes("['a','b','c','d']"), schema.getColumnDesc()); 22 | schema = schema.sortedBy("b", "c"); 23 | assertEquals(aposToQuotes("['b','c','a','d']"), schema.getColumnDesc()); 24 | 25 | Reordered value = new Reordered(); 26 | value.a = 1; 27 | value.b = 2; 28 | value.c = 3; 29 | value.d = 4; 30 | 31 | schema = schema.withHeader(); 32 | String csv = MAPPER.writer(schema).writeValueAsString(Arrays.asList(value)); 33 | assertEquals("b,c,a,d\n2,3,1,4\n", csv); 34 | 35 | // _verifyLinks(schema); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/com/fasterxml/jackson/dataformat/csv/ser/TestGeneratorNoSchema.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.ser; 2 | 3 | import java.io.*; 4 | 5 | import com.fasterxml.jackson.databind.ObjectWriter; 6 | import com.fasterxml.jackson.dataformat.csv.CsvGenerator; 7 | import com.fasterxml.jackson.dataformat.csv.CsvMapper; 8 | import com.fasterxml.jackson.dataformat.csv.CsvSchema; 9 | import com.fasterxml.jackson.dataformat.csv.ModuleTestBase; 10 | 11 | public class TestGeneratorNoSchema extends ModuleTestBase 12 | { 13 | private final CsvSchema SCHEMA = CsvSchema.emptySchema() 14 | .withoutHeader() 15 | .withEscapeChar('\\') 16 | .withQuoteChar('"') 17 | .withColumnSeparator(';') 18 | .withLineSeparator("\r\n") 19 | ; 20 | 21 | private final CsvMapper MAPPER = mapperForCsv(); 22 | 23 | public void testUntypedAsSequenceStreaming() throws Exception 24 | { 25 | StringWriter sw = new StringWriter(); 26 | CsvGenerator gen = MAPPER.getFactory().createGenerator(sw); 27 | gen.setSchema(SCHEMA); 28 | 29 | assertEquals(0, gen.getOutputBuffered()); 30 | 31 | gen.writeStartArray(); 32 | gen.writeString("foo"); 33 | 34 | // this will be buffered because we output in correct order, so: 35 | assertEquals(3, gen.getOutputBuffered()); 36 | 37 | gen.writeNumber(1234567890L); 38 | gen.writeBoolean(true); 39 | gen.writeEndArray(); 40 | 41 | gen.writeStartArray(); 42 | gen.writeString("bar"); 43 | gen.writeNumber(-1250000000000L); 44 | gen.writeBoolean(false); 45 | gen.writeEndArray(); 46 | 47 | gen.close(); 48 | assertEquals(0, gen.getOutputBuffered()); 49 | 50 | String csv = sw.toString(); 51 | 52 | assertEquals("foo;1234567890;true\r\n" 53 | +"bar;-1250000000000;false\r\n", 54 | csv); 55 | } 56 | 57 | public void testUntypedAsSequenceDatabind() throws Exception 58 | { 59 | ObjectWriter writer = MAPPER.writer(SCHEMA); 60 | 61 | String csv = writer.writeValueAsString(new Object[] { 62 | new Object[] { "foo", 13, true }, 63 | new Object[] { "bar", 28, false } 64 | }); 65 | assertEquals("foo;13;true\r\n" 66 | +"bar;28;false\r\n", 67 | csv); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/test/java/com/fasterxml/jackson/dataformat/csv/ser/TestGeneratorWithCustomSeparators.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.ser; 2 | 3 | import com.fasterxml.jackson.dataformat.csv.CsvMapper; 4 | import com.fasterxml.jackson.dataformat.csv.CsvSchema; 5 | import com.fasterxml.jackson.dataformat.csv.ModuleTestBase; 6 | 7 | public class TestGeneratorWithCustomSeparators extends ModuleTestBase 8 | { 9 | // #17 10 | public void testOtherSeparator() throws Exception 11 | { 12 | CsvMapper mapper = mapperForCsv(); 13 | CsvSchema schema = mapper.schemaFor(FiveMinuteUser.class).withoutHeader().withColumnSeparator(';'); 14 | FiveMinuteUser user = new FiveMinuteUser("Barbie", "Benton", false, Gender.FEMALE, null); 15 | String result = mapper.writer(schema).writeValueAsString(user); 16 | assertEquals("Barbie;Benton;FEMALE;false;\n", result); 17 | } 18 | 19 | public void testTSV() throws Exception 20 | { 21 | CsvMapper mapper = mapperForCsv(); 22 | CsvSchema schema = mapper.schemaFor(FiveMinuteUser.class).withoutHeader().withColumnSeparator('\t'); 23 | FiveMinuteUser user = new FiveMinuteUser("Barbie", "Benton", false, Gender.FEMALE, null); 24 | String result = mapper.writer(schema).writeValueAsString(user); 25 | assertEquals("Barbie\tBenton\tFEMALE\tfalse\t\n", result); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/com/fasterxml/jackson/dataformat/csv/ser/TestGeneratorWithSequences.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.ser; 2 | 3 | import java.util.*; 4 | 5 | import com.fasterxml.jackson.annotation.JsonPropertyOrder; 6 | import com.fasterxml.jackson.dataformat.csv.CsvMapper; 7 | import com.fasterxml.jackson.dataformat.csv.CsvSchema; 8 | import com.fasterxml.jackson.dataformat.csv.ModuleTestBase; 9 | 10 | public class TestGeneratorWithSequences extends ModuleTestBase 11 | { 12 | @JsonPropertyOrder({"x", "y"}) 13 | protected static class Entry { 14 | public int x, y; 15 | 16 | public Entry() { } 17 | public Entry(int x, int y) { 18 | this.x = x; 19 | this.y = y; 20 | } 21 | } 22 | 23 | /* 24 | /********************************************************************** 25 | /* Test methods 26 | /********************************************************************** 27 | */ 28 | 29 | /** 30 | * Verify that we should be able to just serialize sequences as is 31 | * because any "array" markers are all but ignored by generator. 32 | */ 33 | public void testAsSequence() throws Exception 34 | { 35 | CsvMapper mapper = mapperForCsv(); 36 | List entries = new ArrayList(); 37 | entries.add(new Entry(1, 2)); 38 | entries.add(new Entry(7, 8)); 39 | CsvSchema schema = mapper.schemaFor(Entry.class) 40 | .withLineSeparator("\n"); 41 | String csv = mapper.writer(schema) 42 | .writeValueAsString(entries); 43 | assertEquals("1,2\n7,8\n", csv); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/test/java/com/fasterxml/jackson/dataformat/csv/ser/TestWriterWithMissingValues.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.ser; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | import com.fasterxml.jackson.databind.ObjectWriter; 5 | 6 | import com.fasterxml.jackson.dataformat.csv.*; 7 | 8 | import com.google.common.collect.ImmutableMap; 9 | 10 | import org.junit.Test; 11 | 12 | import java.lang.String; 13 | 14 | // [Issue#33] 15 | public class TestWriterWithMissingValues extends ModuleTestBase 16 | { 17 | private final CsvSchema SCHEMA = new CsvSchema.Builder() 18 | .addColumn("timestamp", CsvSchema.ColumnType.STRING) 19 | .addColumn("value", CsvSchema.ColumnType.NUMBER) 20 | .addColumn("id", CsvSchema.ColumnType.STRING) 21 | .build(); 22 | final ObjectWriter WRITER = new CsvMapper().writer().with(SCHEMA); 23 | 24 | @Test 25 | public void testWrite_NoNulls() throws JsonProcessingException { 26 | final String csv = WRITER.writeValueAsString( 27 | ImmutableMap.of("timestamp", "2014-03-10T23:32:47+00:00", 28 | "value", 42, "id", "hello")); 29 | 30 | assertEquals("\"2014-03-10T23:32:47+00:00\",42,hello\n", csv); 31 | } 32 | 33 | @Test 34 | public void testWrite_NullFirstColumn() throws JsonProcessingException { 35 | final String csv = WRITER.writeValueAsString( 36 | ImmutableMap.of("value", 42, "id", "hello")); 37 | assertEquals(",42,hello\n", csv); 38 | } 39 | 40 | @Test 41 | public void testWrite_NullSecondColumn() throws JsonProcessingException { 42 | final String csv = WRITER.writeValueAsString( 43 | ImmutableMap.of("timestamp", "2014-03-10T23:32:47+00:00", 44 | "id", "hello")); 45 | 46 | assertEquals("\"2014-03-10T23:32:47+00:00\",,hello\n", csv); 47 | } 48 | 49 | @Test 50 | public void testWrite_NullThirdColumn() throws JsonProcessingException 51 | { 52 | CsvMapper mapper = new CsvMapper(); 53 | assertFalse(mapper.getFactory().isEnabled(CsvGenerator.Feature.OMIT_MISSING_TAIL_COLUMNS)); 54 | String csv = mapper.writer(SCHEMA).writeValueAsString( 55 | ImmutableMap.of("timestamp", "2014-03-10T23:32:47+00:00", 56 | "value", 42)); 57 | 58 | assertEquals("\"2014-03-10T23:32:47+00:00\",42,\n", csv); 59 | mapper.getFactory().enable(CsvGenerator.Feature.OMIT_MISSING_TAIL_COLUMNS); 60 | csv = mapper.writer(SCHEMA).writeValueAsString( 61 | ImmutableMap.of("timestamp", "2014-03-10T23:32:47+00:00", 62 | "value", 42)); 63 | assertEquals("\"2014-03-10T23:32:47+00:00\",42\n", csv); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/test/java/com/fasterxml/jackson/dataformat/csv/ser/TestWriterWithSomeMoreMissingValues.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.ser; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | 5 | import com.fasterxml.jackson.databind.ObjectWriter; 6 | import com.fasterxml.jackson.dataformat.csv.CsvMapper; 7 | import com.fasterxml.jackson.dataformat.csv.CsvSchema; 8 | import com.fasterxml.jackson.dataformat.csv.ModuleTestBase; 9 | 10 | import com.google.common.collect.ImmutableMap; 11 | 12 | public class TestWriterWithSomeMoreMissingValues extends ModuleTestBase { 13 | 14 | public void testWithAStringAndAUuid() throws JsonProcessingException { 15 | final CsvSchema schema = new CsvSchema.Builder() 16 | .addColumn("string1", CsvSchema.ColumnType.STRING) 17 | .addColumn("string2", CsvSchema.ColumnType.STRING) 18 | .build(); 19 | final ObjectWriter writer = new CsvMapper().writer().with(schema); 20 | 21 | final ImmutableMap.Builder builder = new ImmutableMap.Builder(); 22 | builder.put("string1", "hello"); 23 | builder.put("string2", "2a36b911-9699-45d2-abd5-b9f2d2c9c4a3"); 24 | 25 | final String csv = writer.writeValueAsString(builder.build()); 26 | 27 | assertEquals("hello,\"2a36b911-9699-45d2-abd5-b9f2d2c9c4a3\"\n", csv); 28 | } 29 | 30 | public void testWithTwoStringsAndAUuid() throws JsonProcessingException { 31 | 32 | final CsvSchema schema = new CsvSchema.Builder() 33 | .addColumn("string1", CsvSchema.ColumnType.STRING) 34 | .addColumn("string2", CsvSchema.ColumnType.STRING) 35 | .addColumn("string3", CsvSchema.ColumnType.STRING) 36 | .build(); 37 | final ObjectWriter writer = new CsvMapper().writer().with(schema); 38 | 39 | final ImmutableMap.Builder builder = new ImmutableMap.Builder(); 40 | builder.put("string1", "hello"); 41 | builder.put("string2", "world"); 42 | builder.put("string3", "2a36b911-9699-45d2-abd5-b9f2d2c9c4a3"); 43 | 44 | final String csv = writer.writeValueAsString(builder.build()); 45 | 46 | assertEquals("hello,world,\"2a36b911-9699-45d2-abd5-b9f2d2c9c4a3\"\n", csv); 47 | } 48 | 49 | public void testWithANullAStringAndAUuid() throws JsonProcessingException { 50 | 51 | final CsvSchema schema = new CsvSchema.Builder() 52 | .addColumn("string1", CsvSchema.ColumnType.STRING) 53 | .addColumn("string2", CsvSchema.ColumnType.STRING) 54 | .addColumn("string3", CsvSchema.ColumnType.STRING) 55 | .build(); 56 | final ObjectWriter writer = new CsvMapper().writer().with(schema); 57 | 58 | final ImmutableMap.Builder builder = new ImmutableMap.Builder(); 59 | builder.put("string2", "world"); 60 | builder.put("string3", "2a36b911-9699-45d2-abd5-b9f2d2c9c4a3"); 61 | 62 | final String csv = writer.writeValueAsString(builder.build()); 63 | 64 | assertEquals(",world,\"2a36b911-9699-45d2-abd5-b9f2d2c9c4a3\"\n", csv); 65 | } 66 | 67 | public void testWithAStringANullAndAUuid() throws JsonProcessingException { 68 | 69 | final CsvSchema schema = new CsvSchema.Builder() 70 | .addColumn("string1", CsvSchema.ColumnType.STRING) 71 | .addColumn("string2", CsvSchema.ColumnType.STRING) 72 | .addColumn("string3", CsvSchema.ColumnType.STRING) 73 | .build(); 74 | final ObjectWriter writer = new CsvMapper().writer().with(schema); 75 | 76 | final ImmutableMap.Builder builder = new ImmutableMap.Builder(); 77 | builder.put("string1", "hello"); 78 | builder.put("string3", "2a36b911-9699-45d2-abd5-b9f2d2c9c4a3"); 79 | 80 | final String csv = writer.writeValueAsString(builder.build()); 81 | 82 | assertEquals("hello,,\"2a36b911-9699-45d2-abd5-b9f2d2c9c4a3\"\n", csv); 83 | } 84 | 85 | public void testWithThreeStringsAndAUuid() throws JsonProcessingException { 86 | 87 | final CsvSchema schema = new CsvSchema.Builder() 88 | .addColumn("string1", CsvSchema.ColumnType.STRING) 89 | .addColumn("string2", CsvSchema.ColumnType.STRING) 90 | .addColumn("string3", CsvSchema.ColumnType.STRING) 91 | .addColumn("string4", CsvSchema.ColumnType.STRING) 92 | .build(); 93 | final ObjectWriter writer = new CsvMapper().writer().with(schema); 94 | 95 | final ImmutableMap.Builder builder = new ImmutableMap.Builder(); 96 | builder.put("string1", "hello"); 97 | builder.put("string2", "dear"); 98 | builder.put("string3", "world"); 99 | builder.put("string4", "2a36b911-9699-45d2-abd5-b9f2d2c9c4a3"); 100 | 101 | final String csv = writer.writeValueAsString(builder.build()); 102 | 103 | assertEquals("hello,dear,world,\"2a36b911-9699-45d2-abd5-b9f2d2c9c4a3\"\n", csv); 104 | } 105 | 106 | public void testWithANullAStringAStringAndAUuid() throws JsonProcessingException { 107 | 108 | final CsvSchema schema = new CsvSchema.Builder() 109 | .addColumn("string1", CsvSchema.ColumnType.STRING) 110 | .addColumn("string2", CsvSchema.ColumnType.STRING) 111 | .addColumn("string3", CsvSchema.ColumnType.STRING) 112 | .addColumn("string4", CsvSchema.ColumnType.STRING) 113 | .build(); 114 | final ObjectWriter writer = new CsvMapper().writer().with(schema); 115 | 116 | final ImmutableMap.Builder builder = new ImmutableMap.Builder(); 117 | builder.put("string2", "hello"); 118 | builder.put("string3", "world"); 119 | builder.put("string4", "2a36b911-9699-45d2-abd5-b9f2d2c9c4a3"); 120 | 121 | final String csv = writer.writeValueAsString(builder.build()); 122 | 123 | assertEquals(",hello,world,\"2a36b911-9699-45d2-abd5-b9f2d2c9c4a3\"\n", csv); 124 | } 125 | 126 | public void testWithAStringANullAStringAndAUuid() throws JsonProcessingException { 127 | 128 | final CsvSchema schema = new CsvSchema.Builder() 129 | .addColumn("string1", CsvSchema.ColumnType.STRING) 130 | .addColumn("string2", CsvSchema.ColumnType.STRING) 131 | .addColumn("string3", CsvSchema.ColumnType.STRING) 132 | .addColumn("string4", CsvSchema.ColumnType.STRING) 133 | .build(); 134 | final ObjectWriter writer = new CsvMapper().writer().with(schema); 135 | 136 | final ImmutableMap.Builder builder = new ImmutableMap.Builder(); 137 | builder.put("string1", "hello"); 138 | builder.put("string3", "world"); 139 | builder.put("string4", "2a36b911-9699-45d2-abd5-b9f2d2c9c4a3"); 140 | 141 | final String csv = writer.writeValueAsString(builder.build()); 142 | 143 | assertEquals("hello,,world,\"2a36b911-9699-45d2-abd5-b9f2d2c9c4a3\"\n", csv); 144 | } 145 | 146 | public void testWithTwoStringsANullAndAUuid() throws JsonProcessingException { 147 | 148 | final CsvSchema schema = new CsvSchema.Builder() 149 | .addColumn("string1", CsvSchema.ColumnType.STRING) 150 | .addColumn("string2", CsvSchema.ColumnType.STRING) 151 | .addColumn("string3", CsvSchema.ColumnType.STRING) 152 | .addColumn("string4", CsvSchema.ColumnType.STRING) 153 | .build(); 154 | final ObjectWriter writer = new CsvMapper().writer().with(schema); 155 | 156 | final ImmutableMap.Builder builder = new ImmutableMap.Builder(); 157 | builder.put("string1", "hello"); 158 | builder.put("string2", "world"); 159 | builder.put("string4", "2a36b911-9699-45d2-abd5-b9f2d2c9c4a3"); 160 | 161 | final String csv = writer.writeValueAsString(builder.build()); 162 | 163 | assertEquals("hello,world,,\"2a36b911-9699-45d2-abd5-b9f2d2c9c4a3\"\n", csv); 164 | } 165 | 166 | public void testWithTwoStringsANullAndAString() throws JsonProcessingException { 167 | 168 | final CsvSchema schema = new CsvSchema.Builder() 169 | .addColumn("string1", CsvSchema.ColumnType.STRING) 170 | .addColumn("string2", CsvSchema.ColumnType.STRING) 171 | .addColumn("string3", CsvSchema.ColumnType.STRING) 172 | .addColumn("string4", CsvSchema.ColumnType.STRING) 173 | .build(); 174 | final ObjectWriter writer = new CsvMapper().writer().with(schema); 175 | 176 | final ImmutableMap.Builder builder = new ImmutableMap.Builder(); 177 | builder.put("string1", "hello"); 178 | builder.put("string2", "world"); 179 | builder.put("string4", "again"); 180 | 181 | final String csv = writer.writeValueAsString(builder.build()); 182 | 183 | assertEquals("hello,world,,again\n", csv); 184 | } 185 | 186 | // [Issue#45] 187 | public void testWriteNullThirdColumn() throws JsonProcessingException { 188 | final CsvSchema.Builder csvSchemaBuilder = new CsvSchema.Builder(); 189 | csvSchemaBuilder.addColumn("timestamp", CsvSchema.ColumnType.STRING); 190 | csvSchemaBuilder.addColumn("value", CsvSchema.ColumnType.NUMBER); 191 | csvSchemaBuilder.addColumn("id", CsvSchema.ColumnType.STRING); 192 | final CsvSchema schema = csvSchemaBuilder.build(); 193 | final ObjectWriter writer = new CsvMapper().writer().with(schema); 194 | 195 | final String string = writer.writeValueAsString( 196 | ImmutableMap.of("timestamp", 0L, "value", 42)); 197 | assertEquals("0,42,\n", string); 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /src/test/java/com/fasterxml/jackson/dataformat/csv/ser/UnicodeWritingTest.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.ser; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.util.Map; 5 | 6 | import com.fasterxml.jackson.databind.*; 7 | 8 | import com.fasterxml.jackson.dataformat.csv.*; 9 | 10 | /** 11 | * Tests to try to see if Unicode writing, reading work as expected. 12 | */ 13 | public class UnicodeWritingTest extends ModuleTestBase 14 | { 15 | /* 16 | /********************************************************************** 17 | /* Test methods 18 | /********************************************************************** 19 | */ 20 | 21 | final CsvMapper MAPPER = mapperForCsv(); 22 | 23 | public void testSimpleStringSequence() throws Exception 24 | { 25 | // 16-Mar-2017, tatu: Actually, this assumes that read/write defaults are the same, 26 | // and for real Unicode support, UTF-8 (or UTF-16). Whereas many CSV impls assume 27 | // Latin-1 default. Oh well. We'll go UTF-8 unless punched in the face. 28 | 29 | ByteArrayOutputStream bytes = new ByteArrayOutputStream(); 30 | SequenceWriter w = MAPPER.writer() 31 | .writeValues(bytes); 32 | // turns out this writes 2 columns... fine 33 | final String STRING1 = "R\u00F6ck!"; 34 | final String STRING2 = "Smile (\u263A)..."; 35 | w.write(STRING1); 36 | w.write(STRING2); 37 | w.close(); 38 | byte[] b = bytes.toByteArray(); 39 | 40 | String[] stuff = MAPPER.readerFor(String[].class) 41 | .readValue(b); 42 | assertEquals(2, stuff.length); 43 | assertEquals(STRING1, stuff[0]); 44 | assertEquals(STRING2, stuff[1]); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/test/java/com/fasterxml/jackson/dataformat/csv/ser/UnwrappedWriteTest.java: -------------------------------------------------------------------------------- 1 | package com.fasterxml.jackson.dataformat.csv.ser; 2 | 3 | import com.fasterxml.jackson.annotation.*; 4 | 5 | import com.fasterxml.jackson.dataformat.csv.*; 6 | 7 | public class UnwrappedWriteTest extends ModuleTestBase 8 | { 9 | @JsonPropertyOrder({ "f1", "f2", "f3" }) 10 | static class Inner { 11 | public String f1; 12 | public String f2; 13 | public String f3; 14 | } 15 | 16 | @JsonPropertyOrder({ "a", "inner" }) 17 | static class Outer { 18 | public String a; 19 | 20 | @JsonUnwrapped 21 | public Inner inner = new Inner(); 22 | } 23 | 24 | // for [dataformat-csv#125] 25 | public void testWriteUnwrapped() throws Exception 26 | { 27 | CsvMapper mapper = mapperForCsv(); 28 | 29 | // Set null value to 'null' 30 | final CsvSchema schema = mapper.schemaFor(Outer.class).withNullValue("null"); 31 | 32 | // Create an object. All the fields are NULLs 33 | String csv = mapper.writer(schema).writeValueAsString(new Outer()); 34 | assertEquals("null,null,null,null", csv.trim()); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/test/java/perf/BogusOutputStream.java: -------------------------------------------------------------------------------- 1 | package perf; 2 | 3 | import java.io.IOException; 4 | import java.io.OutputStream; 5 | 6 | public class BogusOutputStream extends OutputStream 7 | { 8 | protected int _bytes; 9 | 10 | @Override 11 | public void write(byte[] buf) { write(buf, 0, buf.length); } 12 | @Override 13 | public void write(byte[] buf, int offset, int len) { 14 | _bytes += len; 15 | } 16 | 17 | @Override 18 | public void write(int b) throws IOException { 19 | _bytes++; 20 | } 21 | 22 | public int length() { return _bytes; } 23 | } 24 | -------------------------------------------------------------------------------- /src/test/java/perf/F5500Entry.java: -------------------------------------------------------------------------------- 1 | package perf; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | /** 6 | * POJO representing data from form F-5500 7 | */ 8 | public class F5500Entry 9 | { 10 | // 1 - 10 11 | @JsonProperty("ACK_ID") public String ackId; 12 | @JsonProperty("SF_PLAN_YEAR_BEGIN_DATE") public String sfPlanYearBeginDate; 13 | @JsonProperty("SF_TAX_PRD") public String sfTaxPrd; 14 | @JsonProperty("SF_PLAN_ENTITY_CD") public String sfPlanEntityCD; 15 | @JsonProperty("SF_INITIAL_FILING_IND") public String sfInitialFilingInd; 16 | @JsonProperty("SF_AMENDED_IND") public String sfAmendedInd; 17 | @JsonProperty("SF_FINAL_FILING_IND") public String sfFinalFilingInd; 18 | @JsonProperty("SF_SHORT_PLAN_YR_IND") public String sfShortPlanYearInd; 19 | @JsonProperty("SF_5558_APPLICATION_FILED_IND") public String sf5558ApplicationFiledInd; 20 | @JsonProperty("SF_EXT_AUTOMATIC_IND") public String sfExtAutomaticInd; 21 | 22 | // 11 - 20 23 | @JsonProperty("SF_DFVC_PROGRAM_IND") public String sfDFVCProgramInd; 24 | @JsonProperty("SF_EXT_SPECIAL_IND") public String sfExtSpecialInd; 25 | @JsonProperty("SF_EXT_SPECIAL_TEXT") public String sfExtSpecialText; 26 | @JsonProperty("SF_PLAN_NAME") public String sfPlanName; 27 | @JsonProperty("SF_PLAN_NUM") public long sfPlanNumber; 28 | @JsonProperty("SF_PLAN_EFF_DATE") public String sfPlanEffectiveDate; 29 | @JsonProperty("SF_SPONSOR_NAME") public String sfSponsorName; 30 | @JsonProperty("SF_SPONSOR_DFE_DBA_NAME") public String sfSponsorDFEDBAName; 31 | @JsonProperty("SF_SPONS_US_ADDRESS1") public String sfSponsorUSAddress1; 32 | @JsonProperty("SF_SPONS_US_ADDRESS2") public String sfSponsorUSAddress2; 33 | 34 | // 21 - 30 35 | @JsonProperty("SF_SPONS_US_CITY") public String sfSponsorUSCity; 36 | @JsonProperty("SF_SPONS_US_STATE") public String sfSponsorUSState; 37 | @JsonProperty("SF_SPONS_US_ZIP") public String sfSponsorUSZip; 38 | @JsonProperty("SF_SPONS_FOREIGN_ADDRESS1") public String sfSponsorForeignAddress1; 39 | @JsonProperty("SF_SPONS_FOREIGN_ADDRESS2") public String sfSponsorForeignAddress2; 40 | @JsonProperty("SF_SPONS_FOREIGN_CITY") public String sfSponsorForeignCity; 41 | @JsonProperty("SF_SPONS_FOREIGN_PROV_STATE") public String sfSponsorForeignProvinceOrState; 42 | @JsonProperty("SF_SPONS_FOREIGN_CNTRY") public String sfSponsorForeignCountry; 43 | @JsonProperty("SF_SPONS_FOREIGN_POSTAL_CD") public String sfSponsorForeignPostalCD; 44 | @JsonProperty("SF_SPONS_EIN") public String sfSponsorEIN; 45 | 46 | // 31 - 40 47 | @JsonProperty("SF_SPONS_PHONE_NUM") public String sfSponsorPhoneNumber; 48 | @JsonProperty("SF_BUSINESS_CODE") public String sfBusinessCode; 49 | @JsonProperty("SF_ADMIN_NAME") public String sfAdminName; 50 | @JsonProperty("SF_ADMIN_CARE_OF_NAME") public String sfAdminCareOfName; 51 | @JsonProperty("SF_ADMIN_US_ADDRESS1") public String sfAdminUSAddress1; 52 | @JsonProperty("SF_ADMIN_US_ADDRESS2") public String sfAdminUSAddress2; 53 | @JsonProperty("SF_ADMIN_US_CITY") public String sfAdminUSCity; 54 | @JsonProperty("SF_ADMIN_US_STATE") public String sfAdminUSState; 55 | @JsonProperty("SF_ADMIN_US_ZIP") public String sfAdminUSZip; 56 | @JsonProperty("SF_ADMIN_FOREIGN_ADDRESS1") public String sfAdminForeignAddress1; 57 | 58 | // 41-50 59 | @JsonProperty("SF_ADMIN_FOREIGN_ADDRESS2") public String sfAdminForeignAddress2; 60 | @JsonProperty("SF_ADMIN_FOREIGN_CITY") public String sfAdminForeignCity; 61 | @JsonProperty("SF_ADMIN_FOREIGN_PROV_STATE") public String sfAdminForeignProvinceState; 62 | @JsonProperty("SF_ADMIN_FOREIGN_CNTRY") public String sfAdminForeignCountry; 63 | @JsonProperty("SF_ADMIN_FOREIGN_POSTAL_CD") public String sfAdminForeignPostalCD; 64 | @JsonProperty("SF_ADMIN_EIN") public String sfAdminEin; 65 | @JsonProperty("SF_ADMIN_PHONE_NUM") public String sfAdminPhoneNumber; 66 | @JsonProperty("SF_LAST_RPT_SPONS_NAME") public String sfLastRptSponsorName; 67 | @JsonProperty("SF_LAST_RPT_SPONS_EIN") public String sfLastRptSponsorEIN; 68 | @JsonProperty("SF_LAST_RPT_PLAN_NUM") public String sfLastRptPlanNumber; 69 | 70 | // 51-60 71 | 72 | @JsonProperty("SF_TOT_PARTCP_BOY_CNT") public int sfTotalParcpBoyCount; 73 | @JsonProperty("SF_TOT_ACT_RTD_SEP_BENEF_CNT") public int sfTotalAccountRtdSepBenefCount; 74 | @JsonProperty("SF_PARTCP_ACCOUNT_BAL_CNT") public int sfPartcpAccountBalanceCount; 75 | @JsonProperty("SF_ELIGIBLE_ASSETS_IND") public String sfEligibleAssetsInd; 76 | @JsonProperty("SF_IQPA_WAIVER_IND") public String sfIQPAWaiverInd; 77 | @JsonProperty("SF_TOT_ASSETS_BOY_AMT") public int sfTotalAssetsBoyAmount; 78 | @JsonProperty("SF_TOT_LIABILITIES_BOY_AMT") public int sfTotalLiabilitiesBoyAmount; 79 | @JsonProperty("SF_NET_ASSETS_BOY_AMT") public int sfNetAssetsBoyAmt; 80 | @JsonProperty("SF_TOT_ASSETS_EOY_AMT") public int sfTotAssetsEoyAmt; 81 | @JsonProperty("SF_TOT_LIABILITIES_EOY_AMT") public int sfTotalLiabilitiesEOYAmount; 82 | 83 | // 61-70 84 | @JsonProperty("SF_NET_ASSETS_EOY_AMT") public int sfNetAssetsEoyAmount; 85 | @JsonProperty("SF_EMPLR_CONTRIB_INCOME_AMT") public int sfEmployerContribIncomeAmount; 86 | @JsonProperty("SF_PARTICIP_CONTRIB_INCOME_AMT") public int sfParticipContribIncomeAmount; 87 | @JsonProperty("SF_OTH_CONTRIB_RCVD_AMT") public int sfOtherContribReceivedAmount; 88 | @JsonProperty("SF_OTHER_INCOME_AMT") public int sfOtherIncomeAmount; 89 | @JsonProperty("SF_TOT_INCOME_AMT") public int sfTotalIncomeAmount; 90 | @JsonProperty("SF_TOT_DISTRIB_BNFT_AMT") public int sftotalDistribuBenefitAmount; 91 | @JsonProperty("SF_CORRECTIVE_DEEMED_DISTR_AMT") public int sfCorrectiveDeemedDistrAmount; 92 | @JsonProperty("SF_ADMIN_SRVC_PROVIDERS_AMT") public int sfAdminSrvcProvidersAmount; 93 | @JsonProperty("SF_OTH_EXPENSES_AMT") public int sfOtherExpensesAmount; 94 | 95 | // 71-80 96 | @JsonProperty("SF_TOT_EXPENSES_AMT") public int sfTotalExpensesAmount; 97 | @JsonProperty("SF_NET_INCOME_AMT") public int sfNetIncomeAmount; 98 | @JsonProperty("SF_TOT_PLAN_TRANSFERS_AMT") public int sfTotalPlanTransfersAmount; 99 | @JsonProperty("SF_TYPE_PENSION_BNFT_CODE") public String sfTypePensionBenefitCode; 100 | @JsonProperty("SF_TYPE_WELFARE_BNFT_CODE") public String sfTypeWelfareBenefitCode; 101 | @JsonProperty("SF_FAIL_TRANSMIT_CONTRIB_IND") public String sfFailTransmitContribInd; 102 | @JsonProperty("SF_FAIL_TRANSMIT_CONTRIB_AMT") public int sfFailTransmitContribAmount; 103 | @JsonProperty("SF_PARTY_IN_INT_NOT_RPTD_IND") public String sfPartyInIntNotRptdInd; 104 | @JsonProperty("SF_PARTY_IN_INT_NOT_RPTD_AMT") public int sfPartyInIntNotRptdAmount; 105 | @JsonProperty("SF_PLAN_INS_FDLTY_BOND_IND") public String sfPanInsFidelityBondInd; 106 | 107 | // 81-90 108 | @JsonProperty("SF_PLAN_INS_FDLTY_BOND_AMT") public long sfPlanInsFidelityBondAmount; 109 | @JsonProperty("SF_LOSS_DISCV_DUR_YEAR_IND") public String sfLossDiscvDuringYearInd; 110 | @JsonProperty("SF_LOSS_DISCV_DUR_YEAR_AMT") public int sfLossDiscvDuringYearAmount; 111 | @JsonProperty("SF_BROKER_FEES_PAID_IND") public String sfBrokerFeesPaidInd; 112 | @JsonProperty("SF_BROKER_FEES_PAID_AMT") public int sfBrokerFeesPaidAmount; 113 | @JsonProperty("SF_FAIL_PROVIDE_BENEF_DUE_IND") public String sfFailProvideBenefitDueInd; 114 | @JsonProperty("SF_FAIL_PROVIDE_BENEF_DUE_AMT") public int sfFailProvideBenefitDueAmount; 115 | @JsonProperty("SF_PARTCP_LOANS_IND") public String sfPartcpLoansInd; 116 | @JsonProperty("SF_PARTCP_LOANS_EOY_AMT") public int sfPartcpLoansEOYAmount; 117 | @JsonProperty("SF_PLAN_BLACKOUT_PERIOD_IND") public String sfPlanBlackoutPeriodInd; 118 | 119 | // 91-100 120 | @JsonProperty("SF_COMPLY_BLACKOUT_NOTICE_IND") public String sfComplyBlackoutNoticeInd; 121 | @JsonProperty("SF_DB_PLAN_FUNDING_REQD_IND") public String sfDBPlanFundingRequiredInd; 122 | @JsonProperty("SF_DC_PLAN_FUNDING_REQD_IND") public String sfDCPlanFundingRequiredInd; 123 | @JsonProperty("SF_RULING_LETTER_GRANT_DATE") public String sfRulingLetterGrantDate; 124 | @JsonProperty("SF_SEC_412_REQ_CONTRIB_AMT") public int sfSec412RequiredContribAmount; 125 | @JsonProperty("SF_EMPLR_CONTRIB_PAID_AMT") public int sfEmployerContribPaidAmount; 126 | @JsonProperty("SF_FUNDING_DEFICIENCY_AMT") public int sfFundingDeficiencyAmount; 127 | @JsonProperty("SF_FUNDING_DEADLINE_IND") public String sfFundingDeadlineInd; 128 | @JsonProperty("SF_RES_TERM_PLAN_ADPT_IND") public String sfResTermPlanAdptInd; 129 | @JsonProperty("SF_RES_TERM_PLAN_ADPT_AMT") public int sfResTermPlanAdptAmount; 130 | 131 | // 100-109 132 | @JsonProperty("SF_ALL_PLAN_AST_DISTRIB_IND") public String sfAllPlanAstDistribInd; 133 | @JsonProperty("SF_ADMIN_SIGNED_DATE") public String sfAdminSignedDate; 134 | @JsonProperty("SF_ADMIN_SIGNED_NAME") public String sfAdminSignedName; 135 | @JsonProperty("SF_SPONS_SIGNED_DATE") public String sfSponsorSignedDate; 136 | @JsonProperty("SF_SPONS_SIGNED_NAME") public String sfSponsorSignedName; 137 | @JsonProperty("FILING_STATUS") public String filingStatus; 138 | @JsonProperty("DATE_RECEIVED") public String dateReceived; 139 | @JsonProperty("VALID_ADMIN_SIGNATURE") public String validAdminSignature; 140 | @JsonProperty("VALID_SPONSOR_SIGNATURE") public String validSponsorSignature; 141 | } -------------------------------------------------------------------------------- /src/test/java/perf/F5500Reader.java: -------------------------------------------------------------------------------- 1 | package perf; 2 | 3 | import java.io.*; 4 | import java.util.*; 5 | 6 | import com.fasterxml.jackson.databind.MappingIterator; 7 | 8 | import com.fasterxml.jackson.dataformat.csv.CsvMapper; 9 | import com.fasterxml.jackson.dataformat.csv.CsvSchema; 10 | 11 | /** 12 | * Manual test for checking how fast a F-5500 file 13 | * (from http:///www.dol.gov/) can be read from a file 14 | */ 15 | public final class F5500Reader 16 | { 17 | public static void main(String[] args) throws Exception 18 | { 19 | if (args.length != 1) { 20 | System.err.println("Usage: java .... [input file]"); 21 | System.exit(1); 22 | } 23 | new F5500Reader().read(new File(args[0])); 24 | } 25 | 26 | private void read(File inputFile) throws IOException, InterruptedException 27 | { 28 | int x = 1; 29 | while (true) { 30 | Class cls = ((x & 1) == 0) ? Map.class : F5500Entry.class; 31 | ++x; 32 | long now = System.currentTimeMillis(); 33 | int count = readAll(inputFile, cls); 34 | long time = System.currentTimeMillis() - now; 35 | System.out.printf("DONE! Read %d rows as %s in %.1f seconds.\n", 36 | count, cls.getName(), time / 1000.0); 37 | Thread.sleep(500L); 38 | } 39 | } 40 | 41 | private int readAll(File inputFile, Class cls) throws IOException 42 | { 43 | System.out.print("Reading input as "+cls.getName()+" instances: "); 44 | 45 | int count = 0; 46 | CsvMapper mapper = new CsvMapper(); 47 | CsvSchema schema = CsvSchema.builder() 48 | .setUseHeader(true) 49 | .build(); 50 | 51 | MappingIterator it = mapper.readerFor(cls) 52 | .with(schema).readValues(inputFile); 53 | while (it.hasNext()) { 54 | @SuppressWarnings("unused") 55 | T row = it.nextValue(); 56 | ++count; 57 | if ((count & 0x3FFF) == 0) { 58 | System.out.print('.'); 59 | } 60 | } 61 | System.out.println(); 62 | it.close(); 63 | return count; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/test/java/perf/ManualPerfComparison.java: -------------------------------------------------------------------------------- 1 | package perf; 2 | 3 | import java.io.*; 4 | import java.util.*; 5 | 6 | import com.fasterxml.jackson.core.JsonGenerator; 7 | import com.fasterxml.jackson.databind.*; 8 | import com.fasterxml.jackson.dataformat.csv.*; 9 | 10 | /** 11 | * Simple manual performance micro-benchmark that compares compress and 12 | * decompress speeds of this LZF implementation with other codecs. 13 | */ 14 | @SuppressWarnings("resource") 15 | public final class ManualPerfComparison 16 | { 17 | private ObjectMapper jsonMapper; 18 | 19 | private ObjectReader csvReader; 20 | 21 | private ObjectWriter csvWriter; 22 | 23 | public ManualPerfComparison() 24 | { 25 | jsonMapper = new ObjectMapper(); 26 | CsvMapper mapper = new CsvMapper(); 27 | CsvSchema schema = mapper.schemaFor(RequestEntry.class) 28 | .withColumnSeparator('|') 29 | .withUseHeader(true) 30 | .withSkipFirstDataRow(true) 31 | ; 32 | 33 | csvReader = mapper.readerFor(RequestEntry.class).with(schema); 34 | csvWriter = mapper.writer(schema); 35 | } 36 | 37 | private RequestEntry[] readCsv(byte[] csvInput) throws IOException 38 | { 39 | ArrayList entries = new ArrayList(); 40 | Iterator it = csvReader.readValues(new ByteArrayInputStream(csvInput)); 41 | while (it.hasNext()) { 42 | entries.add(it.next()); 43 | } 44 | return entries.toArray(new RequestEntry[entries.size()]); 45 | } 46 | 47 | private byte[] writeAsJson(RequestEntry[] entries) throws IOException 48 | { 49 | ByteArrayOutputStream bytes = new ByteArrayOutputStream(256 + entries.length * 100); 50 | JsonGenerator jgen = jsonMapper.getFactory().createGenerator(bytes); 51 | for (RequestEntry entry : entries) { 52 | jsonMapper.writeValue(jgen, entry); 53 | } 54 | jgen.close(); 55 | return bytes.toByteArray(); 56 | } 57 | 58 | private void test(byte[] csvInput) throws IOException 59 | { 60 | final RequestEntry[] entries = readCsv(csvInput); 61 | final byte[] jsonInput = writeAsJson(entries); 62 | 63 | // Let's try to guestimate suitable size... to get to 10 megs to process 64 | final int REPS = (int) ((double) (10 * 1000 * 1000) / (double) csvInput.length); 65 | 66 | System.out.printf("Input: %d entries; %d bytes as CSV, %d bytes as JSON\n", 67 | entries.length, csvInput.length, jsonInput.length); 68 | System.out.printf("Will do %d repetitions per test.\n\n", REPS); 69 | 70 | int i = 0; 71 | 72 | while (true) { 73 | try { Thread.sleep(100L); } catch (InterruptedException ie) { } 74 | int round = (i++ % 4); 75 | 76 | // if (true) round = 0; 77 | 78 | String msg; 79 | boolean lf = (round == 0); 80 | 81 | long msecs; 82 | 83 | switch (round) { 84 | 85 | case 0: 86 | msg = "CSV, read"; 87 | msecs = testCsvRead(REPS, csvInput); 88 | break; 89 | case 1: 90 | msg = "CSV, write"; 91 | msecs = testCsvWrite(REPS, entries); 92 | break; 93 | case 2: 94 | msg = "JSON, read"; 95 | msecs = testJsonRead(REPS, jsonInput); 96 | break; 97 | case 3: 98 | msg = "JSON, write"; 99 | msecs = testJsonWrite(REPS, entries); 100 | break; 101 | default: 102 | throw new Error(); 103 | } 104 | 105 | if (lf) { 106 | System.out.println(); 107 | } 108 | System.out.println("Test '"+msg+"' -> "+msecs+" msecs"); 109 | } 110 | } 111 | 112 | private final long testJsonRead(int REPS, byte[] input) throws IOException 113 | { 114 | long start = System.currentTimeMillis(); 115 | while (--REPS >= 0) { 116 | Iterator it = jsonMapper.readerFor(RequestEntry.class).readValues( 117 | input, 0, input.length); 118 | while (it.hasNext()) { 119 | it.next(); 120 | } 121 | } 122 | return System.currentTimeMillis() - start; 123 | } 124 | 125 | private final long testCsvRead(int REPS, byte[] input) throws IOException 126 | { 127 | long start = System.currentTimeMillis(); 128 | while (--REPS >= 0) { 129 | Iterator it = csvReader.readValues(input, 0, input.length); 130 | while (it.hasNext()) { 131 | it.next(); 132 | } 133 | } 134 | return System.currentTimeMillis() - start; 135 | } 136 | 137 | private final long testJsonWrite(int REPS, RequestEntry[] entries) throws IOException 138 | { 139 | long start = System.currentTimeMillis(); 140 | @SuppressWarnings("unused") 141 | int size = 0; 142 | while (--REPS >= 0) { 143 | BogusOutputStream bogus = new BogusOutputStream(); 144 | jsonMapper.writeValue(bogus, entries); 145 | size = bogus.length(); 146 | } 147 | return System.currentTimeMillis() - start; 148 | } 149 | 150 | private final long testCsvWrite(int REPS, RequestEntry[] entries) throws IOException 151 | { 152 | long start = System.currentTimeMillis(); 153 | @SuppressWarnings("unused") 154 | int size = 0; 155 | while (--REPS >= 0) { 156 | BogusOutputStream bogus = new BogusOutputStream(); 157 | csvWriter.writeValue(bogus, entries); 158 | size = bogus.length(); 159 | } 160 | return System.currentTimeMillis() - start; 161 | } 162 | 163 | public static void main(String[] args) throws IOException 164 | { 165 | if (args.length != 1) { 166 | System.err.println("Usage: java ... [file]"); 167 | System.exit(1); 168 | } 169 | new ManualPerfComparison().test(readAll(args[0])); 170 | } 171 | 172 | public static byte[] readAll(String filename) throws IOException 173 | { 174 | File f = new File(filename); 175 | ByteArrayOutputStream bytes = new ByteArrayOutputStream((int) f.length()); 176 | byte[] buffer = new byte[4000]; 177 | int count; 178 | FileInputStream in = new FileInputStream(f); 179 | 180 | while ((count = in.read(buffer)) > 0) { 181 | bytes.write(buffer, 0, count); 182 | } 183 | in.close(); 184 | return bytes.toByteArray(); 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /src/test/java/perf/RequestEntry.java: -------------------------------------------------------------------------------- 1 | package perf; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | public class RequestEntry 6 | { 7 | @JsonProperty("APP_ID") public long appId; 8 | @JsonProperty("USER_SCREEN_NAME") public String userScreenName; 9 | @JsonProperty("REPORTER_SCREEN_NAME") public String reportScreenName; 10 | @JsonProperty("EVENT_DATE") public String eventDate; 11 | @JsonProperty("HOST") public String host; 12 | @JsonProperty("PATH") public String path; 13 | @JsonProperty("USER_AGENT") public String userAgent; 14 | @JsonProperty("IP") public String ip; 15 | @JsonProperty("COOKIE") public String cookie; 16 | @JsonProperty("SUBDOMAIN") public String subdomain; 17 | @JsonProperty("REQUEST_METHOD") public String requestMethod; // or Enum 18 | @JsonProperty("TRACE") public String trace; 19 | @JsonProperty("REFERRER") public String referrer; 20 | @JsonProperty("RELOAD_COUNT") public int reloadCount; 21 | @JsonProperty("SESSION_ID") public String sessionId; 22 | @JsonProperty("ACTION") public String action; 23 | @JsonProperty("CONTENT") public String content; 24 | @JsonProperty("KILL_COUNT") public int killCount; 25 | @JsonProperty("ABUSE_TYPE") public String abuseType; 26 | } 27 | --------------------------------------------------------------------------------