View Javadoc
1   package org.apache.commons.beanutils2;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import static org.apache.commons.beanutils2.Assertions.checkNoneIsNull;
23  import static org.apache.commons.beanutils2.Assertions.checkNotNull;
24  
25  final class TypeUtils
26  {
27  
28      /**
29       * Hidden constructor, this class cannot be instantiated directly.
30       */
31      private TypeUtils()
32      {
33          // do nothing
34      }
35  
36      /**
37       * <p>Determine whether a type can be used as a parameter in a method invocation.
38       * This method handles primitive conversions correctly.</p>
39       *
40       * <p>In order words, it will match a <code>Boolean</code> to a <code>boolean</code>,
41       * a <code>Long</code> to a <code>long</code>,
42       * a <code>Float</code> to a <code>float</code>,
43       * a <code>Integer</code> to a <code>int</code>,
44       * and a <code>Double</code> to a <code>double</code>.
45       * Now logic widening matches are allowed.
46       * For example, a <code>Long</code> will not match a <code>int</code>.
47       *
48       * @param parameterType the type of parameter accepted by the method. Must not be {@code null}!
49       * @param parameterization the type of parameter being tested. Must not be {@code null}!
50       *
51       * @return true if the assignement is compatible.
52       */
53      public static boolean isAssignmentCompatible( Class<?> parameterType, Class<?> parameterization )
54      {
55          parameterType = checkNotNull( parameterType, "parameterType must not be null!" );
56          parameterization = checkNotNull( parameterization, "parameterization must not be null!" );
57          // try plain assignment
58          if ( parameterType.isAssignableFrom( parameterization ) )
59          {
60              return true;
61          }
62  
63          if ( parameterType.isPrimitive() )
64          {
65              // this method does *not* do widening - you must specify exactly
66              // is this the right behaviour?
67              Class<?> parameterWrapperClazz = getPrimitiveWrapper( parameterType );
68              if ( parameterWrapperClazz != null )
69              {
70                  return parameterWrapperClazz.equals( parameterization );
71              }
72          }
73  
74          return false;
75      }
76  
77      /**
78       * Gets the wrapper object class for the given primitive type class.
79       * For example, passing <code>boolean.class</code> returns <code>Boolean.class</code>
80       * @param primitiveType the primitive type class for which a match is to be found
81       * @return the wrapper type associated with the given primitive
82       * or null if no match is found
83       */
84      public static Class<?> getPrimitiveWrapper( Class<?> primitiveType )
85      {
86          // does anyone know a better strategy than comparing names?
87          if ( boolean.class.equals( primitiveType ) )
88          {
89              return Boolean.class;
90          }
91          else if ( float.class.equals( primitiveType ) )
92          {
93              return Float.class;
94          }
95          else if ( long.class.equals( primitiveType ) )
96          {
97              return Long.class;
98          }
99          else if ( int.class.equals( primitiveType ) )
100         {
101             return Integer.class;
102         }
103         else if ( short.class.equals( primitiveType ) )
104         {
105             return Short.class;
106         }
107         else if ( byte.class.equals( primitiveType ) )
108         {
109             return Byte.class;
110         }
111         else if ( double.class.equals( primitiveType ) )
112         {
113             return Double.class;
114         }
115         else if ( char.class.equals( primitiveType ) )
116         {
117             return Character.class;
118         }
119         return null;
120     }
121 
122     /**
123      * Gets the class for the primitive type corresponding to the primitive wrapper class given.
124      * For example, an instance of <code>Boolean.class</code> returns a <code>boolean.class</code>.
125      * @param wrapperType the
126      * @return the primitive type class corresponding to the given wrapper class,
127      * null if no match is found
128      */
129     public static Class<?> getPrimitiveType( Class<?> wrapperType )
130     {
131         // does anyone know a better strategy than comparing names?
132         if ( Boolean.class.equals( wrapperType ) )
133         {
134             return boolean.class;
135         }
136         else if ( Float.class.equals( wrapperType ) )
137         {
138             return float.class;
139         }
140         else if ( Long.class.equals( wrapperType ) )
141         {
142             return long.class;
143         }
144         else if ( Integer.class.equals( wrapperType ) )
145         {
146             return int.class;
147         }
148         else if ( Short.class.equals( wrapperType ) )
149         {
150             return short.class;
151         }
152         else if ( Byte.class.equals( wrapperType ) )
153         {
154             return byte.class;
155         }
156         else if ( Double.class.equals( wrapperType ) )
157         {
158             return double.class;
159         }
160         else if ( Character.class.equals( wrapperType ) )
161         {
162             return char.class;
163         }
164         return null;
165     }
166 
167     /**
168      * Finds a non primitive representation for given primitive class.
169      *
170      * @param clazz the class to find a representation for. Must not be {@code null}!
171      * @return the original class if it not a primitive. Otherwise the wrapper class. Not null
172      */
173     public static Class<?> toNonPrimitiveClass( Class<?> clazz )
174     {
175         clazz = checkNotNull( clazz, "Parameter clazz must not be null!" );
176         if ( clazz.isPrimitive() )
177         {
178             Class<?> primitiveClazz = getPrimitiveWrapper( clazz );
179             // the above method returns
180             if ( primitiveClazz != null )
181             {
182                 return primitiveClazz;
183             }
184             return clazz;
185         }
186         return clazz;
187     }
188 
189     /**
190      * Checks if a set of parameters is compatible to another set. For example this method can be used to check if all
191      * parameter types of one method are compatible to the parameter types of another method. Note that two empty arrays
192      * will pass the test.
193      *
194      * @param types the types check against otherTypes. None must be {@code null}!
195      * @param otherTypes the other types used for comparing. None must be {@code null}!
196      * @return true if all parameters are compatible
197      * @throws NullPointerException if either {@code types}, {@code otherTypes} or one of the contained types is
198      *             {@code null}.
199      */
200     public static boolean checkTypesCompatible( Class<?>[] types, Class<?>[] otherTypes )
201     {
202         checkNotNull( types, "Input parameter 'types' must not be null!" );
203         checkNotNull( otherTypes, "Input parameter 'otherTypes' must not be null!" );
204         checkNoneIsNull( types );
205         checkNoneIsNull( otherTypes );
206         if ( types.length != otherTypes.length )
207         {
208             return false;
209         }
210         for ( int n = 0; n < types.length; n++ )
211         {
212             if ( !isAssignmentCompatible( types[n], otherTypes[n] ) )
213             {
214                 return false;
215             }
216         }
217         return true;
218     }
219 
220 }