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 javax.faces.component;
20  
21  import javax.el.ValueExpression;
22  import javax.faces.FacesException;
23  import javax.faces.context.FacesContext;
24  import javax.faces.convert.Converter;
25  import javax.faces.convert.ConverterException;
26  import java.lang.reflect.Array;
27  import java.util.ArrayList;
28  import java.util.List;
29  
30  /**
31   * The util methods in this class are shared between the javax.faces.component package and
32   * the org.apache.myfaces.renderkit package.
33   * Please note: Any changes here must also apply to the class in the other package!
34   *
35   * @author Manfred Geiler (latest modification by $Author: skitching $)
36   * @version $Revision: 676298 $ $Date: 2008-07-13 05:31:48 -0500 (Sun, 13 Jul 2008) $
37   */
38  class _SharedRendererUtils
39  {
40      static Converter findUIOutputConverter(FacesContext facesContext, UIOutput component)
41      {
42          // Attention!
43          // This code is duplicated in jsfapi component package.
44          // If you change something here please do the same in the other class!
45  
46          Converter converter = component.getConverter();
47          if (converter != null) return converter;
48  
49          //Try to find out by value expression
50          ValueExpression expression = component.getValueExpression("value");
51          if (expression == null) return null;
52  
53          Class valueType = expression.getType(facesContext.getELContext());
54          if (valueType == null) return null;
55  
56          if (Object.class.equals(valueType)) return null;    //There is no converter for Object class
57  
58          try
59          {
60              return facesContext.getApplication().createConverter(valueType);
61          }
62          catch (FacesException e)
63          {
64              log(facesContext, "No Converter for type " + valueType.getName() + " found", e);
65              return null;
66          }
67      }
68  
69      static Object getConvertedUISelectManyValue(FacesContext facesContext,
70                                                  UISelectMany component,
71                                                  String[] submittedValue)
72              throws ConverterException
73      {
74          // Attention!
75          // This code is duplicated in jsfapi component package.
76          // If you change something here please do the same in the other class!
77  
78          if (submittedValue == null) throw new NullPointerException("submittedValue");
79  
80          ValueExpression expression = component.getValueExpression("value");
81          Class valueType = null;
82          Class arrayComponentType = null;
83          if (expression != null)
84          {
85              //By some strange reason vb.getType(facesContext.getELContext());
86              //does not return the same as vb.getValue(facesContext.getELContext()).getClass(),
87              //so we need to use this instead.
88              Object value = expression.getValue(facesContext.getELContext()); 
89              valueType = (value != null) ? value.getClass() :
90                  expression.getType(facesContext.getELContext()) ;
91              
92              if (valueType != null && valueType.isArray())
93              {
94                  arrayComponentType = valueType.getComponentType();
95              }
96          }
97  
98          Converter converter = component.getConverter();
99          if (converter == null)
100         {
101             if (valueType == null)
102             {
103                 // No converter, and no idea of expected type
104                 // --> return the submitted String array
105                 return submittedValue;
106             }
107 
108             if (List.class.isAssignableFrom(valueType))
109             {
110                 // expected type is a List
111                 // --> according to javadoc of UISelectMany we assume that the element type
112                 //     is java.lang.String, and copy the String array to a new List
113                 int len = submittedValue.length;
114                 List lst = new ArrayList(len);
115                 for (int i = 0; i < len; i++)
116                 {
117                     lst.add(submittedValue[i]);
118                 }
119                 return lst;
120             }
121 
122             if (arrayComponentType == null)
123             {
124                 throw new IllegalArgumentException("ValueBinding for UISelectMany must be of type List or Array");
125             }
126 
127             if (Object.class.equals(arrayComponentType)) return submittedValue; //No conversion for Object class
128 
129             converter = facesContext.getApplication().createConverter(arrayComponentType);
130 
131             if (converter == null)
132             {
133                 return submittedValue;
134             }
135         }
136 
137         // Now, we have a converter...
138         // We determine the type of the component array after converting one of it's elements
139         if (expression != null)
140         {
141             valueType = expression.getType(facesContext.getELContext());
142             if (valueType != null && valueType.isArray())
143             {
144                 if (submittedValue.length > 0)
145                 {
146                     arrayComponentType = converter.getAsObject(facesContext, component, submittedValue[0]).getClass();
147                 }
148             }
149         }
150 
151         if (valueType == null)
152         {
153             // ...but have no idea of expected type
154             // --> so let's convert it to an Object array
155             int len = submittedValue.length;
156             Object [] convertedValues = (Object []) Array.newInstance(
157                     arrayComponentType==null?Object.class:arrayComponentType,len);
158             for (int i = 0; i < len; i++)
159             {
160                 convertedValues[i]
161                     = converter.getAsObject(facesContext, component, submittedValue[i]);
162             }
163             return convertedValues;
164         }
165 
166         if (List.class.isAssignableFrom(valueType))
167         {
168             // Curious case: According to specs we should assume, that the element type
169             // of this List is java.lang.String. But there is a Converter set for this
170             // component. Because the user must know what he is doing, we will convert the values.
171             int len = submittedValue.length;
172             List lst = new ArrayList(len);
173             for (int i = 0; i < len; i++)
174             {
175                 lst.add(converter.getAsObject(facesContext, component, submittedValue[i]));
176             }
177             return lst;
178         }
179 
180         if (arrayComponentType == null)
181         {
182             throw new IllegalArgumentException("ValueBinding for UISelectMany must be of type List or Array");
183         }
184 
185         if (arrayComponentType.isPrimitive())
186         {
187             //primitive array
188             int len = submittedValue.length;
189             Object convertedValues = Array.newInstance(arrayComponentType, len);
190             for (int i = 0; i < len; i++)
191             {
192                 Array.set(convertedValues, i,
193                           converter.getAsObject(facesContext, component, submittedValue[i]));
194             }
195             return convertedValues;
196         }
197 
198         //Object array
199         int len = submittedValue.length;
200         ArrayList convertedValues = new ArrayList(len);
201         for (int i = 0; i < len; i++)
202         {
203             convertedValues.add(i, converter.getAsObject(facesContext, component, submittedValue[i]));
204         }
205         return convertedValues.toArray((Object[]) Array.newInstance(arrayComponentType, len));
206     }
207 
208     /**
209      * This method is different in the two versions of _SharedRendererUtils.
210      */
211     private static void log(FacesContext context, String msg, Exception e)
212     {
213         context.getExternalContext().log(msg, e);
214     }
215 }