at.alladin.rmbt.shared.hstoreparser.HstoreParser.java Source code

Java tutorial

Introduction

Here is the source code for at.alladin.rmbt.shared.hstoreparser.HstoreParser.java

Source

/*******************************************************************************
 * Copyright 2013-2015 alladin-IT GmbH
 * 
 * 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 at.alladin.rmbt.shared.hstoreparser;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.ParameterizedType;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import at.alladin.rmbt.shared.hstoreparser.annotation.HstoreCast;
import at.alladin.rmbt.shared.hstoreparser.annotation.HstoreCollection;
import at.alladin.rmbt.shared.hstoreparser.annotation.HstoreKey;

/**
 * 
 * @author lb
 *
 */
public class HstoreParser<T> {

    private Class<T> clazz;

    private HashMap<String, Field> fieldsWithKeys;

    private Constructor<T> constructor;

    private Hstore hstore;

    /**
     * 
     * @param clazz
     * @throws HstoreParseException 
     */
    public HstoreParser(Class<T> clazz, Hstore hstore) throws HstoreParseException {
        this.clazz = clazz;
        this.fieldsWithKeys = new HashMap<>();
        this.hstore = hstore;
        //search all fields of all classes for annotated items
        initFields(clazz);

        //find empty constructor
        try {
            constructor = clazz.getConstructor();
        } catch (NoSuchMethodException | SecurityException e) {
            throw new HstoreParseException(
                    HstoreParseException.HSTORE_CONSTRUCTOR_EXCEPTION + clazz.getCanonicalName(), e);
        }
    }

    /**
     * 
     * @param clazz
     * @throws HstoreParseException 
     */
    private void initFields(Class<?> clazz) throws HstoreParseException {
        if (clazz.getSuperclass() != null) {
            initFields(clazz.getSuperclass());
        }

        for (Field f : clazz.getDeclaredFields()) {
            if (f.isAnnotationPresent(HstoreKey.class)) {
                //annotation: HstoreKey was found
                String hstoreKey = ((HstoreKey) f.getAnnotation(HstoreKey.class)).value();
                //check for duplicates:
                if (!fieldsWithKeys.containsKey(hstoreKey)) {
                    fieldsWithKeys.put(hstoreKey, f);
                } else {
                    throw new HstoreParseException(
                            HstoreParseException.HSTORE_OBJECT_KEY_ALREADY_IN_USE + hstoreKey);
                }
            }

            if (f.isAnnotationPresent(HstoreCollection.class)) {
                //annotation: HstoreCollection was found
                Class<?> hstoreClazz = ((HstoreCollection) f.getAnnotation(HstoreCollection.class)).value();
                //insert class into hstore
                if (!hstore.getParserMap().containsKey(hstoreClazz)) {
                    hstore.addClass(hstoreClazz);
                }
            }
        }
    }

    /**
     * 
     * @param hstore
     * @return
     * @throws HstoreParseException
     * @throws JSONException
     */
    public T fromString(String hstore) throws HstoreParseException {
        try {
            return fromJson(new JSONObject("{" + hstore.replace("=>", ":") + "}"));
        } catch (JSONException e) {
            throw new HstoreParseException(HstoreParseException.HSTORE_FORMAT_UNSUPPORTED + hstore, e);
        }
    }

