View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.commons.converter;
20  
21  import org.apache.myfaces.commons.util.MessageUtils;
22  
23  import javax.faces.component.StateHolder;
24  import javax.faces.component.UIComponent;
25  import javax.faces.context.FacesContext;
26  import javax.faces.convert.Converter;
27  import javax.faces.convert.ConverterException;
28  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFConverter;
29  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFProperty;
30  import javax.faces.application.FacesMessage;
31  
32  /**
33   * Converts a Java 5 Enum.
34   * 
35   * see Javadoc of <a href="http://java.sun.com/j2ee/javaserverfaces/1.2/docs/api/index.html">JSF Specification</a>
36   *
37   *   
38   * @author Stan Silvert
39   */
40  @JSFConverter(
41     name = "mcc:convertEnum",
42     tagClass = "org.apache.myfaces.commons.converter.ConvertEnumTag",
43     tagHandler = "org.apache.myfaces.commons.converter.ConvertEnumTagHandler")
44  public class EnumConverter implements Converter, StateHolder {
45      
46      public static final String CONVERTER_ID = "org.apache.myfaces.commons.converter.Enum";
47      public static final String ENUM_ID = "org.apache.myfaces.commons.converter.EnumConverter.ENUM";
48      public static final String ENUM_NO_CLASS_ID = "org.apache.myfaces.commons.converter.EnumConverter.ENUM_NO_CLASS";
49      public static final String ENUM_NO_ENUM_CLASS = "org.apache.myfaces.commons.converter.EnumConverter.ENUM_NO_ENUM_CLASS";
50      public static final String SEPARATOR = "#";
51  
52      private Class targetClass;
53      
54      private boolean isTransient = false;
55      
56      /** Creates a new instance of EnumConverter */
57      public EnumConverter() {
58      }
59      
60      public EnumConverter(Class targetClass) {
61          if (!targetClass.isEnum()) throw new IllegalArgumentException("targetClass for EnumConverter must be an Enum");
62          this.targetClass = targetClass;
63      }
64  
65      public String getAsString(FacesContext facesContext, UIComponent uiComponent, Object value) throws ConverterException {
66          if (facesContext == null) throw new NullPointerException("facesContext can not be null");
67          if (uiComponent == null) throw new NullPointerException("uiComponent can not be null");
68          if (value == null) return "";
69  
70        Class converterClass = null;
71        String idPrefix = "";
72  
73        if (targetClass != null) {
74          converterClass = targetClass;
75        } else if (value.getClass().isEnum()) {
76          converterClass = value.getClass();
77          idPrefix = value.getClass().getName() + SEPARATOR;
78        } else if (value.getClass().getDeclaringClass() != null && value.getClass().getDeclaringClass().isEnum()) {
79          converterClass = value.getClass().getDeclaringClass();
80          idPrefix = value.getClass().getDeclaringClass().getName() + SEPARATOR;
81        }
82  
83        if (converterClass == null || targetClass != null) {
84          checkTargetClass(facesContext, uiComponent, value, converterClass);
85        }
86  
87        for (Object enumConstant : converterClass.getEnumConstants()) {
88          if (enumConstant == value) {
89            return idPrefix + ((Enum)enumConstant).name();
90          }
91        }
92  
93          return value.toString();
94      }
95  
96      public Object getAsObject(FacesContext facesContext, UIComponent uiComponent, String value) throws ConverterException {
97          if (facesContext == null) throw new NullPointerException("facesContext");
98          if (uiComponent == null) throw new NullPointerException("uiComponent");
99          if (value == null)  return null;
100         value = value.trim();
101         if (value.length() == 0)  return null;
102 
103       Class converterClass = null;
104       String enumName = null;
105 
106       if (targetClass != null) {
107         enumName = value;
108         converterClass = targetClass;
109       } else if (value.indexOf(SEPARATOR) > 0) {
110         int index = value.indexOf(SEPARATOR);
111         if (index < value.length() - 2) {
112           String className = value.substring(0, index);
113           enumName = value.substring(index +1);
114           try {
115             converterClass = Class.forName(className);
116           } catch (ClassNotFoundException e) {
117   //          LOG.error("Catched: " + e.getMessage(), e);
118           }
119         }
120         if (enumName == null || enumName.length() == 0) {
121           return null;
122         }
123       }
124 
125       if (converterClass == null) {
126         checkTargetClass(facesContext, uiComponent, value, converterClass);
127       }
128 
129         // we know targetClass and value can't be null, so we can use Enum.valueOf
130         // instead of the hokey looping called for in the javadoc
131         try {
132           //noinspection unchecked
133           return Enum.valueOf(converterClass, enumName);
134         } catch (IllegalArgumentException e) {
135             Object[] params = new Object[]{value, 
136                                            firstConstantOfEnum(), 
137                                            MessageUtils.getLabel(facesContext, uiComponent)};
138             
139             throw new ConverterException(MessageUtils.getMessage(FacesMessage.SEVERITY_ERROR,
140                                                                        ENUM_ID,
141                                                                        params));
142         }
143     }
144 
145     private void checkTargetClass(FacesContext facesContext, UIComponent uiComponent, Object value, Class converterClass) {
146         if (converterClass == null) {
147             Object[] params = new Object[]{value, MessageUtils.getLabel(facesContext, uiComponent)};
148             throw new ConverterException(MessageUtils.getMessage(FacesMessage.SEVERITY_ERROR,
149                                                                        ENUM_NO_CLASS_ID, 
150                                                                        params));
151         }
152         if (!converterClass.isEnum())
153         {
154             Object[] params = new Object[]{value, MessageUtils.getLabel(facesContext, uiComponent)};
155             throw new ConverterException(MessageUtils.getMessage(FacesMessage.SEVERITY_ERROR,
156                                                                        ENUM_NO_ENUM_CLASS, 
157                                                                        params));
158         }
159     }
160 
161     // find the first constant value of the targetClass and return as a String
162     private String firstConstantOfEnum() {
163         Object[] enumConstants= targetClass.getEnumConstants();
164 
165         if (enumConstants.length != 0 ) return enumConstants[0].toString();
166         
167         return ""; // if empty Enum
168     }
169 
170     public void restoreState(FacesContext context, Object state) {
171         targetClass = (Class)state;
172     }
173 
174     public Object saveState(FacesContext context) {
175         return targetClass;
176     }
177 
178     public void setTransient(boolean newTransientValue) {
179         isTransient = newTransientValue;
180     }
181 
182     public boolean isTransient() {
183         return isTransient;
184     }
185 
186     /**
187      * The enum class to be used for this converter as reference
188      * 
189      */
190     @JSFProperty
191     public Class getTargetClass()
192     {
193         return targetClass;
194     }
195 
196     public void setTargetClass(Class targetClass)
197     {
198         this.targetClass = targetClass;
199     }
200 }