Migration d’une application Android avec Dagger depuis Java vers Kotlin

Introduction

Si vous avez déjà essayé de migrer une classe depuis Java vers Kotlin, vous savez que l’outil fourni par Android Studio n’est pas suffisant. Même si votre nouveau fichier semble correctement converti, l’outil ne sera pas capable de vous éviter certains crashs et tout votre historique GIT aura disparu. Cet article va vous aider à effectuer cette migration sereinement et à conserver votre précieux historique GIT. Il ne sera cependant pas discuté ici des avantages ou inconvénients d’une telle migration par rapport à Java, il existe déjà sur internet de nombreux articles traitant de ce sujet.

Buts de la migration

Si nous voulons considérer notre migration comme étant un succès, nous pouvons fixer comme objectifs :

  • Aucune différence notable dans l’application en terme de fonctionnalités et de taux de crash
  • La conservation des tests unitaires existants et le même pourcentage de coverage
  • La conservation de l’historique git des fichiers convertis

Avant de migrer

Migrer un projet depuis Java vers Kotlin d’un seul coup peut représenter une tâche très longue dans un contexte Agile, mais la méthode présentée vous permettra de le faire à votre propre rythme en découpant en autant de tâches que vous le souhaitez. Cependant, gardez en tête que migrer un fichier quand bon vous semble n’est pas possible car chaque étape de migration nécessitant une étape d’initialisation et de conclusion.

Procédure recommandée

Il y a plusieurs manières de faire une telle migration correctement, en voici un exemple pour ne rien oublier:

  1. Définissez quels fichiers vous allez convertir durant votre migration. Le nombre de fichiers n’a pas d’importance, mais comme dit précédemment il est important de définir exactement les fichiers qui vont être concernés sans en rajouter.
  2. Renommez tous les .java files to .kt, commitez ce changement sur le git puis renommez les en .java et commitez de nouveau. Cette étape va vous aider à garder l’historique GIT, voir la section Conservez l’hitorique GIT.
  3. Concentrez vous d’abord sur le build.gradle:
    • Retirez les implémentations relatives à Java : Butterknife, AutoValue
    • Ajouter les paramètres, plugins, et implémentation relatives à Kotlin 
    • Pensez à changer le mot clé annotationProcessor par kapt
  4. Essayez de compiler. Cela devrait probablement échouer avec une erreur, et c’est tant mieux ! Cela vous permettra de bien cerner les fichiers affectés par l’étape précédente. Convertissez-les tous jusqu’à pouvoir compiler.
  5. Si vous utilisez Dagger, convertissez les Components et les Modules
  6. Compilez et lancez les tests unitaires
  7. Squashez vos commits, voir la section Conservez l’hitorique GIT.
  8. Renommez le dossier src “java” en “kotlin”

Convertir un fichier Java en Kotlin

Pour convertir un fichier Java en Kotlin, vous pouvez utiliser l’outil fourni par Android Studio, sélectionnez votre fichier Java puis dans Android Studio Menu -> Code -> Convert Java File to Kotlin File. Mais ce n’est pas tout. Android Studio a maintenant converti automatiquement votre fichier en Kotlin, mais il n’utilisera pas la syntaxe propre à Kotlin lorsque cela est possible, pour cela vous devez manuellement :

  • Remplacez
@Inject
var myVar: MyType? = null

par

@Inject
lateinit var myVar
  • Remplacez !! par ?. Ce n’est pas obligatoire, mais cela permet d’éviter beaucoup de crashs.
  • Remplacez
if (myVal != null) { …

} else {

…
}

par

myVal?.

let {

…

} ?: run {

…
}

ou si l’instruction en cas de null ne fait qu’une seule ligne

myVal?.

let {

…

} ?: // instruction sur une seule ligne
  • Remplacez
for(int i = 0; i<size; i++){

 list[i]

}

par

list.forEach {

…

}

Pour résumer : il est mieux d’utiliser les fonctions de Kotlin autant que vous le pourrez.

Conserver l'historique Git

Simplement convertir un fichier Kotlin vous fera perdre les changements effectués sur celui-ci depuis sa création, parce que GIT considère que vous avez supprimé l’ancien fichier Java et recréé un nouveau en Kotlin, il n’est pas capable de faire le lien entre les deux. Pour l’aider, vous devrez faire les deux premières étapes de la partie  Procédure recommandée.

Après cela, vous devriez vous retrouver avec ces commits :

last commit: [COS-XXXX] end Kotlin conversion

…

commit 3: [COS-XXXX] begin Kotlin conversion
commit 2: [COS-XXXX] rename .kt files to .java
commit 1: [COS-XXXX] rename .java files to .kt

