Home > Back-end >  Cannot resolve method `values()` for Enum inside the Generic method
Cannot resolve method `values()` for Enum inside the Generic method

Time:04-12

I am trying to build a generic method which gets an enum as an argument and processes some information.

But unfortunately, it doesn't work as I would like. Maybe you have some suggestions to improve my code and prevent the errors.

private static ProductSearchColumnRange extractAllColumnRangeFromEnum(ProductSearchColumn column,
                                                                      Enum someEnum) {
    return ProductSearchColumnRange.builder()
            .column(column)
            .range(Arrays.stream(someEnum.values())
                    .map(element  -> new RangeOption(element.getValue(), element.name()))
                    .collect(Collectors.toList()))
            .build();
}

I get the following error on the someEnum.values() call:

Cannot resolve method values() in Enum

I get the following errors on the element.getValue() and element.name() calls:

Cannot resolve method getValue()

Cannot resolve method name()

The enums I need to use in the method extractAllColumnRangeFromEnum() above all have the same structure.

For example, one of them look like this:

public enum DeploymentModelType {
   PRIVATE("Private"),
   HYBRID("Hybrid"),
   PUBLIC("Public");

   String value;

   DeploymentModelType(String value) {
       this.value = value;
   }

   public String getValue() {
       return value;
   }
}

I know that I can prevent the error by using

private static ProductSearchColumnRange extractAllColumnRangeFromEnum(ProductSearchColumn column,
                                                                      DeploymentModelType someEnum) { 
... 
}

But then my method would not be generic. I want to use this method for any of my enums.

CodePudding user response:

Since you need all the enum elements to generate a list of RangeOption objects, your method should expect as a parameter a Class<T> of the enum, not a single element.

In order to access the enum constants, you can make use of the static method EnumSet.allOf() of the EnumSet. Which expects the enums Class<T> as parameter.

In order to be able to invoke your custom method getValue() you need to introduce an interface, let's say ModelType, that will declare that method. In turn, DeploymentModelType and other enums should implement this interface.

And you need to add a generic type parameter to the declaration of your method. It needs to be placed after modifiers (if any) and before the return type of the method.

In this case, generic type parameter has to be <T extends Enum<T> & ModelType>. I.e. T is a subtype of both java.lang.Enum class and ModelType interface.

for information on the syntax of generic methods, take a look at this tutorial

The code might look like that:

private static <T extends Enum<T> & ModelType>
               ProductSearchColumnRange 
               extractAllColumnRangeFromEnum(ProductSearchColumn column,
                                             Class<T> enumClass) {
    
    return ProductSearchColumnRange.builder()
        .column(column)
        .range(EnumSet.allOf(enumClass).stream()
            .map(element  -> new RangeOption(element.getValue(), element.name()))
            .collect(Collectors.toList()))
        .build();
}

public enum DeploymentModelType implements ModelType {
    // your code
}

public interface ModelType {
    String getValue();
}

CodePudding user response:

the java.lang.Enum don't have values() method, this method is implicitly declared by compiler. It's mean that values() method only exist in MyEnum.class, can't found in MyEnum.java.

More info about implicitly declared method and enum specifications can be found in https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.9

  • Related