All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.pwall.json.JSONFun.kt Maven / Gradle / Ivy

/*
 * @(#) JSONFun.kt
 *
 * json-kotlin Kotlin JSON Auto Serialize/deserialize
 * Copyright (c) 2019, 2020 Peter Wall
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package net.pwall.json

import kotlin.reflect.KClass
import kotlin.reflect.KType
import kotlin.reflect.KTypeProjection
import kotlin.reflect.full.createType
import kotlin.reflect.full.starProjectedType

import java.lang.reflect.ParameterizedType
import java.lang.reflect.Type
import java.lang.reflect.WildcardType
import java.math.BigDecimal
import java.math.BigInteger

/**
 * Type alias for `JSONInt` to make it closer to Kotlin standard class names.
 */
typealias JSONInt = JSONInteger

/**
 * Type alias to simplify the definition of `fromJSON` mapping functions.
 */
typealias FromJSONMapping = (JSONValue?) -> Any?

/**
 * Type alias to simplify the definition of `toJSON` mapping functions.
 */
typealias ToJSONMapping = (Any?) -> JSONValue?

/**
 * More Kotlin-like conversion function name.
 *
 * @return  the value as a [BigInteger]
 */
fun JSONNumberValue.toBigInteger(): BigInteger = bigIntegerValue()

/**
 * More Kotlin-like conversion function name.
 *
 * @return  the value as a [BigDecimal]
 */
fun JSONNumberValue.toBigDecimal(): BigDecimal = bigDecimalValue()

/**
 * Convert a [CharSequence] ([String], [StringBuilder] etc.) to a [JSONValue].
 *
 * @receiver    the [CharSequence] to be converted
 * @return      the [JSONValue]
 */
fun CharSequence.asJSONValue(): JSONValue = JSONString(this)

/**
 * Convert a [Char] to a [JSONValue].
 *
 * @receiver    the [Char] to be converted
 * @return      the [JSONValue]
 */
fun Char.asJSONValue(): JSONValue = JSONString(StringBuilder().append(this))

/**
 * Convert an [Int] to a [JSONValue].
 *
 * @receiver    the [Int] to be converted
 * @return      the [JSONValue]
 */
fun Int.asJSONValue(): JSONValue = JSONInt.valueOf(this)

/**
 * Convert a [Long] to a [JSONValue].
 *
 * @receiver    the [Long] to be converted
 * @return      the [JSONValue]
 */
fun Long.asJSONValue(): JSONValue = JSONLong.valueOf(this)

/**
 * Convert a [Short] to a [JSONValue].
 *
 * @receiver    the [Short] to be converted
 * @return      the [JSONValue]
 */
fun Short.asJSONValue(): JSONValue = JSONInt.valueOf(this.toInt())

/**
 * Convert a [Byte] to a [JSONValue].
 *
 * @receiver    the [Byte] to be converted
 * @return      the [JSONValue]
 */
fun Byte.asJSONValue(): JSONValue = JSONInt.valueOf(this.toInt())

/**
 * Convert a [Float] to a [JSONValue].
 *
 * @receiver    the [Float] to be converted
 * @return      the [JSONValue]
 */
fun Float.asJSONValue(): JSONValue = JSONFloat.valueOf(this)

/**
 * Convert a [Double] to a [JSONValue].
 *
 * @receiver    the [Double] to be converted
 * @return      the [JSONValue]
 */
fun Double.asJSONValue(): JSONValue = JSONDouble.valueOf(this)

/**
 * Convert a [Boolean] to a [JSONValue].
 *
 * @receiver    the [Boolean] to be converted
 * @return      the [JSONValue]
 */
fun Boolean.asJSONValue(): JSONValue = JSONBoolean.valueOf(this)

/**
 * Convert any object to a [JSONValue].
 *
 * @receiver        the object to be converted
 * @param   config  an optional [JSONConfig] to customise the conversion
 * @return          the [JSONValue]
 */
fun Any?.asJSONValue(config: JSONConfig = JSONConfig.defaultConfig): JSONValue? = JSONSerializer.serialize(this, config)

/**
 * Create a [Pair] of [String] and [JSONValue]? for use with [makeJSON].
 *
 * @receiver    the [String]
 * @param   str a [CharSequence] ([String], [StringBuilder] etc.)
 * @return      the [Pair]
 */
infix fun String.isJSON(str: CharSequence?): Pair = this to str?.asJSONValue()

/**
 * Create a [Pair] of [String] and [JSONValue]? for use with [makeJSON].
 *
 * @receiver    the [String]
 * @param   ch  a [Char]
 * @return      the [Pair]
 */
infix fun String.isJSON(ch: Char): Pair = this to ch.asJSONValue()

/**
 * Create a [Pair] of [String] and [JSONValue]? for use with [makeJSON].
 *
 * @receiver    the [String]
 * @param   i   an [Int]
 * @return      the [Pair]
 */
infix fun String.isJSON(i: Int): Pair = this to i.asJSONValue()

/**
 * Create a [Pair] of [String] and [JSONValue]? for use with [makeJSON].
 *
 * @receiver    the [String]
 * @param   i   a [Long]
 * @return      the [Pair]
 */
infix fun String.isJSON(i: Long): Pair = this to i.asJSONValue()

/**
 * Create a [Pair] of [String] and [JSONValue]? for use with [makeJSON].
 *
 * @receiver    the [String]
 * @param   s   a [Short]
 * @return      the [Pair]
 */
