I am writing a program that works on two proto messages, I need to process the byte[] sent from different sources which sends either foo message or bar message. Since I cannot figure out which message it belongs to, I used Any Class (comes along with protobuf) to parse the byte array and
find which class it belongs to, but met with a compile time error. Is there any other method that I can use to detect if I add more proto message classes in future?
//Foo.proto
syntax = "proto3";
option java_outer_classname = "FooProto";
message Foo {
int32 a = 1;
}
and the second proto
//Bar.proto
syntax = "proto3";
option java_outer_classname = "BarProto";
message Bar {
int32 b = 1;
}
Code:
Any anyEvent = Any.parseFrom(protoBytes);
if (any.is(Foo.class)
{
Foo foo = any.unpack(Foo.class);
...
} else {
Bar bar = any.unpack(Bar.class);
...
}
Error in if statement while trying to invoke any.is() :
The method is(Class< T>) in the type Any is not applicable for the arguments (Class< Foo>)
Any doesn't mean "any"; it means "a type serialized via Any". If you didn't store it with Any: you can't decode it via Any.
The key point here is that protobuf does not include type metadata in a message payload. If you have a BLOB, you usually can't know what the message type is. Any solves that by encoding the message type in a wrapper message, but you won't have that here.
If your design is to have an API that accepts two different non-Any message types without prior knowledge of which it is: you probably have a bad design. Because that doesn't work with protobuf. On the wire, there is literally no difference between a Foo with a=42 and a Bar with b=42; the payloads are identical:
Foo with a=42 is the bytes 08 2A; Bar with b=42 is the bytes 08 2A. The 08 means "field 1, encoded as a varint", the 2A is a varint with raw value 42.
A better design might be a wrapper message specific to your scenario:
message RootMessage {
oneof test_oneof {
Foo foo = 1;
Bar bar = 2;
}
}
This adds a wrapper layer similar to how Any works, but much more efficiently - it just knows how to distinguish between your known types as an integer, rather than having to handle every possible type (as a rooted type name).
Related
I mean for example this is my messages.properties file:
BFF.ERROR.PRODUCT_NOT_FOUND = Product with {0} not found
I want to do that if the arguments array is empty, the client shouldn't see the message like this
Product with {0} not found
I want to the user see this one
Product not found.
Can I do something like that?
BFF.ERROR.PRODUCT_NOT_FOUND = Product with {0} not found | Product not found
I think u can define two keys :
BFF.ERROR.PRODUCT_NOT_FOUND = Product with {0} not found
BFF.NULL.PRODUCT_NOT_FOUND = Product not found
then deal with it in code
Why would the arguments array be empty? Can you not use two different keys and check ahead of time to use the correct message based on the arguments? They're two different messages and should have their own keys.
messages.properties
key1=message with argument {0}
key2=message without argument
Somewhere in your code
final String msg;
if (condition) {
msg = ... // if you have the argument for placeholder {0}, get message for key1
} else {
msg = ... // fallback, get message for key2
}
If you really wanted to you could look into creating a custom message source and/or supporting beans and handle this kind of thing there but it seems like more trouble than it's worth. In that case, have a look at the MessageSourceSupport class Spring provides, in particular methods formatMessage and renderDefaultMessage.
We are going to receive the two types of messages from same MQ queue. The structure of these two messages is completely different, there is no common field. I have corresponding POJO's for both the classes. How to I identify smartly which message corresponds to which POJO?
What I am currently doing is as follows:
receivedMessageClassA = objectMapper.readValue(payload, ClassA.class);
Check if the parsing above succeeds OR check if one of mandatory field is present in receivedMessageClassA.
If the above check fails, do the parsing for second class
receivedMessageClassB = objectMapper.readValue(payload, ClassB.class);
However this approach is error prone and I am not completely satisfied with it. Can someone help here please?
Well, I believe the best method is to use instanceof:
if (payload instanceof ClassA)
receivedMessageClassA = objectMapper.readValue(payload, ClassA.class);
else
receivedMessageClassB = objectMapper.readValue(payload, ClassB.class);
I have a grpc client written in GO and a grpc server written in Java (both using the same proto files (syntax 2).
My grpc method takes a message that may contain extensions. I am able to construct a message containing desired extensions on the client and send it to the server. But when I try to read the message on the server, my extensions are available as unknown fields. (In other words, entity.hasExtension(extension) in Java returns false).
So my question is whether grpc allows extensions to be used in messages that are provided as method parameters. If not, is there a way to convert an unknown field to a field of specific type?
My proto file:
syntax = "proto2";
// proto file used as source for go client and java server as well
package my_services;
import "basic_types.proto";
// import "extension_types.proto";
// do not delete: options for generating java code
option java_multiple_files = true;
option java_package = "myservice.grpc";
option java_outer_classname = "MyServiceWrapper";
option objc_class_prefix = "Foo";
// Interface exposed by the server.
service DataService {
// Obtains all objects satisfying the request message
rpc MyMethod(DataRequest) returns (DataResponse) {}
}
message DataRequest {
optional IdDefinition id = 1;
repeated basic_types.Entity templates = 2;
}
message DataResponse {
repeated IdDefinition id = 1;
optional basic_types.DataResult result = 2;
}
message IdDefinition {
optional int32 myid = 1;
}
basic_types.Entity is a basic message containing extensions:
message Entity {
extensions 1 to max;
}
and may be extended e.g. like this:
extend basic_types.Entity {
optional Foo foo = 1000;
optional Bar bar = 1001;
}
Any help or hint would be much appreciated.
In java it is possible, but you need to set an extension registry with ProtoLiteUtils.setExtensionRegistry(). This is an experimental API, and there may be a different way in the future to do this, but for the time being it should be useable.
More generally, All message encodings are supported by gRPC. We natively support Proto3, but there are a lot of existing Proto2 users that use gRPC. Since gRPC is encoding agnostic, you can even use things like thrift or JSON if you really want to, though we don't automatically generate stubs for those.
I am working on refactoring an existing application written in PowerBuilder and Java and which runs on Sybase EA Server (Jaguar). I am building a small framework to wrap around Jaguar API functions that are available in EA Server. One of the classes is to get runtime statistics from EA Server using the Monitoring class.
Without going into too much detail, Monitoring is a class in EA Server API that provides Jaguar Runtime Monitoring statistics (actual classes are in C++; EA Server provides a wrapper for these in Java, so they can be accessed through CORBA).
Below is the simplified version of my class. (I made a superclass which I inherit from for getting stats for components, conn. caches, HTTP etc).
public class JagMonCompStats {
...
public void dumpStats(String type, String entity) {
private String type = "Component";
private String entity = "web_business_rules";
private String[] header = {"Active", "Pooled", "invoke"};
// This has a lot more keys, simplified for this discussion
private static short[] compKeys = {
(short) (MONITOR_COMPONENT_ACTIVE.value),
(short) (MONITOR_COMPONENT_POOLED.value),
(short) (MONITOR_COMPONENT_INVOKE.value)
};
private double[] data = null;
...
/* Call to Jaguar API */
Monitoring jm = MonitoringHelper.narrow(session.create("Jaguar/Monitoring"));
data = jm.monitor(type, entity, keys);
...
printStats(entity, header, data);
...
}
protected void printStats(String entityName, String[] header, double[] data) {
/* print the header and print data in a formatted way */
}
}
The line data = jm.monitor is the call to Jaguar API. It takes the type of the entity, the name of the entity, and the keys of the stats we want. This method returns a double array. I go on to print the header and data in a formatted output.
The program works, but I would like to get experts' opinion on OO design aspect. For one, I want to be able to customize printStats to be able to print in different formats (for e.g., full blown report or a one-liner). Apart from this, I am also thinking of showing the stats on a web page or PowerBuilder screen, in which case printStats may not even be relevant. How would you do this in a real OO way?
Well, it's quite simple. Don't print stats from this class. Return them. And let the caller decide how the returned stats should be displayed.
Now that you can get stats, you can create a OneLinerStatsPrinter, a DetailedStatsPrinter, an HtmlStatsFormatter, or whatever you want.
I've been writing Java swing GUI code for several years but the following syntax stumps me. I'm talking about the " < R extends IPCMessage > R" portion of the method below. I found this in a library another engineer wrote and I have no idea how to use it.
I'm very familiar with the other uses of generics but this one I don't know.
Can someone explain what is going on and how I can use it?
Thank you.
/**
* Sends the specified IPC message to the process the IPC instance is
* connected to
*
* #param msg
* the IPC message to send
* #return IPCMessageRx for the received response message if want_resp is
* true null if want_resp is true and no response was received
* within the timeout null if want_resp is false
* #throws InvalidCastException if the return type doesn't match the actual
* type of the response.
*/
#SuppressWarnings("unchecked")
public <R extends IPCMessage> R sendAndGetResponse(IPCMessage msg)
{
logger.logTrace("IPClient::sendAndGetResponse: entered, msg = \"" + msg.toString() + "\"");
// keep track of whether the message sent
boolean msg_sent = send(msg);
// if the message sent and a response is wanted, try to get one from the
// received message buffer
IPCMessage back = null;
if (msg_sent == true)
{
back = receive(msg.getSequenceNumber());
}
if (back == null)
{
logger.logDebug("IPClient::send: exiting, back = null");
}
else
{
logger.logTrace("IPCClient::send: exiting, back != null");
}
return (R)back;
}
To me, using the generic this way is useless. On the top of that, the InvalidCastException will never be thrown from within the method.
It would be better to use the following code and let the caller do the cast himself:
IPCMessage sendAndGetResponse(IPCMessage msg) {...}
Well, basically the method lets you choose its return type. But because this is no safe way to use generics, a runtime exception may occur (as documented by the method), so one should always try to avoid such situations. However, sometimes it is very hard to accomplish and sometimes it is impossible at all.
Anyway, I think that this engineer was no Java expert, as he does not even adhere to the naming conventions (camel case variable names).
But now, here is what you can do with this method: Say, you have your own IPCMessage class:
class MyMessage implements IPCMessage {
// ... whatever is needed here
}
Then, you need to know that the response of the message you want to send has the type MyMessage (which could be the tough part, but I can't tell this without knowing the rest of the code) and may call:
MyMessage response = sendAndGetResponse.<MyMessage> (messageToSend);
This is a generic method. Basically, the signature of the method is saying that it will return whatever type of object you want it to return, as long as it extends IPCMessage.
The method looks not good to me because it has no guarantee that the last cast is correct. I would therefore remove the SuppressWarning annotation.
These kind of methods can be used as following:
someObject.<SomeTypeExtendingICPMessage>sendAndGetResponse(msg);
But you have to be sure that the type you pass before the method is the one you will actually receive. This looks unsafe to me. It would make a lot more sense to either pass the type as a parameter of the method so that it can check the returned type safely.