skiwi
skiwi

Reputation: 69259

Java generics: Is this safe enough?

Consider the following code snippets:

public interface FieldEnum {
    public String getEnumName();
}

public enum InvoiceStatus implements FieldEnum {
    UNCHECKED("unchecked"),
    ERROR("error"),
    OK("ok");

    private final String enumName;

    private InvoiceStatus(final String enumName) {
        this.enumName = enumName;
    }

    @Override
    public String getEnumName() {
        return enumName;
    }
}

private InvoiceBean(final Integer invoiceId, final Integer businessPartnerId, final String invoiceNumber, final Date invoiceDate, final BigDecimal priceExclVAT, final BigDecimal VAT, final BigDecimal priceInclVAT, final BigDecimal paymentDiscount, final InvoiceStatus status) {
    this.invoiceId = invoiceId;
    this.businessPartnerId = businessPartnerId;
    this.invoiceNumber = invoiceNumber;
    this.invoiceDate = invoiceDate;
    this.priceExclVAT = priceExclVAT;
    this.VAT = VAT;
    this.priceInclVAT = priceInclVAT;
    this.paymentDiscount = paymentDiscount;
    this.status = status;
}

public InvoiceBean(final ResultSet rs) throws SQLException {
    this(rs.getInt(1), rs.getInt(2), rs.getString(3), rs.getDate(4), rs.getBigDecimal(5), rs.getBigDecimal(6), rs.getBigDecimal(7), rs.getBigDecimal(8), EnumConverter.convert(rs.getString(9), InvoiceStatus.values()));
}

Is the following code safe?

public class EnumConverter {
    public static <T extends FieldEnum> T convert(String enumName, T[] enumValues) {
        for (T enumValue : enumValues) {
            if (enumName.equals(enumValue.getEnumName())) {
                return enumValue;
            }
        }
        throw new IllegalStateException("orm.enums.EnumConverter.convert: No suitable enum has been found. enumName = " + enumName + " fieldEnums = " + enumValues);
    }
}

or would there be any advantages by using this? (Note the addition of Class<T> clazz argument)

public class EnumConverter {
    public static <T extends FieldEnum> T convert(String enumName, T[] enumValues, Class<T> clazz) {
        for (T enumValue : enumValues) {
            if (enumName.equals(enumValue.getEnumName())) {
                return enumValue;
            }
        }
        throw new IllegalStateException("orm.enums.EnumConverter.convert: No suitable enum has been found. enumName = " + enumName + " fieldEnums = " + enumValues);
    }
}

And then call it via EnumConverter.convert(rs.getString(9), InvoiceStatus.values(), InvoiceStatus.class) of course.

Regards.

Upvotes: 1

Views: 133

Answers (4)

Stephen D
Stephen D

Reputation: 3076

Generics use the class type of the first T type argument. Adding the new Class<T> does not add any more safeness. In fact, you are now requiring that you have know what class to put in the list of arguments, which can be cumbersome.

Upvotes: 3

Puce
Puce

Reputation: 38132

I suggest to use something like:

public enum InvoiceStatus implements FieldEnum {
    UNCHECKED("unchecked"),
    ERROR("error"),
    OK("ok");

    private static final Map<String, InvoiceStatus> invoiceStatusMap = new HashMap<>(values().length);

    static{
        for (InvoiceStatus  invoiceStatus : values()) {
            invoiceStatusMap.put(invoiceStatus.enumName, invoiceStatus);
        }
    }    
    private final String enumName;

    private InvoiceStatus(final String enumName) {
        this.enumName = enumName;
    }

    @Override
    public String getEnumName() {
        return enumName;
    }

    public static InvoiceStatus getInvoiceStatus(String enumName){
        if (invoiceStatusMap.contains(enumName)){
           return invoiceStatusMap.get(enumName);
        } else {
            throw new IllegalArgumentException("No suitable enum has been found. enumName = " + enumName + " fieldEnums = " + enumValues);
        }
    }
}

Upvotes: 0

Kayaman
Kayaman

Reputation: 73548

A straightforward answer is to forget the EnumConverter and instead use InvoiceStatus.valueOf(rs.getString(9));

Upvotes: 8

tuckermi
tuckermi

Reputation: 879

The extra parameter is not needed - the compiler will be able to determine the type T from the passed array, so there is no need to explicitly take the Class as a parameter.

Upvotes: 0

Related Questions