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