JPA e classe abstrata

2 respostas
java
P

Amigos,
Estou fazendo um pequeno sistema de RECEITAS x DESPESAS, utilizando SERVLETs, JSP e JPA. E me deparei com uma dúvida. Tenho o seguinte cenário:

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "type", length = 15, discriminatorType = DiscriminatorType.STRING)
public abstract class Entry implements LocalEntity, Extract, Comparable<Entry> {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	protected Integer id;

	@Column(nullable = false)
	protected LocalDate date;

	@Enumerated(EnumType.STRING)
	@Column(length = 7, nullable = false)
	protected EntryOperation operation;

	@Column(length = 50, nullable = false)
	protected String title;

	@Column(nullable = false)
	protected BigDecimal value;

	@OneToOne
	@JoinColumn(nullable = false)
	protected User user;
	
	@Convert(converter=BooleanConverter.class)
	@Column(length=1, nullable=false)
	protected Boolean settled;

	@Deprecated
	public Entry() {
	}

	public Entry(LocalDate date, EntryOperation operation, String title, BigDecimal value, boolean settled, User user) {
		this.date = date;
		this.operation = operation;
		this.title = title;
		this.value = value;
		this.settled = settled;
		this.user = user;
	}

  //getters and setters

@Entity
@DiscriminatorValue("SINGLE")
public class EntrySingle extends Entry {

	@Deprecated
	public EntrySingle() {
	}

	public EntrySingle(LocalDate date, EntryOperation operation, String title, BigDecimal value, boolean settled,
			User user) {
		super(date, operation, title, value, settled, user);
	}

}

@Entity
@DiscriminatorValue("INSTALLMENT")
public class EntryInstallment extends Entry {

	@OneToMany(mappedBy="entry", cascade=CascadeType.ALL)
	private List<Installment> installments = new ArrayList<>();
	
	@Deprecated
	public EntryInstallment() {
	}

	public EntryInstallment(LocalDate date, EntryOperation operation, String title, User user) {
		super(date, operation, title, null, false, user);
		this.value = sumInstallments();
		this.settled = checkSettledInstallments();
	}

public abstract class Dao<T extends LocalEntity> {
	
	protected Session session;
	protected Class<T> clazz;
	protected TypedQuery<T> query;
	
	public Dao(Class<T> clazz) {
		this.session = HibernateUtil.getSession();
		this.clazz = clazz;
	}
	
	public T getById(Integer id) throws Exception{
		return session.load(clazz, id);
	}
	
	public T save(T t) throws Exception{
		session.persist(t);
		session.flush();
		return t;
	}
	
	public T update(T t) throws Exception{
		session.merge(t);
		session.flush();
		
		return t;
	}
	
	public void delete(T t) throws Exception{
		session.delete(t);
	}
	
}

public abstract class EntryDao<T extends Entry> extends Dao<T> {

	public EntryDao(Class<T> clazz) {
		super(clazz);
	}

	public List<T> getByUserAndPeriod(User user, LocalDate start, LocalDate end){
		query = session.createQuery("from " + clazz.getSimpleName() + " e where e.user = :User and"
				+ "(e.date >= :Start and e.date <= :End) ", clazz);
		query.setParameter("User", user);
		query.setParameter("Start", start);
		query.setParameter("End", end);
		
		return query.getResultList();
	}
}

public class EntrySingleDao extends EntryDao<EntrySingle>{

	public EntrySingleDao() {
		super(EntrySingle.class);
	}
}

public class EntryInstallmentDao extends EntryDao<EntryInstallment> {

	public EntryInstallmentDao() {
		super(EntryInstallment.class);
	}
}

public abstract class EntryService<T extends Entry> extends Service<T> {

	public EntryService(Dao<T> dao) {
		super(dao);
	}

	public List<T> getByUserAndPeriod(User user, LocalDate start, LocalDate end) {
		return ((EntryDao<T>) dao).getByUserAndPeriod(user, start, end);
	}

}

public class EntrySingleService extends EntryService<EntrySingle> {

	public EntrySingleService() {
		super(new EntrySingleDao());
	}

}

public class EntryInstallmentService extends EntryService<EntryInstallment> {

	public EntryInstallmentService() {
		super(new EntryInstallmentDao());
	}

}

Só que surgiu uma dúvida na hora de buscar a Entry por ID na servlet… pq eu não consigo dar um new na EntryService por que é abstrata…só consigo dar new ou em EntrySingleService ou em EntryInstallmentService… mas como eu recebo um ID eu não sei qual subclasse aquele ID pertence…

2 Respostas

P

Resolvi da seguinte forma e gostaria se saber se foi uma boa forma:

1 - A classe Entry não é mais abstrata
2 - Criei um EntriesService e EntriesDao abstratos e intermediarios entre as classes abstratas genericas DAO e Service e as EntrySingleService, EntryInstallmentService, EntrySingleDao e EntryInstallmentDao para que possam centralizar métodos especificos das Entries e que não estão relacionados aos outros DAOs e Services…
3 - EntrySingleService, EntryInstallmentService, EntrySingleDao e EntryInstallmentDao agora estendem EntriesService e EntriesDao respectivamente.

Dessa forma… uso as classes de Service e Dao, referente a Entry, mais especifica quando preciso realmente de informações diferenciadas…uso EntryService e EntryDao quando preciso de Entry sem separações…

O único problema ai…é que por um descuido… eu posso persistir um Entry puro (e não um EntrySingle ou EntryInstallment)…

Isso realmente não sei como resolver…

J

Realmente precisa dessa “engenharia” toda pra atender a funcionalidade?

Criado 21 de setembro de 2017
Ultima resposta 4 de nov. de 2017
Respostas 2
Participantes 2