How to create dynamic nested object message in protoBuff? - protocol-buffers

Am trying to create a message of nested dynamic objects
The resulting ending data structure should look like this
"content": {
"foo1": "bar1",
"foo2": "bar2"
}
Where the keys and, the values inside the content is dynamic and can be defined by the client.

You can define content as a map<string, string>, so that clients can set any arbitrary key-value pairs (of string type) to it.
message Msg {
map<string, string> content = 1;
}
If the value might be any arbitrary types, you can try google.protobuf.Struct.

Related

How to add message type as object in ProtoBuf (gRPC) - Proto3 Syntax?

How to send message type as object in ProtoBuf - Proto3 Syntax?
I want to transfer object instead of string or number.
Example
{
name: 'One',
date: 'date',
some: 'some',
...
...
}
syntax = "proto3";
package db;
service Proxy
{
rpc myFunction(Request) returns (Response);
}
message Request
{
string name = 1;
}
message Response
{
object keyvalue = 1;
}
Here, I am getting error
throw Error("no such Type or Enum '" + path + "' in " + this);
^
Error: no such Type or Enum 'object' in Type
--
Workaround
I can convert it to string in server side, and then I can JSON.parse() at client.
But I want to know, if there any better way to do it.
protocol-buffer does not support the object data type!
But you can emulate your data as hierarchically by using protocol buffer message type itself.
syntax = "proto3";
package db;
service Proxy
{
rpc myFunction(Request) returns (Response);
}
message Request
{
string name = 1;
}
message Response
{
message obj {
string key1 = 1;
string key2 = 2
}
obj keyvalue = 1; // Here you have created your own type obj.
}
In the above example, you can see that the Response message now has "keyvalue" field of type obj(which is a custom type you have just built).
Now you will pass Object in a callback from the server instead of primitive type.
callback(null, { keyvalue: { key1: "value1", key2: "value2" } });
Let's say if keys are unknown to you but key/value pair data type is same and known to you then, in this case, you can use
map<type, type>
message Response
{
map<string, string> keyvalue = 1;
}
callback(null, { keyvalue: { "key1": "value1", "key5": "value2" } });
References:-
https://developers.google.com/protocol-buffers/docs/proto3#other
https://developers.google.com/protocol-buffers/docs/proto#scalar
https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#google.protobuf.Struct
Depending on what you're trying to accomplish, you can likely use one of three types.
The bytes type represents an arbitrary string of bytes. You can choose to encode your types in anyway you feel appropriate.
The any type represents an arbitrary protobuf message, allowing the client or server to encode non-predefined messages. This is a string of bytes, with a unique identifier per message type and language implementations will have ways to unpack the message.
You mention using Javascript. You could likely define a Javascript object message using a combination of oneof for the basic types and map for object types.
If all of the keys and values you want to send have the same type, you can use a map type. Your example shows string keys and string values, so that could use the type map<string, string>.
If you want to send arbitrary object data with similar structure to JSON objects, you can use the google.protobuf.Struct message type.

Spring Mongo mapping variable data

