代码之家  ›  专栏  ›  技术社区  ›  Jan Wytze

带接口的KTor Gson数据转换

  •  0
  • Jan Wytze  · 技术社区  · 7 年前

    我正在试着注册 PubicKey

    data class StoreRequest(
        val publicKey: PublicKey
    )
    ...
    val publicKey: PublicKey = call.receive<StoreRequest>().publicKey
    

    为此,我使用了以下页面: https://ktor.io/servers/features/data-conversion.html
    我注册了这个数据转换器:

    convert<PublicKey> {
        decode { values, _ ->
            // When I add a breakpoint here it won't be reached.
            values.singleOrNull()?.let { key ->
                val encryptedKey = Base64.getDecoder().decode(key.split(" ")[1])
                val inputStream = DataInputStream(ByteArrayInputStream(encryptedKey))
    
                val format = String(ByteArray(inputStream.readInt()).also(inputStream::readFully))
    
                if (format != "ssh-rsa") throw RuntimeException("Unsupported format")
    
                val publicExponent = ByteArray(inputStream.readInt()).also(inputStream::readFully)
                val modulus = ByteArray(inputStream.readInt()).also(inputStream::readFully)
    
                val spec = RSAPublicKeySpec(BigInteger(modulus), BigInteger(publicExponent))
                val keyFactory = KeyFactory.getInstance("RSA")
    
                keyFactory.generatePublic(spec)
            }
        }
    }
    

    但出于某种原因,Gson正在抱怨,因为我使用的是一个接口:

    java.lang.RuntimeException: Unable to invoke no-args constructor for interface java.security.PublicKey. Register an InstanceCreator with Gson for this type may fix this problem`
    

    InstanceCreator 这是首字母 PublicKey 第一类创建:

    class PkTest : PublicKey {
        override fun getAlgorithm(): String = ""
        override fun getEncoded(): ByteArray = ByteArray(0)
        override fun getFormat(): String = ""
    }
    ...
    install(ContentNegotiation) {
        gson {
            setPrettyPrinting()
            registerTypeAdapter(PublicKey::class.java, InstanceCreator<PublicKey> { PkTest() // This is called when I add a breakpoint })
        }
    }
    

    com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 2 column 16 path $.publicKey
    

    {
        "publicKey": "ssh-rsa AAAAB3NzaC1yc2EABAADAQABAAACAQDBPL2s+25Ank3zS6iHUoVk0tS63dZM0LzAaniiDon0tdWwq4vcL4+fV8BsAEcpMeijS92JhDDc9FccXlHbdDcmd6c4ITOt9h9xxhIefGsi1FTVJ/EjVtbqF5m0bu7ruIMGvuP1p5s004roHx9y0UdHvD/yNWLISMhy4nio6jLailIj3FS53Emj1WRNsOrpja3LzPXzhuuj6YnD9yfByT7iGZipxkmleaXrknChPClLI9uhcqtAzBLdd0NVTJLOt/3+d1cSNwdBw9e53wJvpEmH+P8UOZd+oV/y7cHIej4jQpBXVvpJR1Yaluh5RuxY90B0hSescUAj5g/3HVPpR/gE7op6i9Ab//0iXF15uWGlGzipI4lA2/wYEtv8swTjmdCTMNcTDw/1huTDEzZjghIKVpskHde/Lj416c7eSByLqsMg2OhlZGChKznpIjhuNRXz93DwqKuIKvJKSnhqaJDxmDGfG7nlQ/eTwGeAZ6VR50yMPiRTIpuYd767+Nsg486z7p0pnKoBlL6ffTbfeolUX2b6Nb9ZIOxJdpCSNTQRKQ50p4Y3S580cUM1Y2EfjlfIQG1JdmTQYB75AZXi/cB2PvScmF0bXRoj7iHg4lCnSUvRprWA0xbwzCW/wjNqw6MyRX42FFlvSRrmfaxGZxKYbmk3TzBv+Fp+CADPqQm3OQ== dynmem@memmen.frl"
    }
    

    公钥

    我认为GSON希望将JSON对象序列化为 公钥 . 但我希望它能接受 String . 我认为这应该是可能的,因为类 UUID Date 工作很好。。。

    1 回复  |  直到 7 年前
        1
  •  2
  •   Jan Wytze    7 年前

    我解决了!而不是使用 InstanceCreator 我用了一个 JsonDeserializer :

    install(ContentNegotiation) {
        gson {
            setPrettyPrinting()
            registerTypeAdapter(PublicKey::class.java, JsonDeserializer<PublicKey> { json, _, _ ->
                // TODO some type checking.
                val key = json.asString
                val encryptedKey = Base64.getDecoder().decode(key.split(" ")[1])
                val inputStream = DataInputStream(ByteArrayInputStream(encryptedKey))
    
                val format = String(ByteArray(inputStream.readInt()).also(inputStream::readFully))
    
                if (format != "ssh-rsa") throw RuntimeException("Unsupported format")
    
                val publicExponent = ByteArray(inputStream.readInt()).also(inputStream::readFully)
                val modulus = ByteArray(inputStream.readInt()).also(inputStream::readFully)
    
                val spec = RSAPublicKeySpec(BigInteger(modulus), BigInteger(publicExponent))
                val keyFactory = KeyFactory.getInstance("RSA")
    
                keyFactory.generatePublic(spec)
            })
        }
    }
    

    此零件可以完全拆下:

    convert<PublicKey> {
        decode { values, _ ->
            ...
        }
    }