PropertiesUtils.java

package com.alibaba.fastjson2.util;

import com.alibaba.fastjson2.*;
import com.alibaba.fastjson2.reader.FieldReader;
import com.alibaba.fastjson2.reader.ObjectReader;
import com.alibaba.fastjson2.reader.ObjectReaderProvider;
import com.alibaba.fastjson2.writer.ObjectWriter;
import com.alibaba.fastjson2.writer.ObjectWriterAdapter;
import com.alibaba.fastjson2.writer.ObjectWriterProvider;

import java.lang.reflect.Array;
import java.util.*;

public class PropertiesUtils {
    public static <T> T toJavaObject(Properties properties, Class<T> clazz) {
        return toJavaObject(properties, JSONFactory.getDefaultObjectReaderProvider(), clazz);
    }

    public static <T> T toJavaObject(
            Properties properties,
            ObjectReaderProvider provider,
            Class<T> clazz,
            JSONReader.Feature... features
    ) {
        ObjectReader<T> reader = provider.getObjectReader(clazz);
        T instance = reader.createInstance(JSONReader.Feature.of(features));

        for (Map.Entry<Object, Object> entry : properties.entrySet()) {
            String key = (String) entry.getKey();
            String value = (String) entry.getValue();

            int dotIndex = key.lastIndexOf(".");
            if (dotIndex == -1) {
                FieldReader<T> fieldReader = reader.getFieldReader(key);
                if (fieldReader == null) {
                    continue;
                }
                Object fieldValue = TypeUtils.cast(value, fieldReader.fieldType);
                fieldReader.accept(instance, fieldValue);
            } else {
                JSONPath.set(instance, key, value);
            }
        }

        return instance;
    }

    public static Properties toProperties(Object object) {
        return toProperties(JSONFactory.getDefaultObjectWriterProvider(), object);
    }

    public static Properties toProperties(ObjectWriterProvider provider, Object object, JSONWriter.Feature... features) {
        Map<Object, String> values = new IdentityHashMap<>();
        Properties properties = new Properties();

        paths(provider, values, properties, null, object);
        return properties;
    }

    static void paths(ObjectWriterProvider provider, Map<Object, String> values, Map paths, String parent, Object javaObject) {
        if (javaObject == null) {
            return;
        }

        String p = values.put(javaObject, parent);
        if (p != null) {
            Class<?> type = javaObject.getClass();
            boolean basicType = type == String.class
                    || type == Boolean.class
                    || type == Character.class
                    || type == UUID.class
                    || javaObject instanceof Enum
                    || javaObject instanceof Number
                    || javaObject instanceof Date;

            if (!basicType) {
                return;
            }
        }

        if (javaObject instanceof Map) {
            Map map = (Map) javaObject;

            for (Object entryObj : map.entrySet()) {
                Map.Entry entry = (Map.Entry) entryObj;
                Object key = entry.getKey();

                String path;
                if (key instanceof String) {
                    String strKey = (String) key;
                    boolean escape = strKey.isEmpty();
                    if (!escape) {
                        char c0 = strKey.charAt(0);
                        escape = !((c0 >= 'a' && c0 <= 'z') || (c0 >= 'A' && c0 <= 'Z') || c0 == '_');
                        if (!escape) {
                            for (int i = 1; i < strKey.length(); i++) {
                                char ch = strKey.charAt(i);
                                escape = !((ch >= 'a' && ch <= 'z')
                                        || (ch >= 'A' && ch <= 'Z')
                                        || (ch >= '0' && ch <= '9')
                                        || ch == '_');
                                if (escape) {
                                    break;
                                }
                            }
                        }
                    }
                    if (escape) {
                        path = parent + '[' + JSON.toJSONString(strKey, JSONWriter.Feature.UseSingleQuotes) + ']';
                    } else {
                        path = parent != null ? (parent + "." + strKey) : strKey;
                    }
                    paths(provider, values, paths, path, entry.getValue());
                }
            }
            return;
        }

        if (javaObject instanceof Collection) {
            Collection collection = (Collection) javaObject;

            int i = 0;
            for (Object item : collection) {
                String path = parent + "[" + i + "]";
                paths(provider, values, paths, path, item);
                ++i;
            }

            return;
        }

        Class<?> clazz = javaObject.getClass();

        if (clazz.isArray()) {
            int len = Array.getLength(javaObject);

            for (int i = 0; i < len; ++i) {
                Object item = Array.get(javaObject, i);

                String path = parent + "[" + i + "]";
                paths(provider, values, paths, path, item);
            }

            return;
        }

        if (ObjectWriterProvider.isPrimitiveOrEnum(clazz)) {
            String propertyValue = javaObject == null ? "" : javaObject.toString();
            paths.put(parent, propertyValue);
            return;
        }

        ObjectWriter serializer = provider.getObjectWriter(clazz);
        if (serializer instanceof ObjectWriterAdapter) {
            ObjectWriterAdapter javaBeanSerializer = (ObjectWriterAdapter) serializer;

            try {
                Map<String, Object> fieldValues = javaBeanSerializer.toMap(javaObject);
                for (Map.Entry<String, Object> entry : fieldValues.entrySet()) {
                    String key = entry.getKey();

                    if (key != null) {
                        String path = parent != null ? (parent + "." + key) : key;
                        paths(provider, values, paths, path, entry.getValue());
                    }
                }
            } catch (Exception e) {
                throw new JSONException("toJSON error", e);
            }
        }
    }
}