FasterXML / jackson-module-kotlin

Module that adds support for serialization/deserialization of Kotlin (http://kotlinlang.org) classes and data classes.
Apache License 2.0
1.12k stars 175 forks source link

XML: Support Kotlin's `object { ... }` as a List wrapper #415

Open OndraZizka opened 3 years ago

OndraZizka commented 3 years ago

Is your feature request related to a problem? Please describe. With Spring REST, I want to have this XML:

<transactions>
     <transaction> ... </transaction>
 <transactions>

For that, I hoped I could use some very simple construct, like this:

object { @XmlWrapper val transactions = transactions }

But as you can see, I tried a lot, but the closest I got is <><transactions></> which is, I assume, due to an empty class name Jackson sees.

): ResponseEntity<*> {
    val transactions = loadTransactions(filterType, filterValue)

    val contentType = when(outputFormat) {
        OutputFormat.JSON -> MediaType.APPLICATION_JSON
        OutputFormat.XML -> MediaType.APPLICATION_XML
    }
    val body = when(outputFormat) {
        OutputFormat.JSON -> transactions
        //OutputFormat.XML -> transactions // <EmptyList/>
        //OutputFormat.XML -> mapOf("transactions" to transactions) // <SingletonMap/>
        //OutputFormat.XML -> object { @field:JacksonXmlElementWrapper(name = "transactions") @field:XmlElementWrapper(name = "transactions") val transactions = transactions } // <><transactions/></>
        //OutputFormat.XML -> object { @XmlElement(name = "transactions") val transactions = transactions } // <><transactions/></>
        //OutputFormat.XML -> object { @field:XmlElement(name = "transactions") val transactions = transactions } // <><transactions/></>
        OutputFormat.XML -> transactions(transactions) // <TxWrapper> <transactions/> </TxWrapper>
    }
    return ResponseEntity.status(HttpStatus.OK).contentType(contentType).body(body)

Describe the solution you'd like Make this:

object { @field:XmlElementWrapper(name = "transactions") val transactions: List<Transaction> = transactions } /

produce this:

<transactions>
     <transaction> ... </transaction>
     <transaction> ... </transaction>
 <transactions>

Usage example See above - brief syntax for returning a List<...> from an endpoint.

Additional context

I didn't even manage to persuade Jackson to name the wrapper as I want using annotations. It insisted on using the class name. So I had to rename it to class transactions.
But that's a different story.

cowtowncoder commented 3 years ago

Not sure if it helps but it is possible to specify "root name" to use via ObjectWriter. In Java it'd be like:

ObjectMapper mapper = ...;
ObjectWriter w = mapper.writer()
    .withRootName("transactions"); // or using `PropertyName` if you need to pass XML namespace too
byte[] xml = w.writeValueAsBytes(value);

and that will override outermost xml element name.

cowtowncoder commented 3 years ago

Not sure whether to move to Kotlin or XML project... possibly Kotlin, will transfer.