io.vertx.json.schema.impl.Utils Maven / Gradle / Ivy
package io.vertx.json.schema.impl;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.json.schema.JsonSchema;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
public class Utils {
static class Numbers {
public static boolean isInteger(Object instance) {
if (instance instanceof Number) {
if (instance instanceof Byte || instance instanceof Short || instance instanceof Integer || instance instanceof Long || instance instanceof BigInteger) {
return true;
}
if (instance instanceof Float) {
return (Float) instance % 1 == 0.0f;
}
if (instance instanceof Double) {
return (Double) instance % 1 == 0.0;
}
if (instance instanceof BigDecimal) {
return ((BigDecimal) instance).remainder(BigDecimal.ONE).equals(BigDecimal.ZERO);
}
}
return false;
}
private static BigDecimal toBigDecimal(Number in) {
if (in instanceof BigDecimal) {
return (BigDecimal) in;
}
if (in instanceof BigInteger) {
return new BigDecimal((BigInteger) in);
}
if (in instanceof Float) {
return BigDecimal.valueOf(in.floatValue());
}
if (in instanceof Double) {
return BigDecimal.valueOf(in.doubleValue());
}
return BigDecimal.valueOf(in.longValue());
}
public static boolean ze(Number instance) {
// for big numbers, go slow
if (instance instanceof BigDecimal || instance instanceof BigInteger) {
return toBigDecimal(instance).compareTo(BigDecimal.ZERO) == 0;
}
// approx.
return instance.doubleValue() == 0.0;
}
public static boolean lt(Number instance, Object value) {
if (value instanceof Number) {
// for big numbers, go slow
if (instance instanceof BigDecimal || value instanceof BigDecimal || instance instanceof BigInteger || value instanceof BigInteger) {
return toBigDecimal(instance).compareTo(toBigDecimal(((Number) value))) < 0;
}
// approx.
return instance.doubleValue() < ((Number) value).doubleValue();
}
return false;
}
public static boolean lte(Number instance, Object value) {
if (value instanceof Number) {
// for big numbers, go slow
if (instance instanceof BigDecimal || value instanceof BigDecimal || instance instanceof BigInteger || value instanceof BigInteger) {
return toBigDecimal(instance).compareTo(toBigDecimal(((Number) value))) <= 0;
}
// approx.
return instance.doubleValue() <= ((Number) value).doubleValue();
}
return false;
}
public static boolean gt(Number instance, Object value) {
if (value instanceof Number) {
// for big numbers, go slow
if (instance instanceof BigDecimal || value instanceof BigDecimal || instance instanceof BigInteger || value instanceof BigInteger) {
return toBigDecimal(instance).compareTo(toBigDecimal(((Number) value))) > 0;
}
// approx.
return instance.doubleValue() > ((Number) value).doubleValue();
}
return false;
}
public static boolean gte(Number instance, Object value) {
if (value instanceof Number) {
// for big numbers, go slow
if (instance instanceof BigDecimal || value instanceof BigDecimal || instance instanceof BigInteger || value instanceof BigInteger) {
return toBigDecimal(instance).compareTo(toBigDecimal(((Number) value))) >= 0;
}
// approx.
return instance.doubleValue() >= ((Number) value).doubleValue();
}
return false;
}
public static double remainder(Number instance, Number value) {
// for big numbers, go slow
if (instance instanceof BigDecimal || value instanceof BigDecimal || instance instanceof BigInteger || value instanceof BigInteger) {
return toBigDecimal(instance).remainder(toBigDecimal(value)).doubleValue();
}
// for floating point use double
if (instance instanceof Double || value instanceof Double || instance instanceof Float || value instanceof Float) {
return instance.doubleValue() % value.doubleValue();
}
// for integer use long
return instance.longValue() % value.doubleValue();
}
public static boolean equals(Number a, Number b) {
if (a == null || b == null) {
return false;
}
if (isInteger(a) && isInteger(b)) {
// expensive path
if (a instanceof BigInteger || b instanceof BigInteger) {
return toBigDecimal(a).equals(toBigDecimal(b));
}
// compute using long
return a.longValue() == b.longValue();
}
if (a instanceof BigDecimal || b instanceof BigDecimal) {
// expensive path
return toBigDecimal(a).equals(toBigDecimal(b));
}
// approx. with double value
return a.doubleValue() == b.doubleValue();
}
}
static class Strings {
public static boolean notEmpty(String string) {
return string != null && string.length() > 0;
}
public static boolean empty(String string) {
return string == null || string.length() == 0;
}
/**
* Get UCS-2 length of a string
* https://mathiasbynens.be/notes/javascript-encoding
* https://github.com/bestiejs/punycode.js - punycode.ucs2.decode
*/
public static int ucs2length(String s) {
int result = 0;
int length = s.length();
int index = 0;
char charCode;
while (index < length) {
result++;
charCode = s.charAt(index++);
if (charCode >= 0xd800 && charCode <= 0xdbff && index < length) {
// high surrogate, and there is a next character
charCode = s.charAt(index);
if ((charCode & 0xfc00) == 0xdc00) {
// low surrogate
index++;
}
}
}
return result;
}
}
static class JSON {
public static Object jsonify(Object instance) {
if (instance instanceof Map) {
return new JsonObject((Map) instance);
}
if (instance instanceof List) {
return new JsonArray((List) instance);
}
return instance;
}
public static String typeOf(Object instance) {
if (instance == null) {
return "null";
}
if (instance instanceof Boolean) {
return "boolean";
}
if (instance instanceof Number) {
return "number";
}
if (instance instanceof String) {
return "string";
}
if (instance instanceof JsonObject) {
return "object";
}
if (instance instanceof JsonArray) {
return "array";
}
// nothing can be evaluated for the given instance
throw new IllegalArgumentException("Instances of " + instance.getClass() + " type are not supported");
}
public static boolean deepCompare(Object a, Object b) {
final String typeofa = typeOf(a);
if (!typeofa.equals(typeOf(b))) {
return false;
}
if (a instanceof JsonArray) {
if (!(b instanceof JsonArray)) {
return false;
}
final int length = ((JsonArray) a).size();
if (length != ((JsonArray) b).size()) {
return false;
}
for (int i = 0; i < length; i++) {
if (!deepCompare(((JsonArray) a).getValue(i), ((JsonArray) b).getValue(i))) {
return false;
}
}
return true;
}
if ("object".equals(typeofa)) {
if (a == null || b == null) {
return a == b;
}
final Set aKeys = ((JsonObject) a).fieldNames();
final Set bKeys = ((JsonObject) b).fieldNames();
final int length = aKeys.size();
if (length != bKeys.size()) {
return false;
}
for (String k : aKeys) {
if (!deepCompare(((JsonObject) a).getValue(k), ((JsonObject) b).getValue(k))) {
return false;
}
}
return true;
}
return Objects.equals(a, b);
}
}
public static class Pointers {
private static final String genDelims = ":?#@"; // except /[]
private static final String subDelims = "!$&'()*+,;=";
private static final String unreserved = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-._"; // except ~
private static final String okChars = genDelims + subDelims + unreserved;
public static String encode(String p) {
StringBuilder encoded = new StringBuilder(p.length());
byte[] bytes = p.getBytes(StandardCharsets.UTF_8);
for (byte aByte : bytes) {
if (okChars.indexOf(aByte) >= 0) {
encoded.append((char) aByte);
} else {
// escape
if (aByte == '~') {
encoded.append("~0");
continue;
}
if (aByte == '/') {
encoded.append("~1");
continue;
}
// encode
encoded
.append('%')
.append(Integer.toHexString(Byte.toUnsignedInt(aByte)).toUpperCase(Locale.ROOT));
}
}
return encoded.toString();
}
public static String unescape(String p) {
return p
.replaceAll("~1", "/")
.replaceAll("~0", "~");
}
public static String escape(String p) {
return p
.replaceAll("~", "~0")
.replaceAll("/", "~1");
}
}
static class Objects {
public static boolean equals(Object a, Object b) {
if (a == null && b == null) {
return true;
}
if (a == null) {
return false;
}
if (b == null) {
return false;
}
if (a instanceof Number && b instanceof Number) {
return Numbers.equals((Number) a, (Number) b);
}
return a.equals(b);
}
public static boolean truthy(Object instance) {
if (instance == null) {
return false;
}
if (instance instanceof Boolean) {
return (Boolean) instance;
}
if (instance instanceof String) {
return ((String) instance).length() > 0;
}
if (instance instanceof Number) {
return Numbers.ze((Number) instance);
}
return false;
}
public static boolean isObject(Object instance) {
return instance instanceof JsonObject || instance instanceof JsonArray;
}
}
static class Schemas {
public static JsonSchema wrap(JsonObject object, String key) {
Object value = object.getValue(key);
if (value == null) {
return null;
}
if (value instanceof JsonSchema) {
return (JsonSchema) value;
}
if (value instanceof Boolean) {
return (Boolean) value ?
BooleanSchema.TRUE :
BooleanSchema.FALSE;
}
if (value instanceof JsonObject) {
JsonSchema schema = new JsonObjectSchema((JsonObject) value);
object.put(key, schema);
return schema;
}
// any other type cannot be converted is ignored
return null;
}
public static JsonSchema wrap(JsonArray array, int index) {
Object value = array.getValue(index);
if (value == null) {
return null;
}
if (value instanceof JsonSchema) {
return (JsonSchema) value;
}
if (value instanceof Boolean) {
return (Boolean) value ?
BooleanSchema.TRUE :
BooleanSchema.FALSE;
}
if (value instanceof JsonObject) {
JsonSchema schema = new JsonObjectSchema((JsonObject) value);
array.set(index, schema);
return schema;
}
// any other type cannot be converted is ignored
return null;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy