You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@groovy.apache.org by Eric Berry <el...@gmail.com> on 2019/06/12 22:21:58 UTC
I think I've found an issue with the @MapConstructor defaulting
implementation, when used with @NamedDelegate.
I have a static method marked with @NamedVariant, that takes a
"Configuration" object as a parameter, which is marked with @NamedDelegate.
The "Configuration" object is defined as a static inner class marked with
@Immutable.
My Class:
> class CsvRowMapper {
> private final Settings settings
> @NamedVariant
> CsvRowMapper(Settings settings) {
> this.settings = settings
> }
>
>
>
> *@NamedVariant static CsvRowMapper parse(@NamedDelegate Settings
> settings, Reader reader) { new CsvRowMapper(settings).parse(reader)
> }*
> CsvRowMapper parse(Reader source) {
> // do work here
> return this
> }
>
>
>
>
>
>
> *@Immutable static class Settings { String separator = ','
> boolean headers = true int headersRow = 0 int firstDataRow
> = 1 }*
> }
>
I've highlighted the important parts. The issue is when I use this class
like:
> CsvRowMapper.parse(*separator: '\t'*, tsvFileReader)
>
I get an `GroovyCastException` because it's trying to set `headersRow` or
`firstDataRow` to `null`:
org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast
> object '{separator= , headers=null, headersRow=null, firstDataRow=null}'
> with class 'java.util.LinkedHashMap' to class 'CsvRowMapper$Settings' due
> to: org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot
> cast object 'null' with class 'null' to class 'int'. Try
> 'java.lang.Integer' instead
I loaded up this into GroovyConsole, and I think the issue is that the
`@NameVariant` version of the `parse` method is creating a map with all
keys for the `@NamedDelegate` `Settings` class (See NamedVariant.png).
Furthermore the `@Immutable` annotation adds `@MapConstructor` to my
`Settings` class, which only checks if the given map contains the *`key`*,
not also if it has a `value` (See MapConstructor.png).
I'm thinking this might have been on purpose, to allow for null values to
override defaults? Though I can't think of a situation where I would want
that to be the case.
Maybe an elvis operator when a default is provided would be better?
> this .separator = args.get('separator')' ?: ,'
>
Thank you for your time and consideration.
Eric Berry
--
Learn from the past. Live in the present. Work towards the future.
turtlepaws.com - When was the last time you changed your master password?
Blog: http://eric-berry.blogspot.com
jEdit <http://www.jedit.org> - Programmer's Text Editor