    /**
     * 
     * @param hstore
     * @return
     * @throws HstoreParseException 
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public T fromJson(JSONObject json) throws HstoreParseException {
        T object;
        try {
            object = constructor.newInstance();
        } catch (InstantiationException | IllegalAccessException | IllegalArgumentException
                | InvocationTargetException e) {
            throw new HstoreParseException(HstoreParseException.HSTORE_PARSE_EXCEPTION + e.getLocalizedMessage(),
                    e);
        }

        if (object == null) {
            throw new HstoreParseException(
                    HstoreParseException.HSTORE_COULD_NOT_INSTANTIATE + clazz.getCanonicalName());
        }

        //iterate through all json entries:
        Iterator<String> jsonKeys = json.keys();
        while (jsonKeys.hasNext()) {
            String key = jsonKeys.next();

            //if fieldsWithKeys contain a key (=it was annotated with @HstoreKey) then try to set the value of the field in T object
            if (fieldsWithKeys.containsKey(key)) {
                final Field field = fieldsWithKeys.get(key);
                try {
                    Object value = getFromJsonByField(json, key, field);
                    field.setAccessible(true);
                    //cast / new instance needed?
                    if (field.isAnnotationPresent(HstoreCollection.class)) {
                        Class<?> fieldClazz = field.getType();
                        //System.out.println("FieldClazz: " + fieldClazz + " -> " + fieldClazz.isAssignableFrom(Collection.class));
                        if (Collection.class.isAssignableFrom(fieldClazz)) {
                            //get collection and instantiate if necessary
                            Collection collection = (Collection) field.get(object);
                            if (collection == null) {
                                collection = (Collection) fieldClazz.newInstance();
                            }

                            ParameterizedType fieldType = (ParameterizedType) field.getGenericType();
                            Class<?> genericClazz = (Class<?>) fieldType.getActualTypeArguments()[0];
                            //System.out.println("genericClazz: " + genericClazz);

                            //Object jsonObject = hstore.toJson((String) value, genericClazz);
                            Object jsonObject = null;
                            //System.out.println(value);
                            if (!value.equals(JSONObject.NULL)) {
                                if (value instanceof JSONArray || value instanceof JSONObject) {
                                    jsonObject = hstore.toJson(value.toString(), genericClazz);
                                } else {
                                    jsonObject = hstore.toJson((String) value, genericClazz);
                                }
                            } else {
                                jsonObject = hstore.toJson(null, genericClazz);
                            }

                            if (jsonObject != null) {
                                if (jsonObject instanceof JSONArray) {
                                    //System.out.println(jsonObject);
                                    Object[] array = hstore.fromJSONArray((JSONArray) jsonObject, genericClazz);
                                    for (int i = 0; i < array.length; i++) {
                                        //System.out.println("Created element: " + array[i]);
                                        collection.add(array[i]);
                                    }
                                } else {
                                    Object element = hstore.fromString((String) value, genericClazz);
                                    //System.out.println("Created element: " + element);
                                    collection.add(element);
                                }
                            }

                            value = collection;
                        } else {
                            throw new HstoreParseException(HstoreParseException.HSTORE_MUST_BE_A_COLLECTION + field
                                    + " - " + clazz.getCanonicalName());
                        }
                    }

                    if (field.isAnnotationPresent(HstoreCast.class)) {
                        HstoreCast castDef = field.getAnnotation(HstoreCast.class);
                        if (castDef.simpleCast()) {
                            //simple cast
                            field.set(object, castDef.clazz().cast(value));
                        } else {
                            //new instance
                            field.set(object, castDef.clazz().getConstructor(castDef.constructorParamClazz())
                                    .newInstance(value));
                        }
                    } else {
                        if (JSONObject.NULL.equals(value)) {
                            field.set(object, null);
                        } else {
                            field.set(object, parseFieldValue(field, value));
                        }
                    }

                } catch (IllegalAccessException | IllegalArgumentException | JSONException e) {
                    throw new HstoreParseException(
                            HstoreParseException.HSTORE_COULD_NOT_INSTANTIATE + clazz.getCanonicalName(), e);
                } catch (InstantiationException e) {
                    throw new HstoreParseException(
                            HstoreParseException.HSTORE_COULD_NOT_INSTANTIATE + clazz.getCanonicalName(), e);
                } catch (InvocationTargetException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (NoSuchMethodException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (SecurityException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (ClassCastException e) {
                    System.out.println("field: " + field.toString() + ", key: " + key);
                    e.printStackTrace();
                }
            }
        }

        return object;
    }

    /**
     * 
     * @param hstoreKey
     * @param object
     * @return
     * @throws HstoreParseException
     */
    public <U> Object getValue(String hstoreKey, U object) throws HstoreParseException {
        Field field = fieldsWithKeys.get(hstoreKey);
        if (field != null) {
            try {
                field.setAccessible(true);
                return field.get(object);
            } catch (IllegalArgumentException | IllegalAccessException e) {
                throw new HstoreParseException(HstoreParseException.HSTORE_COULD_NOT_GET_VALUE
                        + clazz.getCanonicalName() + "." + field.getName() + "\n", e);
            }
        }

        return null;
    }

    /**
     * 
     * @return
     */
    public Set<Field> getAnnotatedFields() {
        return new HashSet<>(fieldsWithKeys.values());
    }

