Kotlin 修改器

Kotlin mutators

我将 Ektorp 用作 CouchDB "ORM" 但这个问题似乎比那个问题更笼统。有人可以解释一下

之间的区别吗
@JsonInclude(NON_NULL)
abstract class AbstractEntity(
        id: String?,
        revision: String?
) {

    @JsonProperty("_id")
    val id: String? = id

    @JsonProperty("_rev")
    val revision: String? = revision

}

@JsonInclude(NON_NULL)
abstract class AbstractEntity(
        @JsonProperty("_id")
        val id: String? = null,
        @JsonProperty("_rev")
        val revision: String? = null
)

?

对于第一种情况,Ektorp 没有抱怨,但对于第二种情况,它说:

org.ektorp.InvalidDocumentException: Cannot resolve revision mutator in class com.scherule.calendaring.domain.Meeting

    at org.ektorp.util.Documents$MethodAccessor.assertMethodFound(Documents.java:165)
    at org.ektorp.util.Documents$MethodAccessor.<init>(Documents.java:144)
    at org.ektorp.util.Documents.getAccessor(Documents.java:113)
    at org.ektorp.util.Documents.getRevision(Documents.java:77)
    at org.ektorp.util.Documents.isNew(Documents.java:85)

除此之外如果我这样做

@JsonInclude(NON_NULL)
abstract class AbstractEntity(
        @JsonProperty("_id")
        var id: String? = null,
        @JsonProperty("_rev")
        var revision: String? = null
)

我得到:

org.ektorp.DbAccessException: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "_id" (class com.scherule.calendaring.domain.Meeting), not marked as ignorable

问题是第一个代码片段与第二个代码片段有何不同?在第一种情况下,Ektorp "thinks" 有一个增变器,但在第二种情况下没有...

这是 Ektorp 在定位方法(setId、setRevision)时似乎使用的代码片段。

private Method findMethod(Class<?> clazz, String name,
                Class<?>... parameters) throws Exception {
            for (Method me : clazz.getDeclaredMethods()) {
                if (me.getName().equals(name)
                        && me.getParameterTypes().length == parameters.length) {
                    me.setAccessible(true);
                    return me;
                }
            }
            return clazz.getSuperclass() != null ? findMethod(
                    clazz.getSuperclass(), name, parameters) : null;
        }

不同之处在于将注释应用到 class 主体中定义的属性与在主构造函数中声明的注释属性有何不同。

参见:Annotation Use-site Targets 语言参考:

When you're annotating a property or a primary constructor parameter, there are multiple Java elements which are generated from the corresponding Kotlin element, and therefore multiple possible locations for the annotation in the generated Java bytecode.

If you don't specify a use-site target, the target is chosen according to the @Target annotation of the annotation being used. If there are multiple applicable targets, the first applicable target from the following list is used:

  • param
  • property
  • field

因此,当您注释在主构造函数中声明的 属性 时,它是默认情况下在 Java 字节码中获取注释的构造函数参数。要更改它,请明确指定注释目标,例如:

abstract class AbstractEntity(
    @get:JsonProperty("_id")
    val id: String? = null,
    @get:JsonProperty("_rev")
    val revision: String? = null
)