Repository: ktorio/ktor
File: ktor-server/ktor-server-plugins/ktor-server-content-negotiation/common/src/io/ktor/server/plugins/contentnegotiation/ContentNegotiation.kt (Kotlin)

Code before:
 */
public data class ContentTypeWithQuality(val contentType: ContentType, val quality: Double = 1.0) {
    init {
        require(quality in 0.0..1.0) { "Quality should be in range [0, 1]: $quality" }
    }
}

/**
 * A plugin that serves two primary purposes:
 * - Negotiating media types between the client and server. For this, it uses the `Accept` and `Content-Type` headers.
 * - Serializing/deserializing the content in a specific format.
 *    Ktor supports the following formats out-of-the-box: `JSON`, `XML`, `CBOR` and `ProtoBuf`.
 *
 * You can learn more from [Content negotiation and serialization](https://ktor.io/docs/server-serialization.html).
 *
 * [Report a problem](https://ktor.io/feedback/?fqname=io.ktor.server.plugins.contentnegotiation.ContentNegotiation)
 */
public val ContentNegotiation: RouteScopedPlugin<ContentNegotiationConfig> = createRouteScopedPlugin(
    "ContentNegotiation",
    ::ContentNegotiationConfig
) {
    convertRequestBody()
    convertResponseBody()

    // register default content types for application metadata, used in OpenAPI
    application.attributes[DefaultContentTypesAttribute] = pluginConfig.registrations.map { it.contentType }
}

/**
 * Detects a suitable charset for an application call by using the `Accept` header or fallbacks to [defaultCharset].
 *
 * [Report a problem](https://ktor.io/feedback/?fqname=io.ktor.server.plugins.contentnegotiation.suitableCharset)
 */
public fun ApplicationCall.suitableCharset(defaultCharset: Charset = Charsets.UTF_8): Charset {
    for ((charset, _) in request.acceptCharsetItems()) {
        when {
            charset == "*" -> return defaultCharset
            Charsets.isSupported(charset) -> return Charsets.forName(charset)
        }
    }
    return defaultCharset
}


Review comment (suggestion):
Maybe use `.distinct()` for some cases like this:
```kotlin
install(ContentNegotiation) { r
    register(ContentType.Application.Json, LegacyJsonConverter()) 
    register(ContentType.Application.Json, FasterJsonConverter()) 
}
```

Code after:
 */
public data class ContentTypeWithQuality(val contentType: ContentType, val quality: Double = 1.0) {
    init {
        require(quality in 0.0..1.0) { "Quality should be in range [0, 1]: $quality" }
    }
}

/**
 * A plugin that serves two primary purposes:
 * - Negotiating media types between the client and server. For this, it uses the `Accept` and `Content-Type` headers.
 * - Serializing/deserializing the content in a specific format.
 *    Ktor supports the following formats out-of-the-box: `JSON`, `XML`, `CBOR` and `ProtoBuf`.
 *
 * You can learn more from [Content negotiation and serialization](https://ktor.io/docs/server-serialization.html).
 *
 * [Report a problem](https://ktor.io/feedback/?fqname=io.ktor.server.plugins.contentnegotiation.ContentNegotiation)
 */
public val ContentNegotiation: RouteScopedPlugin<ContentNegotiationConfig> = createRouteScopedPlugin(
    "ContentNegotiation",
    ::ContentNegotiationConfig
) {
    convertRequestBody()
    convertResponseBody()

    // register default content types for application metadata, used in OpenAPI
    application.attributes[DefaultContentTypesAttribute] = pluginConfig.registrations.map { it.contentType }.distinct()
}

/**
 * Detects a suitable charset for an application call by using the `Accept` header or fallbacks to [defaultCharset].
 *
 * [Report a problem](https://ktor.io/feedback/?fqname=io.ktor.server.plugins.contentnegotiation.suitableCharset)
 */
public fun ApplicationCall.suitableCharset(defaultCharset: Charset = Charsets.UTF_8): Charset {
    for ((charset, _) in request.acceptCharsetItems()) {
        when {
            charset == "*" -> return defaultCharset
            Charsets.isSupported(charset) -> return Charsets.forName(charset)
        }
    }
    return defaultCharset
}