1 of 42

Spring Data JPA

Herança e Polimorfismo

Conceitos de herança e polimorfismo, associados ao uso de JPA e construção de APIs

IDS-002

Desenvolvimento para Servidores II

Sistemas para Internet

2 of 42

Herança

  • Para trabalhar com herança o JPA fornece 4 alternativas:
    • Mapped superclass
    • Single table
    • Joined
    • Table per class

3 of 42

Mapped superclass

  • Uma classe anotada como @MappedSuperclass pode ser mapeada de forma semelhante a uma entidade, entretanto os mapeamentos se aplicam somente a suas subclasses já que nenhuma tabela será criada para a própria superclasse
  • Mapped superclasses não podem ser �anotadas com @Entity ou @Table

4 of 42

com.br.fatecrl.conta.model AbstractEntity.java (1/2)

@MappedSuperclass

public abstract class AbstractEntity implements Serializable {

private static final long serialVersionUID = 1L;

@Id

@GeneratedValue(strategy = GenerationType.IDENTITY)

private Long id;

public Long getId() {

return id;

}

public void setId(Long id) {

this.id = id;

}

* Considerar imports

5 of 42

com.br.fatecrl.conta.model AbstractEntity.java (2/2)

@Override

public int hashCode() {

int hash = 7;

hash = 53 * hash +

Objects.hashCode(this.id != null ? this.id : 0);

return hash;

}

@Override

public boolean equals(Object obj) {

if (this == obj)

return true;

if (obj == null || getClass() != obj.getClass())

return false;

final AbstractEntity other = (AbstractEntity) obj;

return Objects.equals(this.id, other.id);

}

}

* Considerar imports

6 of 42

com.br.fatecrl.conta.model Conta.java

@Entity

@Table(name = "tb_conta")

public class Conta extends AbstractEntity {

private static final long serialVersionUID = 1L;

@Id

@GeneratedValue(strategy = GenerationType.IDENTITY)

private Long id;

//demais atributos e métodos

* Considerar imports

7 of 42

Mapped superclass

  • A classe Conta herda da classe AbstractEntity os atributos e métodos que lá existirem
  • Uma Mapped superclass não é persistida, pois não é uma entidade

8 of 42

com.br.fatecrl.conta.model Conta.java

import jakarta.persistence.Column;

import jakarta.persistence.Entity;

import jakarta.persistence.Table;

@Entity

@Table(name = "tb_conta")

public class Conta extends AbstractEntity {

private static final long serialVersionUID = 1L;

@Column(name = "nr_agencia", nullable = false)

private Integer agencia;

@Column(name = "nm_numero", nullable = false, length = 10)

private String numero;

@Column(name = "nm_titular", nullable = false, length = 100)

private String titular;

@Column(name = "vl_saldo", nullable = false)

private Double saldo;

public Conta() {

}

//getters e setters

}

9 of 42

Single Table

  • É possível ter toda a hierarquia de classes de herança persistida em uma única tabela
  • Para tal usamos a seguinte anotação na superclasse:
    • @Inheritance(strategy = InheritanceType.SINGLE_TABLE)

10 of 42

Single Table

  • Vamos considerar a seguinte hierarquia de classes

11 of 42

com.br.fatecrl.conta.model Cliente.java

@Entity

@Table(name = "tb_cliente")

@Inheritance(strategy = InheritanceType.SINGLE_TABLE)

@DiscriminatorColumn(name = "nm_tipo_cliente", length = 20)

public abstract class Cliente extends AbstractEntity {

private static final long serialVersionUID = 1L;

@Column(name = "nm_nome", length = 60)

private String nome;

@Column(name = "ds_endereco", length = 120)

private String endereco;

public Cliente() {

}

}

* Considerar imports

@DiscriminatorColumn indica o

nome da coluna na tabela que determinará

a “dona” da coluna no banco de dados, se

não for especificado, será criada uma

coluna DTYPE para esse fim

12 of 42

com.br.fatecrl.conta.model PessoaFisica.java

@Entity

@DiscriminatorValue("PF")

public class PessoaFisica extends Cliente {

private static final long serialVersionUID = 1L;

@Column(name="cd_cpf", length = 11)

private String cpf;

@Column(name="nm_profissao", length = 30)

private String profissao;

public PessoaFisica() { }

// getters e setters

}

* Considerar imports

@DiscrimatorValue informa o valor que

irá identificar a classe na tabela, se não

for definido o valor será o nome da classe

13 of 42

com.br.fatecrl.conta.model PessoaJuridica.java

@Entity

@DiscriminatorValue("PJ")

public class PessoaJuridica extends Cliente {

private static final long serialVersionUID = 1L;

@Column(name="cd_cnpj", length=14)

private String cnpj;

@Column(name="nm_ramo_atividade", length=20)

private String ramoAtividade;

public PessoaJuridica() {

}

// getters e setters

}

* Considerar imports

@DiscrimatorValue informa o valor que

irá identificar a classe na tabela, se não

for definido o valor será o nome da classe

14 of 42

Single Table

id

BIGINT(20)

nm_tipo_cliente

VARCHAR(20)

nm_nome

VARCHAR(60)

ds_endereco

VARCHAR(120)

cd_cpf

VARCHAR(11)

nm_profissao

VARCHAR(30)

cd_cnpj

VARCHAR(14)

nm_ramo_atividade

VARCHAR(20)

15 of 42

@Inheritance(strategy = InheritanceType.JOINED)

16 of 42

Joined

