Author: jochen
Date: Fri Mar 3 14:10:05 2006
New Revision: 382944
URL: http://svn.apache.org/viewcvs?rev=382944&view=rev
Log:
Performing the next step in the implementation of introspection. (See
XMLRPC-75.)
Added:
webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/metadata/ReflectiveXmlRpcMetaDataHandler.java
webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/metadata/Util.java
webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/metadata/XmlRpcSystemImpl.java
webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/server/ReflectiveXmlRpcHandler.java
Modified:
webservices/xmlrpc/trunk/.settings/org.eclipse.jdt.core.prefs
webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/server/AbstractReflectiveHandlerMapping.java
Modified: webservices/xmlrpc/trunk/.settings/org.eclipse.jdt.core.prefs
URL:
http://svn.apache.org/viewcvs/webservices/xmlrpc/trunk/.settings/org.eclipse.jdt.core.prefs?rev=382944&r1=382943&r2=382944&view=diff
==============================================================================
--- webservices/xmlrpc/trunk/.settings/org.eclipse.jdt.core.prefs (original)
+++ webservices/xmlrpc/trunk/.settings/org.eclipse.jdt.core.prefs Fri Mar 3
14:10:05 2006
@@ -1,9 +1,9 @@
-#Fri Feb 24 13:58:31 CET 2006
+#Fri Mar 03 08:22:27 CET 2006
eclipse.preferences.version=1
-org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=disabled
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.3
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=1.4
+org.eclipse.jdt.core.compiler.compliance=1.5
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
@@ -15,7 +15,7 @@
org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
-org.eclipse.jdt.core.compiler.problem.enumIdentifier=warning
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
org.eclipse.jdt.core.compiler.problem.finalParameterBound=ignore
@@ -59,4 +59,4 @@
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
-org.eclipse.jdt.core.compiler.source=1.4
+org.eclipse.jdt.core.compiler.source=1.5
Added:
webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/metadata/ReflectiveXmlRpcMetaDataHandler.java
URL:
http://svn.apache.org/viewcvs/webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/metadata/ReflectiveXmlRpcMetaDataHandler.java?rev=382944&view=auto
==============================================================================
---
webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/metadata/ReflectiveXmlRpcMetaDataHandler.java
(added)
+++
webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/metadata/ReflectiveXmlRpcMetaDataHandler.java
Fri Mar 3 14:10:05 2006
@@ -0,0 +1,62 @@
+/*
+ * Copyright 1999,2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.xmlrpc.metadata;
+
+import java.lang.reflect.Method;
+
+import org.apache.xmlrpc.XmlRpcException;
+import org.apache.xmlrpc.server.AbstractReflectiveHandlerMapping;
+import org.apache.xmlrpc.server.ReflectiveXmlRpcHandler;
+
+
+/** Default implementation of [EMAIL PROTECTED] XmlRpcMetaDataHandler}.
+ */
+public class ReflectiveXmlRpcMetaDataHandler extends ReflectiveXmlRpcHandler
+ implements XmlRpcMetaDataHandler {
+ private final String[][] signatures;
+ private final String methodHelp;
+
+ /** Creates a new instance.
+ * @param pMapping The mapping, which creates this handler.
+ * @param pClass The class, which has been inspected to create
+ * this handler. Typically, this will be the same as
+ * <pre>pInstance.getClass()</pre>. It is used for diagnostic
+ * messages only.
+ * @param pInstance The instance, which will be invoked for
+ * executing the handler.
+ * @param pMethod The method, which will be invoked for
+ * executing the handler.
+ * @param pSignatures The signature, which will be returned by
+ * [EMAIL PROTECTED] #getSignatures()}.
+ * @param pMethodHelp The help string, which will be returned
+ * by [EMAIL PROTECTED] #getMethodHelp()}.
+ */
+ public ReflectiveXmlRpcMetaDataHandler(AbstractReflectiveHandlerMapping
pMapping,
+ Class pClass, Object pInstance, Method pMethod,
+ String[][] pSignatures, String pMethodHelp) {
+ super(pMapping, pClass, pInstance, pMethod);
+ signatures = pSignatures;
+ methodHelp = pMethodHelp;
+ }
+
+ public String[][] getSignatures() throws XmlRpcException {
+ return signatures;
+ }
+
+ public String getMethodHelp() throws XmlRpcException {
+ return methodHelp;
+ }
+}
Added:
webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/metadata/Util.java
URL:
http://svn.apache.org/viewcvs/webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/metadata/Util.java?rev=382944&view=auto
==============================================================================
---
webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/metadata/Util.java
(added)
+++
webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/metadata/Util.java
Fri Mar 3 14:10:05 2006
@@ -0,0 +1,141 @@
+/*
+ * Copyright 1999,2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.xmlrpc.metadata;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+import org.w3c.dom.Node;
+
+
+/** Utility class, which provides services to meta data
+ * handlers and handler mappings.
+ */
+public class Util {
+ /** This field should solve the problem, that we do not
+ * want to depend on the presence of JAXB. However, if
+ * it is available, we want to support it.
+ */
+ private static final Class jaxbElementClass;
+ static {
+ Class c;
+ try {
+ c = Class.forName("javax.xml.bind.Element");
+ } catch (ClassNotFoundException e) {
+ c = null;
+ }
+ jaxbElementClass = c;
+ }
+
+ /** Returns a signature for the given return type or
+ * parameter class.
+ * @param pType The class for which a signature is being
+ * queried.
+ * @return Signature, if known, or null.
+ */
+ public static String getSignatureType(Class type) {
+ if (type == Integer.TYPE || type == Integer.class)
+ return "int";
+ if (type == Double.TYPE || type == Double.class)
+ return "double";
+ if (type == Boolean.TYPE || type == Boolean.class)
+ return "boolean";
+ if (type == String.class)
+ return "string";
+ if (Object[].class.isAssignableFrom(type)
+ || List.class.isAssignableFrom(type))
+ return "array";
+ if (Map.class.isAssignableFrom(type))
+ return "struct";
+ if (Date.class.isAssignableFrom(type)
+ || Calendar.class.isAssignableFrom(type))
+ return "dateTime.iso8601";
+ if (type == byte[].class)
+ return "base64";
+
+ // extension types
+ if (type == void.class)
+ return "ex:nil";
+ if (type == Byte.TYPE || type == Byte.class)
+ return "ex:i1";
+ if (type == Short.TYPE || type == Short.class)
+ return "ex:i2";
+ if (type == Long.TYPE || type == Long.class)
+ return "ex:i8";
+ if (type == Float.TYPE || type == Float.class)
+ return "ex:float";
+ if (Node.class.isAssignableFrom(type))
+ return "ex:node";
+ if (jaxbElementClass != null
+ && jaxbElementClass.isAssignableFrom(type)) {
+ return "ex:jaxbElement";
+ }
+ if (Serializable.class.isAssignableFrom(type))
+ return "base64";
+
+ // give up
+ return null;
+ }
+
+ /** Returns a signature for the given method.
+ * @param pMethod Method, for which a signature is
+ * being queried.
+ * @return Signature string, or null, if no signature
+ * is available.
+ */
+ public static String[] getSignature(Method pMethod) {
+ Class[] paramClasses = pMethod.getParameterTypes();
+ String[] sig = new String[paramClasses.length + 1];
+ String s = getSignatureType(pMethod.getReturnType());
+ if (s == null) {
+ return null;
+ }
+ sig[0] = s;
+ for (int i = 0; i < paramClasses.length; i++) {
+ s = getSignatureType(paramClasses[i]);
+ if (s == null) {
+ return null;
+ }
+ sig[i+1] = s;
+ }
+ return sig;
+ }
+
+ /** Returns a help string for the given method, which
+ * is applied to the given class.
+ */
+ public static String getMethodHelp(Class pClass, Method pMethod) {
+ StringBuffer sb = new StringBuffer();
+ sb.append("Invokes the method ");
+ sb.append(pMethod.getReturnType().getClass().getName());
+ sb.append(".");
+ sb.append(pClass.getName());
+ sb.append("(");
+ Class[] paramClasses = pMethod.getParameterTypes();
+ for (int i = 0; i < paramClasses.length; i++) {
+ if (i > 0) {
+ sb.append(", ");
+ }
+ sb.append(paramClasses[i].getName());
+ }
+ sb.append(").");
+ return sb.toString();
+ }
+}
Added:
webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/metadata/XmlRpcSystemImpl.java
URL:
http://svn.apache.org/viewcvs/webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/metadata/XmlRpcSystemImpl.java?rev=382944&view=auto
==============================================================================
---
webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/metadata/XmlRpcSystemImpl.java
(added)
+++
webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/metadata/XmlRpcSystemImpl.java
Fri Mar 3 14:10:05 2006
@@ -0,0 +1,56 @@
+/*
+ * Copyright 1999,2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.xmlrpc.metadata;
+
+import org.apache.xmlrpc.XmlRpcException;
+
+
+/** This class implements the various "system" calls,
+ * as specifies by [EMAIL PROTECTED] XmlRpcListableHandlerMapping}.
+ * Suggested use is to create an instance and add it to
+ * the handler mapping with the "system" prefix.
+ */
+public class XmlRpcSystemImpl {
+ private XmlRpcListableHandlerMapping mapping;
+
+ /** Creates a new instance, which provides meta data
+ * for the given handler mappings methods.
+ */
+ public XmlRpcSystemImpl(XmlRpcListableHandlerMapping pMapping) {
+ mapping = pMapping;
+ }
+
+ /** Implements the "system.methodSignature" call.
+ * @see XmlRpcListableHandlerMapping#getMethodSignature(String)
+ */
+ public String[][] methodSignature(String methodName) throws
XmlRpcException {
+ return mapping.getMethodSignature(methodName);
+ }
+
+ /** Implements the "system.methodHelp" call.
+ * @see XmlRpcListableHandlerMapping#getMethodHelp(String)
+ */
+ public String methodHelp(String methodName) throws XmlRpcException {
+ return mapping.getMethodHelp(methodName);
+ }
+
+ /** Implements the "system.listMethods" call.
+ * @see XmlRpcListableHandlerMapping#getListMethods()
+ */
+ public String[] listMethods() throws XmlRpcException {
+ return mapping.getListMethods();
+ }
+}
Modified:
webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/server/AbstractReflectiveHandlerMapping.java
URL:
http://svn.apache.org/viewcvs/webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/server/AbstractReflectiveHandlerMapping.java?rev=382944&r1=382943&r2=382944&view=diff
==============================================================================
---
webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/server/AbstractReflectiveHandlerMapping.java
(original)
+++
webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/server/AbstractReflectiveHandlerMapping.java
Fri Mar 3 14:10:05 2006
@@ -1,22 +1,43 @@
+/*
+ * Copyright 1999,2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.apache.xmlrpc.server;
-import org.apache.xmlrpc.XmlRpcRequest;
-import org.apache.xmlrpc.XmlRpcException;
-import org.apache.xmlrpc.XmlRpcHandler;
-import org.apache.xmlrpc.common.XmlRpcNotAuthorizedException;
-
-import java.util.Map;
-import java.util.HashMap;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
-import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.xmlrpc.XmlRpcException;
+import org.apache.xmlrpc.XmlRpcHandler;
+import org.apache.xmlrpc.XmlRpcRequest;
+import org.apache.xmlrpc.metadata.ReflectiveXmlRpcMetaDataHandler;
+import org.apache.xmlrpc.metadata.Util;
+import org.apache.xmlrpc.metadata.XmlRpcListableHandlerMapping;
+import org.apache.xmlrpc.metadata.XmlRpcMetaDataHandler;
/** Abstract base class of handler mappings, which are
* using reflection.
*/
-public abstract class AbstractReflectiveHandlerMapping implements
XmlRpcHandlerMapping {
- /** An object implementing this interface may be used
+public abstract class AbstractReflectiveHandlerMapping
+ implements XmlRpcListableHandlerMapping {
+ /** An object implementing this interface may be used
* to validate user names and passwords.
*/
public interface AuthenticationHandler {
@@ -106,35 +127,26 @@
if (pInstance == null) {
throw new NullPointerException("The object instance must not be
null.");
}
- return new XmlRpcHandler(){
- public Object execute(XmlRpcRequest pRequest) throws
XmlRpcException {
- AuthenticationHandler authHandler = getAuthenticationHandler();
- if (authHandler != null &&
!authHandler.isAuthorized(pRequest)) {
- throw new XmlRpcNotAuthorizedException("Not authorized");
- }
- Object[] args = new Object[pRequest.getParameterCount()];
- for (int j = 0; j < args.length; j++) {
- args[j] = pRequest.getParameter(j);
- }
- try {
- return pMethod.invoke(pInstance, args);
- } catch (IllegalAccessException e) {
- throw new XmlRpcException("Illegal access to method "
- + pMethod.getName() + " in class
"
- + pClass.getName(), e);
- } catch (IllegalArgumentException e) {
- throw new XmlRpcException("Illegal argument for method "
- + pMethod.getName() + " in class
"
- + pClass.getName(), e);
- } catch (InvocationTargetException e) {
- Throwable t = e.getTargetException();
- throw new XmlRpcException("Failed to invoke method "
- + pMethod.getName() + " in class
"
- + pClass.getName() + ": "
- + t.getMessage(), t);
- }
- }
- };
+ String[] sig = getSignature(pMethod);
+ String help = getMethodHelp(pClass, pMethod);
+ if (sig == null || help == null) {
+ return new ReflectiveXmlRpcHandler(this, pClass, pInstance,
pMethod);
+ }
+ return new ReflectiveXmlRpcMetaDataHandler(this, pClass, pInstance,
+ pMethod, new String[][]{sig}, help);
+ }
+
+ /** Creates a signature for the given method.
+ */
+ protected String[] getSignature(Method pMethod) {
+ return Util.getSignature(pMethod);
+ }
+
+ /** Creates a help string for the given method, when applied
+ * to the given class.
+ */
+ protected String getMethodHelp(Class pClass, Method pMethod) {
+ return Util.getMethodHelp(pClass, pMethod);
}
/** Returns the [EMAIL PROTECTED] XmlRpcHandler} with the given name.
@@ -150,4 +162,33 @@
}
return result;
}
+
+ public String[] getListMethods() throws XmlRpcException {
+ List list = new ArrayList();
+ for (Iterator iter = handlerMap.entrySet().iterator();
+ iter.hasNext(); ) {
+ Map.Entry entry = (Map.Entry) iter.next();
+ if (entry.getValue() instanceof XmlRpcMetaDataHandler) {
+ list.add(entry.getKey());
+ }
+ }
+
+ return (String[]) list.toArray(new String[list.size()]);
+ }
+
+ public String getMethodHelp(String pHandlerName) throws XmlRpcException
{
+ XmlRpcHandler h = getHandler(pHandlerName);
+ if (h instanceof XmlRpcMetaDataHandler)
+ return ((XmlRpcMetaDataHandler)h).getMethodHelp();
+ throw new XmlRpcNoSuchHandlerException("No help available for
method: "
+ + pHandlerName);
+ }
+
+ public String[][] getMethodSignature(String pHandlerName) throws
XmlRpcException {
+ XmlRpcHandler h = getHandler(pHandlerName);
+ if (h instanceof XmlRpcMetaDataHandler)
+ return ((XmlRpcMetaDataHandler)h).getSignatures();
+ throw new XmlRpcNoSuchHandlerException("No metadata available
for method: "
+ + pHandlerName);
+ }
}
Added:
webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/server/ReflectiveXmlRpcHandler.java
URL:
http://svn.apache.org/viewcvs/webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/server/ReflectiveXmlRpcHandler.java?rev=382944&view=auto
==============================================================================
---
webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/server/ReflectiveXmlRpcHandler.java
(added)
+++
webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/server/ReflectiveXmlRpcHandler.java
Fri Mar 3 14:10:05 2006
@@ -0,0 +1,82 @@
+/*
+ * Copyright 1999,2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.xmlrpc.server;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.apache.xmlrpc.XmlRpcException;
+import org.apache.xmlrpc.XmlRpcHandler;
+import org.apache.xmlrpc.XmlRpcRequest;
+import org.apache.xmlrpc.common.XmlRpcNotAuthorizedException;
+import
org.apache.xmlrpc.server.AbstractReflectiveHandlerMapping.AuthenticationHandler;
+
+
+/** Default implementation of [EMAIL PROTECTED] XmlRpcHandler}.
+ */
+public class ReflectiveXmlRpcHandler implements XmlRpcHandler {
+ private final AbstractReflectiveHandlerMapping mapping;
+ private final Class clazz;
+ private final Object instance;
+ private final Method method;
+
+ /** Creates a new instance.
+ * @param pMapping The mapping, which creates this handler.
+ * @param pClass The class, which has been inspected to create
+ * this handler. Typically, this will be the same as
+ * <pre>pInstance.getClass()</pre>. It is used for diagnostic
+ * messages only.
+ * @param pInstance The instance, which will be invoked for
+ * executing the handler.
+ * @param pMethod The method, which will be invoked for
+ * executing the handler.
+ */
+ public ReflectiveXmlRpcHandler(AbstractReflectiveHandlerMapping
pMapping,
+ Class pClass, Object pInstance, Method pMethod)
{
+ mapping = pMapping;
+ clazz = pClass;
+ instance = pInstance;
+ method = pMethod;
+ }
+
+ public Object execute(XmlRpcRequest pRequest) throws XmlRpcException {
+ AuthenticationHandler authHandler =
mapping.getAuthenticationHandler();
+ if (authHandler != null && !authHandler.isAuthorized(pRequest)) {
+ throw new XmlRpcNotAuthorizedException("Not authorized");
+ }
+ Object[] args = new Object[pRequest.getParameterCount()];
+ for (int j = 0; j < args.length; j++) {
+ args[j] = pRequest.getParameter(j);
+ }
+ try {
+ return method.invoke(instance, args);
+ } catch (IllegalAccessException e) {
+ throw new XmlRpcException("Illegal access to method "
+ + method.getName() + " in class "
+ + clazz.getName(), e);
+ } catch (IllegalArgumentException e) {
+ throw new XmlRpcException("Illegal argument for method "
+ + method.getName() + " in class "
+ + clazz.getName(), e);
+ } catch (InvocationTargetException e) {
+ Throwable t = e.getTargetException();
+ throw new XmlRpcException("Failed to invoke method "
+ + method.getName() + " in class "
+ + clazz.getName() + ": "
+ + t.getMessage(), t);
+ }
+ }
+}
\ No newline at end of file