001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau.utils; 014 015import java.io.*; 016import java.lang.reflect.*; 017 018import org.apache.juneau.internal.*; 019import org.apache.juneau.json.*; 020import org.apache.juneau.parser.*; 021 022/** 023 * Used to invoke methods on {@code Objects} using arguments in serialized form. 024 * 025 * <h5 class='section'>Example:</h5> 026 * <p class='bcode'> 027 * String s = <js>"foobar"</js>; 028 * String s2 = (String)<jk>new</jk> PojoIntrospector(s) 029 * .invoke(<js>"substring(int,int)"</js>, <js>"[3,6]"</js>); <jc>// "bar"</jc> 030 * </p> 031 */ 032public final class PojoIntrospector { 033 034 private final Object o; 035 private final ReaderParser p; 036 037 /** 038 * Constructor. 039 * 040 * @param o The object on which Java methods will be invoked. 041 * @param p The parser to use to parse the method arguments. 042 * If <jk>null</jk>, {@link JsonParser#DEFAULT} is used. 043 */ 044 public PojoIntrospector(Object o, ReaderParser p) { 045 if (p == null) 046 p = JsonParser.DEFAULT; 047 this.o = o; 048 this.p = p; 049 } 050 051 /** 052 * Shortcut for calling <code><jk>new</jk> PojoIntrospector(o, <jk>null</jk>);</code> 053 * 054 * @param o The object on which Java methods will be invoked. 055 */ 056 public PojoIntrospector(Object o) { 057 this(o, null); 058 } 059 060 /** 061 * Primary method. Invokes the specified method on this bean. 062 * 063 * @param method The method being invoked. 064 * @param args 065 * The arguments to pass as parameters to the method. 066 * These will automatically be converted to the appropriate object type if possible. 067 * Can be <jk>null</jk> if method has no arguments. 068 * @return The object returned by the call to the method, or <jk>null</jk> if target object is <jk>null</jk>. 069 * @throws IllegalAccessException 070 * If the <code>Constructor</code> object enforces Java language access control and the underlying constructor is 071 * inaccessible. 072 * @throws IllegalArgumentException 073 * If one of the following occurs: 074 * <ul class='spaced-list'> 075 * <li> 076 * The number of actual and formal parameters differ. 077 * <li> 078 * An unwrapping conversion for primitive arguments fails. 079 * <li> 080 * A parameter value cannot be converted to the corresponding formal parameter type by a method invocation 081 * conversion. 082 * <li> 083 * The constructor pertains to an enum type. 084 * </ul> 085 * @throws InvocationTargetException If the underlying constructor throws an exception. 086 * @throws ParseException If the input contains a syntax error or is malformed. 087 * @throws IOException 088 */ 089 public Object invokeMethod(Method method, Reader args) throws InvocationTargetException, IllegalArgumentException, 090 IllegalAccessException, ParseException, IOException { 091 if (o == null) 092 return null; 093 Object[] params = args == null ? null : p.parseArgs(args, method.getGenericParameterTypes()); 094 return method.invoke(o, params); 095 } 096 097 /** 098 * Convenience method for invoking argument from method signature (@see {@link ClassUtils#getMethodSignature(Method)}. 099 * 100 * @param method The method being invoked. 101 * @param args 102 * The arguments to pass as parameters to the method. 103 * These will automatically be converted to the appropriate object type if possible. 104 * Can be <jk>null</jk> if method has no arguments. 105 * @return The object returned by the call to the method, or <jk>null</jk> if target object is <jk>null</jk>. 106 * @throws NoSuchMethodException If method does not exist. 107 * @throws IllegalAccessException 108 * If the <code>Constructor</code> object enforces Java language access control and 109 * the underlying constructor is inaccessible. 110 * @throws IllegalArgumentException 111 * If one of the following occurs: 112 * <ul class='spaced-list'> 113 * <li> 114 * The number of actual and formal parameters differ. 115 * <li> 116 * An unwrapping conversion for primitive arguments fails. 117 * <li> 118 * A parameter value cannot be converted to the corresponding formal parameter type by a method invocation 119 * conversion. 120 * <li> 121 * The constructor pertains to an enum type. 122 * </ul> 123 * @throws InvocationTargetException If the underlying constructor throws an exception. 124 * @throws ParseException If the input contains a syntax error or is malformed. 125 * @throws IOException 126 */ 127 public Object invokeMethod(String method, String args) throws NoSuchMethodException, IllegalArgumentException, 128 InvocationTargetException, IllegalAccessException, ParseException, IOException { 129 if (o == null) 130 return null; 131 Method m = p.getClassMeta(o.getClass()).getPublicMethods().get(method); 132 if (m == null) 133 throw new NoSuchMethodException(method); 134 return invokeMethod(m, args == null ? null : new StringReader(args)); 135 } 136}