2011-01-16 17 views
19

Có cách nào để kiểm tra xem liệu một enum có giá trị được chỉ định hay không. Ví dụ:JSF 2: Sử dụng enums trong thuộc tính được hiển thị

<h:graphicImage name="error.png" library="images" 
    rendered="#{viewController.current.status == Status.ERROR}" /> 

Hơi tẻ nhạt khi xác định phương thức trong beand được quản lý để kiểm tra điều này cho mọi giá trị enum, ví dụ:

public boolean isStateIsError() { 
    return current.getStatus() == Status.ERROR; 
} 

Có cách nào ngắn hơn/tốt hơn để thực hiện việc này không?

Trả lời

34

Until EL 3.0 không thể nhập enums trong phạm vi EL. Tuy nhiên, bạn có thể xử lý và so sánh chúng như chuỗi, tức là giá trị hằng số enum phải được trích dẫn như dưới đây.

<h:graphicImage name="error.png" library="images" 
    rendered="#{viewController.current.status eq 'ERROR'}" /> 
+0

Chuỗi so sánh được đánh giá như gọi equals() phương pháp hay như so sánh bằng cách tham khảo? – user3663882

7

Tôi biết câu hỏi này là một chút cũ bây giờ, nhưng tôi đã có cùng một vấn đề và tìm thấy một giải pháp, mà tôi muốn chia sẻ:

Tạo Custom EL-Resolver và enums sử dụng và java hằng số là các đối tượng trong jsf el:

<h:graphicImage name="error.png" library="images" 
     rendered="#{viewController.current.status == Status.ERROR}" /> 

Nhưng trước khi bạn có thể sử dụng enums theo cách này bạn phải thực hiện 3 bước.

1. bước - Sao chép lớp này và thay thế "MY_ENUM" qua enumClass của bạn (trong ví dụ trên nó sẽ là "Status")

public class EnumCache { 
    private Map<String, Object> propertCache = new HashMap<String, Object>(); 
    private Map<String, Class> baseCache = new HashMap<String, Class>(); 
    private static EnumCache staticEnumCache = null; 

    public static EnumCache instance() { 
     if (staticEnumCache == null) { staticEnumCache = new EnumCache(); } 
     return staticEnumCache; 
    } 
    private EnumCache() { 
     List<Class<?>> classes = new ArrayList<Class<?>>(); 
     classes.add(MY_ENUM.class); 

     for(Class clazz : classes) { 
      try { 
       baseCache.put(clazz.getSimpleName(), clazz); 
       Method m = clazz.getMethod("values", (Class[]) null); 
       Enum<?>[] valueList = (Enum[]) m.invoke(null, (Object[]) null); 
       for (Enum<?> en : valueList) { 
        propertCache.put(clazz.getSimpleName() + "." + en.name(), en); 
       } 
      } catch (Exception e) { 
       System.err.println(clazz.getSimpleName(), e); 
      } 
     } 
    } 
    public Object getValueForKey(String key) { 
     return propertCache.get(key); 
    } 
    public Class getClassForKey(String key) { 
     return baseCache.get(key); 
    } 
} 

2. Bước - thêm EnumResolver này - Đây lớp sẽ lập bản đồ biểu hiện JSF của bạn để enum trong bộ nhớ cache (bước 1)

public class MyEnumResolver extends ELResolver { 

    public Object getValue(ELContext context, Object base, Object property) { 
     Object result = null; 
     if (base == null) { 
      result = EnumCache.instance().getClassForKey(property + ""); 
     } else if (base instanceof Class) { 
      result = EnumCache.instance().getValueForKey(((Class) base).getSimpleName() + "." + property); 
     } 
     if (result != null) { 
      context.setPropertyResolved(true); 
     } 
     return result; 
    } 

    public Class<?> getCommonPropertyType(ELContext context, Object base) { 
     return null; 
    } 
    public Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext context, Object base) { 
     return null; 
    } 
    public Class<?> getType(ELContext context, Object base, Object property) { 
     return null; 
    } 
    public boolean isReadOnly(ELContext context, Object base, Object property) { 
     return false; 
    } 
    public void setValue(ELContext context, Object base, Object property, Object arg3) { 
    } 
} 

3. bước - đăng ký EnumResolver trong faces-config.xml

<faces-config> 
    <application> 
     <el-resolver>com.asd.MyEnumResolver</el-resolver> 
    </application> 
</faces-config> 

LƯU Ý: Nếu bạn muốn truy cập hằng java bạn theo cách này, bạn chỉ cần phải mở rộng các nhà xây dựng của lớp enumCache. Ví dụ này (chưa thử) nên hoạt động:

baseCache.put(CLASS_WITH_CONSTANTS.getSimpleName(), clazz); 
for (Field field : CLASS_WITH_CONSTANTS.getDeclaredFields()) { 
    try { 
     propertCache.put(CLASS_WITH_CONSTANTS.getSimpleName() + "." 
        + field.getName(), field.get(null)); 
    } catch (Exception e) { } 
} 

Hy vọng mã giảm nhưng mã làm việc này có thể giúp bất kỳ ai.


Cập nhật

