【问题标题】:A correct way to override a built-in mapper in Wicket 6在 Wicket 6 中覆盖内置映射器的正确方法
【发布时间】:2017-03-14 04:35:04
【问题描述】:

Wicket 6 有一个默认的复合请求映射器:SystemMapper。它包含BookmarkableMapper。我需要覆盖它,即使用我自己的FancyBookmarkableMapper

我尝试了什么:

  1. 整体复制SystemMapper类并更改以下行

add(new BookmarkableMapper());

add(new FancyBookmarkableMapper());

但是这种方式在升级方面非常丑陋和脆弱(尽管它似乎有效)。为了完整起见,我在这里提到它。

  1. 利用SystemMapperICompoundMapper 的事实,使用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;
    }
    

也不是很好,虽然它也很好用。

  1. 构建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() 方法。

  1. 最简单的方法:

    private SystemMapper customizeSystemMapper2() {
        final SystemMapper rootRequestMapper = (SystemMapper) getRootRequestMapper();
        rootRequestMapper.add(new FancyBookmarkableMapper());
        return rootRequestMapper;
    }
    

在这里,我们将映射器添加到列表的开头。它扩展了BookmarkableMapper 并继承了它的getCompatibilityScore(),因此它与BookmarkableMapper 具有相同的分数,并且它在列表中较早,因此具有优先权。

第 4 项确实有效。唯一让我问这个问题的是,实际上,对于这种方法,两个映射器都在SystemMapper 的内部列表中。是否保证我的映射器(后来添加并具有相同的分数)将优先(包括未来的 Wicket 版本)?

【问题讨论】:

    标签: java wicket


    【解决方案1】:

    最简单(也是官方)的方法是在 YourApplication#init() 方法中使用WebApplication#mount(new FancyBookmarkableMapper ()

    明天我会在 3) 中检查您的问题! 更新:使用https://git1-us-west.apache.org/repos/asf?p=wicket.git;a=commitdiff;h=0eb63480;hp=5821157738ac43a09232a2aeb0fa2ff808340f4d 对其进行了改进 如果您看到更多改进,请告诉我们!谢谢!

    【讨论】:

    • 相关页面实际上是使用我们扩展 MountedMapper 的映射器实现挂载的。但是当处理来自侦听器的请求时(如链接点击),Wicket 使用另一个映射器(即,BookmarkableMapper 来自SystemMapper)。此外,BookmarkableMapper(我的FancyBookmarkableMapper 扩展)没有任何接受挂载路径的构造函数。我很困惑。
    • 你试过我的建议了吗?我不是在谈论页面。
    • 我在我的WebApplication#init() 方法中添加了mount(new FancyBookmarkableMapper()),在使用系统映射器进行任何操作之前和其他挂载之前,它可以工作。谢谢!对于没有mountPath 的映射器,我对使用mount() 感到有点困惑:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-19
    • 2016-11-30
    • 2023-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多