IntrospectionProvider.java

  1. /**
  2.  *
  3.  * Copyright © 2014-2015 Florian Schmaus
  4.  *
  5.  * Licensed under the Apache License, Version 2.0 (the "License");
  6.  * you may not use this file except in compliance with the License.
  7.  * You may obtain a copy of the License at
  8.  *
  9.  *     http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.jivesoftware.smack.provider;

  18. import java.io.IOException;
  19. import java.lang.reflect.InvocationTargetException;

  20. import org.jivesoftware.smack.SmackException;
  21. import org.jivesoftware.smack.packet.IQ;
  22. import org.jivesoftware.smack.packet.ExtensionElement;
  23. import org.jivesoftware.smack.util.ParserUtils;
  24. import org.xmlpull.v1.XmlPullParser;
  25. import org.xmlpull.v1.XmlPullParserException;

  26. public class IntrospectionProvider{

  27.     // Unfortunately, we have to create two introspection providers, with the exactly the same code here

  28.     public static abstract class IQIntrospectionProvider<I extends IQ> extends IQProvider<I> {
  29.         private final Class<I> elementClass;

  30.         protected IQIntrospectionProvider(Class<I> elementClass) {
  31.             this.elementClass = elementClass;
  32.         }

  33.         @SuppressWarnings("unchecked")
  34.         @Override
  35.         public I parse(XmlPullParser parser, int initialDepth) throws XmlPullParserException, IOException,
  36.                         SmackException {
  37.             try {
  38.                 return (I) parseWithIntrospection(elementClass, parser, initialDepth);
  39.             }
  40.             catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException
  41.                             | IllegalArgumentException | InvocationTargetException | ClassNotFoundException e) {
  42.                 throw new SmackException(e);
  43.             }
  44.         }
  45.     }

  46.     public static abstract class PacketExtensionIntrospectionProvider<PE extends ExtensionElement> extends ExtensionElementProvider<PE> {
  47.         private final Class<PE> elementClass;

  48.         protected PacketExtensionIntrospectionProvider(Class<PE> elementClass) {
  49.             this.elementClass = elementClass;
  50.         }

  51.         @SuppressWarnings("unchecked")
  52.         @Override
  53.         public PE parse(XmlPullParser parser, int initialDepth) throws XmlPullParserException, IOException,
  54.                         SmackException {
  55.             try {
  56.                 return (PE) parseWithIntrospection(elementClass, parser, initialDepth);
  57.             }
  58.             catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException
  59.                             | IllegalArgumentException | InvocationTargetException | ClassNotFoundException e) {
  60.                 throw new SmackException(e);
  61.             }
  62.         }
  63.     }

  64.     public static Object parseWithIntrospection(Class<?> objectClass,
  65.                     XmlPullParser parser, final int initialDepth) throws NoSuchMethodException, SecurityException,
  66.                     InstantiationException, IllegalAccessException, XmlPullParserException,
  67.                     IOException, IllegalArgumentException, InvocationTargetException,
  68.                     ClassNotFoundException {
  69.         ParserUtils.assertAtStartTag(parser);
  70.         Object object = objectClass.newInstance();
  71.         outerloop: while (true) {
  72.             int eventType = parser.next();
  73.             switch (eventType) {
  74.             case XmlPullParser.START_TAG:
  75.                 String name = parser.getName();
  76.                 String stringValue = parser.nextText();
  77.                 Class<?> propertyType = object.getClass().getMethod(
  78.                                 "get" + Character.toUpperCase(name.charAt(0)) + name.substring(1)).getReturnType();
  79.                 // Get the value of the property by converting it from a
  80.                 // String to the correct object type.
  81.                 Object value = decode(propertyType, stringValue);
  82.                 // Set the value of the bean.
  83.                 object.getClass().getMethod(
  84.                                 "set" + Character.toUpperCase(name.charAt(0)) + name.substring(1),
  85.                                 propertyType).invoke(object, value);
  86.                 break;

  87.             case  XmlPullParser.END_TAG:
  88.                 if (parser.getDepth() == initialDepth) {
  89.                     break outerloop;
  90.                 }
  91.                 break;
  92.             }
  93.         }
  94.         ParserUtils.assertAtEndTag(parser);
  95.         return object;
  96.     }

  97.     /**
  98.      * Decodes a String into an object of the specified type. If the object
  99.      * type is not supported, null will be returned.
  100.      *
  101.      * @param type the type of the property.
  102.      * @param value the encode String value to decode.
  103.      * @return the String value decoded into the specified type.
  104.      * @throws ClassNotFoundException
  105.      */
  106.     private static Object decode(Class<?> type, String value) throws ClassNotFoundException {
  107.         String name = type.getName();
  108.         switch (name) {
  109.         case "java.lang.String":
  110.             return value;
  111.         case "boolean":
  112.             return Boolean.valueOf(value);
  113.         case "int":
  114.             return Integer.valueOf(value);
  115.         case "long":
  116.             return Long.valueOf(value);
  117.         case "float":
  118.             return Float.valueOf(value);
  119.         case "double":
  120.             return Double.valueOf(value);
  121.         case "short":
  122.             return Short.valueOf(value);
  123.         case "byte":
  124.             return Byte.valueOf(value);
  125.         case "java.lang.Class":
  126.             return Class.forName(value);
  127.         }
  128.         return null;
  129.     }
  130. }