web-dev-qa-db-fra.com

Génération de code de modèle de générateur dans IntelliJ

Existe-t-il un moyen d'automatiser l'écriture de modèles Builder dans IntelliJ?

Par exemple, étant donné cette classe simple:

class Film {
   private String title;
   private int length;

   public void setTitle(String title) {
       this.title = title;
   }

   public String getTitle() {
       return this.title;
   }

   public void setLength(int length) {
       this.length = length;
   }

   public int getLength() {
       return this.length;
   }
}

existe-t-il un moyen d'obtenir le IDE pour générer ceci, ou similaire:

public class FilmBuilder {

    Film film;

    public FilmBuilder() {
        film = new Film();
    }

    public FilmBuilder withTitle(String title) {
        film.setTitle(title);
        return this;
    }

    public FilmBuilder withLength(int length) {
        film.setLength(length);
        return this;
    }

    public Film build() {
        return film;
    }
}
72
Martyn

Utilisez le constructeur de Remplacer avec Builder refactoring.

Pour utiliser cette fonction, cliquez sur la signature du constructeur dans votre code, cliquez avec le bouton droit de la souris et sélectionnez le menu "Refactor", puis cliquez sur "Remplacer le constructeur avec le constructeur ..." pour afficher la boîte de dialogue générant le code.

89
CrazyCoder

J'ai trouvé la génération de modèles de constructeur intégrée à IntelliJ un peu maladroite pour plusieurs raisons:

  1. Il doit utiliser un constructeur existant comme référence.
  2. Ce n'est pas rapidement accessible via le menu "Générer" (command+N sous OS X).
  3. Il ne génère que des classes Builder externes. Comme d'autres l'ont mentionné, il est très courant d'utiliser des classes internes statiques lors de l'implémentation du modèle de générateur.

Le plugin InnerBuilder résout tous ces problèmes et ne nécessite aucune installation ni configuration. Voici un exemple de générateur généré par le plugin:

public class Person {
    private String firstName;
    private String lastName;
    private int age;

    private Person(Builder builder) {
        firstName = builder.firstName;
        lastName = builder.lastName;
        age = builder.age;
    }

    public static final class Builder {
        private String firstName;
        private String lastName;
        private int age;

        public Builder() {
        }

        public Builder firstName(String firstName) {
            this.firstName = firstName;
            return this;
        }

        public Builder lastName(String lastName) {
            this.lastName = lastName;
            return this;
        }

        public Builder age(int age) {
            this.age = age;
            return this;
        }

        public Person build() {
            return new Person(this);
        }
    }
}
19
Mansoor Siddiqui

Voici comment surmonter les lacunes mentionnées par Mansoor Siddiqui :

1) Il doit utiliser un constructeur existant comme référence.

Ce qui est très facile à générer. Il suffit de frapper Alt + Ins sous Windows, appelez le menu Générer et choisissez Constructorname__.

2) Ce n'est pas rapidement accessible via le menu "Générer" (commande + N sous OS X)

Allez simplement à Settings -> Keymap, recherchez Builderet attribuez-lui un raccourci de votre choix (si vous utilisez cette fonctionnalité très souvent, ce qui est rarement le cas). Vous pouvez assigner Alt + B par exemple.

Une autre alternative est Ctrl + Shift + A (Trouver une action). Commencez à taper Builderet vous aurez immédiatement accès à la commande:

Find Action dialog

Vous pouvez utiliser ce raccourci pour obtenir rapidement l’accès à n’importe quelle fonction IntelliJ IDEA (cela vous aidera beaucoup lorsque vous ne vous souvenez pas exactement comment la commande est appelée et où la trouver).

3) Il ne génère que des classes Builder externes. Comme d'autres l'ont mentionné, il est très courant d'utiliser des classes internes statiques lors de la mise en œuvre du modèle de générateur.

Je préfère également mes constructeurs en tant que classes internes statiques. Malheureusement, il n’existe pas de solution simple, mais cela reste réalisable. Il vous suffit de définir vous-même la classe interne imbriquée (laissez-la vide), et lorsque vous appelez la boîte de dialogue Replace Constructor with Builder, choisissez l'option Use existing et sélectionnez votre classe interne. Fonctionne comme un charme! Cependant, il aurait été plus facile de rendre cette option configurable.

13
jFrenetic

Si vous vous demandez si cela peut être utilisé pour créer une classe avec une classe de constructeur interne telle que décrite par Joshua Block -, vous devez tout d'abord définir une classe interne vide, puis cochez la case "Utiliser l'existant" et recherchez votre nouvelle classe. créé (classe intérieure) et cliquez sur "Refactor".