    /**
     * 
     * @return
     * @throws HstoreParseException 
     */
    public <U> Map<String, Object> getValueMap(U object) throws HstoreParseException {
        HashMap<String, Object> resultMap = new HashMap<>();
        for (Entry<String, Field> e : fieldsWithKeys.entrySet()) {
            try {
                e.getValue().setAccessible(true);
                resultMap.put(e.getKey(), e.getValue().get(object));
            } catch (Exception ex) {
                ex.printStackTrace();
                throw new HstoreParseException(HstoreParseException.HSTORE_COULD_NOT_GET_VALUE
                        + clazz.getCanonicalName() + "." + e.getValue().getName() + "\n", ex);
            }
        }

        return resultMap;
    }

    /**
     * parses a simple hstore String to a JSONObject
     * @param hstore
     * @return {@link JSONObject} or null if an error occured
     */
    public static JSONObject parseToJson(String hstore) {
        try {
            return new JSONObject("{" + hstore.replace("=>", ":") + "}");
        } catch (JSONException e) {
            return null;
        }
    }

    /**
     * 
     * @param f
     * @param o
     * @return
     */
    public static Object parseFieldValue(Field f, Object o) {
        if (o != JSONObject.NULL) {
            if (f.getType().equals(Integer.class) || f.getType().equals(Integer.TYPE)) {
                return Integer.parseInt(String.valueOf(o));
            } else if (f.getType().equals(String.class)) {
                return String.valueOf(o);
            } else if (f.getType().equals(Long.class) || f.getType().equals(Long.TYPE)) {
                return Long.parseLong(String.valueOf(o));
            } else if (f.getType().equals(Boolean.class) || f.getType().equals(Boolean.TYPE)) {
                return Boolean.parseBoolean(String.valueOf(o));
            } else if (f.getType().equals(Float.class) || f.getType().equals(Float.TYPE)) {
                return Float.parseFloat(String.valueOf(o));
            } else if (f.getType().equals(Double.class) || f.getType().equals(Double.TYPE)) {
                return Double.parseDouble(String.valueOf(o));
            } else if (f.getType().equals(Short.class) || f.getType().equals(Short.TYPE)) {
                return Short.parseShort(String.valueOf(o));
            } else {
                return o;
            }
        }

        return null;
    }

    /**
     * get a specific key from json by preserving the fields type
     * @param json
     * @param key
     * @param toField
     * @return
     * @throws JSONException 
     */
    public static Object getFromJsonByField(JSONObject json, String key, Field toField) throws JSONException {
        final Object o = json.get(key);
        if (o != JSONObject.NULL) {
            if (toField.getType().equals(Integer.class) || toField.getType().equals(Integer.TYPE)) {
                return Integer.parseInt(String.valueOf(o));
            } else if (toField.getType().equals(String.class)) {
                return o;
            } else if (toField.getType().equals(Long.class) || toField.getType().equals(Long.TYPE)) {
                return Long.parseLong(String.valueOf(o));
            } else if (toField.getType().equals(Boolean.class) || toField.getType().equals(Boolean.TYPE)) {
                return Boolean.parseBoolean(String.valueOf(o));
            } else if (toField.getType().equals(Float.class) || toField.getType().equals(Float.TYPE)) {
                return Float.parseFloat(String.valueOf(o));
            } else if (toField.getType().equals(Double.class) || toField.getType().equals(Double.TYPE)) {
                return Double.parseDouble(String.valueOf(o));
            } else {
                return o;
            }
        }

        return JSONObject.NULL;
    }

    /**
     * 
     * @param json
     * @param key
     * @param toField
     * @return
     * @throws JSONException
     */
    public static Object getFromJsonByField2(JSONObject json, String key, Field toField) throws JSONException {
        final Object o = json.get(key);
        final Class<?> fieldType = toField.getType();
        if (o != JSONObject.NULL) {
            if (fieldType.equals(Integer.class) || fieldType.equals(Integer.TYPE)) {
                return json.getInt(key);
            } else if (fieldType.equals(String.class)) {
                return o;
            } else if (fieldType.equals(Long.class) || fieldType.equals(Long.TYPE)) {
                return json.getLong(key);
            } else if (fieldType.equals(Boolean.class) || fieldType.equals(Boolean.TYPE)) {
                return json.getBoolean(key);
            } else if (fieldType.equals(Float.class) || fieldType.equals(Float.TYPE)) {
                return (float) json.getDouble(key);
            } else if (fieldType.equals(Double.class) || fieldType.equals(Double.TYPE)) {
                return json.getDouble(key);
            } else {
                return o;
            }
        }

        return JSONObject.NULL;
    }
}