概要
Thymeleafで独自のダイアレクトを実装する方法のまとめです。
ダイアレクトでどのようなことが出来るのかを中心にしているので、サンプルコードに実用性はあまりありません。
また、このサンプルコードで説明するダイアレクトのprefixはmy
としています。
ダイアレクトとプロセッサについては公式サイトのチュートリアルの説明が詳しかったので下記にその一部を引用します。
引用部分に書かれているとおり、基本的にはスタンダードダイアレクトだけで十分間に合うことが多いのですが、同じロジックを多くのテンプレートに記述しなければいけないなどの場合は、独自プロセッサに任せることでテンプレート上から冗長性を排除することができます。
1.3 ダイアレクト: スタンダードダイアレクト
http://www.thymeleaf.org/doc/tutorials/2.1/usingthymeleaf_ja.html#ダイアレクト-スタンダードダイアレクト
DOMノードにロジックを適用するものを「プロセッサ」と呼びます。そして、プロセッサ一式 — と、いくつかの特別な生成物 — のことをダイアレクトと呼びます。Thymeleafでは「スタンダードダイアレクト」というそのまますぐに使えるコアライブラリを提供していて、大半のユーザーにとってはこれで十分です。
もちろん、ライブラリの拡張機能を利用して独自の処理ロジックを定義したい、など(スタンダードダイアレクトを拡張することも含めて)独自のダイアレクトを作りたい場合があるかもしれません。テンプレートエンジンは複数のダイアレクトを同時に使用できます。
環境
- Windows10 Professional
- Java 1.8.0_101
- Spring Boot 1.4.1
- thymeleaf 2.1.5
参考
実装方法
独自のダイアレクトの実装は、大きく分けると以下の3つの実装が必要です。
- プロセッサの実装
- ダイアレクトの実装
- 設定の実装
検証用のコントローラーとモデル
サンプルコードの検証に使用するモデルとコントローラーです。
モデル
public class UserModel implements Serializable {
private static final long serialVersionUID = 1595768734175347794L;
public UserModel() {
}
public UserModel(Long id, String name) {
this.id = id;
this.name = name;
}
private Long id;
private String name;
...getter/setterは省略...
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + "]";
}
}
public class ItemModel implements Serializable {
private static final long serialVersionUID = 4429386992827915231L;
public ItemModel() {
}
public ItemModel(Long id, String name, Integer price, Integer remaining, String imageUrl) {
this.id = id;
this.name = name;
this.price = price;
this.remaining = remaining;
this.imageUrl = imageUrl;
}
private Long id;
private String name;
private Integer price;
private Integer remaining;
private String imageUrl;
// ...getter/setterは省略...
@Override
public String toString() {
return "ItemModel [id=" + id + ", name=" + name + ", price=" + price + ", remaining=" + remaining
+ ", imageUrl=" + imageUrl + "]";
}
}
コントローラー
@Controller
public class MyController {
private static final Map<Long, ItemModel> LIST;
static {
Map<Long, ItemModel> tmp = new HashMap<Long, ItemModel>();
tmp.put(1L, new ItemModel(1L, "うまい棒", 10, 50, "/path/to/image/umaibou.png"));
tmp.put(2L, new ItemModel(2L, "チョコバット", 20, 20, "/path/to/image/chocobat.png"));
tmp.put(3L, new ItemModel(3L, "ベビースター", 30, 5, null));
LIST = Collections.unmodifiableMap(tmp);
}
@RequestMapping(value = "/my/{id}", method = RequestMethod.GET)
public String my(@PathVariable(name = "id", required = true) Long id, HttpServletRequest request, Model model) {
UserModel user = new UserModel(100L, "rubytomato");
HttpSession session = request.getSession();
session.setAttribute("user", user);
ItemModel item = LIST.get(id);
model.addAttribute("item", item);
return "my/my";
}
}
1. プロセッサの実装
プロセッサではHTMLの要素や属性を操作する処理を実装します。基本的な機能はThymeleafのスタンダードダイアレクトで使われている抽象クラスで実装されているので、これらを継承して必要なプロセッサを開発します。また、必要があればプロセッサ内からリクエストやセッションスコープのオブジェクトへのアクセス、ThymeleafをSpringと併用する場合にはSpringが管理するBeanを使用することもできます。
プロセッサには、属性プロセッサと要素プロセッサがあります。version 2.1.5ではほとんどが属性プロセッサで、要素プロセッサは1つしかありません。
属性プロセッサ
DOMの属性として使う、例えば下記のようなth:if
などです。
<div th:if="${price} gt 10000" th:remove="tag">
...何かの処理...
</div>
要素プロセッサ
それ自体をDOMの要素として扱います。いまのところth:block
しかありません。
<th:block th:if="${price} gt 10000">
...何かの処理...
</th:block>
属性プロセッサの実装例
AbstractConditionalVisibilityAttrProcessor
AbstractConditionalVisibilityAttrProcessorを継承するとth:if
と同じような機能を持つ属性プロセッサを実装することができます。
オーバーライドするメソッドで重要なのはisVisible
です。isVisibleメソッドの戻り値で要素の表示を制御します。trueを返せば自身の要素と子要素を表示し、falseを返せば表示しません。
サンプルコード
public class MyIfAttrProcessor extends AbstractConditionalVisibilityAttrProcessor {
private static final String ATTR_NAME = "if";
private static final int ATTR_PRECEDENCE = 1000;
public MyIfAttrProcessor() {
super(ATTR_NAME);
}
@Override
public int getPrecedence() {
return ATTR_PRECEDENCE;
}
@Override
protected boolean isVisible(Arguments arguments, Element element, String attributeName) {
// ...オーバーライドします...
}
}
式を評価する
属性に指定された式を評価します。
式はプロセッサ内から文字列として取得できるので、それをパーサーで評価します。
<div my:if="${item.remaining gt 10}">
<p>trueなら表示される</p>
</div>
@Override
protected boolean isVisible(Arguments arguments, Element element, String attributeName) {
final String attributeValue = element.getAttributeValue(attributeName);
System.out.println(attributeValue);
// → ${item.remaining gt 10}
final Configuration configuration = arguments.getConfiguration();
final IStandardExpressionParser parser = StandardExpressions.getExpressionParser(configuration);
final IStandardExpression expression = parser.parseExpression(configuration, arguments, attributeValue);
final Boolean result = (Boolean) expression.execute(configuration, arguments);
System.out.println(result);
// → true
return result;
}
<div>
<p>trueなら表示される</p>
</div>
オブジェクトを扱う
属性にオブジェクトが指定された場合でも、パーサーで評価すればそのオブジェクトを取得することができます。
<div my:if="${item}">
<p>trueなら表示される</p>
</div>
@Override
protected boolean isVisible(Arguments arguments, Element element, String attributeName) {
final String attributeValue = element.getAttributeValue(attributeName);
System.out.println(attributeValue);
// → ${item}
// ...省略...
final ItemModel item = (ItemModel) expression.execute(configuration, arguments);
System.out.println(item.toString());
// → ItemModel [id=1, name=うまい棒, price=10, remaining=50, imageUrl=/path/to/image/umaibou.png]
return item.getRemaining() > 10;
}
<div>
<p>trueなら表示される</p>
</div>
HttpServletRequest、HttpServletResponse、HttpSessionを扱う
プロセッサ内からHttpServletRequest
、HttpServletResponse
、HttpSession
を扱うことができます。
@Override
protected boolean isVisible(Arguments arguments, Element element, String attributeName) {
// ...省略...
final IContext context = arguments.getContext();
final SpringWebContext springWebContext = (SpringWebContext) context;
final HttpServletRequest request = springWebContext.getHttpServletRequest();
final HttpServletResponse response = springWebContext.getHttpServletResponse();
final HttpSession session = springWebContext.getHttpSession();
UserModel user = (UserModel) session.getAttribute("user");
System.out.println(user.toString());
// → User [id=100, name=rubytomato]
// ...省略...
}
ThymeleafをSpringと併用しない場合は下記のコードになります。
Springと併用していない場合はこちら
final IWebContext webContext = (IWebContext) context;
final HttpServletRequest request = webContext.getHttpServletRequest();
final HttpServletResponse response = webContext.getHttpServletResponse();
SpringのApplicationContextを参照する
ThymeleafをSpringと併用している場合は、SpringのApplicationContext
のインスタンスを参照することができます。
@Override
protected boolean isVisible(Arguments arguments, Element element, String attributeName) {
// ...省略...
final IContext context = arguments.getContext();
final SpringWebContext springWebContext = (SpringWebContext) context;
final ApplicationContext applicationContext = springWebContext.getApplicationContext();
// ...省略...
}
他の属性値を取得する
同じ要素の他の属性の値も取得できます。
<div my:if="${item.remaining gt 10}" data-hoge="fuga">
<p>trueなら表示される</p>
</div>
final String hoge = element.getAttributeValue("data-hoge");
System.out.println("hoge:" + hoge);
// → fuga
AbstractSingleAttributeModifierAttrProcessor
AbstractSingleAttributeModifierAttrProcessorを継承するとth:src
と同じような機能を持つ属性プロセッサを実装することができます。
オーバーライドするメソッドで重要なのはgetTargetAttributeName
とgetTargetAttributeValue
です。
getTargetAttributeNameメソッドの戻り値で値を設定する属性を指定します。
getTargetAttributeValueメソッドの戻り値が指定した属性へセットする値になります。
サンプルコード
public class MySrcAttrProcessor extends AbstractSingleAttributeModifierAttrProcessor {
private static final String ATTR_NAME = "src";
private static final int ATTR_PRECEDENCE = 1000;
public MySrcAttrProcessor() {
super(ATTR_NAME);
}
@Override
public int getPrecedence() {
return ATTR_PRECEDENCE;
}
@Override
protected String getTargetAttributeName(Arguments arguments, Element element, String attributeName) {
// 通常はプロセッサの属性名と同じにします。
return ATTR_NAME;
}
@Override
protected String getTargetAttributeValue(Arguments arguments, Element element, String attributeName) {
// ...オーバーライドします...
}
@Override
protected ModificationType getModificationType(Arguments arguments, Element element, String attributeName, String newAttributeName) {
// 属性値の設定方法を指定します。
return ModificationType.SUBSTITUTION;
}
@Override
protected boolean removeAttributeIfEmpty(Arguments arguments, Element element, String attributeName, String newAttributeName) {
// 属性にセットする値が空の場合に属性を削除するか
return true;
}
@Override
protected boolean recomputeProcessorsAfterExecution(Arguments arguments, Element element, String attributeName) {
// 用途不明です。
return false;
}
}
オブジェクトを扱う
プロセッサでできることは上記のmy:if
と同じです。
この例では、属性に指定したItemModelのインスタンスのimageUrlフィールドがnullの場合に代替URLを、nullでない場合にimageUrlの値を返します。
<img my:src="${item}" />
@Override
protected String getTargetAttributeValue(Arguments arguments, Element element, String attributeName) {
final String attributeValue = element.getAttributeValue(attributeName);
System.out.println("attribute:" + attributeValue);
// → ${item}
final Configuration configuration = arguments.getConfiguration();
final IStandardExpressionParser parser = StandardExpressions.getExpressionParser(configuration);
final IStandardExpression expression = parser.parseExpression(configuration, arguments, attributeValue);
final ItemModel item = (ItemModel) expression.execute(configuration, arguments);
System.out.println("request item:" + item.toString());
// → ItemModel [id=1, name=うまい棒, price=10, remaining=50, imageUrl=/path/to/image/umaibou.png]
return StringUtils.isEmpty(item.getImageUrl()) ? "/path/to/image/noimage.png" : item.getImageUrl();
}
<img src="/path/to/image/umaibou.png">
属性値の設定方法を指定する
getModificationTypeメソッドの戻り値で、属性値の設定方法を選択します。返せる値はModificationTypeというEnumで定義されています。
VALUE | 実行内容 |
---|---|
SUBSTITUTION | 指定する属性の値を置き換える |
APPEND | 指定する属性の値の末尾に加える |
APPEND_WITH_SPACE | APPENDを空白区切りで行う |
PREPEND | 指定する属性の値の先頭に加える |
PREPEND_WITH_SPACE | PREPENDを空白区切りで行う |
要素プロセッサの実装例
できることは属性プロセッサと変わりませんが、属性プロセッサと違って属性を必要としませんのでいく分かテンプレート上はすっきりします。
AbstractConditionalVisibilityElementProcessor
AbstractConditionalVisibilityElementProcessorを継承するとth:if
と同じように条件によって内部の要素を表示するか制御することができます。
オーバーライドするメソッドで重要なのは属性プロセッサと同じでisVisible
です。
サンプルコード
public class MyIfElementProcessor extends AbstractConditionalVisibilityElementProcessor {
private static final String ELEMENT_NAME = "if";
private static final int PRECEDENCE = 1000;
public MyIfElementProcessor() {
super(ELEMENT_NAME);
}
@Override
public int getPrecedence() {
return PRECEDENCE;
}
@Override
protected boolean isVisible(Arguments arguments, Element element) {
// ...オーバーライドします...
}
@Override
protected boolean removeHostElementIfVisible(Arguments arguments, Element element) {
// 通常は独自の要素を削除するのでtrueを返します
return true;
}
}
オブジェクトを扱う
属性プロセッサで説明したmy:if
を要素プロセッサで書き換える例です。
<my:if>
<div>
<p>trueなら表示される</p>
</div>
</my:if>
@Override
protected boolean isVisible(Arguments arguments, Element element) {
final IContext context = arguments.getContext();
final SpringWebContext springWebContext = (SpringWebContext) context;
final HttpServletRequest request = springWebContext.getHttpServletRequest();
final ItemModel item = (ItemModel) request.getAttribute("item");
System.out.println(item.toString());
// → ItemModel [id=1, name=うまい棒, price=10, remaining=50, imageUrl=/path/to/image/umaibou.png]
return item.getRemaining() > 10;
}
<div>
<p>trueなら表示される</p>
</div>
要素を出力する
プロセッサで任意の要素を出力させることができます。(属性プロセッサでは触れていませんが属性プロセッサでもできます。)
(多用するとThymeleafの良さを削ぐことになるので使いどころをよく検討する必要があると思います。)
<my:if />
@Override
protected boolean isVisible(Arguments arguments, Element element) {
final IContext context = arguments.getContext();
final SpringWebContext springWebContext = (SpringWebContext) context;
final HttpServletRequest request = springWebContext.getHttpServletRequest();
final ItemModel item = (ItemModel) request.getAttribute("item");
System.out.println(item.toString());
// → ItemModel [id=1, name=うまい棒, price=10, remaining=50, imageUrl=/path/to/image/umaibou.png]
boolean isVisible = item.getRemaining() > 10;
if (isVisible) {
Element pEle = new Element("p");
pEle.addChild(new Text("trueなら表示される"));
Element divEle = new Element("div");
divEle.addChild(pEle);
element.getParent().insertBefore(element, divEle);
}
return isVisible;
}
<div><p>trueなら表示される</p></div>
2. ダイアレクトの実装
用意されている抽象クラスAbstractDialectを継承して独自のダイアレクトを実装します。
ダイアレクトで行うことは、実装したプロセッサのインスタンスを生成することと、このダイアレクトのprefixの指定です。
prefixはプロセッサのネームスペースの役割を果たします。ちなみにスタンダードダイアレクトのprefixは"th"です。
public class MyDialect extends AbstractDialect {
private static final String PREFIX = "my";
private static final Set<IProcessor> PROCESSORS;
static {
Set<IProcessor> tmp = new HashSet<>();
tmp.add(new MyIfAttrProcessor());
tmp.add(new MySrcAttrProcessor());
tmp.add(new MyIfElementProcessor());
PROCESSORS = Collections.unmodifiableSet(tmp);
}
@Override
public String getPrefix() {
return PREFIX;
}
@Override
public boolean isLenient() {
return false;
}
@Override
public Set<IProcessor> getProcessors() {
return PROCESSORS;
}
}
3. 設定の実装
実装したダイアレクトを有効にするために下記のコードで有効化します。
@Configuration
public class MyDialaectConfigurer {
// 独自ダイアレクト
@Bean
MyDialect myDialect() {
return new MyDialect();
}
}
若しくは
@SpringBootApplication
public class App {
public static void main( String[] args ) {
SpringApplication.run(App.class, args);
}
// 独自ダイアレクト
@Bean
MyDialect myDialect() {
return new MyDialect();
}
}
以上で独自のダイアレクトとプロセッサの実装方法の説明は終了です。
独自のユーティリティオブジェクトを実装する
おまけです。
実装方法は、カスタム Utility Object を追加する ー Thymeleafという記事の通りです。
実装方法
- ユーティリティオブジェクトの実装
- ダイアレクトの実装
ユーティリティオブジェクトの実装
public interface ViewHelper {
public String hello(String message);
}
@Component
public class ViewHelperImpl implements ViewHelper {
@Autowired
MessageSource messageSource;
@Override
public String hello(String message) {
return messageSource.getMessage("message.text1", new Object[]{message}, Locale.getDefault());
}
}
ダイアレクトの実装
独自のダイアレクトクラスにIExpressionEnhancingDialectインターフェースを実装します。
public class MyDialect extends AbstractDialect implements IExpressionEnhancingDialect {
// ...省略...
@Override
public Map<String, Object> getAdditionalExpressionObjects(IProcessingContext processingContext) {
final SpringWebContext springWebContext = (SpringWebContext) processingContext.getContext();
final ApplicationContext applicationContext = springWebContext.getApplicationContext();
ViewHelper viewHelper = applicationContext.getBean(ViewHelper.class);
Map<String, Object> tmp = new HashMap<>();
tmp.put("vh", viewHelper);
return Collections.unmodifiableMap(tmp);
}
}
メッセージリソースファイル
message.text1 = こんにちは {0}.
message.text1 = hello {0}.
テンプレート
<p th:text="${#vh.hello(user.name)}"></p>
<p>こんにちは rubytomato.</p>
補足資料
thymeleaf 2.1.5.RELEASE
Dialect
PREFIX | Class |
---|---|
th | AbstractDialect └ AbstractXHTMLEnabledDialect └ StandardDialect |
Processor
Attribute一覧
ATTR NAME |
ATTR PRECEDENCE |
Class |
---|---|---|
assert | 1550 | AbstractAssertionAttrProcessor └ AbstractStandardAssertionAttrProcessor └ StandardAssertAttrProcessor |
inline | 1000 | AbstractAttrProcessor └ AbstractStandardTextInlinerAttrProcessor └ StandardInlineAttrProcessor |
attr | 700 | AbstractAttributeModifierAttrProcessor └ AbstractStandardAttributeModifierAttrProcessor └ StandardAttrAttrProcessor |
attrappend | 900 | AbstractAttributeModifierAttrProcessor └ AbstractStandardAttributeModifierAttrProcessor └ StandardAttrappendAttrProcessor |
attrprepend | 800 | AbstractAttributeModifierAttrProcessor └ AbstractStandardAttributeModifierAttrProcessor └ StandardAttrprependAttrProcessor |
alt-title | 990 | AbstractAttributeModifierAttrProcessor └ AbstractStandardSingleValueMultipleAttributeModifierAttrProcessor └ StandardAltTitleAttrProcessor |
lang-xmllang | 990 | AbstractAttributeModifierAttrProcessor └ AbstractStandardSingleValueMultipleAttributeModifierAttrProcessor └ StandardLangXmlLangAttrProcessor |
async... | 1000 | AbstractConditionalFixedValueAttrProcessor └ AbstractStandardConditionalFixedValueAttrProcessor └ StandardConditionalFixedValueAttrProcessor |
case | 275 | AbstractConditionalVisibilityAttrProcessor └ AbstractStandardCaseAttrProcessor └ StandardCaseAttrProcessor |
if | 300 | AbstractConditionalVisibilityAttrProcessor └ AbstractStandardConditionalVisibilityAttrProcessor └ StandardIfAttrProcessor |
unless | 400 | AbstractConditionalVisibilityAttrProcessor └ AbstractStandardConditionalVisibilityAttrProcessor └ StandardUnlessAttrProcessor |
include | 100 | AbstractFragmentHandlingAttrProcessor └ AbstractStandardFragmentHandlingAttrProcessor └ StandardIncludeFragmentAttrProcessor |
replace | 100 | AbstractFragmentHandlingAttrProcessor └ AbstractStandardFragmentHandlingAttrProcessor └ StandardReplaceFragmentAttrProcessor |
substituteby | 100 | AbstractFragmentHandlingAttrProcessor └ AbstractStandardFragmentHandlingAttrProcessor └ StandardSubstituteByFragmentAttrProcessor |
each | 200 | AbstractIterationAttrProcessor └ AbstractStandardIterationAttrProcessor └ StandardEachAttrProcessor |
with | 600 | AbstractLocalVariableDefinitionAttrProcessor └ AbstractStandardLocalVariableDefinitionAttrProcessor └ StandardWithAttrProcessor |
switch | 250 | AbstractLocalVariableDefinitionAttrProcessor └ AbstractStandardSwitchStructureAttrProcessor └ StandardSwitchAttrProcessor |
remove | 1600 | AbstractMarkupRemovalAttrProcessor └ StandardRemoveAttrProcessor |
fragment | 1500 | AbstractNoOpAttrProcessor └ StandardFragmentAttrProcessor |
object | 500 | AbstractSelectionTargetAttrProcessor └ AbstractStandardSelectionAttrProcessor └ StandardObjectAttrProcessor |
action | 1000 | AbstractSingleAttributeModifierAttrProcessor └ AbstractStandardSingleAttributeModifierAttrProcessor └ StandardActionAttrProcessor |
classappend | 1100 | AbstractSingleAttributeModifierAttrProcessor └ AbstractStandardSingleAttributeModifierAttrProcessor └ StandardClassappendAttrProcessor |
onabort... | 1000 | AbstractSingleAttributeModifierAttrProcessor └ AbstractStandardSingleAttributeModifierAttrProcessor └ StandardDOMEventAttributeModifierAttrProcessor |
href | 1000 | AbstractSingleAttributeModifierAttrProcessor └ AbstractStandardSingleAttributeModifierAttrProcessor └ StandardHrefAttrProcessor |
method | 990 | AbstractSingleAttributeModifierAttrProcessor └ AbstractStandardSingleAttributeModifierAttrProcessor └ StandardMethodAttrProcessor |
name... | 1000 | AbstractSingleAttributeModifierAttrProcessor └ AbstractStandardSingleAttributeModifierAttrProcessor └ StandardSingleNonRemovableAttributeModifierAttrProcessor |
abbr... | 1000 | AbstractSingleAttributeModifierAttrProcessor └ AbstractStandardSingleAttributeModifierAttrProcessor └ StandardSingleRemovableAttributeModifierAttrProcessor |
src | 1000 | AbstractSingleAttributeModifierAttrProcessor └ AbstractStandardSingleAttributeModifierAttrProcessor └ StandardSrcAttrProcessor |
styleappend | 1100 | AbstractSingleAttributeModifierAttrProcessor └ AbstractStandardSingleAttributeModifierAttrProcessor └ StandardStyleappendAttrProcessor |
value | 1010 | AbstractSingleAttributeModifierAttrProcessor └ AbstractStandardSingleAttributeModifierAttrProcessor └ StandardValueAttrProcessor |
xmlbase | 1000 | AbstractSingleAttributeModifierAttrProcessor └ AbstractStandardSingleAttributeModifierAttrProcessor └ StandardXmlBaseAttrProcessor |
xmllang | 1000 | AbstractSingleAttributeModifierAttrProcessor └ AbstractStandardSingleAttributeModifierAttrProcessor └ StandardXmlLangAttrProcessor |
xmlspace | 1000 | AbstractSingleAttributeModifierAttrProcessor └ AbstractStandardSingleAttributeModifierAttrProcessor └ StandardXmlSpaceAttrProcessor |
text | 1300 | AbstractTextChildModifierAttrProcessor └ AbstractStandardTextChildModifierAttrProcessor └ StandardTextAttrProcessor |
utext | 1400 | AbstractUnescapedTextChildModifierAttrProcessor └ AbstractStandardUnescapedTextChildModifierAttrProcessor └ StandardUtextAttrProcessor |
block | 100000 | AbstractNoOpElementProcessor └ StandardBlockElementProcessor |
100 | AbstractTextNodeProcessor └ StandardTextInliningTextProcessor |
thymeleaf-spring4 2.1.5.RELEASE
Dialect
PREFIX | Class |
---|---|
th | AbstractDialect └ AbstractXHTMLEnabledDialect └ StandardDialect └ SpringStandardDialect |
Processor
Attribute一覧
ATTR NAME |
ATTR PRECEDENCE |
Class |
---|---|---|
field | 1200 | AbstractAttrProcessor └ AbstractSpringFieldAttrProcessor |
checkbox | 1200 | AbstractAttrProcessor └ AbstractSpringFieldAttrProcessor └ SpringInputCheckboxFieldAttrProcessor |
file | 1200 | AbstractAttrProcessor └ AbstractSpringFieldAttrProcessor └ SpringInputFileFieldAttrProcessor |
text... | 1200 | AbstractAttrProcessor └ AbstractSpringFieldAttrProcessor └ SpringInputGeneralFieldAttrProcessor |
password | 1200 | AbstractAttrProcessor └ AbstractSpringFieldAttrProcessor └ SpringInputPasswordFieldAttrProcessor |
radio | 1200 | AbstractAttrProcessor └ AbstractSpringFieldAttrProcessor └ SpringInputRadioFieldAttrProcessor |
option | 1200 | AbstractAttrProcessor └ AbstractSpringFieldAttrProcessor └ SpringOptionFieldAttrProcessor |
select | 1200 | AbstractAttrProcessor └ AbstractSpringFieldAttrProcessor └ SpringSelectFieldAttrProcessor |
textarea | 1200 | AbstractAttrProcessor └ AbstractSpringFieldAttrProcessor └ SpringTextareaFieldAttrProcessor |
action | 1000 | AbstractSingleAttributeModifierAttrProcessor └ AbstractStandardSingleAttributeModifierAttrProcessor └ SpringActionAttrProcessor |
errorclass | 1500 | AbstractSingleAttributeModifierAttrProcessor └ AbstractStandardSingleAttributeModifierAttrProcessor └ SpringErrorClassAttrProcessor |
method | 990 | AbstractSingleAttributeModifierAttrProcessor └ AbstractStandardSingleAttributeModifierAttrProcessor └ SpringMethodAttrProcessor |
src | 1000 | AbstractSingleAttributeModifierAttrProcessor └ AbstractStandardSingleAttributeModifierAttrProcessor └ SpringSrcAttrProcessor |
value | 1010 | AbstractSingleAttributeModifierAttrProcessor └ AbstractStandardSingleAttributeModifierAttrProcessor └ SpringValueAttrProcessor |
errors | 1200 | AbstractAttrProcessor └ AbstractStandardTextInlinerAttrProcessor └ SpringErrorsAttrProcessor |
object | 500 | AbstractSelectionTargetAttrProcessor └ AbstractStandardSelectionAttrProcessor └ SpringObjectAttrProcessor |