@Override
    public Value toProto(Object val) {
        Value.Builder builder = Value.newBuilder();

        if (val == null) {
            builder.setNullValue(NullValue.NULL_VALUE);
        } else if (val instanceof Boolean) {
            builder.setBoolValue((Boolean) val);
        } else if (val instanceof Double) {
            builder.setNumberValue((Double) val);
        } else if (val instanceof String) {
            builder.setStringValue((String) val);
        } else if (val instanceof Map) {
            Map<String, Object> map = (Map<String, Object>) val;
            Struct.Builder struct = Struct.newBuilder();
            for (Map.Entry<String, Object> pair : map.entrySet()) {
                struct.putFields(pair.getKey(), toProto(pair.getValue()));
            }
            builder.setStructValue(struct.build());
        } else if (val instanceof List) {
            ListValue.Builder list = ListValue.newBuilder();
            for (Object obj : (List<Object>)val) {
                list.addValues(toProto(obj));
            }
            builder.setListValue(list.build());
        } else {
            throw new ClassCastException("cannot map to Value type: "+val);
        }
        return builder.build();
    }
Convert an {@link Object} instance into its equivalent {@link Value}
ProtoBuf object.

The {@link Value} ProtoBuf message is a variant type that can define any
value representable as a native JSON type. Consequently, this method expects
the given {@link Object} instance to be a Java object instance of JSON-native
value, namely: null, {@link Boolean}, {@link Double}, {@link String},
{@link Map}, {@link List}.

Any other values will cause an exception to be thrown.
See {@link ProtoMapper#fromProto(Value)} for the reverse mapping.

@param val a Java object that can be represented natively in JSON
@return an instance of a {@link Value} ProtoBuf message
grpc/src/main/java/com/netflix/conductor/grpc/ProtoMapper.java