Spring Data JPA
Herança e Polimorfismo
Conceitos de herança e polimorfismo, associados ao uso de JPA e construção de APIs
Código fonte: https://github.com/diegoneri/conta-corrente-api/tree/feat/aula-spring-data-jpa-heranca
IDS-002
Desenvolvimento para Servidores II
Sistemas para Internet
Herança
Mapped superclass
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
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
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
Mapped superclass
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
}
Single Table
Single Table
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
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
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
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) |
@Inheritance(strategy = InheritanceType.JOINED)
Joined
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 {}
Joined - Resultado
A coluna id nas tabelas tb_pessoa_fisica e
tb_pessoa_juridica são chaves estrangeiras
que referenciam o id da tabela tb_cliente
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
Table per class
Table per class
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 {}
Table per Class - Resultado
Interfaces e Polimorfismo
Interfaces e Polimorfismo
Interfaces e Polimorfismo
Interfaces e Polimorfismo
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
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
Implementando IService
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
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
Implementando IController
com.br.fatecrl.conta.service ContaController.java (1/7)
@RestController
@RequestMapping("/contas")
public class ContaController implements IController<Conta>{
@Autowired
private ContaService service;
* Considerar imports
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
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
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
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
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
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
Referências
Obrigado!