I initially solved the same problem using the extension mechanism that I am documenting here
But I found that the Java code needed to work with extensions was terribly ugly and verbose, so I switched to the Union method as described. The code is much cleaner because the generated Java code provides a way to receive and assemble each message at a time.
I use two mechanisms to determine which additional message to retrieve. I use the switch method, also described in another answer when performance is required, and I use the reflection method when performance is not a problem, and I do not want to support the switch statement, I just create a Message handle for each message. The following is an example of the reflection method, in my case the java shell is a class called Commands, and Netty is decoded for me. First, he tries to find a handler that has a specific message as a parameter, and then, if that fails, he calls a method that uses the name of the camel case. For this to work, Enum must have an underlined name for the camel case report.
// Helper that stops me having to create a switch statement for every command // Relies on the Cmd enum naming being uppercase version of the sub message field names // Will call the appropriate handle(Message) method by reflection // If it is a command with no arguments, therefore no sub message it // constructs the method name from the camelcase of the command enum private MessageLite invokeHandler(Commands.Command cmd) throws Exception { Commands.Command.Cmd com= cmd.getCmd(); //String name= CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_UNDERSCORE, com.name()); String name= com.name().toLowerCase(); jlog.debug("invokeHandler() - Looking up {} from {}", name, com.name()); FieldDescriptor field= Commands.Command.getDescriptor().findFieldByName(name); if(field != null) { // if we have a matching field then extract it and call the handle method with that as a parameter Object c = cmd.getField(field); jlog.debug("invokeHandler() - {}\n{}", c.getClass().getCanonicalName(), c); Method m = getClass().getDeclaredMethod("handle", String.class, c.getClass()); return (MessageLite) m.invoke(this, cmd.getUser(), c); } // else we call a method with the camelcase name of the Cmd, this is for commands that take no arguments other than the user String methodName= "handle"+CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, com.name()); jlog.debug("invokeHandler() - using method: {}", methodName); Method m = getClass().getDeclaredMethod(methodName, String.class); return (MessageLite) m.invoke(this, cmd.getUser()); }
source share