Первоначально я решил ту же проблему с помощью механизма расширений, который я документирую здесь
Но я обнаружил, что код на Java, необходимый для работы с расширениями, был ужасно уродлив и многословен, поэтому япереключился на метод объединения, как описано.Код намного чище, поскольку сгенерированный код Java предоставляет способ получить и построить каждое сообщение за один раз.
Я использую два механизма для принятия решения, какое необязательное сообщение извлечь.Я использую метод переключения, также описанный в другом Ответе, когда требуется производительность, и я использую метод отражения, когда производительность не является проблемой, и я не хочу поддерживать оператор переключения, я просто создаю дескриптор (Сообщение) для каждогосообщение.Пример метода отражения приведен ниже, в моем случае java-оболочка - это класс с именем Commands, который декодируется Netty для меня.Сначала он пытается найти обработчик, который имеет конкретное сообщение в качестве параметра, затем, если это не удается, он вызывает метод с использованием имени случая верблюда.Чтобы это работало, Enum должен быть именем подчеркивания сообщения о случае верблюда.
// 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());
}