How to keep type safety in this case?

34 views Asked by At

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

0

There are 0 answers