Help me understand if I am creating something more complex than it should be
Env: Spring Boot 3.1.X, JPA (Hibernate 6.1), Lombok, JDK17, Win11
I have these domains:
@MappedSuperclass
@Data
public abstract class Ticket {
private Long ticketNumber;
}
public enum StatusTicketB {
UNKNOW, SOMETHING_ELSE
}
@Embeddable
public class TicketA extends Ticket{
}
@Getter
@Setter
@Embeddable
public class TicketB extends Ticket{
@Enumerated(EnumType.STRING)
StatusTicketB statusTicketB;
}
@Entity
@Table(name = "schedule")
@Data
public class Schedule{
@Id
@GeneratedValue
protected UUID uuid;
(...)
@ElementCollection
protected List<TicketA> ticketAList;
@ElementCollection
protected List<TicketB> ticketBList;
(...)
}
I have this @RestController that I will focus on these two methods and this Enum
public enum TicketType{
A, B
}
@PostMapping(
value = "/schedule",
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE
)
public void schedule(@Valid @RequestBody(required = true) ScheduleDTO agd){
Schedule schedule= new Schedule();
(...)
List<TicketB> ticketBList = new ArrayList<>();
stringToTickets(agd.tp(), TicketType.A,ticketBList);
ticketTPList.forEach(tp -> tp.setStatusTicketB(StatusTicketB.UNKNOW));
schedule.setTicketBList(ticketBList );
List<TicketA> ticketAList = new ArrayList<>();
stringToTickets(agd.tp(), TicketType.B, ticketAList);
schedule.setTicketAList(ticketAList);
(...)
}
protected <T extends Ticket> void stringToTickets(String tickets, TicketType tt, List<T> ticketList){
final String[] ticketsSplitted= tickets.split(",");
Arrays.stream(ticketsSplitted).forEach(
ticketString -> {
if (tt.equals(TicketType.B)){
T ticket = (T) new TicketB();
ticket.setTicketNumber(Long.parseLong(ticketString));
ticketList.add(ticket);
} else {
T ticket = (T) new TicketA();
ticket.setTicketNumber(Long.parseLong(ticketString));
ticketList.add(ticket);
}
}
);
}
And, of course, there are these warnings:
Unchecked cast: 'com.xpto.domain.TicketB' to 'T'
Unchecked cast: 'com.xpto.domain.TicketA' to 'T'
The thing is, it is type "safe" for the code above. But, if I mistakenly change TicketType to B and send a List will create a runtime error.
I thought using something like a "small dose" of reflection like
T ticket = clazz.getDeclaredConstructor().newInstance() but it doesn't feel right.
EDIT: If I have to choose between handling exception, or suppressing a warning in a REST interface that will create a 4xx error, I choose suppress.
EDIT: Example:
(...)
stringToTickets(agd.getTicketA(), TicketA.class)
(...)
protected <T extends Ticket> List<T> stringToTickets(String tickets, Class<T> clazz) {
final String[] ticketsSeparados = tickets.split(",");
List<T> ticketList = new ArrayList<>(ticketsSeparados.length);
for (String ticketString : ticketsSeparados) {
T ticket;
try {
ticket = clazz.getDeclaredConstructor().newInstance();
} catch (InstantiationException | IllegalAccessException | NoSuchMethodException |
InvocationTargetException e) {
throw new RuntimeException(e);
}
ticket.setNumeroTicket(Long.parseLong(ticketString));
ticketList.add(ticket);
}
return ticketList;
}
My main object is: I need to parse a comma separated string and create the correct Ticket type A or B that is a extends of Ticket. For Ticket B I must set StatusTicketB.UNKNOW and then save all in the database.
I don't like to suppress these warnings. I feel there is a type safe way to do it but I don't know.
Best regards