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