Copiez le SHA-1 du premier commit. Ensuite dans le terminal d’Android Studio tapez :

git rebase -i sha1OfTheFirstCommit

Le terminal devrait vous présenter un fichier avec cette structure :

pick be5418cf9c [COS-XXXX] rename .kt files to .java
pick 794e22c073 [COS-XXXX] begin Kotlin conversion

…

pick 5f4c0f4a2d [COS-XXXX] end Kotlin conversion

Maintenant vous pouvez squashez vos commits sur le premier, pour cela, pour chaque ligne sauf la première, remplacez “pick” par “s” (pour squash) :

pick be5418cf9c [COS-XXXX] rename .kt files to .java
s 794e22c073 [COS-XXXX] begin Kotlin conversion

…

s 5f4c0f4a2d [COS-XXXX] end Kotlin conversion

GIT devrait essayer de rebase et squash vos commits. Si vous avez des conflits à cette étape, résolvez-les et continuez le rebase.

git rebase –continue. 

GIT affiche maintenant :

# This is a combination of X commits.
# This is the 1st commit message:

[COS-XXXX] rename .kt files to .java

# This is the commit message #2:

[COS-XXXX] begin Kotlin conversion

…

# This is the commit message #X:

[COS-XXXX] end Kotlin conversion

Ce sera le nom du commit squashé. Répétez l’étape précédente jusqu’à voir le message de succès.Maintenant si vous essayez de regarder l’historique GIT de votre fichier, il se peut que vous ne voyez pas tous les commits… Pourquoi ? Parce que le squash des commits semble perturber le cache du GIT d’Android Studio, pour voir ces précieux commits et vérifier que tout s’est bien passé, il est recommandé d’invalider ce cache en faisant : Android Studio Menu -> File -> Invalidate Caches / Restart.

Tips

Compile compile compile

Essayez de compiler aussi souvent que vous pouvez lorsque vous convertissez les Modules et Components, cela vous aidera à identifier les fichiers qui provoquent des erreurs de compilation.

Les binds des Dagger Modules

Si vous utilisez des binds dans vos Modules Java :

@Module

abstract class ClientSearchCardChoiceModule {

@Binds

@Provides

abstract SearchClientRepository bindSearchClientRepository(SearchClientLocalRepository repository);
@SingleIn(ClientSearchCardChoiceComponent.class)

@MutableExecutorDecorator

static ClientSearchCardChoiceDisplay provideDisplay(final MutableDecorator<ClientSearchCardChoiceDisplay> decorator) {

 return decorator.asDecorated();
}

…

Vous devez alors rendre votre module abstrait, créer une classe interne ProvideModule Module comme ceci :

@Module(includes = [ProvideModule::class])
abstract class ClientSearchCardChoiceModule {

@Binds

abstract fun bindSearchClientRepository(repository: SearchClientLocalRepository): SearchClientRepository

@Module

internal class ProvideModule {

@Provides

@SingleIn(ClientSearchCardChoiceComponent::class) @MutableExecutorDecorator

internal fun provideClientSearchCardChoiceDisplay(decorator: MutableDecorator): ClientSearchCardChoiceDisplay {

 return decorator.asDecorated()
}

…

Les injections nommées avec Dagger

En Java il est possible de faire :

@Inject @Named(« logOutflwRunnable »)
Runnable logOutflowRunnable;

Mais pour l’utiliser en Kotlin il faudra faire :

@field:[Inject Named(« courseEventInflowRunnable »)]
lateinit var logOutflowRunnable: Runnable

Ne renommez pas avant de squasher

Faites attention à ne pas renommer le dossier src avant de squasher, GIT risque de perdre l’historique de vos fichiers !

Git panic

Si vous vous trompez dans vos commits pendant la conversion et que vous souhaitez revenir en arrière, pensez à faire :

git reflog

puis

git reset –hard HEAD@{x} 

x étant le numéro du commit affiché avec reflog

Conclusion

Si vous avez tout fait correctement vous devriez vous retrouver avec un code Kotlin propre, une application fonctionnelle, un historique GIT complet et des des tests unitaires avec le même coverage. Souvenez-vous de faire ça à votre propre rythme et de ne pas sous-estimer la complexité d’une telle migration, qui peut être difficile à effectuer au début. Mais rassurez-vous,  le jeu en vaut la chandelle et pouvoir utiliser la puissance de Kotlin en vaut la peine !

Vous avez un projet de migration de votre application Android de Java vers Kotlin ? Contactez-nous afin de réaliser cette migration de la meilleure manière avec nos experts via notre formulaire de contact.

Corentin CHATELLIER – Ingénieur développement mobile