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.Argument.getParameterTypes;
23  import static org.apache.commons.beanutils2.Assertions.checkNoneIsNull;
24  import static org.apache.commons.beanutils2.Assertions.checkNotNull;
25  
26  import static java.lang.reflect.Modifier.isAbstract;
27  
28  import java.lang.reflect.Constructor;
29  import java.lang.reflect.InvocationTargetException;
30  
31  final class DefaultClassAccessor<B>
32      implements ClassAccessor<B>
33  {
34  
35      private final AccessibleObjectsRegistry<Constructor<?>> constructorRegistry =
36                      AccessibleObjectsRegistry.getConstructorsRegistry();
37  
38      private final BeanProperties<B> beanProperties;
39  
40      private final Class<B> beanClass;
41  
42      public DefaultClassAccessor( Class<B> beanClass )
43      {
44          this.beanClass = beanClass;
45          beanProperties = new DefaultBeanProperties<B>( beanClass );
46      }
47  
48      // pure new class instantiation
49  
50      /**
51       * {@inheritDoc}
52       */
53      public BeanAccessor<B> newInstance()
54      {
55          return invokeConstructor();
56      }
57  
58      // constructors
59  
60      /**
61       * {@inheritDoc}
62       */
63      public BeanAccessor<B> invokeConstructor( Argument<?>... arguments )
64      {
65          arguments = checkNotNull( arguments,
66                                    "Null arguments not admitted - don't pass any argument to use %s empty constructor",
67                                    beanClass );
68          arguments = checkNoneIsNull( arguments );
69          return invokeConstructor( false, arguments );
70      }
71  
72      /**
73       * {@inheritDoc}
74       */
75      public BeanAccessor<B> invokeExactConstructor( Argument<?>... arguments )
76      {
77          arguments = checkNotNull( arguments,
78                                    "Null arguments not admitted - don't pass any argument to use %s empty constructor",
79                                    beanClass );
80          arguments = checkNoneIsNull( arguments );
81          return invokeConstructor( true, arguments );
82      }
83  
84      private BeanAccessor<B> invokeConstructor( boolean exact, Argument<?>... arguments )
85      {
86          checkInstantiable();
87          @SuppressWarnings( "unchecked" ) // type driven by beanClass
88          Constructor<B> constructor = (Constructor<B>) constructorRegistry.get( exact,
89                                                                                 beanClass,
90                                                                                 getParameterTypes( arguments ) );
91  
92          if ( null == constructor )
93          {
94              throw new NoSuchConstructorException( beanClass, null );
95          }
96  
97          int argumentsLength = arguments.length;
98          Object[] parameterObjects = new Object[argumentsLength];
99          for ( int i = 0; i < argumentsLength; i++ )
100         {
101             parameterObjects[i] = arguments[i].getValue();
102         }
103 
104         B bean = doInvokeConstructor( constructor, parameterObjects );
105         return new DefaultBeanAccessor<B>( bean );
106     }
107 
108     /**
109      * Checks if {@code beanClass} is instantiable and throws a {@link BeanInstantiationException} with an appropriate
110      * message otherwise.
111      */
112     private void checkInstantiable()
113     {
114         if ( beanClass.isInterface() )
115         {
116             throw new BeanInstantiationException( beanClass, "Type is an interface." );
117         }
118         if ( beanClass.isArray() )
119         {
120             throw new BeanInstantiationException( beanClass, "Type is an array class." );
121         }
122         if ( beanClass.isPrimitive() )
123         {
124             throw new BeanInstantiationException( beanClass, "Type is primitive." );
125         }
126         if ( beanClass.equals( Void.TYPE ) )
127         {
128             throw new BeanInstantiationException( beanClass, "Type represents void." );
129         }
130         // has to be the last check because primitives and array types are also abstract
131         if ( isAbstract( beanClass.getModifiers() ) )
132         {
133             throw new BeanInstantiationException( beanClass, "Type is abstract." );
134         }
135     }
136 
137     private B doInvokeConstructor( Constructor<B> constructor, Object[] parameterObjects )
138     {
139         try
140         {
141             return constructor.newInstance( parameterObjects );
142         }
143         catch ( InstantiationException e )
144         {
145             throw new BeanInstantiationException( beanClass, e );
146         }
147         catch ( IllegalAccessException e )
148         {
149             throw new ConstructorNotAccessibleException( beanClass, e );
150         }
151         catch ( InvocationTargetException e )
152         {
153             throw new ConstructorInvocationException( beanClass, e );
154         }
155     }
156 
157     // bean properties
158 
159     public BeanProperties<B> getProperties()
160     {
161         return beanProperties;
162     }
163 
164     // static methods
165 
166     /**
167      * {@inheritDoc}
168      */
169     public ArgumentsAccessor invokeStatic( String methodName )
170     {
171         methodName = checkNotNull( methodName, "Impossible to execute null static method in %s", beanClass );
172         return new DefaultArgumentsAccessor( beanClass, false, methodName, null );
173     }
174 
175     /**
176      * {@inheritDoc}
177      */
178     public ArgumentsAccessor invokeExactStatic( String methodName )
179     {
180         methodName = checkNotNull( methodName, "Impossible to execute null static method in %s", beanClass );
181         return new DefaultArgumentsAccessor( beanClass, true, methodName, null );
182     }
183 
184 }