tôi thấy lợi ích này:

  1. Nếu bạn sử dụng chuỗi trong JSF (viewController.current.status == 'ERROR_abcdefg'), bạn có thể đánh sai giá trị và không nhận ra nó quá nhanh. Với giải pháp của tôi, bạn sẽ gặp lỗi khi tải tệp jsf, vì không thể giải quyết enum.

  2. Bạn có thể thấy trong mã nguồn "ERROR" là giá trị của "STATUS" enum.

  3. Khi bạn so sánh hai giá trị trong el, lớp của các enums cũng sẽ được so sánh. Vì vậy, ví dụ PersonState.ACTIV không giống như AccounState.ACTIV.

  4. Khi tôi phải thay đổi giá trị enum của tôi từ PersonState.ACTIV thành PersonState.ACTIVATED tôi có thể tìm kiếm chuỗi "PersonState.ACTIV" trong mã nguồn của tôi. tìm kiếm "ACTIV" sẽ có nhiều kết quả phù hợp hơn.

+5

Chính sách này mang lại lợi ích gì cho bạn? Trong Java, lợi thế chính của việc sử dụng các tham chiếu enum trực tiếp là biên dịch thời gian thực thi các giá trị hợp lệ, nhưng lợi thế này không tồn tại trong EL, cũng không phải với trình phân giải này. – BalusC

+0

Điều này thậm chí còn tẻ nhạt hơn việc tạo ra một phương pháp trong bean được quản lý của bạn! Tuy nhiên, thật tuyệt khi biết điều này có thể được thực hiện. –

1

tôi giải quyết một vấn đề tương tự bởi statically bán phá giá tất cả các phím enum (được sử dụng trong các thành phần giao diện người dùng trả lại) trong một bản đồ và sau đó tôi sử dụng một getByKey phương pháp tĩnh để chuyển đổi giá trị từ UI thành một thực tế enum có nguồn gốc trong setter, ném ra một ngoại lệ nếu giá trị cung cấp là không hợp lệ:

public enum ReportType { 

    FILING("F", "Filings"), 
    RESOLUTION("R", "Resolutions"), 
    BASIS("B", "Bases"), 
    STAFF("T", "Staff Counts"), 
    COUNTS("I", "Counts"); 

    private String key; 
    private String label; 

    private static Map<String, ReportType> keyMap = new HashMap<String, ReportType>(); 

    static { 
     for(ReportType type : ReportType.values()) { 
      keyMap.put(type.getKey(), type); 
     } 
    } 

    private ReportType(String _key, String _label) { 
     this.key = _key; 
     this.label = _label; 

    } 

    public String getKey() { 
     return this.key; 
    } 

    public String getLabel() { 
     return this.label; 
    } 

    public static List<ReportType> getValueList() { 
     return Arrays.asList(ReportType.values()); 
    } 

    public static ReportType getByKey(String _key) { 
     ReportType result = keyMap.get(_key); 

     if(result == null) { 
      throw new IllegalArgumentException("Invalid report type key: " + _key); 
     } 

     return result; 
    } 
} 

trong lớp UI, chìa khóa enum được sử dụng như giá trị và nhãn enum được sử dụng như nhãn:

<f:selectItems var="rptTypeItem" value="#{reportController.allReportTypes}" 
    itemLabel="#{rptTypeItem.label}" itemValue="#{rptTypeItem.key}"/> 

Trong managed bean, tôi chuyển đổi các enum vào một danh sách renderable, sử dụng getValueList() từ enum:

public List<ReportType> getAllReportTypes() { 
    return ReportType.getValueList(); 
} 

Cuối cùng, [g | s] etters trong giao diện bean được quản lý như sau:

public String getReportType() { 
    return this.crtRptType.getKey(); 
} 

public void setReportType(String _val) { 
    this.crtRptType = ReportType.getByKey(_val); 
} 
1

tôi nghĩ rằng nó có thể được thực hiện nó theo cách sau:

Tạo một phương pháp trong bạn đậu rằng sẽ quay trở lại danh sách các sự đếm, ví dụ

public Status[] getStatuses() { 
    Status.values(); 
} 

sau đó bạn có thể sử dụng enum trong EL như thế này

<h:graphicImage name="error.png" library="images" 
    rendered="#{viewController.current.status == someBean.statuses[0]}" /> 

giả định rằng trật tự của các thành viên enum sẽ không được thay đổi (cho ex. ở đây trạng thái [0] là L ERI). Tuy nhiên, tôi sẽ sửa các vị trí như sau:

public Status[] getStatuses() { 
    Status myStatuses = new Status [2]; // or whatever number of statuses you are going to use in UI 
    myStatuses [0] = Status.ERROR; 
    myStatuses [1] = Status.RUNNING; 
    return myStatuses; 
} 

Đây không phải là giải pháp năng động, nhưng tốt hơn là viết mã cứng trong EL. Có thể đặc biệt hữu ích khi bạn sử dụng nội địa hóa cho các trạng thái của bạn (các giá trị enum tùy thuộc vào ngôn ngữ/bản dịch).

-1

tôi giải quyết một vấn đề tương tự sử dụng:

<p:graphicImage name="images/close.png" rendered="#{i.unityEnum.name().equals('DAY')}" /> 
Các vấn đề liên quan