FasterXML / jackson-dataformats-text

Uber-project for (some) standard Jackson textual format backends: csv, properties, yaml (xml to be added in future)
Apache License 2.0
404 stars 148 forks source link

`@JsonPropertyOrder` ignored for dataformats-csv #279

Open kenyee opened 3 years ago

kenyee commented 3 years ago

Using Kotlin, defining a class like this:


@JsonPropertyOrder(
    "Module", "FilePath", "Line", "Offset", "Severity", "UniqueID", "Category", "Description",
    "FileCount, LinesOfCode", "ComplexityTotal", "CoverageTotal",
    "NumBlockers", "NumCriticals", "NumMajors", "NumMinors", "NumInfos"
)
private data class SonarFileStatsCsv(
    @field:JsonProperty("Module")
    val module: String,
    @field:JsonProperty("FilePath")
    val filePath: String = "-",
    @field:JsonProperty("Line")
    val line: String = "-",
    @field:JsonProperty("Offset")
    val offset: String = "-",
    @field:JsonProperty("Severity")
    val severity: String = "-",
    @field:JsonProperty("UniqueID")
    val uniqueId: String = "-",
    @field:JsonProperty("Category")
    val category: String = "-",
    @field:JsonProperty("Description")
    val description: String = "-",
    @field:JsonProperty("FileCount")
    val fileCount: Int,
    @field:JsonProperty("LinesOfCode")
    val linesOfCode: Int,
    @field:JsonProperty("ComplexityTotal")
    val complexityTotal: Int,
    @field:JsonProperty("CoverageTotal")
    val coverageTotal: Float,
    @field:JsonProperty("NumBlockers")
    val numBlockers: Int,
    @field:JsonProperty("NumCriticals")
    val numCriticals: Int,
    @field:JsonProperty("NumMajors")
    val numMajors: Int,
    @field:JsonProperty("NumMinors")
    val numMinors: Int,
    @field:JsonProperty("NumInfos")
    val numInfos: Int
)

And writing it out using:


        val mapper = CsvMapper().apply {
            disable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY)
        }
        val schema: CsvSchema = mapper.schemaFor(SonarFileStatsCsv::class.java)
            .withHeader()
     val csvWriter: ObjectWriter = mapper.writer(schema)
        withContext(Dispatchers.IO) {
            csvWriter.writeValue(File(fileName), sonarCsvStats)
        }

Doesn't work...the order is not preserved. Workaround is to use the addColumn syntax to force the order:

        val schema = CsvSchema.builder()
            .addColumn("Module")
...

Also had to use @field:JsonProperty...using just @JsonProperty and withHeaders() wrote out the field names instead of the @JsonProperty name.

Used: Kotlin 1.3.72 dataformats-csv 2.12.2 jackson 2.12.2

cowtowncoder commented 3 years ago

Ok, first things first: would it be possible to minimize the example to include fewer columns? Also, it'd be good to have unit test style assertions (write as a String, checkout output). With a quick look usage looks correct: setting of SORT_PROPERTIES_ALPHABETICALLY has no effect with explicit ordering.

Beyond this there are 2 possibilities:

  1. This is general CSV handling problem, reproducible without Kotlin. If so, issue should remain here
  2. This only fails on Kotlin (for some reason), if so, would need to be transferred to jackson-module-kotlin (since CSV format module does not and cannot depend on Kotlin module).

It would be great if a simplified reproduction with Java-only usage could decide between (1) and (2).

cowtowncoder commented 2 years ago

To proceed any further, I will need to know whether this is Kotlin specific or not: the easiest way would be to provide Java-only reproduction.