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.juneau.objecttools; 018 019import java.io.*; 020import java.lang.reflect.*; 021 022import org.apache.juneau.json.*; 023import org.apache.juneau.parser.*; 024import org.apache.juneau.reflect.*; 025 026/** 027 * POJO method introspector. 028 * 029 * <p> 030 * This class is used to invoke methods on {@code Objects} using arguments in serialized form. 031 * </p> 032 * 033 * <h5 class='section'>Example:</h5> 034 * <p class='bjava'> 035 * String <jv>string1</jv> = <js>"foobar"</js>; 036 * String <jv>string2</jv> = ObjectIntrospector 037 * .create(<jv>string</jv>) 038 * .invoke(String.<jk>class</jk>, <js>"substring(int,int)"</js>, <js>"[3,6]"</js>); <jc>// "bar"</jc> 039 * </p> 040 * <p> 041 * The arguments passed to the identified method are POJOs serialized in JSON format. Arbitrarily complex arguments can be passed 042 * in as arguments. 043 * </p> 044 * <ul> 045 * <li class='warn'>This is an extremely powerful but potentially dangerous tool. Use wisely. 046 * </ul> 047 * 048 * <h5 class='section'>See Also:</h5><ul> 049 050 * </ul> 051 */ 052public class ObjectIntrospector { 053 054 //----------------------------------------------------------------------------------------------------------------- 055 // Static 056 //----------------------------------------------------------------------------------------------------------------- 057 058 /** 059 * Static creator. 060 * @param o The object on which Java methods will be invoked. 061 * @return A new {@link ObjectIntrospector} object. 062 */ 063 public static ObjectIntrospector create(Object o) { 064 return new ObjectIntrospector(o); 065 } 066 067 /** 068 * Static creator. 069 * @param o The object on which Java methods will be invoked. 070 * @param parser The parser to use to parse the method arguments. 071 * @return A new {@link ObjectIntrospector} object. 072 */ 073 public static ObjectIntrospector create(Object o, ReaderParser parser) { 074 return new ObjectIntrospector(o, parser); 075 } 076 077 //----------------------------------------------------------------------------------------------------------------- 078 // Instance 079 //----------------------------------------------------------------------------------------------------------------- 080 081 private final Object object; 082 private final ReaderParser parser; 083 084 /** 085 * Constructor. 086 * 087 * @param object The object on which Java methods will be invoked. 088 * @param parser The parser to use to parse the method arguments. 089 * If <jk>null</jk>, {@link JsonParser#DEFAULT} is used. 090 */ 091 public ObjectIntrospector(Object object, ReaderParser parser) { 092 if (parser == null) 093 parser = JsonParser.DEFAULT; 094 this.object = object; 095 this.parser = parser; 096 } 097 098 /** 099 * Shortcut for calling <code><jk>new</jk> ObjectIntrospector(o, <jk>null</jk>);</code> 100 * 101 * @param o The object on which Java methods will be invoked. 102 */ 103 public ObjectIntrospector(Object o) { 104 this(o, null); 105 } 106 107 /** 108 * Primary method. 109 * 110 * <p> 111 * Invokes the specified method on this bean. 112 * 113 * @param method The method being invoked. 114 * @param args 115 * The arguments to pass as parameters to the method. 116 * These will automatically be converted to the appropriate object type if possible. 117 * Can be <jk>null</jk> if method has no arguments. 118 * @return The object returned by the call to the method, or <jk>null</jk> if target object is <jk>null</jk>. 119 * @throws IllegalAccessException 120 * If the <c>Constructor</c> object enforces Java language access control and the underlying constructor is 121 * inaccessible. 122 * @throws IllegalArgumentException 123 * If one of the following occurs: 124 * <ul class='spaced-list'> 125 * <li> 126 * The number of actual and formal parameters differ. 127 * <li> 128 * An unwrapping conversion for primitive arguments fails. 129 * <li> 130 * A parameter value cannot be converted to the corresponding formal parameter type by a method invocation 131 * conversion. 132 * <li> 133 * The constructor pertains to an enum type. 134 * </ul> 135 * @throws InvocationTargetException If the underlying constructor throws an exception. 136 * @throws ParseException Malformed input encountered. 137 * @throws IOException Thrown by underlying stream. 138 */ 139 public Object invokeMethod(Method method, Reader args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException, ParseException, IOException { 140 if (object == null) 141 return null; 142 Object[] params = args == null ? null : parser.parseArgs(args, method.getGenericParameterTypes()); 143 return method.invoke(object, params); 144 } 145 146 /** 147 * Primary method. 148 * 149 * <p> 150 * Invokes the specified method on this bean. 151 * 152 * @param <T> The return type of the method call. 153 * @param returnType The return type of the method call. 154 * @param method The method being invoked. 155 * @param args 156 * The arguments to pass as parameters to the method. 157 * These will automatically be converted to the appropriate object type if possible. 158 * Can be <jk>null</jk> if method has no arguments. 159 * @return The object returned by the call to the method, or <jk>null</jk> if target object is <jk>null</jk>. 160 * @throws IllegalAccessException 161 * If the <c>Constructor</c> object enforces Java language access control and the underlying constructor is 162 * inaccessible. 163 * @throws IllegalArgumentException 164 * If one of the following occurs: 165 * <ul class='spaced-list'> 166 * <li> 167 * The number of actual and formal parameters differ. 168 * <li> 169 * An unwrapping conversion for primitive arguments fails. 170 * <li> 171 * A parameter value cannot be converted to the corresponding formal parameter type by a method invocation 172 * conversion. 173 * <li> 174 * The constructor pertains to an enum type. 175 * </ul> 176 * @throws InvocationTargetException If the underlying constructor throws an exception. 177 * @throws ParseException Malformed input encountered. 178 * @throws IOException Thrown by underlying stream. 179 */ 180 public <T> T invokeMethod(Class<T> returnType, Method method, Reader args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException, ParseException, IOException { 181 return returnType.cast(invokeMethod(method, args)); 182 } 183 184 /** 185 * Convenience method for invoking argument from method signature (@see {@link MethodInfo#getSignature()}. 186 * 187 * @param method The method being invoked. 188 * @param args 189 * The arguments to pass as parameters to the method. 190 * These will automatically be converted to the appropriate object type if possible. 191 * Can be <jk>null</jk> if method has no arguments. 192 * @return The object returned by the call to the method, or <jk>null</jk> if target object is <jk>null</jk>. 193 * @throws NoSuchMethodException If method does not exist. 194 * @throws IllegalAccessException 195 * If the <c>Constructor</c> object enforces Java language access control and 196 * the underlying constructor is inaccessible. 197 * @throws IllegalArgumentException 198 * If one of the following occurs: 199 * <ul class='spaced-list'> 200 * <li> 201 * The number of actual and formal parameters differ. 202 * <li> 203 * An unwrapping conversion for primitive arguments fails. 204 * <li> 205 * A parameter value cannot be converted to the corresponding formal parameter type by a method invocation 206 * conversion. 207 * <li> 208 * The constructor pertains to an enum type. 209 * </ul> 210 * @throws InvocationTargetException If the underlying constructor throws an exception. 211 * @throws ParseException Malformed input encountered. 212 * @throws IOException Thrown by underlying stream. 213 */ 214 public Object invokeMethod(String method, String args) throws NoSuchMethodException, IllegalArgumentException, InvocationTargetException, IllegalAccessException, ParseException, IOException { 215 if (object == null) 216 return null; 217 Method m = parser.getBeanContext().getClassMeta(object.getClass()).getPublicMethods().get(method); 218 if (m == null) 219 throw new NoSuchMethodException(method); 220 return invokeMethod(m, args == null ? null : new StringReader(args)); 221 } 222 223 /** 224 * Convenience method for invoking argument from method signature (@see {@link MethodInfo#getSignature()}. 225 * 226 * @param <T> The return type of the method call. 227 * @param returnType The return type of the method call. 228 * @param method The method being invoked. 229 * @param args 230 * The arguments to pass as parameters to the method. 231 * These will automatically be converted to the appropriate object type if possible. 232 * Can be <jk>null</jk> if method has no arguments. 233 * @return The object returned by the call to the method, or <jk>null</jk> if target object is <jk>null</jk>. 234 * @throws NoSuchMethodException If method does not exist. 235 * @throws IllegalAccessException 236 * If the <c>Constructor</c> object enforces Java language access control and 237 * the underlying constructor is inaccessible. 238 * @throws IllegalArgumentException 239 * If one of the following occurs: 240 * <ul class='spaced-list'> 241 * <li> 242 * The number of actual and formal parameters differ. 243 * <li> 244 * An unwrapping conversion for primitive arguments fails. 245 * <li> 246 * A parameter value cannot be converted to the corresponding formal parameter type by a method invocation 247 * conversion. 248 * <li> 249 * The constructor pertains to an enum type. 250 * </ul> 251 * @throws InvocationTargetException If the underlying constructor throws an exception. 252 * @throws ParseException Malformed input encountered. 253 * @throws IOException Thrown by underlying stream. 254 */ 255 public <T> T invokeMethod(Class<T> returnType, String method, String args) throws NoSuchMethodException, IllegalArgumentException, InvocationTargetException, IllegalAccessException, ParseException, IOException { 256 return returnType.cast(invokeMethod(method, args)); 257 } 258}