[
https://issues.apache.org/jira/browse/GROOVY-11923?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18072941#comment-18072941
]
ASF GitHub Bot commented on GROOVY-11923:
-----------------------------------------
Copilot commented on code in PR #2462:
URL: https://github.com/apache/groovy/pull/2462#discussion_r3069349647
##########
subprojects/groovy-csv/src/main/java/groovy/csv/CsvSlurper.java:
##########
@@ -0,0 +1,229 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package groovy.csv;
+
+import com.fasterxml.jackson.databind.MappingIterator;
+import com.fasterxml.jackson.dataformat.csv.CsvMapper;
+import com.fasterxml.jackson.dataformat.csv.CsvParser;
+import com.fasterxml.jackson.dataformat.csv.CsvSchema;
+import org.apache.groovy.lang.annotation.Incubating;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringReader;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Represents a CSV parser.
+ * <p>
+ * Usage:
+ * <pre><code class="groovyTestCase">
+ * def csv = new
groovy.csv.CsvSlurper().parseText('name,age\nAlice,30\nBob,25')
+ * assert csv[0].name == 'Alice'
+ * assert csv[1].age == '25'
+ * </code></pre>
+ *
+ * @since 6.0.0
+ */
+@Incubating
+public class CsvSlurper {
+ private final CsvMapper mapper;
+ private char separator = ',';
+ private char quoteChar = '"';
+ private boolean useHeader = true;
+
+ public CsvSlurper() {
+ this.mapper = new CsvMapper();
+ }
+
+ /**
+ * Set the column separator character (default: comma).
+ *
+ * @param separator the separator character
+ * @return this slurper for chaining
+ */
+ public CsvSlurper setSeparator(char separator) {
+ this.separator = separator;
+ return this;
+ }
+
+ /**
+ * Set the quote character (default: double-quote).
+ *
+ * @param quoteChar the quote character
+ * @return this slurper for chaining
+ */
+ public CsvSlurper setQuoteChar(char quoteChar) {
+ this.quoteChar = quoteChar;
+ return this;
+ }
+
+ /**
+ * Set whether the first row is a header row (default: true).
+ *
+ * @param useHeader true to treat the first row as headers
+ * @return this slurper for chaining
+ */
+ public CsvSlurper setUseHeader(boolean useHeader) {
+ this.useHeader = useHeader;
+ return this;
+ }
+
+ /**
+ * Parse the content of the specified CSV text.
+ *
+ * @param csv the CSV text
+ * @return a list of maps (one per row), keyed by column headers
+ */
+ public List<Map<String, String>> parseText(String csv) {
+ return parse(new StringReader(csv));
+ }
+
+ /**
+ * Parse CSV from a reader.
+ *
+ * @param reader the reader of CSV
+ * @return a list of maps (one per row), keyed by column headers
+ */
+ public List<Map<String, String>> parse(Reader reader) {
+ try (Reader r = reader) {
+ CsvSchema schema = buildSchema();
+ MappingIterator<Map<String, String>> it = mapper
+ .readerFor(Map.class)
+ .with(schema)
+ .readValues(r);
Review Comment:
`parse(Reader)` currently uses try-with-resources and will always close the
caller-provided Reader. This is surprising for a slurper-style API (e.g.
JsonSlurper does not close the supplied Reader) and can break callers that want
to reuse/wrap the Reader. Consider not closing externally supplied Readers here
(and instead close only the Readers/Streams you create in
`parse(Path/File/InputStream)`), or clearly document the ownership/closing
semantics.
```suggestion
* <p>
* The supplied reader is not closed by this method; the caller retains
responsibility
* for closing it.
*
* @param reader the reader of CSV
* @return a list of maps (one per row), keyed by column headers
*/
public List<Map<String, String>> parse(Reader reader) {
try {
CsvSchema schema = buildSchema();
MappingIterator<Map<String, String>> it = mapper
.readerFor(Map.class)
.with(schema)
.readValues(reader);
```
##########
subprojects/groovy-csv/src/main/java/groovy/csv/CsvSlurper.java:
##########
@@ -0,0 +1,229 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package groovy.csv;
+
+import com.fasterxml.jackson.databind.MappingIterator;
+import com.fasterxml.jackson.dataformat.csv.CsvMapper;
+import com.fasterxml.jackson.dataformat.csv.CsvParser;
+import com.fasterxml.jackson.dataformat.csv.CsvSchema;
+import org.apache.groovy.lang.annotation.Incubating;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringReader;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Represents a CSV parser.
+ * <p>
+ * Usage:
+ * <pre><code class="groovyTestCase">
+ * def csv = new
groovy.csv.CsvSlurper().parseText('name,age\nAlice,30\nBob,25')
+ * assert csv[0].name == 'Alice'
+ * assert csv[1].age == '25'
+ * </code></pre>
+ *
+ * @since 6.0.0
+ */
+@Incubating
+public class CsvSlurper {
+ private final CsvMapper mapper;
+ private char separator = ',';
+ private char quoteChar = '"';
+ private boolean useHeader = true;
+
+ public CsvSlurper() {
+ this.mapper = new CsvMapper();
+ }
+
+ /**
+ * Set the column separator character (default: comma).
+ *
+ * @param separator the separator character
+ * @return this slurper for chaining
+ */
+ public CsvSlurper setSeparator(char separator) {
+ this.separator = separator;
+ return this;
+ }
+
+ /**
+ * Set the quote character (default: double-quote).
+ *
+ * @param quoteChar the quote character
+ * @return this slurper for chaining
+ */
+ public CsvSlurper setQuoteChar(char quoteChar) {
+ this.quoteChar = quoteChar;
+ return this;
+ }
+
+ /**
+ * Set whether the first row is a header row (default: true).
+ *
+ * @param useHeader true to treat the first row as headers
+ * @return this slurper for chaining
+ */
+ public CsvSlurper setUseHeader(boolean useHeader) {
+ this.useHeader = useHeader;
+ return this;
+ }
+
+ /**
+ * Parse the content of the specified CSV text.
+ *
+ * @param csv the CSV text
+ * @return a list of maps (one per row), keyed by column headers
+ */
+ public List<Map<String, String>> parseText(String csv) {
+ return parse(new StringReader(csv));
+ }
+
+ /**
+ * Parse CSV from a reader.
+ *
+ * @param reader the reader of CSV
+ * @return a list of maps (one per row), keyed by column headers
+ */
+ public List<Map<String, String>> parse(Reader reader) {
+ try (Reader r = reader) {
+ CsvSchema schema = buildSchema();
+ MappingIterator<Map<String, String>> it = mapper
+ .readerFor(Map.class)
+ .with(schema)
+ .readValues(r);
+ List<Map<String, String>> result = it.readAll();
+ // Jackson may return a single empty map for empty/header-only
input
+ if (result.size() == 1 && result.get(0).isEmpty()) {
+ result.clear();
+ }
+ return result;
+ } catch (Exception e) {
+ String msg = e.getMessage();
+ if (msg != null && (msg.contains("No content") ||
msg.contains("Empty header"))) {
+ return List.of();
+ }
+ throw new CsvRuntimeException(e);
Review Comment:
The empty-input handling relies on substring checks against
`Exception.getMessage()` ("No content"/"Empty header"). This is brittle across
Jackson versions/locales and may accidentally mask real parse errors. Prefer
handling empty input explicitly (e.g., in `parseText`/`parse` before invoking
Jackson) and/or catching specific Jackson exception types/codes rather than
matching message text.
##########
subprojects/groovy-csv/src/spec/test/groovy/csv/CsvSlurperTest.groovy:
##########
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package groovy.csv
+
+import groovy.test.GroovyTestCase
+
+class CsvSlurperTest extends GroovyTestCase {
+
+ void testParseText() {
+ // tag::parse_text[]
+ def csv = new CsvSlurper().parseText('name,age\nAlice,30\nBob,25')
+ assert csv.size() == 2
+ assert csv[0].name == 'Alice'
+ assert csv[0].age == '30'
+ assert csv[1].name == 'Bob'
+ // end::parse_text[]
+ }
+
+ void testPropertyAccess() {
+ // tag::property_access[]
+ def csv = new CsvSlurper().parseText('''\
+ name,city,country
+ Alice,London,UK
+ Bob,Paris,France''')
Review Comment:
This triple-quoted CSV literal is indented, so the parsed header/value
fields may include leading spaces (e.g. `' name'`) unless the parser
trims them. To make the test (and userguide snippet) robust, consider
left-aligning the CSV content or applying `.stripIndent()`/`.stripMargin()` to
the string before parsing.
```suggestion
def csv = new CsvSlurper().parseText(('''\
name,city,country
Alice,London,UK
Bob,Paris,France''').stripIndent())
```
##########
subprojects/groovy-csv/src/main/java/groovy/csv/CsvSlurper.java:
##########
@@ -0,0 +1,229 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package groovy.csv;
+
+import com.fasterxml.jackson.databind.MappingIterator;
+import com.fasterxml.jackson.dataformat.csv.CsvMapper;
+import com.fasterxml.jackson.dataformat.csv.CsvParser;
+import com.fasterxml.jackson.dataformat.csv.CsvSchema;
+import org.apache.groovy.lang.annotation.Incubating;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringReader;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Represents a CSV parser.
+ * <p>
+ * Usage:
+ * <pre><code class="groovyTestCase">
+ * def csv = new
groovy.csv.CsvSlurper().parseText('name,age\nAlice,30\nBob,25')
+ * assert csv[0].name == 'Alice'
+ * assert csv[1].age == '25'
+ * </code></pre>
+ *
+ * @since 6.0.0
+ */
+@Incubating
+public class CsvSlurper {
+ private final CsvMapper mapper;
+ private char separator = ',';
+ private char quoteChar = '"';
+ private boolean useHeader = true;
+
+ public CsvSlurper() {
+ this.mapper = new CsvMapper();
+ }
+
+ /**
+ * Set the column separator character (default: comma).
+ *
+ * @param separator the separator character
+ * @return this slurper for chaining
+ */
+ public CsvSlurper setSeparator(char separator) {
+ this.separator = separator;
+ return this;
+ }
+
+ /**
+ * Set the quote character (default: double-quote).
+ *
+ * @param quoteChar the quote character
+ * @return this slurper for chaining
+ */
+ public CsvSlurper setQuoteChar(char quoteChar) {
+ this.quoteChar = quoteChar;
+ return this;
+ }
+
+ /**
+ * Set whether the first row is a header row (default: true).
+ *
+ * @param useHeader true to treat the first row as headers
+ * @return this slurper for chaining
+ */
+ public CsvSlurper setUseHeader(boolean useHeader) {
+ this.useHeader = useHeader;
+ return this;
+ }
+
+ /**
+ * Parse the content of the specified CSV text.
+ *
+ * @param csv the CSV text
+ * @return a list of maps (one per row), keyed by column headers
+ */
+ public List<Map<String, String>> parseText(String csv) {
+ return parse(new StringReader(csv));
+ }
Review Comment:
`setUseHeader(false)` changes behavior so results may no longer be "keyed by
column headers", but the Javadoc for `parseText` (and `parse`) still promises
header-keyed maps unconditionally. Please clarify the contract when `useHeader`
is false (or restrict `useHeader` to typed parsing only) to avoid misleading
API docs.
##########
subprojects/groovy-csv/src/main/java/groovy/csv/CsvSlurper.java:
##########
@@ -0,0 +1,229 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package groovy.csv;
+
+import com.fasterxml.jackson.databind.MappingIterator;
+import com.fasterxml.jackson.dataformat.csv.CsvMapper;
+import com.fasterxml.jackson.dataformat.csv.CsvParser;
+import com.fasterxml.jackson.dataformat.csv.CsvSchema;
+import org.apache.groovy.lang.annotation.Incubating;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringReader;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Represents a CSV parser.
+ * <p>
+ * Usage:
+ * <pre><code class="groovyTestCase">
+ * def csv = new
groovy.csv.CsvSlurper().parseText('name,age\nAlice,30\nBob,25')
+ * assert csv[0].name == 'Alice'
+ * assert csv[1].age == '25'
+ * </code></pre>
+ *
+ * @since 6.0.0
+ */
+@Incubating
+public class CsvSlurper {
+ private final CsvMapper mapper;
+ private char separator = ',';
+ private char quoteChar = '"';
+ private boolean useHeader = true;
+
+ public CsvSlurper() {
+ this.mapper = new CsvMapper();
+ }
+
+ /**
+ * Set the column separator character (default: comma).
+ *
+ * @param separator the separator character
+ * @return this slurper for chaining
+ */
+ public CsvSlurper setSeparator(char separator) {
+ this.separator = separator;
+ return this;
+ }
+
+ /**
+ * Set the quote character (default: double-quote).
+ *
+ * @param quoteChar the quote character
+ * @return this slurper for chaining
+ */
+ public CsvSlurper setQuoteChar(char quoteChar) {
+ this.quoteChar = quoteChar;
+ return this;
+ }
+
+ /**
+ * Set whether the first row is a header row (default: true).
+ *
+ * @param useHeader true to treat the first row as headers
+ * @return this slurper for chaining
+ */
+ public CsvSlurper setUseHeader(boolean useHeader) {
+ this.useHeader = useHeader;
+ return this;
+ }
+
+ /**
+ * Parse the content of the specified CSV text.
+ *
+ * @param csv the CSV text
+ * @return a list of maps (one per row), keyed by column headers
+ */
+ public List<Map<String, String>> parseText(String csv) {
+ return parse(new StringReader(csv));
+ }
+
+ /**
+ * Parse CSV from a reader.
+ *
+ * @param reader the reader of CSV
+ * @return a list of maps (one per row), keyed by column headers
+ */
+ public List<Map<String, String>> parse(Reader reader) {
+ try (Reader r = reader) {
+ CsvSchema schema = buildSchema();
+ MappingIterator<Map<String, String>> it = mapper
+ .readerFor(Map.class)
+ .with(schema)
+ .readValues(r);
+ List<Map<String, String>> result = it.readAll();
+ // Jackson may return a single empty map for empty/header-only
input
+ if (result.size() == 1 && result.get(0).isEmpty()) {
+ result.clear();
+ }
+ return result;
+ } catch (Exception e) {
+ String msg = e.getMessage();
+ if (msg != null && (msg.contains("No content") ||
msg.contains("Empty header"))) {
+ return List.of();
+ }
+ throw new CsvRuntimeException(e);
+ }
+ }
+
+ /**
+ * Parse CSV from an input stream.
+ *
+ * @param stream the input stream of CSV
+ * @return a list of maps (one per row), keyed by column headers
+ */
+ public List<Map<String, String>> parse(InputStream stream) {
+ return parse(new InputStreamReader(stream));
+ }
+
+ /**
+ * Parse CSV from a file.
+ *
+ * @param file the CSV file
+ * @return a list of maps (one per row), keyed by column headers
+ */
+ public List<Map<String, String>> parse(File file) throws IOException {
+ return parse(file.toPath());
+ }
+
+ /**
+ * Parse CSV from a path.
+ *
+ * @param path the path to the CSV file
+ * @return a list of maps (one per row), keyed by column headers
+ */
+ public List<Map<String, String>> parse(Path path) throws IOException {
+ return parse(Files.newInputStream(path));
+ }
+
+ /**
+ * Parse CSV into typed objects using Jackson databinding.
+ * Supports {@code @JsonProperty} and {@code @JsonFormat} annotations for
+ * column mapping and type conversion.
+ *
+ * @param type the target type
+ * @param csv the CSV text
+ * @param <T> the target type
+ * @return a list of typed objects
+ */
+ public <T> List<T> parseAs(Class<T> type, String csv) {
+ return parseAs(type, new StringReader(csv));
+ }
+
+ /**
+ * Parse CSV from a reader into typed objects.
+ *
+ * @param type the target type
+ * @param reader the reader of CSV
+ * @param <T> the target type
+ * @return a list of typed objects
+ */
+ public <T> List<T> parseAs(Class<T> type, Reader reader) {
+ try (Reader r = reader) {
+ // Use empty schema with header — Jackson matches columns by name
Review Comment:
`parseAs(Class, Reader)` also closes the caller-provided Reader via
try-with-resources. For consistency with other Groovy slurpers and to avoid
unexpected stream closure, consider leaving Reader lifecycle management to the
caller (and only closing resources you open inside the API).
##########
subprojects/groovy-csv/src/main/java/groovy/csv/CsvBuilder.java:
##########
@@ -0,0 +1,163 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package groovy.csv;
+
+import com.fasterxml.jackson.dataformat.csv.CsvMapper;
+import com.fasterxml.jackson.dataformat.csv.CsvSchema;
+import groovy.lang.Writable;
+import org.apache.groovy.lang.annotation.Incubating;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Builds CSV output from collections of maps or typed objects.
+ * <p>
+ * Example with maps:
+ * <pre><code class="groovyTestCase">
+ * def data = [[name: 'Alice', age: 30], [name: 'Bob', age: 25]]
+ * def csv = groovy.csv.CsvBuilder.toCsv(data)
+ * assert csv.contains('name,age')
+ * assert csv.contains('Alice,30')
+ * </code></pre>
+ *
+ * @since 6.0.0
+ */
+@Incubating
+public class CsvBuilder implements Writable {
+ private final CsvMapper mapper;
+ private char separator = ',';
+ private char quoteChar = '"';
+ private String content;
+
+ public CsvBuilder() {
+ this.mapper = new CsvMapper();
+ }
+
+ /**
+ * Set the column separator character (default: comma).
+ *
+ * @param separator the separator character
+ * @return this builder for chaining
+ */
+ public CsvBuilder setSeparator(char separator) {
+ this.separator = separator;
+ return this;
+ }
+
+ /**
+ * Set the quote character (default: double-quote).
+ *
+ * @param quoteChar the quote character
+ * @return this builder for chaining
+ */
+ public CsvBuilder setQuoteChar(char quoteChar) {
+ this.quoteChar = quoteChar;
+ return this;
+ }
+
+ /**
+ * Convert a collection of maps to CSV.
+ * The keys of the first map are used as column headers.
+ *
+ * @param data the collection of maps
+ * @return the CSV string
+ */
+ @SuppressWarnings("unchecked")
+ public static String toCsv(Collection<? extends Map<String, ?>> data) {
+ if (data == null || data.isEmpty()) {
+ return "";
+ }
Review Comment:
`@SuppressWarnings("unchecked")` doesn't appear to be needed here (no
unchecked cast/operation in the method body). Removing it will keep warnings
meaningful and avoid hiding real unchecked issues.
##########
subprojects/groovy-csv/src/main/java/groovy/csv/CsvSlurper.java:
##########
@@ -0,0 +1,229 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package groovy.csv;
+
+import com.fasterxml.jackson.databind.MappingIterator;
+import com.fasterxml.jackson.dataformat.csv.CsvMapper;
+import com.fasterxml.jackson.dataformat.csv.CsvParser;
+import com.fasterxml.jackson.dataformat.csv.CsvSchema;
+import org.apache.groovy.lang.annotation.Incubating;
Review Comment:
There are unused imports here (e.g. `CsvParser`, `LinkedHashMap`). These
will trigger compiler/IDE warnings and may fail strict build checks; please
remove unused imports.
##########
subprojects/groovy-csv/src/main/java/groovy/csv/CsvBuilder.java:
##########
@@ -0,0 +1,163 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package groovy.csv;
+
+import com.fasterxml.jackson.dataformat.csv.CsvMapper;
+import com.fasterxml.jackson.dataformat.csv.CsvSchema;
+import groovy.lang.Writable;
+import org.apache.groovy.lang.annotation.Incubating;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.List;
Review Comment:
Unused imports (`LinkedHashMap`, `List`) should be removed to keep the
module warning-free and consistent with the rest of the codebase.
```suggestion
```
> Provide a groovy-csv optional module
> ------------------------------------
>
> Key: GROOVY-11923
> URL: https://issues.apache.org/jira/browse/GROOVY-11923
> Project: Groovy
> Issue Type: New Feature
> Reporter: Paul King
> Assignee: Paul King
> Priority: Major
>
> The idea is to produce a thin wrapper over Jackson CSV support much like what
> we do for TOML/YAML.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)