在 Wicket 6 中覆盖内置映射器的正确方法
A correct way to override a built-in mapper in Wicket 6
Wicket 6 有一个默认的复合请求映射器:SystemMapper
。它包含 BookmarkableMapper
。我需要覆盖它,即使用我自己的 FancyBookmarkableMapper
代替。
我尝试了什么:
- 将
SystemMapper
class作为一个整体复制并更改以下行
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 版本)?
最简单(也是官方)的方法是在 YourApplication#init() 方法中使用 WebApplication#mount(new FancyBookmarkableMapper ()
。
我明天会在 3) 中检查您的问题! 更新:用https://git1-us-west.apache.org/repos/asf?p=wicket.git;a=commitdiff;h=0eb63480;hp=5821157738ac43a09232a2aeb0fa2ff808340f4d改进了它
如果您看到更多改进,请告诉我们!谢谢!
Wicket 6 有一个默认的复合请求映射器:SystemMapper
。它包含 BookmarkableMapper
。我需要覆盖它,即使用我自己的 FancyBookmarkableMapper
代替。
我尝试了什么:
- 将
SystemMapper
class作为一个整体复制并更改以下行
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 版本)?
最简单(也是官方)的方法是在 YourApplication#init() 方法中使用 WebApplication#mount(new FancyBookmarkableMapper ()
。
我明天会在 3) 中检查您的问题! 更新:用https://git1-us-west.apache.org/repos/asf?p=wicket.git;a=commitdiff;h=0eb63480;hp=5821157738ac43a09232a2aeb0fa2ff808340f4d改进了它 如果您看到更多改进,请告诉我们!谢谢!