infix fun String.isJSON(s: Short): Pair = this to s.asJSONValue()

/**
 * Create a [Pair] of [String] and [JSONValue]? for use with [makeJSON].
 *
 * @receiver    the [String]
 * @param   b   a [Byte]
 * @return      the [Pair]
 */
infix fun String.isJSON(b: Byte): Pair = this to b.asJSONValue()

/**
 * Create a [Pair] of [String] and [JSONValue]? for use with [makeJSON].
 *
 * @receiver    the [String]
 * @param   f   a [Float]
 * @return      the [Pair]
 */
infix fun String.isJSON(f: Float): Pair = this to f.asJSONValue()

/**
 * Create a [Pair] of [String] and [JSONValue]? for use with [makeJSON].
 *
 * @receiver    the [String]
 * @param   d   a [Double]
 * @return      the [Pair]
 */
infix fun String.isJSON(d: Double): Pair = this to d.asJSONValue()

/**
 * Create a [Pair] of [String] and [JSONValue]? for use with [makeJSON].
 *
 * @receiver    the [String]
 * @param   b   a [Boolean]
 * @return      the [Pair]
 */
infix fun String.isJSON(b: Boolean): Pair = this to b.asJSONValue()

/**
 * Create a [JSONObject] from a list of [Pair]s of [String]s and [JSONValue]s.
 *
 * @param   pairs   the list of pairs
 * @return          the [JSONObject]
 */
fun makeJSON(vararg pairs: Pair) = JSONObject().apply { putAll(pairs) }

/**
 * Deserialize JSON from string ([CharSequence]) to a specified [KType].
 *
 * @receiver            the JSON in string form
 * @param   resultType  the target type
 * @param   config      an optional [JSONConfig] to customise the conversion
 * @return              the converted object
 */
fun CharSequence.parseJSON(resultType: KType, config: JSONConfig = JSONConfig.defaultConfig): Any? =
        JSONAuto.parse(resultType, this, config)

/**
 * Deserialize JSON from string ([CharSequence]) to a specified [KClass].
 *
 * @receiver            the JSON in string form
 * @param   resultClass the target class
 * @param   config      an optional [JSONConfig] to customise the conversion
 * @param   T           the target class
 * @return              the converted object
 */
fun  CharSequence.parseJSON(resultClass: KClass, config: JSONConfig = JSONConfig.defaultConfig): T? =
        JSONAuto.parse(resultClass, this, config)

/**
 * Deserialize JSON from string ([CharSequence]) to a the inferred [KClass].
 *
 * @receiver        the JSON in string form
 * @param   config  an optional [JSONConfig] to customise the conversion
 * @param   T       the target class
 * @return          the converted object
 */
inline fun  CharSequence.parseJSON(config: JSONConfig = JSONConfig.defaultConfig): T? =
        JSONAuto.parse(this, config)

/**
 * Stringify any object to JSON.
 *
 * @receiver        the object to be converted to JSON (`null` will be converted to `"null"`).
 * @param   config  an optional [JSONConfig] to customise the conversion
 * @return          the JSON string
 */
fun Any?.stringifyJSON(config: JSONConfig = JSONConfig.defaultConfig): String = JSONStringify.stringify(this, config)

/**
 * Helper method to create a [KType] for a parameterised type, for use as the target type of a deserialization.
 *
 * @param   mainClass       the parameterised class
 * @param   paramClasses    the parameter classes
 * @param   nullable        `true` if the [KType] is to be nullable
 * @return                  the [KType]
 */
fun targetKType(mainClass: KClass<*>, vararg paramClasses: KClass<*>, nullable: Boolean = false): KType =
        mainClass.createType(paramClasses.map { KTypeProjection.covariant(it.starProjectedType) }, nullable)

/**
 * Helper method to create a [KType] for a parameterised type, for use as the target type of a deserialization.
 *
 * @param   mainClass       the parameterised class
 * @param   paramTypes      the parameter types
 * @param   nullable        `true` if the [KType] is to be nullable
 * @return                  the [KType]
 */
fun targetKType(mainClass: KClass<*>, vararg paramTypes: KType, nullable: Boolean = false): KType =
        mainClass.createType(paramTypes.map { KTypeProjection.covariant(it) }, nullable)

/**
 * Convert a Java [Type] to a Kotlin [KType].  This allows Java [Type]s to be used as the target type of a
 * deserialization operation.
 *
 * This function is not complete, but with any luck it will cover the great majority of usages.
 *
 * @receiver    the Java [Type] to be converted
 * @param       nullable    `true` if the [KType] is to be nullable
 * @return      the resulting Kotlin [KType]
 * @throws      JSONException if the [Type] can not be converted
 */
fun Type.toKType(nullable: Boolean = false): KType = when (this) {
    is Class<*> -> this.kotlin.createType(nullable = nullable)
    is ParameterizedType -> (this.rawType as Class<*>).kotlin.createType(this.actualTypeArguments.map {
        when (it) {
            is WildcardType ->
                if (it.lowerBounds?.firstOrNull() == null)
                    KTypeProjection.covariant(it.upperBounds[0].toKType(true))
                else
                    KTypeProjection.contravariant(it.lowerBounds[0].toKType(true))
            else -> KTypeProjection.invariant(it.toKType(true))
        } }, nullable)
    else -> throw JSONException("Can't handle type: $this")
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy