package org.jetbrains.jsonProtocol; import com.google.gson.stream.JsonToken; import com.intellij.util.ArrayUtilRt; import gnu.trove.TDoubleArrayList; import gnu.trove.THashMap; import gnu.trove.TIntArrayList; import gnu.trove.TLongArrayList; import org.jetbrains.annotations.NotNull; import org.jetbrains.io.JsonReaderEx; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; public final class JsonReaders { private JsonReaders() { } private static void checkIsNull(JsonReaderEx reader, String fieldName) { if (reader.peek() == JsonToken.NULL) { throw new RuntimeException("Field is not nullable" + (fieldName == null ? "" : (": " + fieldName))); } } public static String readString(JsonReaderEx reader, String fieldName) { checkIsNull(reader, fieldName); return reader.nextString(); } public static String readRawString(JsonReaderEx reader) { return reader.nextString(true); } public static Object readRawStringOrMap(JsonReaderEx reader) { if (reader.peek() == JsonToken.BEGIN_OBJECT) { return readMap(reader, null); } else { return reader.nextString(true); } } public static String readNullableString(JsonReaderEx reader) { if (reader.peek() == JsonToken.NULL) { reader.skipValue(); return null; } return reader.nextString(); } public static boolean readBoolean(JsonReaderEx reader, String fieldName) { checkIsNull(reader, fieldName); return reader.nextBoolean(); } public static boolean readNullableBoolean(JsonReaderEx reader) { if (reader.peek() == JsonToken.NULL) { reader.skipValue(); return false; } return reader.nextBoolean(); } public static int readInt(JsonReaderEx reader, String fieldName) { checkIsNull(reader, fieldName); return reader.nextInt(); } public static int readNullableInt(JsonReaderEx reader) { if (reader.peek() == JsonToken.NULL) { reader.skipValue(); return -1; } return reader.nextInt(); } public static long readLong(JsonReaderEx reader, String fieldName) { checkIsNull(reader, fieldName); return reader.nextLong(); } public static double readDouble(JsonReaderEx reader, String fieldName) { checkIsNull(reader, fieldName); return reader.nextDouble(); } public static long readNullableLong(JsonReaderEx reader) { if (reader.peek() == JsonToken.NULL) { reader.skipValue(); return -1; } return reader.nextLong(); } public static > T readEnum(JsonReaderEx reader, String fieldName, Class enumClass) { checkIsNull(reader, fieldName); try { return Enum.valueOf(enumClass, readEnumName(reader)); } catch (IllegalArgumentException ignored) { return Enum.valueOf(enumClass, "NO_ENUM_CONST"); } } public static String convertRawEnumName(@NotNull String enumValue) { StringBuilder builder = new StringBuilder(enumValue.length() + 4); boolean prevIsLowerCase = false; for (int i = 0; i < enumValue.length(); i++) { char c = enumValue.charAt(i); if (c == '-' || c == ' ') { builder.append('_'); continue; } if (Character.isUpperCase(c)) { // second check handle "CSPViolation" (transform to CSP_VIOLATION) if (prevIsLowerCase || ((i + 1) < enumValue.length() && Character.isLowerCase(enumValue.charAt(i + 1)))) { builder.append('_'); } builder.append(c); } else { builder.append(Character.toUpperCase(c)); prevIsLowerCase = true; } } return builder.toString(); } private static String readEnumName(JsonReaderEx reader) { return convertRawEnumName(reader.nextString()); } public static > T readNullableEnum(JsonReaderEx reader, Class enumClass) { if (reader.peek() == JsonToken.NULL) { reader.skipValue(); return null; } return Enum.valueOf(enumClass, readEnumName(reader)); } public static List readObjectArray(JsonReaderEx reader, String fieldName, ObjectFactory factory, boolean nullable) { if (reader.peek() == JsonToken.NULL) { if (nullable) { reader.skipValue(); return null; } else { checkIsNull(reader, fieldName); } } reader.beginArray(); if (!reader.hasNext()) { reader.endArray(); if (nullable) { return null; } else { return Collections.emptyList(); } } List result = new ArrayList(); do { result.add(factory.read(reader)); } while (reader.hasNext()); reader.endArray(); return result; } public static Map readMap(JsonReaderEx reader, String fieldName) { checkIsNull(reader, fieldName); reader.beginObject(); if (!reader.hasNext()) { reader.endObject(); return Collections.emptyMap(); } return nextObject(reader); } public static Object read(JsonReaderEx reader) { switch (reader.peek()) { case BEGIN_ARRAY: return nextList(reader); case BEGIN_OBJECT: reader.beginObject(); return nextObject(reader); case STRING: return reader.nextString(); case NUMBER: return reader.nextDouble(); case BOOLEAN: return reader.nextBoolean(); case NULL: reader.nextNull(); return null; default: throw new IllegalStateException(); } } public static Map nextObject(JsonReaderEx reader) { Map map = new THashMap(); while (reader.hasNext()) { map.put(reader.nextName(), read(reader)); } reader.endObject(); return map; } public static List nextList(JsonReaderEx reader) { reader.beginArray(); if (!reader.hasNext()) { reader.endArray(); return Collections.emptyList(); } List list = new ArrayList(); do { //noinspection unchecked list.add((T)read(reader)); } while (reader.hasNext()); reader.endArray(); return list; } public static List readListOfPrimitive(JsonReaderEx reader) { reader.beginArray(); if (!reader.hasNext()) { reader.endArray(); return Collections.emptyList(); } List list = new ArrayList(); do { //noinspection unchecked list.add(reader.nextString(true)); } while (reader.hasNext()); reader.endArray(); return list; } public static long[] readLongArray(JsonReaderEx reader) { checkIsNull(reader, null); reader.beginArray(); if (!reader.hasNext()) { reader.endArray(); return ArrayUtilRt.EMPTY_LONG_ARRAY; } TLongArrayList result = new TLongArrayList(); do { result.add(reader.nextLong()); } while (reader.hasNext()); reader.endArray(); return result.toNativeArray(); } public static double[] readDoubleArray(JsonReaderEx reader) { checkIsNull(reader, null); reader.beginArray(); if (!reader.hasNext()) { reader.endArray(); return new double[]{0}; } TDoubleArrayList result = new TDoubleArrayList(); do { result.add(reader.nextDouble()); } while (reader.hasNext()); reader.endArray(); return result.toNativeArray(); } public static int[] readIntArray(JsonReaderEx reader) { checkIsNull(reader, null); reader.beginArray(); if (!reader.hasNext()) { reader.endArray(); return ArrayUtilRt.EMPTY_INT_ARRAY; } TIntArrayList result = new TIntArrayList(); do { result.add(reader.nextInt()); } while (reader.hasNext()); reader.endArray(); return result.toNativeArray(); } public static List readIntStringPairs(JsonReaderEx reader) { checkIsNull(reader, null); reader.beginArray(); if (!reader.hasNext()) { reader.endArray(); return Collections.emptyList(); } List result = new ArrayList(); do { reader.beginArray(); result.add(new StringIntPair(reader.nextInt(), reader.nextString())); reader.endArray(); } while (reader.hasNext()); reader.endArray(); return result; } public static JsonReaderEx createReader(CharSequence string) { return new JsonReaderEx(string); } public static boolean findBooleanField(String name, JsonReaderEx reader) { reader.beginObject(); while (reader.hasNext()) { if (reader.nextName().equals(name)) { return reader.nextBoolean(); } else { reader.skipValue(); } } return false; } }