Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Getters needed for ignored properties #476

Open
maroony opened this issue May 14, 2024 · 12 comments
Open

Getters needed for ignored properties #476

maroony opened this issue May 14, 2024 · 12 comments
Labels
csv has-failing-test Indicates that there exists a test case (under `failing/`) to reproduce the issue

Comments

@maroony
Copy link

maroony commented May 14, 2024

I'm wondering that I have to write getters for ignored properties. Here's an working example:

import java.io.IOException;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.databind.MappingIterator;
import com.fasterxml.jackson.dataformat.csv.CsvMapper;
import com.fasterxml.jackson.dataformat.csv.CsvSchema;
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;

@JsonPropertyOrder({
    "text",
    "ignored",
    "number"
})
@JsonIgnoreProperties(ignoreUnknown = true)
public class Example {

  private String text;
  private Integer number;

  @JsonCreator()
  public Example(String text, Integer number) {
    this.text = text;
    this.number = number;
  }

  public String getText() {
    return text;
  }

  public Integer getNumber() {
    return number;
  }

  // jackson needed getter
  public Object getIgnored() {
    return null;
  }

  public static void main(String[] args) throws IOException {

    CsvMapper csvMapper = new CsvMapper();
    csvMapper.registerModule(new ParameterNamesModule());
    CsvSchema csvSchema = csvMapper.schemaFor(Example.class);

    String value = "foo, ignoredValue, 123";

    MappingIterator<Example> iterator = csvMapper.readerFor(Example.class)
        .with(csvSchema)
        .readValues(value);

    var nextValue = iterator.next();

    System.out.println(nextValue.getText() + ", " + nextValue.getNumber());

  }
}

If you delete the getter getIgnored(), the following exception will be thrown:

Exception in thread "main" com.fasterxml.jackson.databind.RuntimeJsonMappingException: Cannot deserialize value of type `java.lang.Integer` from String "ignoredValue": not a valid `java.lang.Integer` value
 at [Source: (StringReader); line: 1, column: 5] (through reference chain: Example["number"])
        at com.fasterxml.jackson.databind.MappingIterator._handleMappingException(MappingIterator.java:416)
        at com.fasterxml.jackson.databind.MappingIterator.next(MappingIterator.java:201)
        at Example.main(Example.java:55)
Caused by: com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `java.lang.Integer` from String "ignoredValue": not a valid `java.lang.Integer` value
 at [Source: (StringReader); line: 1, column: 5] (through reference chain: Example["number"])
        at com.fasterxml.jackson.databind.exc.InvalidFormatException.from(InvalidFormatException.java:67)
        at com.fasterxml.jackson.databind.DeserializationContext.weirdStringException(DeserializationContext.java:1958)
        at com.fasterxml.jackson.databind.DeserializationContext.handleWeirdStringValue(DeserializationContext.java:1245)
        at com.fasterxml.jackson.databind.deser.std.StdDeserializer._parseInteger(StdDeserializer.java:848)
        at com.fasterxml.jackson.databind.deser.std.StdDeserializer._parseInteger(StdDeserializer.java:827)
        at com.fasterxml.jackson.databind.deser.std.NumberDeserializers$IntegerDeserializer.deserialize(NumberDeserializers.java:531)
        at com.fasterxml.jackson.databind.deser.std.NumberDeserializers$IntegerDeserializer.deserialize(NumberDeserializers.java:506)
        at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:545)
        at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeWithErrorWrapping(BeanDeserializer.java:570)
        at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:440)
        at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1493)
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:348)
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:185)
        at com.fasterxml.jackson.databind.MappingIterator.nextValue(MappingIterator.java:283)
        at com.fasterxml.jackson.databind.MappingIterator.next(MappingIterator.java:199)
        ... 1 more

Is this expected behavior? Is there something I can do to omit writing these getters?

What's also interesting: You got a different exception when the ignored column is the last:

import java.io.IOException;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.databind.MappingIterator;
import com.fasterxml.jackson.dataformat.csv.CsvMapper;
import com.fasterxml.jackson.dataformat.csv.CsvSchema;
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;

@JsonPropertyOrder({
    "text",
    "number",
    "ignored"
})
@JsonIgnoreProperties(ignoreUnknown = true)
public class Example2 {

  private String text;
  private Integer number;

  @JsonCreator()
  public Example2(String text, Integer number) {
    this.text = text;
    this.number = number;
  }

  public String getText() {
    return text;
  }

  public Integer getNumber() {
    return number;
  }

  // jackson needed getter
  public Object getIgnored() {
    return null;
  }

  public static void main(String[] args) throws IOException {

    CsvMapper csvMapper = new CsvMapper();
    csvMapper.registerModule(new ParameterNamesModule());
    CsvSchema csvSchema = csvMapper.schemaFor(Example2.class);

    String value = "foo, 123, ignoredValue";

    MappingIterator<Example2> iterator = csvMapper.readerFor(Example2.class)
        .with(csvSchema)
        .readValues(value);

    var nextValue = iterator.next();

    System.out.println(nextValue.getText() + ", " + nextValue.getNumber());
  }
}