  • A estratégia JOINED utiliza a abordagem de uma tabela para cada entidade da herança
  • É especificada pela seguinte anotação na superclasse:
    • @Inheritance(strategy = InheritanceType.JOINED)

17 of 42

Exemplo de Joined

@Entity

@Table(name = "tb_cliente")

@Inheritance(strategy = InheritanceType.JOINED)

public abstract class Cliente extends AbstractEntity {}

@Entity

@Table(name="tb_pessoa_fisica")

public class PessoaFisica extends Cliente {}

@Entity

@Table(name="tb_pessoa_juridica")

public class PessoaJuridica extends Cliente {}

18 of 42

Joined - Resultado

  • Gera 3 tabelas com as seguintes estruturas:
    • tb_cliente: id, nm_nome, ds_endereco
    • tb_pessoa_fisica: id, cd_cpf, nm_profissao
    • tb_pessoa_juridica: id, cd_cnpj, nm_ramo_atividade

A coluna id nas tabelas tb_pessoa_fisica e

tb_pessoa_juridica são chaves estrangeiras

que referenciam o id da tabela tb_cliente

19 of 42

@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)

20 of 42

Table per class

  • Table per class trabalha com a ideia de uma tabela para cada entidade representada por classe concreta
  • É especificada pela seguinte anotação na superclasse:
    • @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)

21 of 42

Table per class

  • É necessário alterar a estratégia de geração das chaves primárias de IDENTITY para TABLE
    • Garante que chaves distintas serão geradas para as subclasses

22 of 42

Table per Class - Exemplo

@Entity

@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)

public abstract class Cliente extends AbstractEntity {}

@Entity

@Table(name="tb_pessoa_fisica")

public class PessoaFisica extends Cliente {}

@Entity

@Table(name="tb_pessoa_juridica")

public class PessoaJuridica extends Cliente {}

23 of 42

Table per Class - Resultado

  • Gera 2 tabelas com as seguintes estruturas:
    • tb_pessoa_fisica: id, nm_nome, ds_endereco, cd_cpf, nm_profissao
    • tb_pessoa_juridica: id, nm_nome, ds_endereco, cd_cnpj, �nm_ramo_atividade

24 of 42

Interfaces e Polimorfismo

25 of 42

Interfaces e Polimorfismo

  • Uma interface é uma classe que contém especificações que serão usadas pelas outras classes.
  • Cria-se um contrato a ser seguido pelas classes onde for implementada.
  • Os métodos criados na interface não têm corpo, apenas assinatura.

26 of 42

Interfaces e Polimorfismo

  • Polimorfismo → “várias formas”,
  • A implementação de uma interface faz a sobrescrita - override
  • Define ou altera o comportamento dos métodos definidos na interface.

27 of 42

Interfaces e Polimorfismo

  • Evolução da estrutura atual de Controller e Service
  • Uso de interfaces para definir o contrato de comportamento das camadas

28 of 42

com.br.fatecrl.conta.service IService.java

import java.util.List;

public interface IService<T> {

T create(T obj);

T findById(Long id);

List<T> findAll();

boolean update(T obj);

boolean delete(Long id);

}

* Considerar imports

29 of 42

com.br.fatecrl.conta.controller IController.java

import java.util.List;

import org.springframework.http.ResponseEntity;

public interface IController<T> {

ResponseEntity<List<T>> getAll();

ResponseEntity<?> get(Long id);

ResponseEntity<T> post(T obj);

ResponseEntity<?> put(T obj);

ResponseEntity<?> patch(T obj);

ResponseEntity<?> delete(Long id);

}

