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

com.ait.tooling.json.JSONUtils Maven / Gradle / Ivy

/*
 * Copyright (c) 2014,2015 Ahome' Innovation Technologies. All rights reserved.
 *
 * 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 com.ait.tooling.json;

import java.io.IOException;
import java.io.Writer;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;

import com.ait.tooling.common.server.io.NoSyncStringBuilderWriter;

public final class JSONUtils
{
    private static final String     NULL_FOR_OUTPUT = "null".intern();

    private final static BigDecimal BIG_DECIMAL_MAX = BigDecimal.valueOf(Double.MAX_VALUE);

    private final static BigDecimal BIG_DECIMAL_MIN = BigDecimal.valueOf(Double.MIN_VALUE);

    private final static BigInteger BIG_INTEGER_MAX = BigInteger.valueOf(Integer.MAX_VALUE);

    private final static BigInteger BIG_INTEGER_MIN = BigInteger.valueOf(Integer.MIN_VALUE);

    private final static BigInteger BIG_INTLONG_MAX = BigInteger.valueOf(Long.MAX_VALUE);

    private final static BigInteger BIG_INTLONG_MIN = BigInteger.valueOf(Long.MIN_VALUE);

    private final static BigDecimal BIG_DEC_INT_MAX = BigDecimal.valueOf(Integer.MAX_VALUE);

    private final static BigDecimal BIG_DEC_INT_MIN = BigDecimal.valueOf(Integer.MIN_VALUE);

    private final static BigDecimal BIG_DEC_LONGMAX = BigDecimal.valueOf(Long.MAX_VALUE);

    private final static BigDecimal BIG_DEC_LONGMIN = BigDecimal.valueOf(Long.MIN_VALUE);

    private final static BigInteger BIG_INT_DEC_MAX = BIG_DECIMAL_MAX.toBigInteger();

    private final static BigInteger BIG_INT_DEC_MIN = BIG_DECIMAL_MIN.toBigInteger();

    private JSONUtils()
    {
    }

    public static final String toJSONString(final Object value, final boolean strict)
    {
        return toJSONString(value, null, strict);
    }

    public static final String toJSONString(final Object value, final IJSONContext context, final boolean strict)
    {
        if (null == value)
        {
            return NULL_FOR_OUTPUT;
        }
        final NoSyncStringBuilderWriter out = new NoSyncStringBuilderWriter();

        try
        {
            writeJSONString(value, out, context, strict);
        }
        catch (IOException e)
        {
            // We should never get an IOException on a JSONStringWriter!!! ( I hope )

            throw new RuntimeException(e);
        }
        return out.toString();
    }

    public static final void writeJSONString(final Object value, final Writer out, final IJSONContext context, final boolean strict) throws IOException
    {
        if (null == value)
        {
            out.write(NULL_FOR_OUTPUT);

            return;
        }
        if (value instanceof String)
        {
            out.write('\"');

            escape(value.toString(), out);

            out.write('\"');

            return;
        }
        if (value instanceof Integer)
        {
            out.write(value.toString());

            return;
        }
        if (value instanceof Long)
        {
            if (strict)
            {
                final Integer thunk = asInteger(value);

                if (null != thunk)
                {
                    out.write(thunk.toString());
                }
                else
                {
                    out.write(NULL_FOR_OUTPUT);
                }
            }
            else
            {
                out.write(value.toString());
            }
            return;
        }
        if (value instanceof Double)
        {
            final Double dval = ((Double) value);

            if (isDoubleInfiniteOrNan(dval))
            {
                out.write(NULL_FOR_OUTPUT);
            }
            else
            {
                out.write(dval.toString());
            }
            return;
        }
        if (value instanceof Float)
        {
            final Float fval = ((Float) value);

            if (isFloatInfiniteOrNan(fval))
            {
                out.write(NULL_FOR_OUTPUT);
            }
            else
            {
                out.write(fval.toString());
            }
            return;
        }
        if (value instanceof Number)
        {
            final Number nval = asNumber(value);

            if (null != nval)
            {
                out.write(nval.toString());
            }
            else
            {
                out.write(NULL_FOR_OUTPUT);
            }
            return;
        }
        if (value instanceof Boolean)
        {
            out.write(value.toString());

            return;
        }
        if (value instanceof IJSONStreamAware)
        {
            ((IJSONStreamAware) value).writeJSONString(out, context, strict);

            return;
        }
        if (value instanceof Map)
        {
            JSONObject.writeJSONString((Map) value, out, context, strict);

            return;
        }
        if (value instanceof List)
        {
            JSONArray.writeJSONString((List) value, out, context, strict);

            return;
        }
        if (value instanceof Date)
        {
            out.write('\"');

            escape(format((Date) value, context), out);

            out.write('\"');

            return;
        }
        if (value instanceof Collection)
        {
            JSONArray.writeJSONString((Collection) value, out, context, strict);

            return;
        }
        out.write('\"');

        escape(value.toString(), out);

        out.write('\"');
    }

    public static final String format(final Date date, final IJSONContext context)
    {
        if (null == date)
        {
            return NULL_FOR_OUTPUT;
        }
        if (null != context)
        {
            final JSONDateFormatter formatter = context.getDateFormatter();

            if (null != formatter)
            {
                return formatter.format(date);
            }
        }
        return date.toString();
    }

    static final void escape(final String string, final Writer out) throws IOException
    {
        final int leng = string.length();

        for (int i = 0; i < leng; i++)
        {
            final char c = string.charAt(i);

            if (((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) || (c == ' ') || ((c >= '0') && (c <= '9')))
            {
                out.write(c); // ASCII will be most common, this improves write speed about 5%, FWIW.
            }
            else
            {
                switch (c)
                {
                    case '"':
                        out.write("\\\"");
                        break;
                    case '\\':
                        out.write("\\\\");
                        break;
                    case '\b':
                        out.write("\\b");
                        break;
                    case '\f':
                        out.write("\\f");
                        break;
                    case '\n':
                        out.write("\\n");
                        break;
                    case '\r':
                        out.write("\\r");
                        break;
                    case '\t':
                        out.write("\\t");
                        break;
                    case '/':
                        out.write("\\/");
                        break;
                    default:
                        // Reference: http://www.unicode.org/versions/Unicode5.1.0/

                        if (((c >= '\u0000') && (c <= '\u001F')) || ((c >= '\u007F') && (c <= '\u009F')) || ((c >= '\u2000') && (c <= '\u20FF')))
                        {
                            final String unic = Integer.toHexString(c);

                            final int size = 4 - unic.length();

                            out.write("\\u");

                            for (int k = 0; k < size; k++)
                            {
                                out.write('0');
                            }
                            out.write(unic.toUpperCase());
                        }
                        else
                        {
                            out.write(c);
                        }
                }
            }
        }
    }

    public static final boolean isInteger(final Object object)
    {
        if (null == object)
        {
            return false;
        }
        if (object instanceof Integer)
        {
            return true;
        }
        if (object instanceof Long)
        {
            final long value = ((Long) object);

            if ((value > Integer.MAX_VALUE) || (value < Integer.MIN_VALUE))
            {
                return false;
            }
            return true;
        }
        if (object instanceof BigInteger)
        {
            final BigInteger value = ((BigInteger) object);

            if ((value.compareTo(BIG_INTEGER_MAX) > 0) || (value.compareTo(BIG_INTEGER_MIN) < 0))
            {
                return false;
            }
            return true;
        }
        if (object instanceof Short)
        {
            return true;
        }
        return false;
    }

    public static final boolean isDoubleInfiniteOrNan(final Double dval)
    {
        return (dval.isInfinite() || dval.isNaN());
    }

    public static final boolean isFloatInfiniteOrNan(final Float fval)
    {
        return (fval.isInfinite() || fval.isNaN());
    }

    public static final boolean isDouble(final Object object)
    {
        if (null == object)
        {
            return false;
        }
        if (object instanceof Double)
        {
            if (isDoubleInfiniteOrNan(((Double) object)))
            {
                return false;
            }
            return true;
        }
        if (object instanceof Float)
        {
            if (isFloatInfiniteOrNan((Float) object))
            {
                return false;
            }
            return true;
        }
        if (object instanceof BigDecimal)
        {
            final BigDecimal value = ((BigDecimal) object);

            if ((value.compareTo(BIG_DECIMAL_MAX) > 0) || (value.compareTo(BIG_DECIMAL_MIN) < 0))
            {
                return false;
            }
            if (isDoubleInfiniteOrNan(value.doubleValue()))
            {
                return false;
            }
            return true;
        }
        return false;
    }

    public static final boolean isNumber(final Object object)
    {
        if (object instanceof Number)
        {
            return (isInteger(object) || isDouble(object));
        }
        return false;
    }

    public static final Integer asInteger(final Object object)
    {
        if (null == object)
        {
            return null;
        }
        if (object instanceof Integer)
        {
            return ((Integer) object);
        }
        if (object instanceof Long)
        {
            final Long value = ((Long) object);

            if ((value > Integer.MAX_VALUE) || (value < Integer.MIN_VALUE))
            {
                return null;
            }
            return value.intValue();
        }
        if (object instanceof Short)
        {
            return ((Short) object).intValue();
        }
        if (object instanceof BigInteger)
        {
            final BigInteger value = ((BigInteger) object);

            if ((value.compareTo(BIG_INTEGER_MAX) > 0) || (value.compareTo(BIG_INTEGER_MIN) < 0))
            {
                return null;
            }
            return value.intValue();
        }
        if (object instanceof BigDecimal)
        {
            final BigDecimal value = ((BigDecimal) object);

            if ((value.compareTo(BIG_DEC_INT_MAX) > 0) || (value.compareTo(BIG_DEC_INT_MIN) < 0))
            {
                return null;
            }
            return value.intValue();
        }
        if (object instanceof Number)
        {
            final long lval = new Long(((Number) object).longValue());

            if ((lval > Integer.MAX_VALUE) || (lval < Integer.MIN_VALUE))
            {
                return null;
            }
            return ((int) lval);
        }
        return null;
    }

    public static final Long asLong(final Object object)
    {
        if (null == object)
        {
            return null;
        }
        if (object instanceof Long)
        {
            return ((Long) object);
        }
        if (object instanceof Integer)
        {
            return ((Integer) object).longValue();
        }
        if (object instanceof Double)
        {
            final Double dval = ((Double) object);

            if (isDoubleInfiniteOrNan(dval))
            {
                return null;
            }
            if ((dval.doubleValue() > Long.MAX_VALUE) || (dval.doubleValue() < Long.MIN_VALUE))
            {
                return null;
            }
            return dval.longValue();
        }
        if (object instanceof BigInteger)
        {
            final BigInteger value = ((BigInteger) object);

            if ((value.compareTo(BIG_INTLONG_MAX) > 0) || (value.compareTo(BIG_INTLONG_MIN) < 0))
            {
                return null;
            }
            return value.longValue();
        }
        if (object instanceof BigDecimal)
        {
            final BigDecimal value = ((BigDecimal) object);

            if ((value.compareTo(BIG_DEC_LONGMAX) > 0) || (value.compareTo(BIG_DEC_LONGMIN) < 0))
            {
                return null;
            }
            return value.longValue();
        }
        if (object instanceof Number)
        {
            final long lval = new Long(((Number) object).longValue());

            if ((lval > Integer.MAX_VALUE) || (lval < Integer.MIN_VALUE))
            {
                return null;
            }
            return lval;
        }
        return null;
    }

    public static final Double asDouble(final Object object)
    {
        if (null == object)
        {
            return null;
        }
        if (object instanceof Double)
        {
            final Double dval = ((Double) object);

            if (isDoubleInfiniteOrNan(dval))
            {
                return null;
            }
            return dval;
        }
        if (object instanceof Float)
        {
            final Double dval = new Double(((Float) object).doubleValue());

            if (isDoubleInfiniteOrNan(dval))
            {
                return null;
            }
            return dval;
        }
        if (object instanceof BigDecimal)
        {
            final BigDecimal value = ((BigDecimal) object);

            if ((value.compareTo(BIG_DECIMAL_MAX) > 0) || (value.compareTo(BIG_DECIMAL_MIN) < 0))
            {
                return null;
            }
            if (isDoubleInfiniteOrNan(value.doubleValue()))
            {
                return null;
            }
            return value.doubleValue();
        }
        if (object instanceof BigInteger)
        {
            final BigInteger value = ((BigInteger) object);

            if ((value.compareTo(BIG_INT_DEC_MAX) > 0) || (value.compareTo(BIG_INT_DEC_MIN) < 0))
            {
                return null;
            }
            return value.doubleValue();
        }
        if (object instanceof Number)
        {
            final Double dval = new Double(((Number) object).doubleValue());

            if (isDoubleInfiniteOrNan(dval))
            {
                return null;
            }
            return dval;
        }
        return null;
    }

    public static final Number asNumber(final Object object)
    {
        if (object instanceof Number)
        {
            if (isInteger(object))
            {
                return asInteger(object);
            }
            if (isDouble(object))
            {
                return asDouble(object);
            }
            return asLong(object);
        }
        return null;
    }

    public static final JSONArray asArray(final Object object)
    {
        if (null == object)
        {
            return null;
        }
        if (object instanceof JSONArray)
        {
            return ((JSONArray) object);
        }
        if (object instanceof List)
        {
            return new JSONArray((List) object);
        }
        return null;
    }

    @SuppressWarnings("unchecked")
    public static final JSONObject asObject(final Object object)
    {
        if (null == object)
        {
            return null;
        }
        if (object instanceof JSONObject)
        {
            return ((JSONObject) object);
        }
        if (object instanceof Map)
        {
            return new JSONObject((Map) object);
        }
        return null;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy