Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.microsoft.azure.documentdb.JsonSerializable Maven / Gradle / Ivy
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
*/
package com.microsoft.azure.documentdb;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Represents a base resource that can be serialized to JSON in the Azure Cosmos DB database service.
*
* Note on Serializable: this interface is implemented solely for the use with the CosmosDB Spark Connector.
* In RDD transformation, it is a requirement of the RDD item type to be Serializable so that they can be
* transferred among the work nodes by the default serializer. The Serializable is not intended to be used by the user
* of the Cosmos DB Java SDK. Avoid relying on the serialized string format as it can change in the future.
*/
public class JsonSerializable implements Serializable {
private final static int INDENT_FACTOR = 4;
private final Logger logger = LoggerFactory.getLogger(JsonSerializable.class);
private final static ObjectMapper OBJECT_MAPPER = new ObjectMapper();
static {
OBJECT_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
private ObjectMapper om;
transient JSONObject propertyBag = null;
protected JsonSerializable() {
this.propertyBag = new JSONObject();
}
/**
* Constructor.
*
* @param jsonString the json string that represents the JsonSerializable.
* @param objectMapper the custom object mapper
*/
protected JsonSerializable(String jsonString, ObjectMapper objectMapper) {
try {
this.propertyBag = new JSONObject(jsonString);
} catch (JSONException e) {
throw new IllegalArgumentException(String.format("Unable to parse JSON %s", jsonString), e);
}
this.om = objectMapper;
}
/**
* Constructor.
*
* @param jsonString the json string that represents the JsonSerializable.
*/
protected JsonSerializable(String jsonString) {
try {
this.propertyBag = new JSONObject(jsonString);
} catch (JSONException e) {
throw new IllegalArgumentException(String.format("Invalid JSON String: '%s'", jsonString), e);
}
}
/**
* Constructor.
*
* @param jsonObject the json object that represents the JsonSerializable.
*/
protected JsonSerializable(JSONObject jsonObject) {
this.propertyBag = new JSONObject(jsonObject);
}
protected ObjectMapper getMapper() {
if (this.om != null) { return this.om; }
return OBJECT_MAPPER;
}
private static HashMap toMap(JSONObject object) throws JSONException {
HashMap map = new HashMap();
@SuppressWarnings("unchecked") // Using legacy API
Iterator keysItr = object.keys();
while (keysItr.hasNext()) {
String key = keysItr.next();
Object value = object.get(key);
if (value instanceof JSONArray) {
value = toList((JSONArray) value);
} else if (value instanceof JSONObject) {
value = toMap((JSONObject) value);
}
map.put(key, value);
}
return map;
}
private static List toList(JSONArray array) throws JSONException {
List list = new ArrayList();
for (int i = 0; i < array.length(); i++) {
Object value = array.get(i);
if (value instanceof JSONArray) {
value = toList((JSONArray) value);
} else if (value instanceof JSONObject) {
value = toMap((JSONObject) value);
}
list.add(value);
}
return list;
}
private static Object[] convertToObjectArray(Object array) {
Class> ofArray = array.getClass().getComponentType();
if (ofArray.isPrimitive()) {
List ar = new ArrayList();
int length = Array.getLength(array);
for (int i = 0; i < length; i++) {
ar.add(Array.get(array, i));
}
return ar.toArray();
} else {
return (Object[]) array;
}
}
private static void checkForValidPOJO(Class> c) {
if (c.isAnonymousClass() || c.isLocalClass()) {
throw new IllegalArgumentException(
String.format("%s can't be an anonymous or local class.", c.getName()));
}
if (c.isMemberClass() && !Modifier.isStatic(c.getModifiers())) {
throw new IllegalArgumentException(
String.format("%s must be static if it's a member class.", c.getName()));
}
}
protected Logger getLogger() {
return this.logger;
}
void populatePropertyBag() {
}
/**
* Returns the propertybag(JSONObject) in a hashMap
*
* @return the HashMap.
*/
public HashMap getHashMap() {
return JsonSerializable.toMap(this.propertyBag);
}
/**
* Checks whether a property exists.
*
* @param propertyName the property to look up.
* @return true if the property exists.
*/
public boolean has(String propertyName) {
return this.propertyBag.has(propertyName);
}
/**
* Removes a value by propertyName.
*
* @param propertyName the property to remove.
*/
public void remove(String propertyName) {
this.propertyBag.remove(propertyName);
}
/**
* Sets the value of a property.
*
* @param the type of the object.
* @param propertyName the property to set.
* @param value the value of the property.
*/
@SuppressWarnings({"unchecked", "rawtypes"})
public void set(String propertyName, T value) {
if (value == null) {
// Sets null.
this.propertyBag.put(propertyName, JSONObject.NULL);
} else if (value instanceof Collection) {
// Collection.
JSONArray jsonArray = new JSONArray();
this.internalSetCollection(propertyName, (Collection) value, jsonArray);
this.propertyBag.put(propertyName, jsonArray);
} else if (value.getClass().isArray()) {
// Array.
JSONArray jsonArray = new JSONArray();
this.internalSetCollection(propertyName, Arrays.asList(JsonSerializable.convertToObjectArray(value)),
jsonArray);
this.propertyBag.put(propertyName, jsonArray);
} else if (value instanceof JSONArray) {
this.propertyBag.put(propertyName, value);
} else if (value instanceof Number || value instanceof Boolean || value instanceof String
|| value instanceof JSONObject) {
// JSONObject, number (includes int, float, double etc), boolean,
// and string.
this.propertyBag.put(propertyName, value);
} else if (value instanceof JsonSerializable) {
// JsonSerializable
JsonSerializable castedValue = (JsonSerializable) value;
if (castedValue != null) {
castedValue.populatePropertyBag();
}
this.propertyBag.put(propertyName, castedValue != null ? castedValue.propertyBag : null);
} else {
// POJO
try {
this.propertyBag.put(propertyName, new JSONObject(this.getMapper().writeValueAsString(value)));
} catch (IOException e) {
throw new IllegalArgumentException("Can't serialize the object into the json string", e);
}
}
}
@SuppressWarnings({"unchecked", "rawtypes"})
private void internalSetCollection(String propertyName, Collection collection, JSONArray targetArray) {
for (T childValue : collection) {
if (childValue == null) {
// Sets null.
targetArray.put(JSONObject.NULL);
} else if (childValue instanceof Collection) {
// When T is also a Collection, use recursion.
JSONArray childArray = new JSONArray();
this.internalSetCollection(propertyName, (Collection) childValue, childArray);
targetArray.put(childArray);
} else if (childValue instanceof Number || childValue instanceof Boolean || childValue instanceof String
|| childValue instanceof JSONObject) {
// JSONObject, Number (includes Int, Float, Double etc),
// Boolean, and String.
targetArray.put(childValue);
} else if (childValue instanceof JsonSerializable) {
// JsonSerializable
JsonSerializable castedValue = (JsonSerializable) childValue;
castedValue.populatePropertyBag();
targetArray.put(castedValue.propertyBag != null ? castedValue.propertyBag : new JSONObject());
} else {
// POJO
try {
targetArray.put(new JSONObject(this.getMapper().writeValueAsString(childValue)));
} catch (IOException e) {
throw new IllegalArgumentException("Can't serialize the object into the json string", e);
}
}
}
}
/**
* Gets a property value as Object.
*
* @param propertyName the property to get.
* @return the value of the property.
*/
public Object get(String propertyName) {
if (this.has(propertyName) && !this.propertyBag.isNull(propertyName)) {
return this.propertyBag.get(propertyName);
} else {
return null;
}
}
/**
* Gets a string value.
*
* @param propertyName the property to get.
* @return the string value.
*/
public String getString(String propertyName) {
if (this.has(propertyName) && !this.propertyBag.isNull(propertyName)) {
return this.propertyBag.getString(propertyName);
} else {
return null;
}
}
/**
* Gets a boolean value.
*
* @param propertyName the property to get.
* @return the boolean value.
*/
public Boolean getBoolean(String propertyName) {
if (this.has(propertyName) && !this.propertyBag.isNull(propertyName)) {
return Boolean.valueOf(this.propertyBag.getBoolean(propertyName));
} else {
return null;
}
}
/**
* Gets an integer value.
*
* @param propertyName the property to get.
* @return the boolean value
*/
public Integer getInt(String propertyName) {
if (this.has(propertyName) && !this.propertyBag.isNull(propertyName)) {
return Integer.valueOf(this.propertyBag.getInt(propertyName));
} else {
return null;
}
}
/**
* Gets a long value.
*
* @param propertyName the property to get.
* @return the long value
*/
public Long getLong(String propertyName) {
if (this.has(propertyName) && !this.propertyBag.isNull(propertyName)) {
return Long.valueOf(this.propertyBag.getLong(propertyName));
} else {
return null;
}
}
/**
* Gets a double value.
*
* @param propertyName the property to get.
* @return the double value.
*/
public Double getDouble(String propertyName) {
if (this.has(propertyName) && !this.propertyBag.isNull(propertyName)) {
return new Double(this.propertyBag.getDouble(propertyName));
} else {
return null;
}
}
/**
* Gets an object value.
*
* @param the type of the object.
* @param propertyName the property to get.
* @param c the class of the object. If c is a POJO class, it must be a member (and not an anonymous or local)
* and a static one.
* @return the object value.
*/
public T getObject(String propertyName, Class c) {
if (this.propertyBag.has(propertyName) && !this.propertyBag.isNull(propertyName)) {
Object jsonObj = this.propertyBag.get(propertyName);
if (Number.class.isAssignableFrom(c) || String.class.isAssignableFrom(c)
|| Boolean.class.isAssignableFrom(c) || Object.class == c) {
// Number, String, Boolean
return c.cast(jsonObj);
} else if (Enum.class.isAssignableFrom(c)) {
try {
return c.cast(c.getMethod("valueOf", String.class).invoke(null, String.class.cast(jsonObj)));
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
| NoSuchMethodException | SecurityException | JSONException e) {
throw new IllegalStateException("Failed to create enum.", e);
}
} else if (JsonSerializable.class.isAssignableFrom(c)) {
try {
return c.getConstructor(String.class).newInstance(jsonObj.toString());
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException | NoSuchMethodException | SecurityException e) {
throw new IllegalStateException("Failed to instantiate class object.", e);
}
} else {
// POJO
JsonSerializable.checkForValidPOJO(c);
try {
return this.getMapper().readValue(jsonObj.toString(), c);
} catch (IOException e) {
throw new IllegalStateException("Failed to get POJO.", e);
}
}
}
return null;
}
/**
* Gets an object collection.
*
* @param the type of the objects in the collection.
* @param propertyName the property to get
* @param c the class of the object. If c is a POJO class, it must be a member (and not an anonymous or local)
* and a static one.
* @return the object collection.
*/
public Collection getCollection(String propertyName, Class c) {
if (this.propertyBag.has(propertyName) && !this.propertyBag.isNull(propertyName)) {
JSONArray jsonArray = this.propertyBag.getJSONArray(propertyName);
Collection result = new ArrayList();
boolean isBaseClass = false;
boolean isEnumClass = false;
boolean isJsonSerializable = false;
// Check once.
if (Number.class.isAssignableFrom(c) || String.class.isAssignableFrom(c)
|| Boolean.class.isAssignableFrom(c) || Object.class == c) {
isBaseClass = true;
} else if (Enum.class.isAssignableFrom(c)) {
isEnumClass = true;
} else if (JsonSerializable.class.isAssignableFrom(c)) {
isJsonSerializable = true;
} else {
JsonSerializable.checkForValidPOJO(c);
}
for (int i = 0; i < jsonArray.length(); i++) {
if (isBaseClass) {
// Number, String, Boolean
result.add(c.cast(jsonArray.get(i)));
} else if (isEnumClass) {
try {
result.add(c.cast(c.getMethod("valueOf", String.class).invoke(null,
String.class.cast(jsonArray.get(i)))));
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
| NoSuchMethodException | SecurityException | JSONException e) {
throw new IllegalStateException("Failed to create enum.", e);
}
} else if (isJsonSerializable) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
// JsonSerializable
try {
result.add(c.getConstructor(String.class).newInstance(jsonObject.toString()));
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException | NoSuchMethodException | SecurityException e) {
throw new IllegalStateException("Failed to instantiate class object.", e);
}
} else {
JSONObject jsonObject = jsonArray.getJSONObject(i);
// POJO
try {
result.add(this.getMapper().readValue(jsonObject.toString(), c));
} catch (IOException e) {
throw new IllegalStateException("Failed to get POJO.", e);
}
}
}
return result;
}
return null;
}
/**
* Gets a JSONObject.
*
* @param propertyName the property to get.
* @return the JSONObject.
*/
public JSONObject getObject(String propertyName) {
if (this.propertyBag.has(propertyName) && !this.propertyBag.isNull(propertyName)) {
JSONObject jsonObj = this.propertyBag.getJSONObject(propertyName);
return jsonObj;
}
return null;
}
/**
* Gets a JSONObject collection.
*
* @param propertyName the property to get.
* @return the JSONObject collection.
*/
public Collection getCollection(String propertyName) {
Collection result = null;
if (this.propertyBag.has(propertyName) && !this.propertyBag.isNull(propertyName)) {
result = new ArrayList();
JSONArray jsonArray = this.propertyBag.getJSONArray(propertyName);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
result.add(jsonObject);
}
}
return result;
}
/**
* Gets the value of a property identified by an array of property names that forms the path.
*
* @param propertyNames that form the path to the the property to get.
* @return the value of the property.
*/
public Object getObjectByPath(Collection propertyNames) {
JSONObject propBag = this.propertyBag;
Object value = null;
String propertyName = null;
Integer matchedProperties = 0;
Iterator iterator = propertyNames.iterator();
if (iterator.hasNext()) {
do {
propertyName = iterator.next();
if (propBag.has(propertyName)) {
matchedProperties++;
value = propBag.get(propertyName);
if (value.getClass() != JSONObject.class) {
break;
}
propBag = (JSONObject) value;
} else {
break;
}
} while (iterator.hasNext());
if (value != null && matchedProperties == propertyNames.size()) {
return value;
}
}
return null;
}
/**
* Converts to an Object (only POJOs and JSONObject are supported).
*
* @param the type of the object.
* @param c the class of the object, either a POJO class or JSONObject. If c is a POJO class, it must be a member
* (and not an anonymous or local) and a static one.
* @return the POJO.
*/
public T toObject(Class c) {
if (JsonSerializable.class.isAssignableFrom(c) || String.class.isAssignableFrom(c)
|| Number.class.isAssignableFrom(c) || Boolean.class.isAssignableFrom(c)) {
throw new IllegalArgumentException("c can only be a POJO class or JSONObject");
}
if (JSONObject.class.isAssignableFrom(c)) {
// JSONObject
if (JSONObject.class != c) {
throw new IllegalArgumentException("We support JSONObject but not its sub-classes.");
}
return c.cast(this.propertyBag);
} else {
// POJO
JsonSerializable.checkForValidPOJO(c);
try {
return this.getMapper().readValue(this.toJson(), c);
} catch (IOException e) {
throw new IllegalStateException("Failed to get POJO.", e);
}
}
}
/**
* Converts to a JSON string.
*
* @return the JSON string.
*/
public String toJson() {
return this.toJson(SerializationFormattingPolicy.None);
}
/**
* Converts to a JSON string.
* @param formattingPolicy the formatting policy instance
* @return the JSON string.
*/
public String toJson(SerializationFormattingPolicy formattingPolicy) {
this.populatePropertyBag();
if (SerializationFormattingPolicy.Indented.equals(formattingPolicy) ) {
return this.propertyBag.toString(INDENT_FACTOR);
} else {
return this.propertyBag.toString();
}
}
/**
* Gets Simple String representation of property bag.
*
* For proper conversion to json and inclusion of the default values
* use {@link #toJson()}.
*
* @return string representation of property bag.
*/
public String toString() {
return this.propertyBag.toString();
}
/**
* Gets formatted String representation of property bag.
*
* @param indentFactor formatting indentation factor.
* @return formatted string representation of property bag.
*
* @deprecated For proper conversion to json and inclusion of the default values
* use {@link #toJson(SerializationFormattingPolicy)}.
*
*/
@Deprecated
public String toString(int indentFactor) {
return this.propertyBag.toString(indentFactor);
}
private void writeObject(ObjectOutputStream outputStream) throws IOException {
// Since all of the properties of the JSONSerializable objects are in propertyBag
// Serializing it should be sufficient. Calling to defaultWriteObject() is not necessary.
outputStream.writeObject(propertyBag.toString());
}
private void readObject(ObjectInputStream inputStream) throws ClassNotFoundException, IOException, JSONException {
propertyBag = new JSONObject((String) inputStream.readObject());
}
}