All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.theagilemonkeys.meets.magento.utils.soap.SoapParser Maven / Gradle / Ivy

Go to download

A native SDK connector designed to ease communication between java environments and Magento stores

The newest version!
package com.theagilemonkeys.meets.magento.utils.soap;

import org.ksoap2.serialization.PropertyInfo;
import org.ksoap2.serialization.SoapObject;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;

import static com.theagilemonkeys.meets.utils.Reflections.getAllFields;

/**
 * Android Meets SDK
 * Original work Copyright (c) 2014 [TheAgileMonkeys]
 *
 * @author Álvaro López Espinosa
 */
public class SoapParser {
    /**
     * A list with all classes known to be immutables. They will be assigned directly from SoapObject
     * to target object
     */
    private static final List immutables = Arrays.asList(
            String.class, Byte.class, Short.class, Integer.class, Long.class,
            Float.class, Double.class, Boolean.class, BigInteger.class, BigDecimal.class
    );

    /**
     * Parse a SoapObject into any object.
     * @param in The SoapObject
     * @param out The target object. This will be used as a "template" to correctly parse the SoapObject, so field names
     *            must match and types must be compatible. All types are supported but native array. Any subclass of Collection
     *            can be used in that case (ArrayList, for example). If that subclass is an interface or an abstract class, an
     *            annotation must be used to specify the concrete collection type. Only List and AbstractList classes are supported
     *            without annotation (ArrayList is used in both cases)
     * @throws IllegalAccessException
     * @throws InstantiationException
     */
    public static void parse(SoapObject in, Object out) throws IllegalAccessException, InstantiationException {
        if ( isCollection(out.getClass())) {
            parseCollection(in, (Collection) out);
        }
        else if (isMap(out.getClass())) {
            parseMap(in, (Map) out);
        }
        else {
            parseObject(in, out);
        }
    }

    private static Object getPrimitiveValue(Class valueClass, Object value) {
        // With this avoid some types mismatches. Maybe there is a better and shorter way to do this...
        if ( valueClass == Float.class || valueClass == float.class ){
            return Float.parseFloat(value.toString());
        }
        else if ( valueClass == Double.class || valueClass == double.class ){
            return Double.parseDouble(value.toString());
        }
        else if ( valueClass == Integer.class || valueClass == int.class ) {
            return Integer.parseInt(value.toString());
        }
        return value;
    }

    private static void parseCollection(SoapObject in, Collection outCollection) throws IllegalAccessException, InstantiationException {
        // Get the type of the elements in the collection
        ParameterizedType fieldParametrizedType = (ParameterizedType) outCollection.getClass().getGenericSuperclass();
        Class componentType = (Class) fieldParametrizedType.getActualTypeArguments()[0];

        int n = in.getPropertyCount();

        for (int i = 0; i < n; ++i){
            Object soapElem = in.getProperty(i);
            Object elem;
            if ( canBeAssignedDirectly(soapElem.getClass()) ) {
                elem = soapElem;
            }
            else {
                elem = componentType.newInstance();
                parse((SoapObject) soapElem, elem);
            }
            outCollection.add(elem);
        }
    }

    private static void parseMap(SoapObject in, Map outMap) throws IllegalAccessException, InstantiationException {
        // Get the type of the elements in the collection
        ParameterizedType fieldParametrizedType = (ParameterizedType) outMap.getClass().getGenericSuperclass();
        Class valType = (Class) fieldParametrizedType.getActualTypeArguments()[1];

        int n = in.getPropertyCount();

        for (int i = 0; i < n; ++i){
            PropertyInfo propInfo = new PropertyInfo();
            in.getPropertyInfo(i, propInfo);

            Object soapElem = in.getProperty(i);
            String key = propInfo.getName();
            Object elem;

            if ( soapElem == null || canBeAssignedDirectly(soapElem.getClass()) ) {
                elem = soapElem;
            }
            else {
                elem = valType.newInstance();
                parse((SoapObject) soapElem, elem);
            }

            outMap.put(key, elem);
        }
    }

    private static void parseObject(SoapObject in, Object out) throws IllegalAccessException, InstantiationException {

        for(Field field : getAllFields(out.getClass())){
            field.setAccessible(true);
            String fieldName = field.getName();

            // Ignore fields that doesn't exist in SoapObject
            if ( ! in.hasProperty(fieldName) ) continue;

            Object valueToParse = in.getProperty(fieldName);
            Class fieldClass = field.getType();

            try {
                // If the type of field is Object, primitive or immutable, assign it directly
                if (canBeAssignedDirectly(fieldClass)) {
                    field.set(out, getPrimitiveValue(fieldClass, valueToParse));
                } else if (isCollection(fieldClass)) {
                    fieldClass = getSpecificCollectionClass(field);
                    Collection c = (Collection) fieldClass.newInstance();
                    parse((SoapObject) valueToParse, c);
                    field.set(out, c);
                } else if (isMap(fieldClass)) {
                    fieldClass = getSpecificMapClass(field);
                    Map map = (Map) fieldClass.newInstance();
                    parse((SoapObject) valueToParse, map);
                    field.set(out, map);
                } else {
                    Object fieldObject = fieldClass.newInstance();
                    parse((SoapObject) valueToParse, fieldObject);
                    field.set(out, fieldObject);
                }
            }
            catch (ClassCastException | IllegalArgumentException ignored) {}
        }
    }

    private static Class getSpecificCollectionClass(Field field) {
        Class fieldType = field.getType();
        int modifiers = fieldType.getModifiers();

        // Only in these cases an specific class is needed
        if ( Modifier.isAbstract(modifiers) || Modifier.isInterface(modifiers) ){
            SoapAnnotations.ListInfo listTypeAnnotation = field.getAnnotation(SoapAnnotations.ListInfo.class);

            if ( listTypeAnnotation != null )
                fieldType = listTypeAnnotation.value();
             else
                fieldType = ArrayList.class;
        }
        return fieldType;
    }

    private static Class getSpecificMapClass(Field field) {
        Class fieldType = field.getType();
        int modifiers = fieldType.getModifiers();

        // Only in these cases an specific class is needed
        if ( Modifier.isAbstract(modifiers) || Modifier.isInterface(modifiers) ){
            SoapAnnotations.MapType mapTypeAnnotation = field.getAnnotation(SoapAnnotations.MapType.class);

            if ( mapTypeAnnotation != null )
                fieldType = mapTypeAnnotation.value();
             else
                fieldType = HashMap.class;
        }
        return fieldType;
    }

    private static boolean canBeAssignedDirectly(Class c){
        return isPrimitiveOrInmutable(c) || c == Object.class;
    }

    private static boolean isCollection(Class klass){
        return Collection.class.isAssignableFrom(klass);
    }

    private static boolean isMap(Class klass){
        return Map.class.isAssignableFrom(klass);
    }

    // Public useful methods

    /**
     * Returns true if the class passed is primitive or immutable (the Java known immutables: Integer, Long, String, etc.)
     * @param c The class to check
     * @return
     */
    public static boolean isPrimitiveOrInmutable(Class c){
        return c.isPrimitive() || immutables.contains(c);
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy