Search in sources :

Example 1 with JsonToken

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);
    }
}
Also used : JsonException(net.morimekta.util.json.JsonException) IOException(java.io.IOException) PEnumDescriptor(net.morimekta.providence.descriptor.PEnumDescriptor) ByteArrayInputStream(java.io.ByteArrayInputStream) JsonToken(net.morimekta.util.json.JsonToken) PMessageDescriptor(net.morimekta.providence.descriptor.PMessageDescriptor) JsonTokenizer(net.morimekta.util.json.JsonTokenizer)

Example 2 with JsonToken

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);
    }
}
Also used : JsonException(net.morimekta.util.json.JsonException) PServiceCallType(net.morimekta.providence.PServiceCallType) PApplicationException(net.morimekta.providence.PApplicationException) PServiceCall(net.morimekta.providence.PServiceCall) JsonToken(net.morimekta.util.json.JsonToken) PServiceMethod(net.morimekta.providence.descriptor.PServiceMethod)

Example 3 with JsonToken

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();
}
Also used : PField(net.morimekta.providence.descriptor.PField) JsonToken(net.morimekta.util.json.JsonToken)

Aggregations

JsonToken (net.morimekta.util.json.JsonToken)3 JsonException (net.morimekta.util.json.JsonException)2 ByteArrayInputStream (java.io.ByteArrayInputStream)1 IOException (java.io.IOException)1 PApplicationException (net.morimekta.providence.PApplicationException)1 PServiceCall (net.morimekta.providence.PServiceCall)1 PServiceCallType (net.morimekta.providence.PServiceCallType)1 PEnumDescriptor (net.morimekta.providence.descriptor.PEnumDescriptor)1 PField (net.morimekta.providence.descriptor.PField)1 PMessageDescriptor (net.morimekta.providence.descriptor.PMessageDescriptor)1 PServiceMethod (net.morimekta.providence.descriptor.PServiceMethod)1 JsonTokenizer (net.morimekta.util.json.JsonTokenizer)1