I'm using Spring Data MongoDB for my project. I work with a mongo database containing a lot of data, and I want to map this data within my Java application.
The problem I have is that some data back in time had a different structure.
For example sport_name is an array now, while in some old records is a String:
sport_name: "Soccer" // Old data
sport_name: [ // Most recent entries
{
"lang" : "en",
"val" : "Soccer"
},
{
"lang" : "de",
"val" : "Fussball"
}
]
Here is what I have until now:
#Document(collection = "matches")
public class MatchMongo {
#Id
private String id;
private ??? sport_name; // Best way?!
(What's the best way to)/(How would you) handle something like this?
If old data can be considered as "en" language, then separate structure can be used to store localized text:
class LocalName {
private String language;
private String text;
// getters/setters
}
So mapped object will store the collection of localized values:
public class MatchMongo {
// it can also be a map (language -> text),
// in this case we don't need additional structure
private List<LocalName> names;
}
This approach can be combined with custom converter, to use plain string as "en" locale value:
public class MatchReadConverter implements Converter<DBObject, MatchMongo> {
public Person convert(DBObject source) {
// check what kind of data located under "sport_name"
// and define it as "en" language text if it is an old plain text
// if "sport_name" is an array, then simply convert the values
}
}
Custom mapping is described here in details.
Probably you can write a utility class which will fetch all the data where sport_name is not an array and update the element sport_name to array. But this all depends on the amount of data you have.
You can use query {"sport_name":{$type:2}}, here 2 stands for String.
Refer for more details on $type: http://docs.mongodb.org/manual/reference/operator/query/type/

Are there simple way to receive Map instead of List when using Spring JdbcTemplate.query?

getSimpleJdbcTemplate().query(sql, getMapper()); returns List, but I need a Map where key will be store data of one of the field of object. For example, I have object named "Currency" which has fields: id, code, name, etc. Code above will return List object, but I want to get currency by id from Map. Now, I wrote the following code:
#Override
public Map<Integer, Currency> listCurrencies() {
String sql = "select cur_id, cur_code, cur_name ... from currencies";
List<Currency> currencies = getSimpleJdbcTemplate().query(sql, getMapper());
Map<Integer, Currency> map = new HashMap<Integer, Currency>(currencies.size());
for (Currency currency : currencies) {
map.put(currency.getId(), currency);
}
return map;
}
Are there any way to do same but without creating List object and looping inside it?
You have ResultSetExtractor for extracting values from the ResultSet. So in your case you can write a custom ResultSetExtractor which will return you the Map object.

C# Dictionary LINQ

I have a class that returns all items in a database table (Code below). I also have a dictionary that contains key,value pair. Before I return the data from my function, can I look inside the dictionary and return the value that's associated with the key from my linq?
public IEnumerable<Code> Return_All_Codes()
{
return _db.Codes.ToList();
//can the above list look inside my dictionary below and return Administrative when it find the number 1 for my code type?
}
public Dictionary<int, string> GetCodeTypes()
{
var dict = new Dictionary<int, string>();
dict.Add(1, "Administrative");
dict.Add(2, "Regular");
return dict;
}
Can the above list look inside my dictionary and return Administrative when it finds the number 1 for my code type? Kind of an IF statement inside my LINQ? If 1 then Administrative, else Regular.
You can do this mapping via:
var dict = GetCodeTypes();
return _db.Codes.AsEnumerable().Select(code => dict[code.cType]).ToList();
However, I'd recommend storing the dictionary in your class to prevent creating it each time, especially if this is called many times.

XmlReader.ReadContentAsObject always returns string type

According to the MSDN documentation, XMLWriter.WriteValue writes xsd type information to the xml for simple CLR types. Then XMLReader.ReadContentAsObject supposedly reads out the appropriately-typed object when the XML is parsed. However, this always seems to return a string object for me and the ValueType property of the XMLReader is string. I've tried inserting longs and DateTimes, but they always end up as strings. Any ideas what I'm doing wrong or is this a Windows Phone bug?
XML Writing Code
public void WriteXml(XmlWriter writer) {
// KeyValuePair<string, object> pair initialized previously
writer.WriteStartElement(pair.Key);
writer.WriteValue(pair.Value)
writer.WriteEndElement();
}
XML Parsing Code
public void ReadXml(XMLReader reader) {
while (reader.Read()) {
if (reader.NodeType == XmlNodeType.Element) {
Type T = reader.ValueType; // T is string
reader.ReadStartElement();
object o = reader.ReadContentAsObject(); // o is string
o = reader.ReadContentAs(T, null); // o is string
}
}
}
You need to use a schema file (XSD) so that the framework can infer the type of a node. Otherwise ValueType will always return System.String.
MSDN says:
If a validation error occurs while parsing the content and the reader is an XmlReader object created by the Create method, the reader returns the content as a string. In other words when a validation error or warning occurs, the content is considered to be untyped.
I was making this too difficult. My goal was to serialize a Dictionary with generic type (string, object) by traversing its KeyValuePairs , but that class doesn't seem to be serializeable using XmlSerializer. I just created another class with two public properties, Key and Value, so I could use XmlSerializer. When deserializing with XmlSerializer, the type of Value is restored as long as it is a supported CLR type.
public void WriteXml(XmlWriter writer) {
// KeyValuePair<string, object> pair initialized previously
writer.WriteStartElement("entry");
MyClass toSerialize = new MyClass(pair.Key, pair.Value);
XmlSerializer serializer = new XmlSerializer(typeof(MyClass));
serializer.Serialize(writer, toSerialize);
writer.WriteEndElement();
}

Resources