PS! Le curseur doit résider dans le constructeur (pré-écrit) pour pouvoir utiliser la fonction de refactoring "Remplacer le constructeur par le constructeur".

9
PålOliver

Le moyen IntelliJ pour y parvenir est, à mon humble avis, est compliqué. Il existe deux plugins (je préfère celui-ci: https://plugins.jetbrains.com/plugin/7354 ) qui servent beaucoup mieux.

Par exemple, je préfère avoir la classe Builder comme classe interne du PoJo. Pour atteindre cet objectif avec IntelliJ, vous avez besoin de quelques coups supplémentaires.

Un autre avantage pour le plugin est l'emplacement de la fonctionnalité (dans le menu contextuel Generate...). 

5
nucatus

Lombok est le meilleur moyen de le faire! (Il a un plugin Intellij pour le support de la syntaxe https://plugins.jetbrains.com/plugin/6317-lombok-plugin )

Ajoutez simplement une annotation @Builder et, derrière les murs, ajoutera une implémentation de générateur à l'intérieur de l'objet. De nos jours, Lombok est comme un standard de l'industrie :)

Avec Lombok:

import lombok.Builder;
import lombok.Singular;
import Java.util.Set;

@Builder
public class BuilderExample {
  @Builder.Default private long created = System.currentTimeMillis();
  private String name;
  private int age;
  @Singular private Set<String> occupations;
}

Sans Lombok:

import Java.util.Set;

public class BuilderExample {
  private long created;
  private String name;
  private int age;
  private Set<String> occupations;

  BuilderExample(String name, int age, Set<String> occupations) {
    this.name = name;
    this.age = age;
    this.occupations = occupations;
  }

  private static long $default$created() {
    return System.currentTimeMillis();
  }

  public static BuilderExampleBuilder builder() {
    return new BuilderExampleBuilder();
  }

  public static class BuilderExampleBuilder {
    private long created;
    private boolean created$set;
    private String name;
    private int age;
    private Java.util.ArrayList<String> occupations;

    BuilderExampleBuilder() {
    }

    public BuilderExampleBuilder created(long created) {
      this.created = created;
      this.created$set = true;
      return this;
    }

    public BuilderExampleBuilder name(String name) {
      this.name = name;
      return this;
    }

    public BuilderExampleBuilder age(int age) {
      this.age = age;
      return this;
    }

    public BuilderExampleBuilder occupation(String occupation) {
      if (this.occupations == null) {
        this.occupations = new Java.util.ArrayList<String>();
      }

      this.occupations.add(occupation);
      return this;
    }

    public BuilderExampleBuilder occupations(Collection<? extends String> occupations) {
      if (this.occupations == null) {
        this.occupations = new Java.util.ArrayList<String>();
      }

      this.occupations.addAll(occupations);
      return this;
    }

    public BuilderExampleBuilder clearOccupations() {
      if (this.occupations != null) {
        this.occupations.clear();
      }

      return this;
    }

    public BuilderExample build() {
      // complicated switch statement to produce a compact properly sized immutable set omitted.
      Set<String> occupations = ...;
      return new BuilderExample(created$set ? created : BuilderExample.$default$created(), name, age, occupations);
    }

    @Java.lang.Override
    public String toString() {
      return "BuilderExample.BuilderExampleBuilder(created = " + this.created + ", name = " + this.name + ", age = " + this.age + ", occupations = " + this.occupations + ")";
    }
  }
}

Source: https://projectlombok.org/features/Builder

0
veysiertekin

À mon avis, le moyen le plus simple d'obtenir la classe statique interne au lieu d'une classe distincte est le suivant:

  1. Si vous n'avez pas encore de constructeur, générez-en un en utilisant Générer un dialogue constructeur
  2. Ensuite, utilisez Remplacer le constructeur par le constructeur
  3. Ramenez la classe nouvellement créée à la classe initiale en utilisant Déplacer le refactoring (raccourci clavier: F6)
0
Gaket

Pour ceux qui souhaitent remplacer "trop ​​de paramètres" par un motif de générateur, "extraire un objet de paramètre", puis le constructeur de conversion en générateur mentionné dans d'autres réponses ici.

0
rogerdpack

Générez le constructeur de la classe en cliquant avec le bouton droit de la souris sur la classe Generate> Constructor. Ensuite, sous Windows, appuyez sur les touches Ctrl + Maj + A pour rechercher une action et tapez "constructeur", sélectionnez "Remplacer le constructeur par le constructeur .."

0
Vijay Nandwana

En complément de la réponse de @ CrazyCoder, je pense qu’il est très utile de savoir que Dans la partie supérieure droite de Remplacer le constructeur par le générateur dialogue, il existe un bouton de configuration que vous pouvez utiliser pour renommer le préfixe des installateurs.

0
tibtof