use of net.morimekta.util.json.JsonToken in project providence by morimekta.
the class JsonSerializer method parseMapKey.
private Object parseMapKey(String key, PDescriptor keyType) throws SerializerException {
try {
switch(keyType.getType()) {
case BOOL:
if (key.equalsIgnoreCase("true")) {
return Boolean.TRUE;
} else if (key.equalsIgnoreCase("false")) {
return Boolean.FALSE;
}
throw new SerializerException("Invalid boolean value: \"" + Strings.escape(key) + "\"");
case BYTE:
return Byte.parseByte(key);
case I16:
return Short.parseShort(key);
case I32:
return Integer.parseInt(key);
case I64:
return Long.parseLong(key);
case DOUBLE:
try {
JsonTokenizer tokenizer = new JsonTokenizer(new ByteArrayInputStream(key.getBytes(StandardCharsets.US_ASCII)));
JsonToken token = tokenizer.next();
if (!token.isNumber()) {
throw new SerializerException("Unable to parse double from key \"" + key + "\"");
} else if (tokenizer.hasNext()) {
throw new SerializerException("Garbage after double: \"" + key + "\"");
}
return token.doubleValue();
} catch (SerializerException e) {
throw e;
} catch (JsonException | IOException e) {
throw new SerializerException(e, "Unable to parse double from key \"" + key + "\"");
}
case STRING:
return key;
case BINARY:
try {
return Binary.fromBase64(key);
} catch (IllegalArgumentException e) {
throw new SerializerException(e, "Unable to parse Base64 data");
}
case ENUM:
PEnumBuilder<?> eb = ((PEnumDescriptor<?>) keyType).builder();
if (Strings.isInteger(key)) {
eb.setById(Integer.parseInt(key));
} else {
eb.setByName(key);
}
if (readStrict && !eb.valid()) {
throw new SerializerException("\"%s\" is not a known enum value for %s", Strings.escape(key), keyType.getQualifiedName());
}
return eb.build();
case MESSAGE:
PMessageDescriptor<?, ?> st = (PMessageDescriptor<?, ?>) keyType;
if (!st.isSimple()) {
throw new SerializerException("Only simple structs can be used as map key. %s is not.", st.getQualifiedName());
}
ByteArrayInputStream input = new ByteArrayInputStream(key.getBytes(StandardCharsets.UTF_8));
try {
JsonTokenizer tokenizer = new JsonTokenizer(input);
if (JsonToken.kMapStart == tokenizer.expectSymbol("message start", JsonToken.kMapStart, JsonToken.kListStart)) {
return parseMessage(tokenizer, st);
} else {
return parseCompactMessage(tokenizer, st);
}
} catch (JsonException | IOException e) {
throw new SerializerException(e, "Error parsing message key: " + e.getMessage());
}
default:
throw new SerializerException("Illegal key type: %s", keyType.getType());
}
} catch (NumberFormatException nfe) {
throw new SerializerException(nfe, "Unable to parse numeric value %s", key);
}
}
use of net.morimekta.util.json.JsonToken in project providence by morimekta.
the class JsonSerializer method parseServiceCall.
@SuppressWarnings("unchecked")
private <T extends PMessage<T, F>, F extends PField> PServiceCall<T, F> parseServiceCall(JsonTokenizer tokenizer, PService service) throws IOException {
PServiceCallType type = null;
String methodName = null;
int sequence = 0;
try {
tokenizer.expectSymbol("service call start", JsonToken.kListStart);
methodName = tokenizer.expectString("method name").rawJsonLiteral();
tokenizer.expectSymbol("entry sep", JsonToken.kListSep);
JsonToken callTypeToken = tokenizer.expect("call type");
if (callTypeToken.isInteger()) {
int typeKey = callTypeToken.byteValue();
type = PServiceCallType.findById(typeKey);
if (type == null) {
throw new SerializerException("Service call type " + typeKey + " is not valid").setExceptionType(PApplicationExceptionType.INVALID_MESSAGE_TYPE);
}
} else if (callTypeToken.isLiteral()) {
String typeName = callTypeToken.rawJsonLiteral();
type = PServiceCallType.findByName(typeName.toUpperCase(Locale.US));
if (type == null) {
throw new SerializerException("Service call type \"" + Strings.escape(typeName) + "\" is not valid").setExceptionType(PApplicationExceptionType.INVALID_MESSAGE_TYPE);
}
} else {
throw new SerializerException("Invalid service call type token " + callTypeToken.asString()).setExceptionType(PApplicationExceptionType.INVALID_MESSAGE_TYPE);
}
tokenizer.expectSymbol("entry sep", JsonToken.kListSep);
sequence = tokenizer.expectNumber("Service call sequence").intValue();
tokenizer.expectSymbol("entry sep", JsonToken.kListSep);
if (type == PServiceCallType.EXCEPTION) {
PApplicationException ex = (PApplicationException) parseTypedValue(tokenizer.expect("Message start"), tokenizer, PApplicationException.kDescriptor, false);
tokenizer.expectSymbol("service call end", JsonToken.kListEnd);
return (PServiceCall<T, F>) new PServiceCall<>(methodName, type, sequence, ex);
}
PServiceMethod method = service.getMethod(methodName);
if (method == null) {
throw new SerializerException("No such method " + methodName + " on " + service.getQualifiedName()).setExceptionType(PApplicationExceptionType.UNKNOWN_METHOD);
}
@SuppressWarnings("unchecked") PMessageDescriptor<T, F> descriptor = isRequestCallType(type) ? method.getRequestType() : method.getResponseType();
if (descriptor == null) {
throw new SerializerException("No %s type for %s.%s()", isRequestCallType(type) ? "request" : "response", service.getQualifiedName(), methodName).setExceptionType(PApplicationExceptionType.UNKNOWN_METHOD);
}
T message = (T) parseTypedValue(tokenizer.expect("message start"), tokenizer, descriptor, false);
tokenizer.expectSymbol("service call end", JsonToken.kListEnd);
return new PServiceCall<>(methodName, type, sequence, message);
} catch (SerializerException se) {
throw new SerializerException(se).setMethodName(methodName).setCallType(type).setSequenceNo(sequence);
} catch (JsonException je) {
throw new JsonSerializerException(je).setMethodName(methodName).setCallType(type).setSequenceNo(sequence);
}
}
use of net.morimekta.util.json.JsonToken in project providence by morimekta.
the class JsonSerializer method parseMessage.
private <T extends PMessage<T, F>, F extends PField> T parseMessage(JsonTokenizer tokenizer, PMessageDescriptor<T, F> type) throws JsonException, IOException {
PMessageBuilder<T, F> builder = type.builder();
if (tokenizer.peek("message end or key").isSymbol(JsonToken.kMapEnd)) {
tokenizer.next();
} else {
char sep = JsonToken.kMapStart;
while (sep != JsonToken.kMapEnd) {
JsonToken token = tokenizer.expectString("field spec");
String key = token.rawJsonLiteral();
PField field;
if (Strings.isInteger(key)) {
field = type.findFieldById(Integer.parseInt(key));
} else {
field = type.findFieldByName(key);
}
tokenizer.expectSymbol("field KV sep", JsonToken.kKeyValSep);
if (field != null) {
Object value = parseTypedValue(tokenizer.expect("field value"), tokenizer, field.getDescriptor(), true);
builder.set(field.getId(), value);
} else {
consume(tokenizer.expect("field value"), tokenizer);
}
sep = tokenizer.expectSymbol("message end or sep", JsonToken.kMapEnd, JsonToken.kListSep);
}
}
if (readStrict) {
try {
builder.validate();
} catch (IllegalStateException e) {
throw new SerializerException(e, e.getMessage());
}
}
return builder.build();
}
Aggregations