【发布时间】:2017-03-14 04:35:04
【问题描述】:
Wicket 6 有一个默认的复合请求映射器:SystemMapper。它包含BookmarkableMapper。我需要覆盖它,即使用我自己的FancyBookmarkableMapper。
我尝试了什么:
- 整体复制
SystemMapper类并更改以下行
add(new BookmarkableMapper());
到
add(new FancyBookmarkableMapper());
但是这种方式在升级方面非常丑陋和脆弱(尽管它似乎有效)。为了完整起见,我在这里提到它。
-
利用
SystemMapper是ICompoundMapper的事实,使用add()、remove()和iterator()方法替换映射器:private SystemMapper customizeSystemMapper() { final SystemMapper rootRequestMapper = (SystemMapper) getRootRequestMapper(); IRequestMapper originalBookmarkableMapper = null; boolean afterBookmarkable = false; List<IRequestMapper> mappersAfterBookmarkable = new ArrayList<>(); for (IRequestMapper mapper : rootRequestMapper) { if (mapper.getClass() == BookmarkableMapper.class) { if (originalBookmarkableMapper != null) { throw new IllegalStateException("There are two BookmarkableMapper instances in the initial mappers list"); } originalBookmarkableMapper = mapper; afterBookmarkable = true; } else { if (afterBookmarkable) { mappersAfterBookmarkable.add(mapper); } } } if (originalBookmarkableMapper == null) { throw new IllegalStateException("There is no BookmarkableMapper in the initial mappers list"); } for (IRequestMapper mapperToRemove : mappersAfterBookmarkable) { rootRequestMapper.remove(mapperToRemove); } rootRequestMapper.remove(originalBookmarkableMapper); rootRequestMapper.add(new FancyBookmarkableMapper()); for (IRequestMapper mapperToAdd : mappersAfterBookmarkable) { rootRequestMapper.add(mapperToAdd); } return rootRequestMapper; }
也不是很好,虽然它也很好用。
-
构建
ICompoundMapper的实现并用它装饰SystemMapper实例。替换内置映射器的唯一方法是尝试使用iterator()方法:@Override public Iterator<IRequestMapper> iterator() { return new Iterator<IRequestMapper>() { private Iterator<IRequestMapper> originalIterator = delegate.iterator(); @Override public boolean hasNext() { return originalIterator.hasNext(); } @Override public IRequestMapper next() { IRequestMapper nextMapper = originalIterator.next(); if (nextMapper != null && nextMapper.getClass() == BookmarkableMapper.class) { nextMapper = bookmarkableMapperReplacement; } return nextMapper; } @Override public void remove() { originalIterator.remove(); } }; }
但是,这不起作用,因为SystemMapper#mapRequest()(实际上在CompoundRequestMapper 中定义)直接使用mappers 字段而不是通过iterator() 方法。
-
最简单的方法:
private SystemMapper customizeSystemMapper2() { final SystemMapper rootRequestMapper = (SystemMapper) getRootRequestMapper(); rootRequestMapper.add(new FancyBookmarkableMapper()); return rootRequestMapper; }
在这里,我们将映射器添加到列表的开头。它扩展了BookmarkableMapper 并继承了它的getCompatibilityScore(),因此它与BookmarkableMapper 具有相同的分数,并且它在列表中较早,因此具有优先权。
第 4 项确实有效。唯一让我问这个问题的是,实际上,对于这种方法,两个映射器都在SystemMapper 的内部列表中。是否保证我的映射器(后来添加并具有相同的分数)将优先(包括未来的 Wicket 版本)?
【问题讨论】: