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      {
70          if (facesContext == null)
71          {
72              throw new NullPointerException("facesContext can not be null");
73          }
74          if (uiComponent == null)
75          {
76              throw new NullPointerException("uiComponent can not be null");
77          }
78  
79          checkTargetClass(facesContext, uiComponent, value);
80  
81          if (value == null)
82          {
83              return "";
84          }
85          
86          if (value instanceof String
87                  && _isPassThroughStringValues(facesContext))
88          {
89              // pass through the String value
90              return (String) value;
91          }
92  
93          // check if the value is an instance of the enum class
94          if (targetClass.isInstance(value))
95          {
96              return ((Enum<?>) value).name();
97          }
98          
99          Object[] params =
100             new Object[] { value, firstConstantOfEnum(), _MessageUtils.getLabel(facesContext, uiComponent) };
101 
102         throw new ConverterException(_MessageUtils.getErrorMessage(facesContext, ENUM_ID, params));
103     }
104 
105     public Object getAsObject(FacesContext facesContext, UIComponent uiComponent, String value)
106     {
107         if (facesContext == null)
108         {
109             throw new NullPointerException("facesContext");
110         }
111         if (uiComponent == null)
112         {
113             throw new NullPointerException("uiComponent");
114         }
115         if (value == null)
116         {
117             return null;
118         }
119         value = value.trim();
120         if (value.length() == 0)
121         {
122             return null;
123         }
124         checkTargetClass(facesContext, uiComponent, value);
125 
126         // we know targetClass and value can't be null, so we can use Enum.valueOf
127         // instead of the hokey looping called for in the javadoc
128         try
129         {
130             return Enum.valueOf(targetClass, value);
131         }
132         catch (IllegalArgumentException e)
133         {
134             Object[] params =
135                     new Object[] { value, firstConstantOfEnum(), _MessageUtils.getLabel(facesContext, uiComponent) };
136 
137             throw new ConverterException(_MessageUtils.getErrorMessage(facesContext, ENUM_ID, params));
138         }
139     }
140 
141     private void checkTargetClass(FacesContext facesContext, UIComponent uiComponent, Object value)
142     {
143         if (targetClass == null)
144         {
145             Object[] params = new Object[] { value, _MessageUtils.getLabel(facesContext, uiComponent) };
146             throw new ConverterException(_MessageUtils.getErrorMessage(facesContext, ENUM_NO_CLASS_ID, params));
147         }
148     }
149 
150     // find the first constant value of the targetClass and return as a String
151     private String firstConstantOfEnum()
152     {
153         Object[] enumConstants = targetClass.getEnumConstants();
154 
155         if (enumConstants.length != 0)
156         {
157             return enumConstants[0].toString();
158         }
159 
160         return ""; // if empty Enum
161     }
162 
163     public void restoreState(FacesContext context, Object state)
164     {
165         if (state != null)
166         {
167             targetClass = (Class<?>)state;
168         }
169     }
170 
171     public Object saveState(FacesContext context)
172     {
173         if (!initialStateMarked())
174         {
175             return targetClass;
176         }
177         return null;
178     }
179 
180     public void setTransient(boolean newTransientValue)
181     {
182         isTransient = newTransientValue;
183     }
184 
185     public boolean isTransient()
186     {
187         return isTransient;
188     }
189     
190     private boolean _initialStateMarked = false;
191 
192     public void clearInitialState()
193     {
194         _initialStateMarked = false;
195     }
196 
197     public boolean initialStateMarked()
198     {
199         return _initialStateMarked;
200     }
201 
202     public void markInitialState()
203     {
204         _initialStateMarked = true;
205     }
206     
207     private boolean _isPassThroughStringValues(FacesContext facesContext)
208     {
209         String param = facesContext.getExternalContext().getInitParameter(ALLOW_STRING_PASSTROUGH);
210         if (param != null)
211         {
212             return param.trim().equalsIgnoreCase("true");
213         }
214         // default: false
215         return false;
216     }
217 
218 }