jp.rikinet.util.dto.DtoFactory.java Source code

Java tutorial

Introduction

Here is the source code for jp.rikinet.util.dto.DtoFactory.java

Source

/*
The MIT License (MIT)
    
Copyright (c) 2015 Riki Network Systems Inc.
    
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
    
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
    
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
package jp.rikinet.util.dto;

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

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;

/**
 * Root ?? Root ?? DTO ? JSON ??
 */
public class DtoFactory {

    /**
     * ?????JSON???
     * ?????????????
     */
    static final String KEY_CLASS = "_class_";

    /**
     * ?????
     * ???????????????
     *
     * @see DtoFactory#register(Class)
     */
    private static HashMap<String, Class<? extends Root>> classTable;

    static {
        classTable = new HashMap<>();
    }

    private DtoFactory() {
        // singleton
    }

    /**
     * ??????? DTO ??
     * @param cl classTable ???? DTO 
     * @param jo DTO ??????? JSONObject
     * @param <T> DTO ?
     * @return ??? DTO
     */
    private static <T extends Root> T newSimpleDto(Class<T> cl, JSONObject jo) {
        T dto;
        try {
            Constructor<T> cons = cl.getConstructor(JSONObject.class);
            dto = cons.newInstance(jo);
        } catch (NoSuchMethodException e) {
            throw new IllegalArgumentException("constructor not found", e);
        } catch (InvocationTargetException | InstantiationException | IllegalAccessException e) {
            throw new IllegalArgumentException("constructor call failed", e);
        }
        return dto;
    }

    /**
     * ?? DTO ??
     * @param dto ??? DTO
     * @param name ??birthDate ? setter ? setBirthDate()
     * @param value ?
     */
    private static void setProperty(Root dto, String name, Object value) {
        Class<?> cl = dto.getClass();
        String mName = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
        try {
            Method m = cl.getMethod(mName, value.getClass());
            m.invoke(dto, value);
        } catch (NoSuchMethodException e) {
            throw new IllegalArgumentException("setter not found", e);
        } catch (InvocationTargetException | IllegalAccessException e) {
            throw new IllegalArgumentException("setter call failed", e);
        }
    }

    /**
     * JSONArray  DtoArray ???
     * array  object ?????????????
     * @param ja ???? JSONArray
     * @return ??? DtoArray
     */
    @SuppressWarnings("unchecked")
    private static <E> DtoArray<E> convert(JSONArray ja) {
        DtoArray da = new DtoArray<E>(ja.length());
        // ?????????????
        for (int i = 0; i < ja.length(); i++) {
            Object obj = ja.get(i);
            if (obj instanceof JSONArray) {
                DtoArray subArr = convert((JSONArray) obj);
                da.put(i, subArr);
            } else if (obj instanceof JSONObject) {
                Root dto = convert((JSONObject) obj);
                da.put(i, dto);
            } else {
                da.put(i, obj);
            }
        }
        return da;
    }

    /**
     * ?? JSDONObject ? DTO ??
     * ?????DTO ??? setter ????
     * ????????
     * @param jo ????? DTO ??
     * @param <T> ?? DTO ?
     * @return ??? DTO
     */
    private static <T extends Root> T convert(JSONObject jo) {
        String typeName = jo.getString(KEY_CLASS);
        if (typeName == null) {
            // ????
            throw new IllegalArgumentException("Type key _class_ undefined.");
        }

        Class<?> cl = classTable.get(typeName);
        if (cl == null) {
            // ??????
            throw new IllegalArgumentException("Type " + classTable.get(typeName) + "not registered.");
        }
        T newDto = newSimpleDto((Class<T>) cl, jo);

        // ??????????
        Iterator<String> iter = jo.keys();
        while (iter.hasNext()) {
            String key = iter.next();
            Object val = jo.get(key);
            if (val instanceof JSONArray) {
                // construct array
                DtoArray da = convert((JSONArray) val);
                // set as property value
                setProperty(newDto, key, da);
            } else if (val instanceof JSONObject) {
                // construct sub object
                Root subObj = convert((JSONObject) val);
                // set as property value
                setProperty(newDto, key, subObj);
            }
        }
        return newDto;
    }

    /**
     * JSON ??????? DTO ??
     * @param str JSON ??? _class_ ????
     * @param <T> ?? DTO ?
     * @return T ? DTO
     */
    public static <T extends Root> T deserialize(String str) {
        JSONObject jObj = new JSONObject(str);
        return convert(jObj);
    }

    /**
     * JSON ?????????
     * ?????
     * @param clazz Root ??
     */
    public static void register(Class<? extends Root> clazz) {
        if (!clazz.isAnnotationPresent(DtoType.class))
            return;
        DtoType dt = clazz.getAnnotation(DtoType.class);
        classTable.put(dt.value(), clazz);
    }
}