io.github.kits.json.parser.JsonParser Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of whimthen-kits Show documentation
Show all versions of whimthen-kits Show documentation
Easy to use java tool library.
The newest version!
package io.github.kits.json.parser;
import io.github.kits.EnvKit;
import io.github.kits.ReflectKit;
import io.github.kits.StringKit;
import io.github.kits.annotations.IgnoreJsonSerialize;
import io.github.kits.annotations.JsonCamelCase;
import io.github.kits.annotations.JsonSerializeName;
import io.github.kits.annotations.NoneSerializeNull;
import io.github.kits.exception.JsonParseException;
import io.github.kits.json.JsonKit;
import io.github.kits.json.tokenizer.JsonToken;
import io.github.kits.json.tokenizer.JsonTokenList;
import io.github.kits.json.tokenizer.JsonTokenType;
import io.github.kits.json.tokenizer.JsonTokenizer;
import java.io.IOException;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import static io.github.kits.json.tokenizer.JsonTokenType.BEGIN_ARRAY;
import static io.github.kits.json.tokenizer.JsonTokenType.BEGIN_OBJECT;
import static io.github.kits.json.tokenizer.JsonTokenType.BOOLEAN;
import static io.github.kits.json.tokenizer.JsonTokenType.END_ARRAY;
import static io.github.kits.json.tokenizer.JsonTokenType.END_OBJECT;
import static io.github.kits.json.tokenizer.JsonTokenType.NULL;
import static io.github.kits.json.tokenizer.JsonTokenType.NUMBER;
import static io.github.kits.json.tokenizer.JsonTokenType.OBJECT;
import static io.github.kits.json.tokenizer.JsonTokenType.SEP_COLON;
import static io.github.kits.json.tokenizer.JsonTokenType.SEP_COMMA;
import static io.github.kits.json.tokenizer.JsonTokenType.STRING;
/**
* @project: kits
* @created: with IDEA
* @author: whimthen
* @date: 2019-03-05-14:15 | March. Tuesday
*/
public class JsonParser {
private final JsonTokenizer tokenizer = new JsonTokenizer();
private JsonTokenList tokens;
/**
* Convert jsonTokenizer to JsonObject or JsonArray
*
* @return JsonObject or JsonArray
*/
private Object parse() {
JsonToken token = tokens.next();
if (token == null) {
return new JsonObject();
} else if (token.getTokenType() == BEGIN_OBJECT) {
return parseJsonObject();
} else if (token.getTokenType() == BEGIN_ARRAY) {
return parseJsonArray();
} else {
throw new JsonParseException("Parse error, invalid JsonToken.");
}
}
/**
* Convert a JSON string to a List collection
* {@code
* public class Case {
* private boolean json;
*
* getter and setter .......
* }
*
* List cases = JsonKit.toList("[{\"json\": true}, {\"json\": false}]", Case.class);
* }
*
* @param json JSON String
* @param tClass List Type
* @param Generic
* @return List
* @throws IOException IOException
*/
public List parseList(String json, Class tClass) throws IOException {
this.tokens = tokenizer.tokenize(json);
Object object = parse();
if (object instanceof JsonArray) {
JsonArray jsonArray = (JsonArray) object;
if (JsonObject.class.isAssignableFrom(tClass)) {
throw new JsonParseException("JsonArray can not be cast JsonObject.");
}
if (JsonArray.class.isAssignableFrom(tClass)) {
return jsonArray.getList();
}
ArrayList arrayList = new ArrayList<>();
if (jsonArray.getList()
.isEmpty()) {
return arrayList;
}
jsonArray.getList()
.forEach(jsonObject -> {
try {
arrayList.add(convertObject((JsonObject) jsonObject, tClass));
} catch (ReflectiveOperationException e) {
throw new JsonParseException(e);
}
});
return arrayList;
}
return new ArrayList<>();
}
/**
* Convert a JSON string to an object
* {@code
* public class User {
* private int userId;
* private String userName;
*
* getter and setter .......
* }
*
* User user = JsonKit.toObject("{\"userId\": 1, \"userName\": \"whimthen\"}", User.class);
* }
*
* @param json JSON String
* @param tClass Object Type
* @param Generic
* @return Object
* @throws ReflectiveOperationException Abnormal reflection operation
* @throws IOException IOException
*/
public T parseObject(String json, Class tClass) throws ReflectiveOperationException, IOException {
this.tokens = tokenizer.tokenize(json);
Object object = parse();
if (object instanceof JsonObject) {
if (JsonArray.class.isAssignableFrom(tClass)) {
throw new JsonParseException("JsonObject can not be cast JsonArray.");
}
if (JsonObject.class.isAssignableFrom(tClass)) {
return (T) object;
}
return convertObject((JsonObject) object, tClass);
}
return (T) object;
}
/**
* Convert Object to JSON String
* {@code
* User user = new User();
* user.setUserId(1);
* user.setUserName(\"whimthen\");
*
* String json = JsonKit.toJson(user);
* // json = {\"userId\": 1, \"userName\": \"whimthen\"}
* }
*
* @param object Object
* @return JsonString
*/
public String toJson(Object object) {
if (Objects.isNull(object)) {
return NULL.getValue();
}
Class> aClass = object.getClass();
JsonTokenList jsonTokenList = new JsonTokenList();
if (object instanceof Collection) {
jsonTokenList.add(new JsonToken(BEGIN_ARRAY));
((Collection) object).forEach(val -> listOrMapAddJsonTokenList(jsonTokenList, val));
return getStringFromJsonTokenList(jsonTokenList, END_ARRAY);
} else if (Map.class.isAssignableFrom(aClass)) {
jsonTokenList.add(new JsonToken(BEGIN_OBJECT));
((Map) object).forEach((k, v) -> {
jsonTokenList.add(new JsonToken(STRING, k));
jsonTokenList.add(new JsonToken(SEP_COLON));
listOrMapAddJsonTokenList(jsonTokenList, v);
});
return getStringFromJsonTokenList(jsonTokenList, END_OBJECT);
} else if (aClass.equals(JsonObject.class)) {
return toJson(((JsonObject) object).getEntry());
} else if (CharSequence.class.isAssignableFrom(object.getClass())) {
return object.toString();
} else if (EnvKit.isBasicType(aClass) || aClass.isPrimitive()) {
return object.toString();
} else if (EnvKit.isSystemType(aClass)) {
return object.toString();
} else {
jsonTokenList.add(new JsonToken(BEGIN_OBJECT));
}
NoneSerializeNull serializeNull = aClass.getAnnotation(NoneSerializeNull.class);
AtomicBoolean isSerializeNull = new AtomicBoolean(Objects.isNull(serializeNull));
ReflectKit.getFields(aClass)
.forEach(field -> complexJsonTokenListForObject(object, jsonTokenList, isSerializeNull, field));
jsonTokenList.remove(jsonTokenList.size() - 1);
jsonTokenList.add(new JsonToken(END_OBJECT));
return toJsonString(jsonTokenList);
}
private String getStringFromJsonTokenList(JsonTokenList jsonTokenList, JsonTokenType endTokenType) {
if (jsonTokenList.size() - 1 > 0) {
jsonTokenList.remove(jsonTokenList.size() - 1);
}
jsonTokenList.add(new JsonToken(endTokenType));
return toJsonString(jsonTokenList);
}
private void listOrMapAddJsonTokenList(JsonTokenList jsonTokenList, Object v) {
JsonToken valueType = getValueType(v.getClass(), v.toString());
if (Objects.nonNull(valueType)) {
jsonTokenList.add(valueType);
} else {
jsonTokenList.add(new JsonToken(OBJECT, toJson(v)));
}
jsonTokenList.add(new JsonToken(SEP_COMMA));
}
private void complexJsonTokenListForObject(Object object, JsonTokenList jsonTokenList, AtomicBoolean isSerializeNull, Field field) {
try {
if (isSerializeNull.get()) {
isSerializeNull.set(Objects.isNull(field.getAnnotation(NoneSerializeNull.class)));
}
IgnoreJsonSerialize ignoreJson = field.getAnnotation(IgnoreJsonSerialize.class);
if (Objects.isNull(ignoreJson)) {
String name = field.getName();
JsonSerializeName serializeName = field.getAnnotation(JsonSerializeName.class);
if (Objects.nonNull(serializeName)) {
name = serializeName.value();
}
if (!field.isAccessible()) {
field.setAccessible(true);
}
Object value = field.get(object);
boolean isNotNullValue = Objects.nonNull(value);
boolean isSerializeNullOrNotNullValue = isSerializeNull.get() || isNotNullValue;
if (isSerializeNullOrNotNullValue) {
jsonTokenList.add(new JsonToken(STRING, name));
jsonTokenList.add(new JsonToken(SEP_COLON));
}
if (isNotNullValue) {
JsonToken jsonToken = getValueType(field.getType(), value.toString());
if (Objects.isNull(jsonToken)) {
jsonTokenList.add(new JsonToken(OBJECT, toJson(field.get(object))));
} else {
jsonTokenList.add(jsonToken);
}
} else if (isSerializeNull.get()) {
jsonTokenList.add(new JsonToken(NULL));
}
if (isSerializeNullOrNotNullValue) {
jsonTokenList.add(new JsonToken(SEP_COMMA));
}
}
} catch (IllegalAccessException ex) {
throw new JsonParseException(ex);
}
}
/**
* Convert JsonTokenList to JsonString
*
* @param tokens JsonTokenList
* @return JsonString
*/
private String toJsonString(JsonTokenList tokens) {
if (Objects.isNull(tokens) || tokens.size() <= 0) {
return null;
}
StringBuilder json = new StringBuilder();
while (tokens.hasMore()) {
JsonToken jsonToken = tokens.next();
switch (jsonToken.getTokenType()) {
case BEGIN_OBJECT:
case END_OBJECT:
case BEGIN_ARRAY:
case END_ARRAY:
case END_DOCUMENT:
case NULL:
case OBJECT:
json.append(jsonToken.getValue());
break;
case SEP_COMMA:
case SEP_COLON:
json.append(jsonToken.getValue()).append(" ");
break;
case STRING:
json.append("\"").append(jsonToken.getValue()).append("\"");
break;
case NUMBER:
if (jsonToken.getValue().contains(".")) {
json.append(Double.valueOf(jsonToken.getValue()));
} else {
json.append(Long.valueOf(jsonToken.getValue()));
}
break;
case BOOLEAN:
json.append(Boolean.valueOf(jsonToken.getValue()));
break;
}
}
return json.toString();
}
/**
* Get the corresponding JsonToken
* according to the Field type, and assign the value
*
* @param type Field
* @param value Value
* @return JsonToken
*/
private JsonToken getValueType(Class> type, String value) {
if (type.equals(Boolean.class) || type.equals(boolean.class)) {
return new JsonToken(BOOLEAN, value);
} else if (type.equals(Short.class) || type.equals(short.class)
|| type.equals(Integer.class) || type.equals(int.class)
|| type.equals(Long.class) || type.equals(long.class)
|| type.equals(Float.class) || type.equals(float.class)
|| type.equals(Double.class) || type.equals(double.class)
|| type.equals(BigDecimal.class)) {
return new JsonToken(NUMBER, value);
} else if (CharSequence.class.isAssignableFrom(type)) {
return new JsonToken(STRING, value);
}
return null;
}
/**
* Convert a JsonObject to a specific type of object
*
* @param object JsonObject
* @param tClass Object Type
* @param Generic
* @return Object
* @throws ReflectiveOperationException Abnormal reflection operation
*/
private T convertObject(JsonObject object, Class tClass) throws ReflectiveOperationException {
T t;
if (CharSequence.class.isAssignableFrom(tClass)) {
if (object.size() != 0) {
return (T) object.getEntry();
} else {
return null;
}
} else if (EnvKit.isBasicType(tClass)) {
// generic type
if (CharSequence.class.isAssignableFrom(tClass)) {
return (T) JsonKit.toJson(object.getEntry());
} else {
throw new JsonParseException("JsonToken can not parse to basic type");
}
} else if (Collection.class.isAssignableFrom(tClass)) {
// Collection Type
ArrayList