Использование генерации кода для создания похожих классов Java Action
Я создаю приложение с графическим интерфейсом в Java, используя платформу приложений (Netbeans Platform), которая требует большого количества почти идентичных классов для реализации чрезвычайно похожих Action
классы. Я потратил много времени, пытаясь сгенерировать эти действия программно. Несмотря на то, что я могу генерировать действия, платформа использует аннотации во время компиляции для генерации других файлов внутреннего кэша / данных, которые мне не удалось воспроизвести с помощью программного подхода.
Мне интересно, являются ли инструменты генерации кода лучшим решением, или, возможно, некоторые пользовательские аннотации, которые обертывают аннотации платформы. Возможно что-то вроде Lombok
или, может быть, плагин Maven. Но не знаю, с чего начать, и я не уверен, что это даже хороший путь для изучения. В идеале, я думаю, было бы здорово определить действия в файле данных и сгенерировать Java-код во время компиляции.
Проект с открытым исходным кодом, а также ряд других действий на github. Вот пример того, как может выглядеть шаблон: части, которые мне нужно добавить, заменены на {{string}}
, {{code}}
а также {{int}}
:
// imports omitted
@ActionID(
category = {{string}},
id = {{string}})
@ActionRegistration(
iconBase = {{string}},
displayName = "resources.MessagesBundle#" + {{string}},
lazy = false)
@ActionReferences({
@ActionReference(
path = {{string}},
position = {{int}})
})
public final class {{string}} extends AbstractAction implements UGSEventListener {
public static final String ICON_BASE = {{string}};
private BackendAPI backend;
public SoftResetAction() {
this.backend = CentralLookup.getDefault().lookup(BackendAPI.class);
this.backend.addUGSEventListener(this);
putValue("iconBase", ICON_BASE);
putValue(SMALL_ICON, ImageUtilities.loadImageIcon(ICON_BASE, false));
putValue("menuText", {{string}});
putValue(NAME, {{string}});
}
@Override
public void UGSEvent(UGSEvent cse) {
java.awt.EventQueue.invokeLater(() -> setEnabled(isEnabled()));
}
@Override
public boolean isEnabled() {
{{code}}
}
@Override
public void actionPerformed(ActionEvent e) {
{{code}}
}
}
2 ответа
Вы должны попробовать генератор кода, такой как Telosys ( http://www.telosys.org/)
Этот инструмент предназначен для такой ситуации, вам просто нужно создать шаблон для каждого типа повторяющегося класса и запустить генерацию.
Для получения дополнительной информации см. Принципы шаблонов: http://www.telosys.org/templates.html
Все бесплатно и с открытым исходным кодом, так что вы можете повторно использовать существующие шаблоны и адаптировать их в соответствии с вашими потребностями.
Несколько интересных постов об этом инструменте:
Вы можете создать общедоступный класс Action для обычного использования, как удар. Это только часть примера кода. Если у некоторых модулей есть свой собственный логический бизнес, вы можете реализовать этот PubAction для любого подкласса.
import java.awt.event.ActionEvent;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import javax.swing.AbstractAction;
public abstract class PubAction
extends AbstractAction
implements AppEventListener
{
protected ActionInterceptor interceptor;
protected IExceptionHandler exceptionHandler;
protected IActionStatusJudge actionStatusJudge = null;
public static final String TOOLBAR_SHOWNAME_KEY = "TOOLBAR_SHOWNAME_KEY";
public PubAction()
{
setShowNameInToolbar(false);
}
public String getBtnName() {
return (String)getValue("Name");
}
public void setBtnName(String btnName) {
putValue("Name", btnName);
}
public void setCode(String code)
{
putValue("Code", code);
}
public void handleEvent(AppEvent event)
{
updateStatus();
}
public void updateStatus()
{
boolean isEnable = isActionEnable();
setEnabled(getActionStatusJudge() == null ? isEnable : getActionStatusJudge().isActionEnable(this, isEnable));
}
protected boolean isActionEnable() {
return true;
}
public void setShowNameInToolbar(boolean isShow)
{
putValue("TOOLBAR_SHOWNAME_KEY", isShow ? Boolean.TRUE : Boolean.FALSE);
}
public void actionPerformed(ActionEvent e) {
Logger.debug("Entering " + getClass().toString() + ".actionPerformed");
beforeDoAction();
try
{
if ((interceptor == null) || (interceptor.beforeDoAction(this, e)))
{
try
{
doAction(e);
if (interceptor != null) {
interceptor.afterDoActionSuccessed(this, e);
}
} catch (Exception ex) {
if ((interceptor == null) || (interceptor.afterDoActionFailed(this, e, ex)))
{
if (getExceptionHandler() != null)
{
processExceptionHandler(ex);
}
else if ((ex instanceof RuntimeException))
{
throw ((RuntimeException)ex);
}
throw new RuntimeException(ex);
}
}
}
}
finally
{
Logger.debug("Leaving " + getClass().toString() + ".actionPerformed");
}
}
protected void processExceptionHandler(Exception ex)
{
new ExceptionHandlerUtil().processErrorMsg4SpecialAction(this, getExceptionHandler(), ex);
}
protected void beforeDoAction()
{
Method[] ms = getClass().getMethods();
for (Method m : ms)
{
Class<?> clazz = m.getReturnType();
if (AbstractUIAppModel.class.isAssignableFrom(clazz)) {
try
{
AbstractUIAppModel model = (AbstractUIAppModel)m.invoke(this, null);
if (model == null)
return;
LoginContext ctx = model.getContext();
if (ctx == null)
break;
ShowStatusBarMsgUtil.showStatusBarMsg("", ctx);
} catch (IllegalArgumentException e) {
Logger.debug(e.getMessage());
} catch (IllegalAccessException e) {
Logger.debug(e.getMessage());
} catch (InvocationTargetException e) {
Logger.debug(e.getMessage());
}
}
}
}
public abstract void doAction(ActionEvent paramActionEvent) throws Exception;
public ActionInterceptor getInterceptor()
{
return interceptor;
}
public void setInterceptor(ActionInterceptor interceptor) {
this.interceptor = interceptor;
}
public IExceptionHandler getExceptionHandler() {
return exceptionHandler;
}
public void setExceptionHandler(IExceptionHandler exceptionHandler) {
this.exceptionHandler = exceptionHandler;
}
public IActionStatusJudge getActionStatusJudge() {
return actionStatusJudge;
}
public void setActionStatusJudge(IActionStatusJudge actionStatusJudge) {
this.actionStatusJudge = actionStatusJudge;
}
}