伴生对象与多态
package com.tencent.bk.devops.atom.task.repository import com.tencent.bk.devops.atom.task.utils.RepoAuthType data class CodeBitbucketRepository( override val aliasName: String, override val url: String, override val credentialId: String, override val projectName: String, override val userName: String, val authType: RepoAuthType? = RepoAuthType.SSH, override val projectId: String?, override val repoHashId: String? ) : Repository { companion object { // const val classType = "codeGitLab" const val classType = "gitlab" } override fun getStartPrefix() = "git@git.code.oa.com" override fun isLegal() = true }
详细解释一下 companion object { // const val classType = "codeGitLab" const val classType = "gitlab" }
companion object
是 Kotlin 中的一种机制,用来在类中定义一个伴生对象(Companion Object)。伴生对象的成员类似于 Java 中的静态成员(static members),即它们属于类而不是某个具体的实例。使用伴生对象可以在不创建类实例的情况下访问其成员。在你的代码中,伴生对象的定义如下:
kotlin
companion object { // const val classType = "codeGitLab" const val classType = "gitlab" }
下面是对这段代码的详细解释:
-
companion object:
- 这表示定义一个伴生对象。伴生对象的名字可以省略,默认名字是
Companion
。 - 伴生对象中的成员可以通过类名直接访问,无需实例化类。
- 这表示定义一个伴生对象。伴生对象的名字可以省略,默认名字是
-
const val classType = "gitlab":
const val
是 Kotlin 中用于定义编译时常量(compile-time constant)的关键字。classType
是一个常量属性,它的值是字符串"gitlab"
。- 这意味着
classType
是一个不可变的常量,并且可以在编译时确定其值。
-
被注释掉的代码
// const val classType = "codeGitLab"
:- 这是被注释掉的代码行,表示之前
classType
的值是"codeGitLab"
。注释掉它可能是因为不再需要这个值,或者是为了保留历史记录。
- 这是被注释掉的代码行,表示之前
在实际使用中,这个 classType
常量可以在 JsonSubTypes
注解中用于标识 CodeBitbucketRepository
类型。例如:
kotlin
@JsonSubTypes( JsonSubTypes.Type(value = CodeBitbucketRepository::class, name = CodeBitbucketRepository.classType) )
在上述注解中,CodeBitbucketRepository::class
表示 CodeBitbucketRepository
类,而 CodeBitbucketRepository.classType
使用了伴生对象中的 classType
常量作为标识符。这种做法使代码更具可读性和可维护性,因为标识符集中在一个地方定义,可以避免硬编码字符串散布在代码中。
总结:
companion object
定义了一个伴生对象,使得classType
常量可以通过类名直接访问。const val classType = "gitlab"
定义了一个编译时常量。- 伴生对象的这种用法有助于更好地组织代码,使标识符和常量更容易管理和维护。
package com.tencent.bk.devops.atom.task.repository import com.fasterxml.jackson.annotation.JsonSubTypes import com.fasterxml.jackson.annotation.JsonTypeInfo @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "@type") @JsonSubTypes( JsonSubTypes.Type(value = CodeBitbucketRepository::class, name = CodeBitbucketRepository.classType) ) interface Repository { val aliasName: String val url: String val credentialId: String val projectName: String val userName: String val projectId: String? val repoHashId: String? // svn start with svn+ssh:// fun isLegal() = url.startsWith(getStartPrefix()) fun getStartPrefix(): String fun getFormatURL() = url } 详细解释一下@JsonSubTypes( JsonSubTypes.Type(value = CodeBitbucketRepository::class, name = CodeBitbucketRepository.classType) )
ChatGPT
@JsonSubTypes
注解用于指定在反序列化时可用的子类型。这个注解通常与 @JsonTypeInfo
一起使用,以支持多态类型的序列化和反序列化。它允许 Jackson 库根据类型信息正确地实例化具体的子类。
在你的代码中:
kotlin
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "@type") @JsonSubTypes( JsonSubTypes.Type(value = CodeBitbucketRepository::class, name = CodeBitbucketRepository.classType) ) interface Repository { val aliasName: String val url: String val credentialId: String val projectName: String val userName: String val projectId: String? val repoHashId: String? fun isLegal() = url.startsWith(getStartPrefix()) fun getStartPrefix(): String fun getFormatURL() = url }
这里有两个注解:@JsonTypeInfo
和 @JsonSubTypes
,我们来详细解释它们。
@JsonTypeInfo
kotlin
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "@type")
- use:指定类型信息的使用方式。
JsonTypeInfo.Id.NAME
表示使用类型名称。 - include:指定类型信息的包含方式。
JsonTypeInfo.As.PROPERTY
表示将类型信息作为一个属性包含在 JSON 对象中。 - property:指定类型信息的属性名称。在这个例子中,类型信息会作为
@type
属性包含在 JSON 中。
@JsonSubTypes
kotlin
@JsonSubTypes( JsonSubTypes.Type(value = CodeBitbucketRepository::class, name = CodeBitbucketRepository.classType) )
- 这个注解定义了一个多态类型的子类型映射,使得 Jackson 能够在反序列化时根据
@type
属性的值来实例化具体的子类。 - JsonSubTypes.Type:这是一个内部类,用于指定子类型映射。
- value:指定具体的子类。在这个例子中是
CodeBitbucketRepository::class
,表示CodeBitbucketRepository
类。 - name:指定子类型的名称。在这个例子中使用了
CodeBitbucketRepository.classType
,其值是"gitlab"
。
- value:指定具体的子类。在这个例子中是
具体使用场景
假设你有以下 JSON 数据:
json
{ "@type": "gitlab", "aliasName": "MyRepo", "url": "http://example.com/repo.git", "credentialId": "12345", "projectName": "Project", "userName": "User", "projectId": "67890", "repoHashId": "abcde" }
当 Jackson 反序列化这个 JSON 数据时,它会查看 @type
属性的值,发现是 "gitlab"
。然后,它会使用 JsonSubTypes
注解中定义的映射来决定实例化 CodeBitbucketRepository
类,并将 JSON 数据映射到这个类的实例中。
为什么这样使用
- 多态支持:使用
@JsonTypeInfo
和@JsonSubTypes
注解可以使 Jackson 支持多态类型的序列化和反序列化。在处理复杂对象结构时,这非常有用。 - 可扩展性:你可以轻松地添加新的子类型,只需在
@JsonSubTypes
注解中添加新的映射即可。 - 避免硬编码:通过使用
classType
常量,可以避免在多个地方硬编码类型名称,提高代码的可维护性。
总结:
@JsonTypeInfo
定义了类型信息的使用方式和包含方式。@JsonSubTypes
定义了多态类型的子类型映射,使得 Jackson 能够正确地实例化具体的子类。- 这种组合使用可以帮助 Jackson 在处理多态类型时更灵活和可扩展。
不积跬步,无以至千里;不积小流,无以成江海。