Estamos com a classe DadosSerie modelada conforme o desafio.
DadosSerie.java:
package br.com.alura.screenmatch.model;
import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@JsonIgnoreProperties(ignoreUnknown = true)
public record DadosSerie(@JsonAlias("Title") String titulo,
@JsonAlias("totalSeasons") Integer totalTemporadas,
@JsonAlias("imdbRating") String avaliacao,
@JsonAlias("Genre") String genero,
@JsonAlias("Actors") String atores,
@JsonAlias("Poster") String poster,
@JsonAlias("Plot") String sinopse) {
}
A primeira coisa que fizemos foi adicionar a anotação @JsonAlias para cada atributo vindo do OMDB, e criamos os atributos genero, atores, poster e sinopse. Podemos então tentar executar para verificar o que vai acontecer.
Jacqueline: Isso, vamos conferir se já serão exibidos esses atores, os gêneros e até o pôster da série, que será exibido posteriormente para a pessoa usuária.
Modelando categorias e séries
Iasmin: Vamos abrir o arquivo ScreenmatchApplication.java e executar no método main(). Com o terminal aberto, vamos digitar 1 e buscar pela série "The Boys".
Vamos analisar como os dados vieram para nós. Temos o título, o total de temporadas, a avaliação, e a novidade são gênero, atores, o pôster e a sinopse. Conseguimos pegar nossos dados da forma como desejávamos.
Jacqueline: Porém, da mesma forma que fizemos com Episodio, talvez seja necessária uma classe própria para tratar as coisas como precisamos.
O motivo é que o atributo avaliacao vem como string. O genero vem com três itens: ação (Action), comédia (Comedy) e crime (Crime), e ainda está em inglês.
Como vamos mostrar isso para a pessoa usuária? Se ela buscar por categoria, a série vai aparecer em três categorias? Talvez não seja o ideal. Queremos que, por exemplo, somente essa primeira categoria de ação seja a categoria que vai representar a série.
Portanto, precisamos ter uma classe própria chamada Serie, assim como fizemos com Episodio, para representar as informações e tratá-las como de fato vamos querer apresentá-las futuramente para a nossa pessoa usuária.
Criando a classe Serie
Iasmin: Vamos minimizar o terminal e começar a criar a classe Serie. No pacote "model", clicaremos com botão direito e vamos até "New > Java Class". Chamaremos a classe de Serie. Essa será uma classe real, não mais um registro.
A nova classe terá os mesmos atributos que a DadosSerie, então podemos copiar todos esses atributos do arquivo DadosSerie.java e colá-los na classe Serie.java.
Vamos modificar conforme a necessidade, então no lugar de @JsonAlias(), colocaremos private em todos os atributos. Além disso, substituiremos as vírgulas por ponto e vírgula.
Serie.java:
package br.com.alura.screenmatch.model;
public class Serie {
private String titulo;
private Integer totalTemporadas;
private String avaliacao;
private String genero;
private String atores;
private String poster;
private String sinopse;
}
Agora temos todos os atributos devidamente declarados. Como alguns atributos estão como string e precisaremos mudar, faremos isso agora.
Para avaliacao, não é uma boa ideia deixarmos como String, então vamos converter para Double, da mesma forma que estava em Episodio. Os outros atributos podem permanecer como String, exceto pelo genero.
Se pensarmos no gênero, geralmente identificamos uma série por um gênero específico. Não pensamos em "Friends" como uma série de comédia, drama, romance e vários outros gêneros. Portanto, podemos representar esse gênero como uma categoria, e essa categoria pode ser um enum. Dessa forma, substituiremos String antes de genero por Categoria.
public class Serie {
private String titulo;
private Integer totalTemporadas;
private Double avaliacao;
private Categoria genero;
private String atores;
private String poster;
private String sinopse;
}
Criando o enum Categoria
Podemos descrever Categoria como um enum. Por que isso é possível?
Sempre que tivermos gêneros, teremos uma lista de constantes que serão os gêneros. Sempre teremos ação, romance, crime, drama, que são coisas fixas. Podemos adicionar à nossa lista, mas não virão coisas muito diferentes disso. Nossa lista será bem estática. Portanto, podemos representar como um enum.
Então, clicaremos com o botão direito sobre Categoria, selecionaremos a opção "Show Context Actions" e criaremos um enum chamado "Categoria" (Create enum 'Categoria').
No novo arquivo criado (Categoria.java), declararemos os gêneros que conhecemos. Declaramos estes gêneros em letras maiúsculas, porque normalmente associamos constantes a estes termos.
Dito isso, teremos os gêneros ACAO, ROMANCE, COMEDIA, DRAMA, e CRIME.
Categoria.java:
package br.com.alura.screenmatch.model;
public enum Categoria {
ACAO,
ROMANCE,
COMEDIA,
DRAMA,
CRIME;
}
Jacqueline: Por enquanto, podemos deixá-los assim. Se necessário, podemos inserir outros gêneros. Basicamente, queremos limitar as categorias, de modo que estejam restritas a estes tipos específicos. Esta é a nossa ideia central: limitá-las a uma constante.
Iasmin: Existem algumas diferenças a serem consideradas. Por exemplo: digitamos "ACAO" e "COMEDIA", mas se recebermos esses rótulos no terminal, notaremos que se tratam de "Action" e "Comedy", por exemplo.
Embora alguns gêneros apresentem a mesma denominação em inglês e em português, nem todos seguem esse padrão. Portanto, necessitaremos de uma correspondência entre essas nomenclaturas. No enum, essa correspondência é feita adicionando um novo atributo.
Após o gênero CRIME, vamos declarar um novo atributo que será a categoria do OMDB. Em seguida, veremos como isso será aplicado. Este atributo será uma string privada (private String) chamada categoriaOmdb. Essa categoria deverá ser passada para cada constante.
Assim, para ACAO, o correspondente seria Action. Para ROMANCE, repetimos a palavra, já que o termo é igual em inglês. Da mesma forma, temos Comedy correspondendo a COMEDIA, Drama para DRAMA, e Crime para CRIME.
public enum Categoria {
ACAO("Action"),
ROMANCE("Romance"),
COMEDIA("Comedy"),
DRAMA("Drama"),
CRIME("Crime");
private String categoriaOmdb;
}
Feito isso, teremos um construtor que será responsável por adicionar essa categoriaOmdb ao que está no enum. Na linha 12, podemos declarar o construtor chamado Categoria que receberá uma String chamada categoriaOmdb.
Ao completar, podemos perceber que o IntelliJ já nos mostra o que é feito, pois ele identifica o atributo ao instanciá-lo.
Em seguida, fazemos como um construtor normal. A categoriaOmdb, ou seja, this.categoriaOmdb, recebe a string categoriaOmdb. Assim, temos um enum de categorias.
public enum Categoria {
ACAO("Action"),
ROMANCE("Romance"),
COMEDIA("Comedy"),
DRAMA("Drama"),
CRIME("Crime");
private String categoriaOmdb;
Categoria(String categoriaOmdb){
this.categoriaOmdb = categoriaOmdb;
}
}
Modificações na classe Serie
Podemos voltar para a classe Serie e começar a modificar os dados recebidos. Primeiramente, criaremos um construtor. Da mesma forma que a classe Episodio recebe DadosEpisodio, agora a classe Serie receberá um objeto DadosSerie.
Jacqueline: Exatamente, iniciaremos a associação e transformação de valores, pois em DadosSerie, tudo vem em String, e agora já sabemos haver alguns valores que queremos tratar de forma diferente, como avaliacao e genero.
Iasmin: Então, após a declaração dos atributos, na linha de código 14, vamos criar um construtor public chamado Serie(), recebendo DadosSerie.
Serie.java:
public Serie(DadosSerie dadosSerie){
}
Feito isso, começaremos a fazer as atribuições.
O campo this.titulo receberá o correspondente no objeto dadosSerie, ou seja, dadosSerie.titulo(). Todos os campos que são strings podem ser atribuídos diretamente.
Da mesma forma, o campo totalTemporadas será atribuído com o valor correspondente da classe dadosSerie, então dadosSerie.totalTemporadas(). No campo avaliacao, haverá uma mudança. A avaliacao era uma String, mas precisará ser transformada em Double.
Na classe Episodio, usamos o try…catch para fazer essa conversão, em que se algo desse errado na conversão, o valor era transformado em 0.0. Agora, nessa classe, faremos a mesma coisa, mas utilizando a estrutura Optional, que já conhecemos.
O processo agora será utilizar a classe OptionalDouble, chamar o método of() dela, e passar um valor Double. Faremos isso com a parte onde tentamos ler o valor da avaliação. Portanto, faremos um Double.valueOf(dadosSerie.avaliacao()). No entanto, isso pode falhar, sendo necessário inserir algum outro valor. Agora entra a outra parte do Optional.
Após fazer isto, precisaremos chamar um orElse(), onde podemos passar o zero. Feito isto, temos uma estrutura bastante semelhante ao que tínhamos no try-catch, mas de forma diferente.
public Serie(DadosSerie dadosSerie){
this.titulo = dadosSerie.titulo();
this.totalTemporadas = dadosSerie.totalTemporadas();
this.avaliacao = OptionalDouble.of(Double.valueOf(dadosSerie.avaliacao())).orElse(0);
}
Jacqueline: Temos quase um if…else melhorado. Tentamos obter o valor Double. Caso isso não aconteça, atribuímos 0 para a avaliação. Essa é uma maneira de estipularmos um valor padrão, caso ocorra qualquer erro e não consigamos obter o valor da avaliação.
Modificações na classe Categoria
Iasmin: Para Categoria, também serão necessárias algumas alterações.
Se usarmos this.genero e, em seguida, chamarmos a categoria, o que seria a maneira normal de lidarmos com o enum, poderíamos até atribuir algo à série. Porém, o que queremos é sempre ter dados dinâmicos vindos de nossa API, do OMDB, e convertidos na nossa série.
Para isso, precisaremos de um método auxiliar no enum que fará essa conversão para nós. Apresentaremos esse método e vamos copiá-lo e colá-lo no enum, após o construtor.
Categoria.java:
public static Categoria fromString(String text) {
for (Categoria categoria : Categoria.values()) {
if (categoria.categoriaOmdb.equalsIgnoreCase(text)) {
return categoria;
}
}
throw new IllegalArgumentException("Nenhuma categoria encontrada para a string fornecida: " + text);
}
Jacqueline: O funcionamento é simples: se o OMDB retornar a palavra "Action", consideramos isso como ACAO; se retornar "Comedy", consideramos isso como COMEDIA.
Ou seja, esse método vai interpretar dinamicamente o valor textual vindo do OMDB e irá converter na nossa categoria de enum, correto?
Iasmin: Exatamente. Podemos observar que se trata de um método estático que percorrerá nossa lista de constantes e, para cada uma delas, se o texto correspondente for igual à categoria do OMDB, ele associará à nossa categoria.
Finalizando as atribuições
Agora, em Serie.java, chamaremos esse método. Em vez de instanciar uma categoria, como nós temos um método estático, podemos usar Categoria.fromString() e passar o texto que vem de dadosSerie. Assim, faremos dadosSerie.genero() e com isso teremos a correspondência.
Serie.java:
public Serie(DadosSerie dadosSerie){
this.titulo = dadosSerie.titulo();
this.totalTemporadas = dadosSerie.totalTemporadas();
this.avaliacao = OptionalDouble.of(Double.valueOf(dadosSerie.avaliacao())).orElse(0);
this.genero = Categoria.fromString(dadosSerie.genero());
}
Para as outras strings, só precisamos fazer a atribuição básica.
Jacqueline: No entanto, ao observarmos o gênero no terminal, percebemos que são retornadas três palavras, como, por exemplo, "Action, Crime, Romance". Se quisermos pegar apenas a primeira palavra, o que podemos fazer? Afinal, não queremos usar a string inteira para tentar achar a correspondência, pois isso dará errado.
Iasmin: Verdade, temos que pegar o primeiro gênero antes da vírgula. Para isso, podemos usar o método split() para separar as palavras que estão divididas por vírgula.
O método split() vai separar uma string grande, contendo todos os gêneros, e um array de strings, então em vez de termos "Drama, Romance, Comédia", teremos palavras separadas e pegaremos apenas a primeira, representada pelo 0 entre colchetes.
Porém, como isso pode ter alguns espaços em branco ou coisas que não queremos que sejam diferentes da palavra em si, nós também devemos usar o método trim(), que vai remover caracteres em branco, como espaços e quebras de linha.
public Serie(DadosSerie dadosSerie){
this.titulo = dadosSerie.titulo();
this.totalTemporadas = dadosSerie.totalTemporadas();
this.avaliacao = OptionalDouble.of(Double.valueOf(dadosSerie.avaliacao())).orElse(0);
this.genero = Categoria.fromString(dadosSerie.genero().split(",")[0].trim());
}
Agora está correto, não é, Jacque?
Jacqueline: Sim, vamos pegar apenas o primeiro item que vier do OMDB como categoria.
Iasmin: Para as outras strings, faremos atribuições simples e rápidas.
Jacqueline: Ainda falta atores, poster e sinopse.
Iasmin: this.atores receberá dadosSerie.atores(). A própria IDE nos auxiliará nessa atribuição. Na sequência, this.poster receberá dadosSerie.poster(); e, por fim, this.sinopse receberá dadosSeries.sinopse().
public Serie(DadosSerie dadosSerie){
this.titulo = dadosSerie.titulo();
this.totalTemporadas = dadosSerie.totalTemporadas();
this.avaliacao = OptionalDouble.of(Double.valueOf(dadosSerie.avaliacao())).orElse(0);
this.genero = Categoria.fromString(dadosSerie.genero().split(",")[0].trim());
this.atores = dadosSerie.atores();
this.poster = dadosSerie.poster();
this.sinopse = dadosSerie.sinopse();
}
Conclusão
Fechamos o nosso construtor, correto, Jacque?
Jacqueline: Sim, nosso construtor já contempla tudo. O que vier de dadosSerie, nós conseguiremos transformar efetivamente em uma série. Na sequência, podemos começar a testar, fazer os getters e setters, o toString(), e o que mais for necessário nessa classe.
Iasmin: Vamos tomar nosso café, pois fizemos bastante coisa!
Jacqueline: Até daqui a pouco!