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

org.h2.value.ValueJson Maven / Gradle / Ivy

There is a newer version: 1.0.0-beta2
Show newest version
/*
 * Copyright 2004-2019 H2 Group. Multiple-Licensed under the MPL 2.0,
 * and the EPL 1.0 (https://h2database.com/html/license.html).
 * Initial Developer: Lazarev Nikita 
 */
package org.h2.value;

import java.io.ByteArrayOutputStream;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Arrays;

import org.h2.api.ErrorCode;
import org.h2.engine.CastDataProvider;
import org.h2.message.DbException;
import org.h2.util.Bits;
import org.h2.util.StringUtils;
import org.h2.util.Utils;
import org.h2.util.json.JSONByteArrayTarget;
import org.h2.util.json.JSONBytesSource;
import org.h2.util.json.JSONItemType;
import org.h2.util.json.JSONStringSource;
import org.h2.util.json.JSONStringTarget;

/**
 * Implementation of the JSON data type.
 */
public class ValueJson extends Value {

    private static final byte[] NULL_BYTES = "null".getBytes(StandardCharsets.ISO_8859_1),
            TRUE_BYTES = "true".getBytes(StandardCharsets.ISO_8859_1),
            FALSE_BYTES = "false".getBytes(StandardCharsets.ISO_8859_1);

    /**
     * {@code null} JSON value.
     */
    public static final ValueJson NULL = new ValueJson(NULL_BYTES);

    /**
     * {@code true} JSON value.
     */
    public static final ValueJson TRUE = new ValueJson(TRUE_BYTES);

    /**
     * {@code false} JSON value.
     */
    public static final ValueJson FALSE = new ValueJson(FALSE_BYTES);

    /**
     * {@code 0} JSON value.
     */
    public static final ValueJson ZERO = new ValueJson(new byte[] { '0' });

    private final byte[] value;

    /**
     * The hash code.
     */
    private int hash;

    private ValueJson(byte[] value) {
        this.value = value;
    }

    @Override
    public StringBuilder getSQL(StringBuilder builder) {
        String s = JSONBytesSource.parse(value, new JSONStringTarget(true));
        return builder.append("JSON '").append(s).append('\'');
    }

    @Override
    public TypeInfo getType() {
        return TypeInfo.TYPE_JSON;
    }

    @Override
    public int getValueType() {
        return Value.JSON;
    }

    @Override
    public String getString() {
        return new String(value, StandardCharsets.UTF_8);
    }

    @Override
    public byte[] getBytes() {
        return value.clone();
    }

    @Override
    public byte[] getBytesNoCopy() {
        return value;
    }

    @Override
    public Object getObject() {
        return value;
    }

    /**
     * Returns JSON item type.
     *
     * @return JSON item type
     */
    public JSONItemType getItemType() {
        switch (value[0]) {
        case '[':
            return JSONItemType.ARRAY;
        case '{':
            return JSONItemType.OBJECT;
        default:
            return JSONItemType.SCALAR;
        }
    }

    @Override
    public int getMemory() {
        return value.length + 24;
    }

    @Override
    public void set(PreparedStatement prep, int parameterIndex) throws SQLException {
        prep.setBytes(parameterIndex, value);
    }

    @Override
    public int hashCode() {
        if (hash == 0) {
            hash = Utils.getByteArrayHash(value);
        }
        return hash;
    }

    @Override
    public boolean equals(Object other) {
        return other instanceof ValueJson && Arrays.equals(value, ((ValueJson) other).value);
    }

    @Override
    public int compareTypeSafe(Value v, CompareMode mode, CastDataProvider provider) {
        return Bits.compareNotNullUnsigned(value, ((ValueJson) v).value);
    }

    /**
     * Returns JSON value with the specified content.
     *
     * @param s
     *            JSON representation, will be normalized
     * @return JSON value
     * @throws DbException
     *             on invalid JSON
     */
    public static ValueJson fromJson(String s) {
        byte[] bytes;
        try {
            bytes = JSONStringSource.normalize(s);
        } catch (RuntimeException ex) {
            throw DbException.get(ErrorCode.DATA_CONVERSION_ERROR_1, s);
        }
        return getInternal(bytes);
    }

    /**
     * Returns JSON value with the specified content.
     *
     * @param bytes
     *            JSON representation, will be normalized
     * @return JSON value
     * @throws DbException
     *             on invalid JSON
     */
    public static ValueJson fromJson(byte[] bytes) {
        try {
            bytes = JSONBytesSource.normalize(bytes);
        } catch (RuntimeException ex) {
            throw DbException.get(ErrorCode.DATA_CONVERSION_ERROR_1, StringUtils.convertBytesToHex(bytes));
        }
        return getInternal(bytes);
    }

    /**
     * Returns JSON value with the specified boolean content.
     *
     * @param bool
     *            boolean value
     * @return JSON value
     */
    public static ValueJson get(boolean bool) {
        return bool ? TRUE : FALSE;
    }

    /**
     * Returns JSON value with the specified numeric content.
     *
     * @param number
     *            integer value
     * @return JSON value
     */
    public static ValueJson get(int number) {
        return number != 0 ? getNumber(Integer.toString(number)) : ZERO;
    }

    /**
     * Returns JSON value with the specified numeric content.
     *
     * @param number
     *            long value
     * @return JSON value
     */
    public static ValueJson get(long number) {
        return number != 0L ? getNumber(Long.toString(number)) : ZERO;
    }

    /**
     * Returns JSON value with the specified numeric content.
     *
     * @param number
     *            big decimal value
     * @return JSON value
     */
    public static ValueJson get(BigDecimal number) {
        if (number.signum() == 0 && number.scale() == 0) {
            return ZERO;
        }
        String s = number.toString();
        int index = s.indexOf('E');
        if (index >= 0 && s.charAt(++index) == '+') {
            int length = s.length();
            s = new StringBuilder(length - 1).append(s, 0, index).append(s, index + 1, length).toString();
        }
        return getNumber(s);
    }

    /**
     * Returns JSON value with the specified string content.
     *
     * @param string
     *            string value
     * @return JSON value
     */
    public static ValueJson get(String string) {
        return new ValueJson(JSONByteArrayTarget.encodeString( //
                new ByteArrayOutputStream(string.length() + 2), string).toByteArray());
    }

    /**
     * Returns JSON value with the specified content.
     *
     * @param bytes
     *            normalized JSON representation
     * @return JSON value
     */
    public static ValueJson getInternal(byte[] bytes) {
        int l = bytes.length;
        switch (l) {
        case 1:
            if (bytes[0] == '0') {
                return ZERO;
            }
            break;
        case 4:
            if (Arrays.equals(TRUE_BYTES, bytes)) {
                return TRUE;
            } else if (Arrays.equals(NULL_BYTES, bytes)) {
                return NULL;
            }
            break;
        case 5:
            if (Arrays.equals(FALSE_BYTES, bytes)) {
                return FALSE;
            }
        }
        return new ValueJson(bytes);
    }

    private static ValueJson getNumber(String s) {
        return new ValueJson(s.getBytes(StandardCharsets.ISO_8859_1));
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy