Skip to content
This repository has been archived by the owner on Jan 22, 2019. It is now read-only.

Commit

Permalink
Fix #142
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed Mar 16, 2017
1 parent 43835ca commit ad36414
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 11 deletions.
5 changes: 5 additions & 0 deletions release-notes/CREDITS
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,8 @@ George Fraser (georgewfraser@github)
* Contributed #127: Add `CsvGenerator.Feature.ALWAYS_QUOTE_EMPTY_STRINGS` to allow forced
quoting of empty Strings.
(2.9.0)

Austin Sharp (sharpau@github)

* Suggested #142: Add methods for appending columns of a `CsvSchema` into another
(2.9.0)
4 changes: 3 additions & 1 deletion release-notes/VERSION
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ Project: jackson-dataformat-csv
#130: Add fluent addColumns operation to CsvSchema.Builder
(contributed by Peter A)
#139: Add `CsvParser.Feature.ALLOW_TRAILING_COMMA` to allow enforcing strict handling
(contributed by Nick B)
(contributed by Nick B)
#142: Add methods for appending columns of a `CsvSchema` into another
(suggested by Austin S)

2.8.6 (12-Jan-2017)
2.8.5 (14-Nov-2016)
Expand Down
106 changes: 98 additions & 8 deletions src/main/java/com/fasterxml/jackson/dataformat/csv/CsvSchema.java
Original file line number Diff line number Diff line change
Expand Up @@ -453,21 +453,37 @@ public Builder(CsvSchema src)
_anyPropertyName = src._anyPropertyName;
}

/**
* NOTE: does NOT check for duplicate column names so it is possibly to
* accidentally add duplicates.
*/
public Builder addColumn(String name) {
int index = _columns.size();
return addColumn(new Column(index, name));
}

/**
* NOTE: does NOT check for duplicate column names so it is possibly to
* accidentally add duplicates.
*/
public Builder addColumn(String name, ColumnType type) {
int index = _columns.size();
return addColumn(new Column(index, name, type));
}

/**
* NOTE: does NOT check for duplicate column names so it is possibly to
* accidentally add duplicates.
*/
public Builder addColumn(Column c) {
_columns.add(c);
return this;
}

/**
* NOTE: does NOT check for duplicate column names so it is possibly to
* accidentally add duplicates.
*
* @since 2.9
*/
public Builder addColumns(Iterable<Column> cs) {
Expand All @@ -478,6 +494,9 @@ public Builder addColumns(Iterable<Column> cs) {
}

/**
* NOTE: does NOT check for duplicate column names so it is possibly to
* accidentally add duplicates.
*
* @since 2.9
*/
public Builder addColumns(Iterable<String> names, ColumnType type) {
Expand All @@ -488,6 +507,24 @@ public Builder addColumns(Iterable<String> names, ColumnType type) {
return result;
}

/**
* NOTE: unlike many other add methods, this method DOES check for, and
* discard, possible duplicate columns: that is, if this builder already
* has a column with same name as column to be added, existing column
* is retained and new column ignored.
*
* @since 2.9
*/
public Builder addColumnsFrom(CsvSchema schema) {
Builder result = this;
for (Column col : schema) {
if (!hasColumn(col.getName())) {
result = result.addColumn(col);
}
}
return result;
}

public Builder addArrayColumn(String name) {
int index = _columns.size();
return addColumn(new Column(index, name, ColumnType.ARRAY, ""));
Expand Down Expand Up @@ -577,7 +614,25 @@ public int size() {
public Iterator<Column> getColumns() {
return _columns.iterator();
}


/**
*<p>
* NOTE: this method requires linear scan over existing columns
* so it may be more efficient to use other types of lookups if
* available (for example, {@link CsvSchema#column(String)} has a
* hash lookup to use).
*
* @since 2.9
*/
public boolean hasColumn(String name) {
for (int i = 0, end = _columns.size(); i < end; ++i) {
if (_columns.get(i).getName().equals(name)) {
return true;
}
}
return false;
}

/**
* Method for specifying whether Schema should indicate that
* a header line (first row that contains column names) is to be
Expand Down Expand Up @@ -1114,10 +1169,7 @@ public CsvSchema withoutEscapeChar() {
*/
@Deprecated // in 2.7; remove in 2.8
public CsvSchema withArrayElementSeparator(char c) {
return (Character.toString(c).equals(_arrayElementSeparator)) ? this
: new CsvSchema(_columns, _features,
_columnSeparator, _quoteChar, _escapeChar, _lineSeparator, Character.toString(c),
_nullValue, _columnsByName, _anyPropertyName);
return withArrayElementSeparator( Character.toString(c));
}

/**
Expand Down Expand Up @@ -1157,13 +1209,40 @@ public CsvSchema withNullValue(String nvl) {
(nvl == null) ? null : nvl.toCharArray(),
_columnsByName, _anyPropertyName);
}

public CsvSchema withoutColumns() {
return new CsvSchema(NO_COLUMNS, _features,
_columnSeparator, _quoteChar, _escapeChar, _lineSeparator, _arrayElementSeparator,
_nullValue, _columnsByName, _anyPropertyName);
}

/**
* Mutant factory method that will try to combine columns of this schema with those
* from `toAppend`, starting with columns of this instance, and ignoring
* duplicates (if any) from argument `toAppend`.
* All settings aside from column sets are copied from `this` instance.
*<p>
* As with all `withXxx()` methods this method never modifies `this` but either
* returns it unmodified (if no new columns found from `toAppend`), or constructs
* a new instance and returns that.
*
* @since 2.9
*/
public CsvSchema withColumnsFrom(CsvSchema toAppend) {
int addCount = toAppend.size();
if (addCount == 0) {
return this;
}
Builder b = rebuild();
for (int i = 0; i < addCount; ++i) {
Column col = toAppend.column(i);
if (column(col.getName()) == null) {
b.addColumn(col);
}
}
return b.build();
}

/**
* @since 2.7
*/
Expand Down Expand Up @@ -1318,9 +1397,20 @@ public String getNullValueString() {
public Iterator<Column> iterator() {
return Arrays.asList(_columns).iterator();
}


/**
* Accessor for finding out how many columns this schema defines.
*
* @return Number of columns this schema defines
*/
public int size() { return _columns.length; }


/**
* Accessor for column at specified index (0-based); index having to be within
*<pre>
* 0 &lt;= index &lt; size()
*</pre>
*/
public Column column(int index) {
return _columns[index];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,25 @@ static class ArrayWrapper {
public List<String> c;
}

// for [databind#74]
// for [dataformat-csv#74]
static class Point {
public int y;
public int x;
}

@JsonPropertyOrder()
public static class PointWithAnnotation extends Point {}

// for [dataformat-csv#142]
interface Named {
public String getFirstName();
public String getLastName();
}

static abstract class YZ {
public abstract int getY();
public abstract int getZ();
}

/*
/**********************************************************************
Expand Down Expand Up @@ -133,7 +144,7 @@ private void _verifyLinks(CsvSchema schema)
prev = curr;
}
}

// For [dataformat-csv#74]: problems applying default do-sort handling
public void testSchemaWithOrdering() throws Exception
{
Expand All @@ -158,4 +169,41 @@ public void testSchemaWithReordering()
CsvSchema schemaWithoutReordering = schemaWithReordering.withColumnReordering(false);
assertFalse(schemaWithoutReordering.reordersColumns());
}

// For [dataformat-csv#142]: append columns from POJOs
public void testSchemaComposition() throws Exception
{
CsvSchema pointSchema = MAPPER.typedSchemaFor(Point.class);
CsvSchema yzSchema = MAPPER.typedSchemaFor(YZ.class);
CsvSchema namedSchema = MAPPER.typedSchemaFor(Named.class);

// should only add `z` since there's already `y`
CsvSchema schema = pointSchema;
schema = schema.withColumnsFrom(yzSchema);
// but then two name properties
schema = schema.withColumnsFrom(namedSchema);

assertEquals(5, schema.size());
Iterator<CsvSchema.Column> it = schema.iterator();
assertEquals("x", it.next().getName());
assertEquals("y", it.next().getName());
assertEquals("z", it.next().getName());
assertEquals("firstName", it.next().getName());
assertEquals("lastName", it.next().getName());

// and try alternate way as well.
CsvSchema.Builder builder = CsvSchema.builder();
builder.addColumnsFrom(yzSchema)
.addColumnsFrom(namedSchema)
.addColumnsFrom(pointSchema);
schema = builder.build();

assertEquals(5, schema.size());
it = schema.iterator();
assertEquals("y", it.next().getName());
assertEquals("z", it.next().getName());
assertEquals("firstName", it.next().getName());
assertEquals("lastName", it.next().getName());
assertEquals("x", it.next().getName());
}
}

0 comments on commit ad36414

Please sign in to comment.