com.reandroid.json.JSONItem Maven / Gradle / Ivy
/*
* Copyright (C) 2022 github.com/REAndroid
*
* 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.reandroid.json;
import java.io.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Collection;
import java.util.Map;
public abstract class JSONItem {
public abstract Writer write(Writer writer, int indentFactor, int indent) throws JSONException;
public void write(File file) throws IOException{
write(file, INDENT_FACTOR);
}
@SuppressWarnings("ResultOfMethodCallIgnored")
public void write(File file, int indentFactor) throws IOException{
File dir = file.getParentFile();
if(dir != null && !dir.exists()){
dir.mkdirs();
}
FileOutputStream outputStream=new FileOutputStream(file);
write(outputStream, indentFactor);
outputStream.close();
}
public void write(OutputStream outputStream) throws IOException {
write(outputStream, INDENT_FACTOR);
}
public void write(OutputStream outputStream, int indentFactor) throws IOException {
Writer writer=new OutputStreamWriter(outputStream, StandardCharsets.UTF_8);
writer= write(writer, indentFactor, 0);
writer.flush();
writer.close();
}
public Writer write(Writer writer) throws JSONException {
return this.write(writer, 0, 0);
}
@Override
public String toString() {
try {
return this.toString(0);
} catch (Exception e) {
return null;
}
}
public String toString(int indentFactor) throws JSONException {
StringWriter w = new StringWriter();
synchronized (w.getBuffer()) {
return this.write(w, indentFactor, 0).toString();
}
}
static void writeValue(Writer writer, Object value, int indentFactor, int indent) throws JSONException, IOException {
if (isNull(value)) {
writer.write("null");
} else if (value instanceof JSONString) {
Object o;
try {
o = ((JSONString) value).toJSONString();
} catch (Exception e) {
throw new JSONException(e);
}
writer.write(o != null ? o.toString() : quote(value.toString()));
} else if (value instanceof Number) {
writer.write(numberToString((Number) value));
} else if (value instanceof Boolean) {
writer.write(value.toString());
} else if (value instanceof Enum>) {
writer.write(quote(((Enum>)value).name()));
} else if (value instanceof JSONObject) {
((JSONObject) value).write(writer, indentFactor, indent);
} else if (value instanceof JSONArray) {
((JSONArray) value).write(writer, indentFactor, indent);
} else if (value instanceof Map) {
Map, ?> map = (Map, ?>) value;
new JSONObject(map).write(writer, indentFactor, indent);
} else if (value instanceof Collection) {
Collection> coll = (Collection>) value;
new JSONArray(coll).write(writer, indentFactor, indent);
} else if (value.getClass() == byte[].class) {
writeBase64(writer, (byte[]) value);
} else if (value.getClass().isArray()) {
new JSONArray(value).write(writer, indentFactor, indent);
} else {
quote(value.toString(), writer);
}
}
static void indent(Writer writer, int indent) throws IOException {
for (int i = 0; i < indent; i += 1) {
writer.write(' ');
}
}
public static String quote(String string) {
StringWriter sw = new StringWriter();
synchronized (sw.getBuffer()) {
try {
return quote(string, sw).toString();
} catch (IOException ignored) {
// will never happen - we are writing to a string writer
return "";
}
}
}
public static Writer quote(String string, Writer w) throws IOException {
if (string == null || string.isEmpty()) {
w.write("\"\"");
return w;
}
char b;
char c = 0;
String hhhh;
int i;
int len = string.length();
w.write('"');
for (i = 0; i < len; i += 1) {
b = c;
c = string.charAt(i);
switch (c) {
case '\\':
case '"':
w.write('\\');
w.write(c);
break;
case '/':
if (b == '<') {
w.write('\\');
}
w.write(c);
break;
case '\b':
w.write("\\b");
break;
case '\t':
w.write("\\t");
break;
case '\n':
w.write("\\n");
break;
case '\f':
w.write("\\f");
break;
case '\r':
w.write("\\r");
break;
default:
if (c < ' ' || (c >= '\u0080' && c < '\u00a0')
|| (c >= '\u2000' && c < '\u2100')) {
w.write("\\u");
hhhh = Integer.toHexString(c);
w.write("0000", 0, 4 - hhhh.length());
w.write(hhhh);
} else {
w.write(c);
}
}
}
w.write('"');
return w;
}
public static String numberToString(Number number) throws JSONException {
return number.toString();
}
public static void testValidity(Object o) throws JSONException {
if (o != null) {
if (o instanceof Double) {
if (((Double) o).isInfinite() || ((Double) o).isNaN()) {
throw new JSONException(
"JSON does not allow non-finite numbers.");
}
} else if (o instanceof Float) {
if (((Float) o).isInfinite() || ((Float) o).isNaN()) {
throw new JSONException(
"JSON does not allow non-finite numbers.");
}
}
}
}
public static String valueToString(Object value) throws JSONException {
// moves the implementation to JSONWriter as:
// 1. It makes more sense to be part of the writer class
// 2. For Android support this method is not available. By implementing it in the Writer
// Android users can use the writer with the built in Android JSONObject implementation.
return JSONWriter.valueToString(value);
}
public static Object wrap(Object object) {
try {
if (object == null) {
return NULL;
}
if (object instanceof JSONObject || object instanceof JSONArray
|| NULL.equals(object) || object instanceof JSONString
|| object instanceof Byte || object instanceof Character
|| object instanceof Short || object instanceof Integer
|| object instanceof Long || object instanceof Boolean
|| object instanceof Float || object instanceof Double
|| object instanceof String || object instanceof BigInteger
|| object instanceof BigDecimal || object instanceof Enum) {
return object;
}
if (object instanceof Collection) {
Collection> coll = (Collection>) object;
return new JSONArray(coll);
}
if (object.getClass().isArray()) {
return new JSONArray(object);
}
if (object instanceof Map) {
Map, ?> map = (Map, ?>) object;
return new JSONObject(map);
}
Package objectPackage = object.getClass().getPackage();
String objectPackageName = objectPackage != null ? objectPackage
.getName() : "";
if (objectPackageName.startsWith("java.")
|| objectPackageName.startsWith("javax.")
|| object.getClass().getClassLoader() == null) {
return object.toString();
}
return new JSONObject(object);
} catch (Exception exception) {
return null;
}
}
private static void writeBase64(Writer writer, byte[] bytes) throws IOException {
writer.write("\"");
writer.write(MIME_BIN_BASE64);
try{
Base64.Encoder encoder = Base64.getUrlEncoder();
String base64 = encoder.encodeToString(bytes);
writer.write(base64);
}catch (IOException exception){
throw exception;
}catch (Throwable throwable){
throw new JSONException(throwable);
}
writer.write("\"");
}
static boolean isNull(Object obj){
return obj == null || obj == NULL;
}
@SuppressWarnings("all")
private static final class Null {
@Override
public final Object clone() {
return this;
}
@Override
public boolean equals(Object object) {
return object == null || object == this;
}
@Override
public int hashCode() {
return 0;
}
@Override
public String toString() {
return "null";
}
}
public static final Object NULL = new Null();
private static final int INDENT_FACTOR = 2;
public static final String MIME_BIN_BASE64 = "data:binary/octet-stream;base64,";
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy