
oracle.kv.table.FieldValueFactory Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of oracle-nosql-server Show documentation
Show all versions of oracle-nosql-server Show documentation
NoSQL Database Server - supplies build and runtime support for the server (store) side of the Oracle NoSQL Database.
The newest version!
/*-
* Copyright (C) 2011, 2018 Oracle and/or its affiliates. All rights reserved.
*
* This file was distributed by Oracle as part of a version of Oracle NoSQL
* Database made available at:
*
* http://www.oracle.com/technetwork/database/database-technologies/nosqldb/downloads/index.html
*
* Please see the LICENSE file included in the top-level directory of the
* appropriate version of Oracle NoSQL Database for a copy of the license and
* additional information.
*/
package oracle.kv.table;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
import java.math.BigDecimal;
import java.sql.Timestamp;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.JsonToken;
import oracle.kv.table.TimestampDef;
import oracle.kv.impl.api.table.ArrayDefImpl;
import oracle.kv.impl.api.table.ArrayValueImpl;
import oracle.kv.impl.api.table.BinaryDefImpl;
import oracle.kv.impl.api.table.ComplexValueImpl;
import oracle.kv.impl.api.table.EnumDefImpl;
import oracle.kv.impl.api.table.FieldDefImpl;
import oracle.kv.impl.api.table.FixedBinaryDefImpl;
import oracle.kv.impl.api.table.JsonDefImpl;
import oracle.kv.impl.api.table.MapDefImpl;
import oracle.kv.impl.api.table.MapValueImpl;
import oracle.kv.impl.api.table.RecordDefImpl;
import oracle.kv.impl.api.table.RecordValueImpl;
import oracle.kv.impl.api.table.StringDefImpl;
import oracle.kv.impl.api.table.TableJsonUtils;
import oracle.kv.impl.api.table.TimestampDefImpl;
import oracle.kv.impl.api.table.TimestampUtils;
/**
* Factory class to create FieldValue instance objects.
*
* @since 4.0
*/
public class FieldValueFactory {
/**
* Creates a FieldValue instance from JSON input where the type is not
* known. This method maps the JSON into a map (object) or array where
* the element type is JSON or one of the scalar types supporting JSON:
* INTEGER, LONG, FLOAT, DOUBLE, STRING, and BOOLEAN.
*
* @param jsonString the JSON representation
*
* @return a FieldValue
*
* @throws IllegalArgumentException if the input is not valid JSON or the
* input cannot be parsed, or it cannot be mapped into supported data types.
*
* @since 4.2
*/
public static FieldValue createValueFromJson(String jsonString) {
return createValueFromJson(FieldDefImpl.jsonDef, jsonString);
}
/**
* Creates a FieldValue instance from JSON input where the type is not
* known. This method maps the JSON into a map (object) or array where
* the element type is JSON or one of the scalar types supporting JSON:
* INTEGER, LONG, FLOAT, DOUBLE, STRING, and BOOLEAN.
*
* @param jsonReader a Reader over JSON
*
* @return a FieldValue
*
* @throws IllegalArgumentException if the input is not valid JSON or the
* input cannot be parsed, or it cannot be mapped into supported data types.
*
* @throws IOException if the input is not valid JSON or the input cannot
* be parse, or it cannot be mapped into supported data types.
*
* @since 4.2
*/
public static FieldValue createValueFromJson(Reader jsonReader)
throws IOException {
return createValueFromJson(FieldDefImpl.jsonDef, jsonReader);
}
/**
* Creates a new value from a JSON doc (which is given as a String).
*
* If type is RecordDef then:
* (a) the JSON doc may have fields that do not appear in the record
* schema. Such fields are simply skipped.
* (b) the JSON doc may be missing fields that appear in the record's
* schema. Such fields will remain unset in the record value. This
* means {@link RecordValue#get(String)} will return null and {@link
* RecordValue#toJsonString(boolean)} will skip unset fields.
*
* If type is BINARY then the value must be a base64 encoded value.
*
* Note: This methods doesn't handle arbitrary JSON, it has to comply to
* the given type. Also, top level null is not supported.
*
* @param type the type definition of the instance.
* @param jsonString the JSON representation
* @return the newly created instance
* @throws IllegalArgumentException for invalid documents
*/
public static FieldValue createValueFromJson(
FieldDef type,
String jsonString) {
if (jsonString == null) {
throw new IllegalArgumentException("Not a valid JSON input.");
}
int l;
InputStream jsonInput;
switch (type.getType()) {
case ARRAY:
final ArrayValueImpl arrayValue =
((ArrayDefImpl)type).createArray();
jsonInput = new ByteArrayInputStream(jsonString.getBytes());
ComplexValueImpl.createFromJson(arrayValue, jsonInput, false);
return arrayValue;
case BINARY:
l = jsonString.length();
if (jsonString.charAt(0) != '"' ||
jsonString.charAt(l - 1) != '"' ||
l <= 1) {
throw new IllegalArgumentException("Invalid input for " +
"BinaryValue: " + jsonString);
}
return ((BinaryDefImpl)type).
fromString(jsonString.substring(1, l - 1));
case BOOLEAN:
if ("true".equals(jsonString.toLowerCase())) {
return createBoolean(true);
} else if ("false".equals(jsonString.toLowerCase())) {
return createBoolean(false);
}
throw new IllegalArgumentException("Illegal input for a BooleanValue");
case DOUBLE:
try {
return createDouble(Double.parseDouble(jsonString));
} catch (NumberFormatException e) {
throw new IllegalArgumentException(
("Failed to parse DoubleValue: " + e.getMessage()), e);
}
case ENUM:
l = jsonString.length();
if (jsonString.charAt(0) != '"' ||
jsonString.charAt(l - 1) != '"' ||
l <= 1) {
throw new IllegalArgumentException("Invalid input for a " +
"StringValue: " + jsonString);
}
return ((EnumDefImpl)type).
createEnum(jsonString.substring(1, l - 1));
case FIXED_BINARY:
l = jsonString.length();
if (jsonString.charAt(0) != '"' ||
jsonString.charAt(l - 1) != '"' ||
l <= 1) {
throw new IllegalArgumentException("Invalid input for " +
"FixedBinaryValue: " + jsonString);
}
return ((FixedBinaryDefImpl)type).
fromString(jsonString.substring(1, l - 1));
case FLOAT:
try {
return createFloat(Float.parseFloat(jsonString));
} catch (NumberFormatException e) {
throw new IllegalArgumentException(
("Failed to parse FloatValue: " + e.getMessage()), e);
}
case INTEGER:
try {
return createInteger(Integer.parseInt(jsonString));
} catch (NumberFormatException e) {
throw new IllegalArgumentException(
("Failed to parse IntegerValue: " + e.getMessage()), e);
}
case LONG:
try {
return createLong(Long.parseLong(jsonString));
} catch (NumberFormatException e) {
throw new IllegalArgumentException(
("Failed to parse LongValue: " + e.getMessage()), e);
}
case NUMBER:
try {
return createNumber(new BigDecimal(jsonString));
} catch (NumberFormatException e) {
throw new IllegalArgumentException(
("Failed to parse NumberValue: Malformed numeric value: " +
jsonString), e);
}
case TIMESTAMP:
l = jsonString.length();
if (jsonString.charAt(0) != '"' ||
jsonString.charAt(l - 1) != '"' ||
l <= 1) {
throw new IllegalArgumentException("Invalid input for " +
"TimestampValue: " + jsonString);
}
return ((TimestampDefImpl)type).
fromString(jsonString.substring(1, l - 1));
case MAP:
final MapValueImpl mapValue = ((MapDefImpl)type).createMap();
jsonInput = new ByteArrayInputStream(jsonString.getBytes());
ComplexValueImpl.createFromJson(mapValue, jsonInput, false);
return mapValue;
case RECORD:
final RecordValueImpl recordValue =
((RecordDefImpl)type).createRecord();
jsonInput = new ByteArrayInputStream(jsonString.getBytes());
ComplexValueImpl.createFromJson(recordValue, jsonInput, false);
return recordValue;
case STRING:
l = jsonString.length();
if (jsonString.charAt(0) != '"' ||
jsonString.charAt(l - 1) != '"' ||
l <= 1) {
throw new IllegalArgumentException("Invalid input for a " +
"StringValue: " + jsonString);
}
return ((StringDefImpl)type).
createString(jsonString.substring(1, l - 1));
case JSON:
Reader reader = new StringReader(jsonString);
try {
return createValueFromJson(FieldDefImpl.jsonDef, reader);
} catch (IOException ioe) {
throw new IllegalArgumentException("Unable to parse JSON " +
"input: " + jsonString +
": " + ioe);
} finally {
try { reader.close(); } catch (IOException ioe) {}
}
case ANY:
case ANY_ATOMIC:
case ANY_RECORD:
case EMPTY:
default:
throw new IllegalArgumentException("Type not supported by " +
"fromJson: " + type);
}
}
/**
* Creates a new value from a JSON doc (which is given as a Reader).
* If type is RecordDef then:
* (a) the JSON doc may have fields that do not appear in the record
* schema. Such fields are simply skipped.
* (b) the JSON doc may be missing fields that appear in the record's
* schema. Such fields will remain unset in the record value.
* If type is BINARY then the value must be a base64 encoded value.
*
* Note: This methods doesn't handle arbitrary JSON, it has to comply to
* the given type. Also, top level null is not supported.
*
* @param type the type definition of the instance.
* @param jsonReader the JSON representation
* @return the newly created instance
* @throws IllegalArgumentException for invalid documents
* @throws IOException for an invalid Reader
*/
public static FieldValue createValueFromJson(
FieldDef type,
Reader jsonReader)
throws IOException {
JsonParser jp = null;
try {
jp = TableJsonUtils.createJsonParser(jsonReader);
return fromJson(type, jp);
} finally {
if (jp != null) {
jp.close();
}
}
}
/**
* Creates a new value from a JSON doc (which is given as an InputStream).
* If type is RecordDef then:
* (a) the JSON doc may have fields that do not appear in the record
* schema. Such fields are simply skipped.
* (b) the JSON doc may be missing fields that appear in the record's
* schema. Such fields will remain unset in the record value.
* If type is BINARY then the value must be a base64 encoded value.
*
* Note: This methods doesn't handle arbitrary JSON, it has to comply to
* the given type. Also, top level null is not supported.
*
* @param type the type definition of the instance.
* @param jsonStream the JSON representation
* @return the newly created instance
* @throws IllegalArgumentException for invalid documents
* @throws IOException for an invalid InputStream
*/
public static FieldValue createValueFromJson(
FieldDef type,
InputStream jsonStream)
throws IOException {
JsonParser jp = null;
try {
jp = TableJsonUtils.createJsonParser(jsonStream);
return fromJson(type, jp);
} finally {
if (jp != null) {
jp.close();
}
}
}
private static FieldValue fromJson(FieldDef type, JsonParser jp)
throws IOException {
JsonToken t;
switch (type.getType()) {
case ARRAY:
final ArrayValueImpl arrayValue = ((ArrayDefImpl)type).createArray();
jp.nextToken();
arrayValue.addJsonFields(jp, null, false, true/*addMissingFields*/);
arrayValue.validate();
return arrayValue;
case BINARY:
t = jp.nextToken();
if (t == JsonToken.VALUE_STRING) {
return ((BinaryDefImpl)type).fromString(jp.getText());
}
throw new IllegalArgumentException("Invalid input for " +
"BinaryValue.");
case BOOLEAN:
t = jp.nextToken();
return createBoolean(jp.getBooleanValue());
case DOUBLE:
t = jp.nextToken();
return createDouble(jp.getDoubleValue());
case ENUM:
t = jp.nextToken();
if (t == JsonToken.VALUE_STRING) {
return ((EnumDefImpl)type).createEnum(jp.getText());
}
throw new IllegalArgumentException("Invalid input for " +
"StringValue.");
case FIXED_BINARY:
t = jp.nextToken();
if (t == JsonToken.VALUE_STRING) {
return ((FixedBinaryDefImpl)type).fromString(jp.getText());
}
throw new IllegalArgumentException("Invalid input for " +
"FixedBinaryValue.");
case FLOAT:
t = jp.nextToken();
return createFloat(jp.getFloatValue());
case INTEGER:
t = jp.nextToken();
return createInteger(jp.getIntValue());
case LONG:
t = jp.nextToken();
return createLong(jp.getLongValue());
case NUMBER:
t = jp.nextToken();
return createNumber(TableJsonUtils.jsonParserGetDecimalValue(jp));
case TIMESTAMP:
t = jp.nextToken();
if (t == JsonToken.VALUE_STRING) {
return ((TimestampDefImpl)type).fromString(jp.getText());
}
throw new IllegalArgumentException("Invalid input for " +
"TimestampValue.");
case MAP:
final MapValueImpl mapValue = ((MapDefImpl)type).createMap();
jp.nextToken();
mapValue.addJsonFields(jp, null, false, true /*addMissingFields*/);
mapValue.validate();
return mapValue;
case RECORD:
final RecordValueImpl recordValue =
((RecordDefImpl)type).createRecord();
jp.nextToken();
recordValue.addJsonFields(
jp, null, false, true /*addMissingFields*/);
recordValue.validate();
return recordValue;
case STRING:
t = jp.nextToken();
if (t == JsonToken.VALUE_STRING) {
return ((StringDefImpl)type).createString(jp.getText());
}
throw new IllegalArgumentException("Invalid input for " +
"StringValue.");
case JSON:
return JsonDefImpl.createFromJson(jp, true);
case ANY:
case ANY_ATOMIC:
case ANY_RECORD:
case EMPTY:
default:
throw new IllegalArgumentException("Type not supported by " +
"fromJson: " + type);
}
}
/**
* Creates a BinaryValue instance from its java representation.
*
* @param v the java value
* @return the newly created instance
*/
public static BinaryValue createBinary(byte[] v) {
return FieldDefImpl.binaryDef.createBinary(v);
}
/**
* Creates a BooleanValue instance from its java representation.
*
* @param v the java value
* @return the newly created instance
*/
public static BooleanValue createBoolean(boolean v) {
return FieldDefImpl.booleanDef.createBoolean(v);
}
/**
* Creates a DoubleValue instance from its java representation.
*
* @param v the java value
* @return the newly created instance
*/
public static DoubleValue createDouble(double v) {
return FieldDefImpl.doubleDef.createDouble(v);
}
/**
* Creates a FloatValue instance from its java representation.
*
* @param v the java value
* @return the newly created instance
*/
public static FloatValue createFloat(float v) {
return FieldDefImpl.floatDef.createFloat(v);
}
/**
* Creates a IntegerValue instance from its java representation.
*
* @param v the java value
* @return the newly created instance
*/
public static IntegerValue createInteger(int v) {
return FieldDefImpl.integerDef.createInteger(v);
}
/**
* Creates a LongValue instance from its java representation.
*
* @param v the java value
* @return the newly created instance
*/
public static LongValue createLong(long v) {
return FieldDefImpl.longDef.createLong(v);
}
/**
* Creates a NumberValue instance from a int value.
*
* @param v the java value
* @return the newly created instance
*
* @since 4.4
*/
public static NumberValue createNumber(int v) {
return FieldDefImpl.numberDef.createNumber(v);
}
/**
* Creates a NumberValue instance from a long value.
*
* @param v the java value
* @return the newly created instance
*
* @since 4.4
*/
public static NumberValue createNumber(long v) {
return FieldDefImpl.numberDef.createNumber(v);
}
/**
* Creates a NumberValue instance from a float value.
*
* @param v the java value
* @return the newly created instance
*
* @since 4.4
*/
public static NumberValue createNumber(float v) {
return FieldDefImpl.numberDef.createNumber(v);
}
/**
* Creates a NumberValue instance from a double value.
*
* @param v the java value
* @return the newly created instance
*
* @since 4.4
*/
public static NumberValue createNumber(double v) {
return FieldDefImpl.numberDef.createNumber(v);
}
/**
* Creates a NumberValue instance from a BigDecimal value.
*
* @param v the java value
* @return the newly created instance
*
* @since 4.4
*/
public static NumberValue createNumber(BigDecimal v) {
return FieldDefImpl.numberDef.createNumber(v);
}
/**
* Creates a special FieldValue instance representing a JSON null
* value, which returns true from {@link FieldValue#isJsonNull}.
*
* @return the newly created instance
*
* @since 4.3
*/
public static FieldValue createJsonNull() {
return FieldDefImpl.jsonDef.createJsonNull();
}
/**
* Creates a StringValue instance from its java representation.
*
* @param v the java value
* @return the newly created instance
*/
public static StringValue createString(String v) {
return FieldDefImpl.stringDef.createString(v);
}
/**
* Creates a TimestampValue instance from its java representation.
*
* @param v the java value
* @param precision the precision of Timestamp value
* @return the newly created instance
*
* @throws IllegalArgumentException if precision is invalid.
*/
public static TimestampValue createTimestamp(Timestamp v, int precision) {
if (precision < 0 || precision >= FieldDefImpl.timestampDefs.length) {
throw new IllegalArgumentException
("Invalid precision, it should be in range from 0 to " +
(FieldDefImpl.timestampDefs.length - 1) + ": " + precision);
}
return FieldDefImpl.timestampDefs[precision].createTimestamp(v);
}
/**
* Creates a TimestampValue instance from a string in format of
* {@link TimestampDef#DEFAULT_PATTERN}.
*
* @param s the string value
* @param precision the precision of Timestamp value
* @return the newly created instance
*
* @throws IllegalArgumentException if precision is invalid or the string
* is not in the format of {@link TimestampDef#DEFAULT_PATTERN}.
*/
public static TimestampValue createTimestamp(String s, int precision) {
if (precision < 0 || precision >= FieldDefImpl.timestampDefs.length) {
throw new IllegalArgumentException
("Invalid precision, it should be in range from 0 to " +
(FieldDefImpl.timestampDefs.length - 1) + ": " + precision);
}
return FieldDefImpl.timestampDefs[precision].fromString(s);
}
/**
* Creates a TimestampValue instance from date time components.
*
* @param year the year, from -6383 to 9999.
* @param month the month of year, from 1 to 12
* @param day the day of month, from 1 to 31
* @param hour the hour of day, from 0 to 23
* @param minute the minute of hour, from 0 to 59
* @param second the second of minute, from 0 to 59
* @param fracSeconds the number of fractional seconds in the specified
* precision. e.g. if precision is 3, then fractional seconds can be a
* value within the range 0 ~ 999.
* @param precision the precision of Timestamp value
*
* @return the newly created instance
*
* @throws IllegalArgumentException if precision is invalid or any component
* is invalid.
*/
public static TimestampValue createTimestamp(int year, int month, int day,
int hour, int minute,
int second, int fracSeconds,
int precision) {
if (precision < 0 || precision >= FieldDefImpl.timestampDefs.length) {
throw new IllegalArgumentException
("Invalid precision, it should be in range from 0 to " +
(FieldDefImpl.timestampDefs.length - 1) + ": " + precision);
}
TimestampUtils.validateComponent(0, year);
TimestampUtils.validateComponent(1, month);
TimestampUtils.validateComponent(2, day);
TimestampUtils.validateComponent(3, hour);
TimestampUtils.validateComponent(4, minute);
TimestampUtils.validateComponent(5, second);
if (precision == 0) {
if (fracSeconds != 0) {
throw new IllegalArgumentException
("Invalid fracSeconds, it should be 0 with precision 0");
}
} else {
int max = (int)Math.pow(10, precision) - 1;
if (fracSeconds < 0 || fracSeconds > max) {
throw new IllegalArgumentException
("Invalid fracSeconds, it should be in range 0 ~ " + max);
}
}
byte[] bytes = TimestampUtils.toBytes(year, month, day,
hour, minute, second,
fracSeconds, precision);
return FieldDefImpl.timestampDefs[precision].createTimestamp(bytes);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy