Loom
Stripesにかなり似てるんですが、結構良い感じのActionベースのフレームワーク。
AjaxianではアノテーションベースなWebフレームワークという紹介でしたがそうでもないかも。
レスポンスとしてどういうものを返すかをResolutionというクラスで表現しているのですが
これはかなりStripesに似てる。T2もその辺はStripesのシンプルっぽさを真似て
Navigationを作っているので似たような感じです。
サンプルのコードはこんな感じのようです。
public class MortgagesAction extends AbstractActionImpl { /** controller that handles the CRUD stuff */ @Injected private BasicManager basicManager; @Injected private DemoManager demoController; /** the list in the main page */ private PaginatedListImpl mortgages; /** the current editing instance */ @NestedAnnotations(on="save") @RetrieveEntity(on={"save", "preEdit"}) private Mortgage mortgage; /** the uploaded file, if any */ @NumberValidation(propertyPath="fileSize", maxValue="102400", message="error.custom.imageFileSize", on="save") @StringValidation(propertyPath="filename", mask="(.*?)\\.(jpg|jpeg|png|gif)$", message="error.custom.imageFileName", maskCaseInsensitive=true, on="save") private PersistentFile uploadedFile; /** list of selected rows */ private Set<Integer> selectedRows; private static Log log = Log.getLog(); @Event(defaultEvent=true) public Resolution listAll() { mortgages = new PaginatedListImpl(context.getRequest()); basicManager.query(mortgages, "from Mortgage mortgage"); return forward("listAll.jsp"); } public Resolution preEdit() { return forward("editMortgage.jsp"); } public Resolution save() { mortgage = demoController.merge(mortgage, uploadedFile); return redirect(MortgagesAction.class, "listAll"); } /** * Delete a selected list of Mortage instances */ public Resolution delete() { if (selectedRows != null) { for (Integer rowId : selectedRows) { try { demoController.delete(rowId); } catch (EntityNotFoundException e) { log.debug("Mortgage instance " + rowId + " could not be deleted because it was not found: " + e.getMessage()); } } } return redirect(MortgagesAction.class, "listAll"); } @SuppressWarnings("unchecked") public Set<Option> getCountries() { LabelComparator comparator = new LabelComparator(); comparator.setRepository(getMessagesRepository()); Set<Option> countries = new TreeSet<Option>(comparator); Locale currentLocale = getMessagesRepository().getLocale(); Locale[] locales = Locale.getAvailableLocales(); for (Locale locale : locales) { countries.add(new Option(locale.getCountry(), locale.getDisplayCountry(currentLocale), false)); // translated by locale.getDisplayCountry() } return countries; } public Mortgage getMortgage() { return mortgage; } public PaginatedListImpl getMortgages() { return mortgages; } public void setBasicManager(BasicManager basicManager) { this.basicManager = basicManager; } public void setMortgage(Mortgage mortgage) { this.mortgage = mortgage; } }
インジェクトする先の@Injectedでの明示的な指定とか、遷移先を
return redirect(MortgagesAction.class, "listAll");とかして上手く指定できるあたりは
中々よいんじゃないかと思います。ちょうどよい感じ。
ただし、AbstractActionImpl の継承はちょっといまいちかな。貴重なextendsはユーザさんのためにあけておいて
あげたいのが心情。あと、Validationがやや押し付けがましい感じがするかな。これは好みの問題ですが、
Validationもユーザさんが好きなものを選べばいいと思います。
全体としては好印象を受けました。SpringがDIコンテナのデフォルトですが、DependencyInjectionAdapterを実装して
好きに切り替えられるのでその辺の手軽さも好きです。