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  
20  package javax.faces.convert;
21  
22  import javax.faces.component.PartialStateHolder;
23  import javax.faces.component.UIComponent;
24  import javax.faces.context.FacesContext;
25  
26  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFConverter;
27  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
28  
29  /**
30   * see Javadoc of <a href="http://java.sun.com/j2ee/javaserverfaces/1.2/docs/api/index.html">JSF Specification</a>
31   */
32  @JSFConverter
33  public class EnumConverter implements Converter, PartialStateHolder
34  {
35  
36      public static final String CONVERTER_ID = "javax.faces.Enum";
37      public static final String ENUM_ID = "javax.faces.converter.EnumConverter.ENUM";
38      public static final String ENUM_NO_CLASS_ID = "javax.faces.converter.EnumConverter.ENUM_NO_CLASS";
39  
40      /**
41       * If value is a String instance and this param is true, pass it directly without try any change.
42       * 
43       * See MYFACES-2739 for details.
44       */
45      @JSFWebConfigParam(name="org.apache.myfaces.ENUM_CONVERTER_ALLOW_STRING_PASSTROUGH", since="2.0.1",
46                         expectedValues="true,false",defaultValue="false", group="validation")
47      private static final String ALLOW_STRING_PASSTROUGH = "org.apache.myfaces.ENUM_CONVERTER_ALLOW_STRING_PASSTROUGH";
48      
49      // TODO: Find a valid generic usage -= Simon Lessard =-
50      private Class targetClass;
51  
52      private boolean isTransient = false;
53  
54      /** Creates a new instance of EnumConverter */
55      public EnumConverter()
56      {
57      }
58  
59      public EnumConverter(Class targetClass)
60      {
61          if (!targetClass.isEnum())
62          {
63              throw new IllegalArgumentException("targetClass for EnumConverter must be an Enum");
64          }
65          this.targetClass = targetClass;
66      }
67  
68      public String getAsString(FacesContext facesContext, UIComponent uiComponent, Object value)
69          throws ConverterException
70      {
71          if (facesContext == null)
72          {
73              throw new NullPointerException("facesContext can not be null");
74          }
75          if (uiComponent == null)
76          {
77              throw new NullPointerException("uiComponent can not be null");
78          }
79  
80          checkTargetClass(facesContext, uiComponent, value);
81  
82          if (value == null)
83          {
84              return null;
85          }
86          
87          if (value instanceof String
88                  && _isPassThroughStringValues(facesContext))
89          {
90              // pass through the String value
91              return (String) value;
92          }
93  
94          // check if the value is an instance of the enum class
95          if (targetClass.isInstance(value))
96          {
97              return ((Enum<?>) value).name();
98          }
99          
100         Object[] params =
101             new Object[] { value, firstConstantOfEnum(), _MessageUtils.getLabel(facesContext, uiComponent) };
102 
103         throw new ConverterException(_MessageUtils.getErrorMessage(facesContext, ENUM_ID, params));
104     }
105 
106     public Object getAsObject(FacesContext facesContext, UIComponent uiComponent, String value)
107         throws ConverterException
108     {
109         if (facesContext == null)
110         {
111             throw new NullPointerException("facesContext");
112         }
113         if (uiComponent == null)
114         {
115             throw new NullPointerException("uiComponent");
116         }
117         if (value == null)
118         {
119             return null;
120         }
121         value = value.trim();
122         if (value.length() == 0)
123         {
124             return null;
125         }
126         checkTargetClass(facesContext, uiComponent, value);
127 
128         // we know targetClass and value can't be null, so we can use Enum.valueOf
129         // instead of the hokey looping called for in the javadoc
130         try
131         {
132             return Enum.valueOf(targetClass, value);
133         }
134         catch (IllegalArgumentException e)
135         {
136             Object[] params =
137                     new Object[] { value, firstConstantOfEnum(), _MessageUtils.getLabel(facesContext, uiComponent) };
138 
139             throw new ConverterException(_MessageUtils.getErrorMessage(facesContext, ENUM_ID, params));
140         }
141     }
142 
143     private void checkTargetClass(FacesContext facesContext, UIComponent uiComponent, Object value)
144     {
145         if (targetClass == null)
146         {
147             Object[] params = new Object[] { value, _MessageUtils.getLabel(facesContext, uiComponent) };
148             throw new ConverterException(_MessageUtils.getErrorMessage(facesContext, ENUM_NO_CLASS_ID, params));
149         }
150     }
151 
152     // find the first constant value of the targetClass and return as a String
153     private String firstConstantOfEnum()
154     {
155         Object[] enumConstants = targetClass.getEnumConstants();
156 
157         if (enumConstants.length != 0)
158         {
159             return enumConstants[0].toString();
160         }
161 
162         return ""; // if empty Enum
163     }
164 
165     public void restoreState(FacesContext context, Object state)
166     {
167         if (state != null)
168         {
169             targetClass = (Class<?>)state;
170         }
171     }
172 
173     public Object saveState(FacesContext context)
174     {
175         if (!initialStateMarked())
176         {
177             return targetClass;
178         }
179         return null;
180     }
181 
182     public void setTransient(boolean newTransientValue)
183     {
184         isTransient = newTransientValue;
185     }
186 
187     public boolean isTransient()
188     {
189         return isTransient;
190     }
191     
192     private boolean _initialStateMarked = false;
193 
194     public void clearInitialState()
195     {
196         _initialStateMarked = false;
197     }
198 
199     public boolean initialStateMarked()
200     {
201         return _initialStateMarked;
202     }
203 
204     public void markInitialState()
205     {
206         _initialStateMarked = true;
207     }
208     
209     private boolean _isPassThroughStringValues(FacesContext facesContext)
210     {
211         String param = facesContext.getExternalContext().getInitParameter(ALLOW_STRING_PASSTROUGH);
212         if (param != null)
213         {
214             return param.trim().equalsIgnoreCase("true");
215         }
216         // default: false
217         return false;
218     }
219 
220 }