001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.jexl3.internal.introspection; 018 019import java.beans.IntrospectionException; 020import java.lang.reflect.Constructor; 021import java.lang.reflect.InvocationTargetException; 022import org.apache.commons.jexl3.JexlException; 023import org.apache.commons.jexl3.introspection.JexlMethod; 024 025/** 026 * A JexlMethod that wraps a constructor. 027 */ 028public final class ConstructorMethod implements JexlMethod { 029 /** The wrapped constructor. */ 030 private final Constructor<?> ctor; 031 032 /** 033 * Discovers a class constructor and wrap it as a JexlMethod. 034 * @param is the introspector 035 * @param ctorHandle a class or class name 036 * @param args constructor arguments 037 * @return a {@link JexlMethod} 038 */ 039 public static ConstructorMethod discover(final Introspector is, final Object ctorHandle, final Object... args) { 040 String className; 041 Class<?> clazz = null; 042 if (ctorHandle instanceof Class<?>) { 043 clazz = (Class<?>) ctorHandle; 044 className = clazz.getName(); 045 } else if (ctorHandle != null) { 046 className = ctorHandle.toString(); 047 } else { 048 return null; 049 } 050 final Constructor<?> ctor = is.getConstructor(clazz, new MethodKey(className, args)); 051 if (ctor != null) { 052 return new ConstructorMethod(ctor); 053 } 054 return null; 055 } 056 /** 057 * Creates a constructor method. 058 * @param theCtor the constructor to wrap 059 */ 060 ConstructorMethod(final Constructor<?> theCtor) { 061 this.ctor = theCtor; 062 } 063 064 @Override 065 public Object invoke(final Object obj, final Object... params) throws Exception { 066 final Class<?> ctorClass = ctor.getDeclaringClass(); 067 boolean invoke = true; 068 if (obj != null) { 069 if (obj instanceof Class<?>) { 070 invoke = ctorClass.equals(obj); 071 } else { 072 invoke = ctorClass.getName().equals(obj.toString()); 073 } 074 } 075 if (invoke) { 076 return ctor.newInstance(params); 077 } 078 throw new IntrospectionException("constructor resolution error"); 079 } 080 081 @Override 082 public Object tryInvoke(final String name, final Object obj, final Object... params) { 083 try { 084 final Class<?> ctorClass = ctor.getDeclaringClass(); 085 boolean invoke = true; 086 if (obj != null) { 087 if (obj instanceof Class<?>) { 088 invoke = ctorClass.equals(obj); 089 } else { 090 invoke = ctorClass.getName().equals(obj.toString()); 091 } 092 } 093 invoke &= name == null || ctorClass.getName().equals(name); 094 if (invoke) { 095 return ctor.newInstance(params); 096 } 097 } catch (InstantiationException | IllegalArgumentException | IllegalAccessException xinstance) { 098 return Uberspect.TRY_FAILED; 099 } catch (final InvocationTargetException xinvoke) { 100 throw JexlException.tryFailed(xinvoke); // throw 101 } 102 return Uberspect.TRY_FAILED; 103 } 104 105 @Override 106 public boolean tryFailed(final Object rval) { 107 return rval == Uberspect.TRY_FAILED; 108 } 109 110 @Override 111 public boolean isCacheable() { 112 return true; 113 } 114 115 @Override 116 public Class<?> getReturnType() { 117 return ctor.getDeclaringClass(); 118 } 119 120}