Assuming Update#getMessage() is of type Message and Update#getCallbackQuery() is of type CallbackQuery:
You can make a function getUpdateAttribute that receives higher-order functions as handlers for the situation where your update has a message or callback query as follows.
private static <T> T getUpdateAttribute(Update update,
Function<Message, T> messageFunc,
Function<CallbackQuery, T> callbackQueryFunc) {
if (updateHasMessage(update)) {
return messageFunc.apply(update.getMessage());
}
if (updateHasCallbackQuery(update)) {
return callbackQueryFunc.apply(update.getCallbackQuery());
}
return null;
}
I simplified the if/else code flow to take advantage of early returns. getUpdateAttribute is also generic over T because your attributes can be various types, like Integer and String. Finally, I made it private so your public attribute fetchers are the only interface exposed. Those attribute fetchers then become:
public static Long getChatId(Update update) {
return getUpdateAttribute(
update,
Message::getChatId,
callbackQuery -> callbackQuery.getMessage().getChatId()
);
}
public static String getUserName(Update update) {
return getUpdateAttribute(
update,
message -> message.getFrom().getUserName(),
callbackQuery -> callbackQuery.getFrom().getUserName()
);
}
public static String getInputUserData(Update update) {
return getUpdateAttribute(
update,
Message::getText,
CallbackQuery::getData
);
}
public static Integer getMessageId(Update update) {
return getUpdateAttribute(
update,
Message::getMessageId,
callbackQuery -> callbackQuery.getMessage().getMessageId()
);
}
Apart from this de-duplication, there is something else you can potentially improve. I'm not familiar with the Telegram API, but if it is possible that a message may have neither a message nor a callback query, then returning null seems like a valid response, in which case you may want to return Optional<T> from getUpdateAttribute (and all the other attribute fetchers), as that would signal your intent better.