If you now delete the getter getIgnored(), the following exception will be thrown:

Exception in thread "main" com.fasterxml.jackson.databind.RuntimeJsonMappingException: Too many entries: expected at most 2 (value #2 (12 chars) "ignoredValue")
 at [Source: (StringReader); line: 1, column: 9]
        at com.fasterxml.jackson.databind.MappingIterator._handleMappingException(MappingIterator.java:416)
        at com.fasterxml.jackson.databind.MappingIterator.next(MappingIterator.java:201)
        at Example2.main(Example2.java:56)
Caused by: com.fasterxml.jackson.dataformat.csv.CsvReadException: Too many entries: expected at most 2 (value #2 (12 chars) "ignoredValue")
 at [Source: (StringReader); line: 1, column: 9]
        at com.fasterxml.jackson.dataformat.csv.CsvReadException.from(CsvReadException.java:25)
        at com.fasterxml.jackson.dataformat.csv.CsvParser._reportCsvMappingError(CsvParser.java:1421)
        at com.fasterxml.jackson.dataformat.csv.CsvParser._handleExtraColumn(CsvParser.java:1163)
        at com.fasterxml.jackson.dataformat.csv.CsvParser._handleNextEntry(CsvParser.java:1030)
        at com.fasterxml.jackson.dataformat.csv.CsvParser.nextToken(CsvParser.java:758)
        at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:442)
        at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1493)
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:348)
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:185)
        at com.fasterxml.jackson.databind.MappingIterator.nextValue(MappingIterator.java:283)
        at com.fasterxml.jackson.databind.MappingIterator.next(MappingIterator.java:199)
        ... 1 more

Jackson-Version: 2.17.1

@maroony maroony added the to-evaluate Issue that has been received but not yet evaluated label May 14, 2024
@JooHyukKim
Copy link
Member

  1. There is separate repo for csv format repository and ParamNameModules repo.
  2. Ignore unknown option literally means it ignores any undeclared property. Getter may or may not be related?

@maroony
Copy link
Author

maroony commented May 14, 2024

I really don't know, if this is specific to CSV. So I opened the issue here. Feel free to move it to a better place.

@maroony
Copy link
Author

maroony commented May 14, 2024

I'm using version 2.17.0 for all jackson dependencies.

@maroony
Copy link
Author

maroony commented May 14, 2024

Just updated to version 2.17.1: same behavior.

@JooHyukKim
Copy link
Member

JooHyukKim commented May 14, 2024

Did it ever work? like in other version?
Most probably it's csv format related, so not jackson-databind issue.

You may try asking over at Stackoverflow (or similar) first or inquire over at jackson-dataformats-text repo.
But mind that usage inquiry should be asked vis Github Discussions, not Issue

@maroony
Copy link
Author

maroony commented May 14, 2024

I didn't see this working before. I started a discussion in jackson-dataformats-text.

@yihtserns
Copy link

Seems related to FasterXML/jackson-dataformat-csv#82. Has there been any new enhancement to better support such use case since then?

(Credit: https://stackoverflow.com/a/56067713)

@cowtowncoder
Copy link
Member

It definitely looks like CSV specific; I will transfer.

Ok so... in general with ignoreUnknown = true it should not be necessary to have getter or setter for ignored property.

However. For generating CsvSchema there has to be something indicating what is in position, and this might be the source of problem. If you built CsvSchema manually, or it was created from header line, things might work better.
But if using CsvMapper.schemaFor() I think matching property is indeed needed.

@cowtowncoder cowtowncoder transferred this issue from FasterXML/jackson-databind May 14, 2024
@cowtowncoder cowtowncoder added csv and removed to-evaluate Issue that has been received but not yet evaluated labels May 14, 2024
@maroony
Copy link
Author

maroony commented May 15, 2024

Thanks for pointing this out. Header lines are usually not usable in my case, because the CSV files are delivered from external sources. Manually building the CsvSchema feels like a lot of extra work for files with hundreds of columns. Looking forward to an improvement:-)

@JooHyukKim
Copy link
Member

Looking forward to an improvement:-)

Contributions are welcome also! 😆

@cowtowncoder cowtowncoder added the has-failing-test Indicates that there exists a test case (under `failing/`) to reproduce the issue label May 15, 2024
@cowtowncoder
Copy link
Member

Also: ideas of how this could work: as things are, I am not sure how this could be made to work.

But I have to say I am also surprised by the exception as that would suggest decoder did actually know about the property mapping from column.

Test needs some tweaks to be used here (need to get rid of parameter module), but that should be doable. So the first thing we could do is add a failing test based on code included here. And yes, PRs are welcome (even just for failing test)!

@maroony
Copy link
Author

maroony commented May 16, 2024

I added a second example to my issue description where I put the ignoredValue to the last column. Now there is a different exception. Maybe this is also interesting for you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
csv has-failing-test Indicates that there exists a test case (under `failing/`) to reproduce the issue
Projects
None yet
Development

No branches or pull requests

4 participants