/** * * Copyright © 2014-2015 Florian Schmaus * * 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.jivesoftware.smack.provider; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.packet.ExtensionElement; import org.jivesoftware.smack.packet.IQ; import org.jivesoftware.smack.util.ParserUtils; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; public class IntrospectionProvider{ // Unfortunately, we have to create two introspection providers, with the exactly the same code here public static abstract class IQIntrospectionProvider extends IQProvider { private final Class elementClass; protected IQIntrospectionProvider(Class elementClass) { this.elementClass = elementClass; } @SuppressWarnings("unchecked") @Override public I parse(XmlPullParser parser, int initialDepth) throws XmlPullParserException, IOException, SmackException { try { return (I) parseWithIntrospection(elementClass, parser, initialDepth); } catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | ClassNotFoundException e) { throw new SmackException(e); } } } public static abstract class PacketExtensionIntrospectionProvider extends ExtensionElementProvider { private final Class elementClass; protected PacketExtensionIntrospectionProvider(Class elementClass) { this.elementClass = elementClass; } @SuppressWarnings("unchecked") @Override public PE parse(XmlPullParser parser, int initialDepth) throws XmlPullParserException, IOException, SmackException { try { return (PE) parseWithIntrospection(elementClass, parser, initialDepth); } catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | ClassNotFoundException e) { throw new SmackException(e); } } } public static Object parseWithIntrospection(Class objectClass, XmlPullParser parser, final int initialDepth) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, XmlPullParserException, IOException, IllegalArgumentException, InvocationTargetException, ClassNotFoundException { ParserUtils.assertAtStartTag(parser); Object object = objectClass.getConstructor().newInstance(); outerloop: while (true) { int eventType = parser.next(); switch (eventType) { case XmlPullParser.START_TAG: String name = parser.getName(); String stringValue = parser.nextText(); Class propertyType = object.getClass().getMethod( "get" + Character.toUpperCase(name.charAt(0)) + name.substring(1)).getReturnType(); // Get the value of the property by converting it from a // String to the correct object type. Object value = decode(propertyType, stringValue); // Set the value of the bean. object.getClass().getMethod( "set" + Character.toUpperCase(name.charAt(0)) + name.substring(1), propertyType).invoke(object, value); break; case XmlPullParser.END_TAG: if (parser.getDepth() == initialDepth) { break outerloop; } break; } } ParserUtils.assertAtEndTag(parser); return object; } /** * Decodes a String into an object of the specified type. If the object * type is not supported, null will be returned. * * @param type the type of the property. * @param value the encode String value to decode. * @return the String value decoded into the specified type. * @throws ClassNotFoundException */ private static Object decode(Class type, String value) throws ClassNotFoundException { String name = type.getName(); switch (name) { case "java.lang.String": return value; case "boolean": return Boolean.valueOf(value); case "int": return Integer.valueOf(value); case "long": return Long.valueOf(value); case "float": return Float.valueOf(value); case "double": return Double.valueOf(value); case "short": return Short.valueOf(value); case "byte": return Byte.valueOf(value); case "java.lang.Class": return Class.forName(value); } return null; } }