View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.jexl3.internal.introspection;
18  
19  import java.beans.IntrospectionException;
20  import java.lang.reflect.Constructor;
21  import java.lang.reflect.InvocationTargetException;
22  
23  import org.apache.commons.jexl3.JexlException;
24  import org.apache.commons.jexl3.introspection.JexlMethod;
25  
26  /**
27   * A JexlMethod that wraps a constructor.
28   */
29  public final class ConstructorMethod implements JexlMethod {
30      /**
31       * Discovers a class constructor and wrap it as a JexlMethod.
32       * @param is the introspector
33       * @param ctorHandle a class or class name
34       * @param args constructor arguments
35       * @return a {@link JexlMethod}
36       */
37      public static ConstructorMethod discover(final Introspector is, final Object ctorHandle, final Object... args) {
38          String className;
39          Class<?> clazz = null;
40          if (ctorHandle instanceof Class<?>) {
41              clazz = (Class<?>) ctorHandle;
42              className = clazz.getName();
43          } else if (ctorHandle != null) {
44              className = ctorHandle.toString();
45          } else {
46              return null;
47          }
48          final Constructor<?> ctor = is.getConstructor(clazz, new MethodKey(className, args));
49          if (ctor != null) {
50              return new ConstructorMethod(ctor);
51          }
52          return null;
53      }
54  
55      /** The wrapped constructor. */
56      private final Constructor<?> ctor;
57      /**
58       * Creates a constructor method.
59       * @param theCtor the constructor to wrap
60       */
61      ConstructorMethod(final Constructor<?> theCtor) {
62          this.ctor = theCtor;
63      }
64  
65      @Override
66      public Class<?> getReturnType() {
67          return ctor.getDeclaringClass();
68      }
69  
70      @Override
71      public Object invoke(final Object obj, final Object... params) throws Exception {
72          final Class<?> ctorClass = ctor.getDeclaringClass();
73          boolean invoke = true;
74          if (obj != null) {
75              if (obj instanceof Class<?>) {
76                  invoke = ctorClass.equals(obj);
77              } else {
78                  invoke = ctorClass.getName().equals(obj.toString());
79              }
80          }
81          if (invoke) {
82                  return ctor.newInstance(params);
83              }
84          throw new IntrospectionException("constructor resolution error");
85      }
86  
87      @Override
88      public boolean isCacheable() {
89          return true;
90      }
91  
92      @Override
93      public boolean tryFailed(final Object rval) {
94          return rval == Uberspect.TRY_FAILED;
95      }
96  
97      @Override
98      public Object tryInvoke(final String name, final Object obj, final Object... args) {
99          // Don't try to invoke if no parameter but call has arguments
100         if (ctor.getParameterCount() > 0 || args.length == 0) {
101             try {
102                 final Class<?> ctorClass = ctor.getDeclaringClass();
103                 boolean invoke = true;
104                 if (obj != null) {
105                     if (obj instanceof Class<?>) {
106                         invoke = ctorClass.equals(obj);
107                     } else {
108                         invoke = ctorClass.getName().equals(obj.toString());
109                     }
110                 }
111                 invoke &= name == null || ctorClass.getName().equals(name);
112                 if (invoke) {
113                     return ctor.newInstance(args);
114                 }
115             } catch (InstantiationException | IllegalArgumentException | IllegalAccessException xinstance) {
116                 return Uberspect.TRY_FAILED;
117             } catch (final InvocationTargetException xinvoke) {
118                 throw JexlException.tryFailed(xinvoke); // throw
119             }
120         }
121         return Uberspect.TRY_FAILED;
122     }
123 
124 }