* Considerar imports

30 of 42

Implementando IService

31 of 42

com.br.fatecrl.conta.service ContaService.java (1/2)

@Service

public class ContaService implements IService<Conta> {

@Autowired

private ContaRepository repository;

public ContaService() {

}

@Override

public Conta findById(Long id) {

Optional<Conta> obj = repository.findById(id);

return obj.orElse(null);

}

@Override

public List<Conta> findAll() {

return repository.findAll();

}

* Considerar imports

32 of 42

com.br.fatecrl.conta.service ContaService.java (2/2)

@Override

public Conta create(Conta conta) {

repository.save(conta);

return conta;

}

@Override

public boolean update(Conta conta) {

if (repository.existsById(conta.getId())) {

repository.save(conta);

return true;

}

return false;

}

@Override

public boolean delete(Long id) {

if (repository.existsById(id)) {

repository.deleteById(id);

return true;

}

return false;

}

}

* Considerar imports

33 of 42

Implementando IController

34 of 42

com.br.fatecrl.conta.service ContaController.java (1/7)

@RestController

@RequestMapping("/contas")

public class ContaController implements IController<Conta>{

@Autowired

private ContaService service;

* Considerar imports

35 of 42

com.br.fatecrl.conta.service ContaController.java (2/7)

@Override

@GetMapping(produces = "application/json")

@ApiResponses(value = {

@ApiResponse(responseCode = "200"

, description = "Resultado com sucesso"

// , content = {@Content(mediaType = "application/json")}

),

@ApiResponse(responseCode = "500"

, description = "Erro interno do servidor"

// , content = {@Content(mediaType = "application/json")}

)

})

@Operation(summary = "Retorna a lista de contas")

public ResponseEntity<List<Conta>> getAll(){

return ResponseEntity.ok(service.findAll());

}

* Considerar imports

36 of 42

com.br.fatecrl.conta.service ContaController.java (3/7)

@Override

@GetMapping(value = "/{id}", produces = "application/json")

public ResponseEntity<Conta> get(@PathVariable("id") Long id) {

Conta conta = service.findById(id);

if (conta != null) {

return ResponseEntity.ok(conta);

//HTTP 200 OK

}

return ResponseEntity.notFound().build();

}

* Considerar imports

37 of 42

com.br.fatecrl.conta.service ContaController.java (4/7)

@Override

@PostMapping

@Operation(summary = "Cria uma conta")

public ResponseEntity<Conta> post(@RequestBody Conta conta){

service.create(conta);

URI location = ServletUriComponentsBuilder

.fromCurrentRequest()

.path("/{id}")

.buildAndExpand(conta.getId())

.toUri();

return ResponseEntity.created(location).body(conta);

}

* Considerar imports

38 of 42

com.br.fatecrl.conta.service ContaController.java (5/7)

@Override

@PutMapping

@Operation(summary = "Atualiza uma conta")

public ResponseEntity<Conta> put(@RequestBody Conta conta){

if (service.update(conta)) {

return ResponseEntity.ok(conta);

}

return ResponseEntity.notFound().build();

}

* Considerar imports

39 of 42

com.br.fatecrl.conta.service ContaController.java (6/7)

@Override

@PatchMapping

@Operation(summary = "Atualiza uma conta")

public ResponseEntity<Conta> patch(@RequestBody Conta conta){

if (service.update(conta)) {

return ResponseEntity.ok(conta);

}

return ResponseEntity.notFound().build();

}

* Considerar imports

40 of 42

com.br.fatecrl.conta.service ContaController.java (7/7)

@Override

@DeleteMapping(value = "/{id}")

@Operation(summary = "Exclui uma conta")

public ResponseEntity<Conta> delete(@PathVariable("id") Long id){

if (service.delete(id)) {

return ResponseEntity.noContent().build();

}

return ResponseEntity.notFound().build();

}

}

* Considerar imports

41 of 42

Referências

  • CORDEIRO, G. Aplicações Java para web com JSF e JPA. São Paulo: Casa do Código, 2012.
  • GEARY, David; HORSTMANN, Cay. Core JavaServer Faces. 3. ed., Prentice-Hall, 2010.
  • ORACLE Corporation. The Java EE 7 Tutorial. Disponível em: https://docs.oracle.com/javaee/7/JEETT.pdf, 2014.
  • Repositório com código-fonte: �https://github.com/diegoneri/conta-corrente-api/tree/feat/aula-spring-data-jpa-heranca

42 of 42

Obrigado!