2017-08-16 3 views
2

J'utilise Ektorp comme CouchDB "ORM" mais cette question semble plus générale. Quelqu'un pourrait-il expliquer quelle est la différence entreKotlin mutators

@JsonInclude(NON_NULL) 
abstract class AbstractEntity(
     id: String?, 
     revision: String? 
) { 

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

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

} 

et

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

?

Pour le premier cas Ektorp ne se plaint pas, mais pour le second, il dit:

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) 

En plus de cela, si je

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

je reçois:

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

La question est de savoir en quoi le premier extrait de code est différent du second? Dans le premier cas Ektorp "pense" il y a un mutateur mais pas dans le second ...

Voici l'extrait de code qu'Ektorp semble utiliser pour localiser une méthode (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; 
     } 

Répondre

1

La différence est la façon dont l'application des annotations aux propriétés définies dans le corps de la classe diffère des propriétés déclarées dans annoter un constructeur primaire.

Voir: Annotation Use-site Targets dans la référence de la langue:

Lorsque vous annoter une propriété ou un paramètre constructeur primaire, il y a plusieurs éléments Java qui sont générés à partir de l'élément Kotlin correspondant, et donc plusieurs emplacements possibles pour l'annotation dans le bytecode Java généré.

Si vous ne spécifiez pas une cible utilisation du site, la cible est choisie en fonction de l'annotation @Target de l'annotation utilisée. Si plusieurs cibles applicables, la première cible applicable dans la liste suivante est utilisée:

  • param
  • property
  • field

Ainsi, lorsque vous annoter une propriété déclarée un constructeur principal, c'est le paramètre constructeur qui obtient par défaut l'annotation dans le bytecode Java. Pour modifier cela, spécifier la cible d'annotation explicitement, par exemple:

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

Bien que cela résout le problème avec var cela n'explique pas encore pourquoi l'utilisation * val * champ ne produit pas exception « ne peut pas résoudre la révision mutator » lors de l'utilisation il dans le constructeur (même avec votre solution) fait ... des idées? La logique suggère que val ne devrait pas fonctionner car il ne crée pas de setter ...mais il le fait (lorsqu'il est utilisé comme un champ, pas dans une déclaration constructeur qui rend les choses encore plus bizarres) – kboom

+0

Je n'ai pas travaillé avec cet outil, donc je peux seulement supposer qu'il détecte un constructeur qu'il peut utiliser pour créer un nouvel objet avec les valeurs de propriété mises à jour au lieu de définir les propriétés mutables, ce qui est suffisant. – hotkey

+0

Sauf que cela fonctionne dans l'autre sens - cela ne fonctionne que si j'utilise les champs déclaration (constructeur externe) - mais toujours "val". Quoi qu'il en soit, cela doit être plus de détails de mise en œuvre ektorp lib ... – kboom