Podemos cozinhar Java, Kotlin RestController?

Quase qualquer programador Java escreveu RestController em sua vida, mas poucas pessoas se perguntam se ele faz isso corretamente. Mesmo se você é um programador experiente, você pode ter perguntas que tentarei responder. O artigo abordará estruturas como as versões 1.5 e 2.0 da bota de mola, bem como o quarkus - o recém-surgido rival da bota de primavera da red hat.

imagem


O problema


Programado por muito tempo em java e spring boot 1.5. Mas havia uma necessidade de escrever um novo projeto:

  1. Eu tenho json para integrar 1600 linhas, algumas classes têm 100 campos
  2. Eu queria experimentar Kotlin e Quarkus.
  3. Escreva um controlador restante que possa trabalhar com a classe de dados kotlin sem anotações e sem envolver a magia lombok. Eu quero que a classe de dados seja pequena

Você provavelmente adivinhou que a classe de dados kotlin é uma classe imutável ou imutável. Uma classe cujo construtor contém todos os campos. Eu acredito muito nesse conceito; depois de criar uma classe, ela não pode ser alterada; não há setters nela. Como a imagem da janela de encaixe não pode ser alterada no mundo, a classe de data que caiu no controlador é algo que não pode ser alterado.

Vejamos maneiras possíveis de resolver o problema, mais precisamente como em projetos modernos você pode escrever um controlador:

A opção padrão. manualmente na mola ou na bota de mola 1.5


Os controladores de descanso apareceram há muito tempo, e o exemplo a seguir é um exemplo típico de uso em java, que está em todos os tutoriais.

Nós apenas criamos o controlador mais simples

@RestController public class FruitController { @PostMapping("/fruit") public void greeting(@RequestBody Fruit request) { System.out.println(request); } } 

E crie um POJO (objeto java antigo simples)

 public class Fruit { public String name; public String description; public Fruit() { } public Fruit(String name, String description) { this.name = name; this.description = description; } } 

pode haver variações com campos particulares e getters / setters ou anotações de lombok, mas não é o ponto.
Ótimo, criamos o primeiro controlador restante que funciona. Para 90% dos casos, a opção de trabalho. Você pode ficar aqui.

Os problemas:

O conceito imutável está quebrado.
Uma classe de dados um pouco detalhada.

Podemos tornar imutáveis?


Uma reação natural a esse problema será a decisão de remover o construtor padrão e impedir a edição dos campos da classe.
 @Getter public class Fruit { private String name; private String description; // public Fruit() { // } public Fruit(String name, String description) { this.name = name; this.description = description; } } 

Mas agora que surge um problema, verifica-se que a biblioteca (provavelmente jackson) não pode criar a classe. Provavelmente, você verá um erro como Nenhum construtor padrão encontrado.

Então, jackson criou a classe usando o construtor sem parâmetros e depois chamou getter / setter . Que horror! Afinal, existe um construtor com todos os parâmetros? Infelizmente, porém, quando a classe é compilada, os parâmetros são mais ou menos assim.

imagem

I.e. em tempo de execução, java não sabe nada sobre nomes de parâmetros no construtor. O compilador os perde.

A segunda opção é a mola ou a bota com mola 1.5 + anotações como salvação


Então, percebemos que queremos uma classe imutável e sabemos que estamos usando jackson. Então a anatotação vem em socorro.

 @Getter public class Fruit { private String name; private String description; @JsonCreator public Fruit(@JsonProperty("name") String name, @JsonProperty("description")String description) { this.name = name; this.description = description; } } 

No momento, em nosso projeto sobre sping boot 1.5, essas anotações estão literalmente cheias de tudo.
E se você usar o popular gerador jsonschema2pojo , ele gerará ainda mais anotações. Honestamente, eu não gosto deles.

Tente copiar para lá:

 { "description": "description", "name": "name" } 

Na saída que obtemos (você pode apertar os olhos e folhear):

 @JsonInclude(JsonInclude.Include.NON_NULL) @JsonPropertyOrder({ "description", "name" }) public class Example { @JsonProperty("description") private String description; @JsonProperty("name") private String name; @JsonProperty("description") public String getDescription() { return description; } @JsonProperty("description") public void setDescription(String description) { this.description = description; } @JsonProperty("name") public String getName() { return name; } @JsonProperty("name") public void setName(String name) { this.name = name; } } 

Contras: as anotações aumentam muito a classe. Muito detalhado, para um amador.

Terceira opção mola ou bota com mola 1.5 + lombok flag


Thanks Throwable Vou citar o comentário:

“Se você usa o Lombok, a melhor maneira é escrever no lombok.config:

lombok.allArgsConstructor.addConstructorProperties = true

Isso gerará no construtor @java.beans.ConstructorProperties , que Jackson sabe entender. ”

Ótima opção. Ele certamente me salvaria da verbosidade das anotações.

Contras:

Mas eu quero usar o Kotlin sem lombok.
Aprendi essa opção tarde demais.

A quarta versão do Spring boot 2.0


 @Getter public class Fruit { private String name; private String description; public Fruit( String name, String description) { this.name = name; this.description = description; } } 

Surpreendentemente, a bota de mola 2.0 funciona silenciosamente com uma classe tão imutável. E também com sua classe de dados irmão gêmeo kotlin

 data class Fruit( val name : String, val description : String) 

Parece que o java em tempo de execução não conhece os nomes dos parâmetros no construtor, mas por alguma razão o spring boot2 já sabe como trabalhar com a classe de dados. Então, olhe para spring-boot-starter-parent, o suporte ao Kotlin foi adicionado lá.

 <plugin> <groupId>org.jetbrains.kotlin</groupId> ... <configuration> <javaParameters>true</javaParameters> </configuration> </plugin> <plugin> <artifactId>maven-compiler-plugin</artifactId> <configuration> <parameters>true</parameters> </configuration> </plugin> 

Eu decifrei. Para que os nomes de parâmetro no construtor da classe não sejam perdidos durante o tempo de execução, o compilador precisa passar o sinalizador javac -parameters E o spring boot 2.0 faz isso.

Exemplo de projeto na bota de mola 2 .

A quinta opção. Quarkus + Kotlin


Quarkus tem um exemplo de serviço de descanso , um análogo da minha primeira opção. I.e. controlador de descanso à moda antiga. No entanto, se você quiser usá-lo com o Kotlin, precisará adicionar sinalizadores, como o boot 2 da primavera fez.

Descrição do problema aqui . Um exemplo de como adicionar suporte à classe de dados kotlin no quarkus aqui .

Conclusões


Você pode usar a primeira opção mais simples para criar controladores de descanso, mas eu aconselho a avançar para classes imutáveis. Escreva no Kotlin e você não precisará do lombok. O código deve ser cada vez mais fácil. Estou certo de que os criadores do Spring deliberadamente adicionaram parâmetros javac às opções do compilador e não deve haver crime nisso. Boa sorte a todos no caminho para o código perfeito.

Obrigado a todos pela atenção!

Source: https://habr.com/ru/post/pt480158/


All Articles