【问题标题】:Generically typed visitor getting called on wrong types通用类型的访问者被错误类型调用
【发布时间】:2019-06-23 19:50:58
【问题描述】:

我正在使用框架AbstractProcessor<T extends CtElement>的通用抽象类,它基本上是一个访问所有元素T的访问者。有一个方法

public void process(T element)

作用于指定类型的所有元素并做某事。

然后我有这个AbstractProcessor 的具体类实现,我使用某种工厂模式创建,同时持有一个公共超类型AbstractProcessor 的列表,然后通过它们的多态性调用process 方法。这些具体类之一可能类似于XYZProcessor<T extends CtElement> extends AbstractProcessor<T>

我现在创建这些具体的处理器,例如new XYZProcessor<CtNamedElement>(),其中CtNamedElementCtElement 的子类型,因此XYZProcessorprocess 方法只能使用CTNamedElements 调用。但是process-method 似乎被所有CtElement 类型的访问元素调用,而不仅仅是我想要的CtNamedElement 类型的元素。

有人知道这里发生了什么吗?

编辑:相关代码:

创建这样的处理器

case CLASS:
 //CtClass is subtype of CtNamedElement
 this.setProcessor(new AnnotatedWithProcessor<CtClass>(targetName, attributeMappings, metapackage));
break;

类定义:

public class AnnotatedWithProcessor<T extends CtNamedElement> extends AbstractProcessor<T> {
    @Override
    public void process(T element) {
     //do stuff here with elements of correct type
    }

然后像这样调用处理器:

//this gets set with a concrete case like above
AbstractProcessor<?> processor;
...
//this astModel gets processed with the respective processor,
//where I expect the process method only getting called for the correct types (in this case only when coming over elements of type CtClass),
//but the method gets called for all types of CtNamedElement, not only for those of type CtClass
this.astModel.processWith(processor);

【问题讨论】:

  • 请分享相关代码。
  • 在原问题中添加了相关代码

标签: java generics polymorphism visitor-pattern


【解决方案1】:

似乎您在某处进行了非法强制转换,但如果不查看更多实施情况就很难判断。谁在打电话给XYZProcessor::process?为什么您希望定义一个通用接口来执行任何类型的过滤?

在这里,我想在黑暗中试一试,但您可能想要的是类型与处理器的查找图。这种代码可能会变得混乱,因此最好使用经过良好测试的方法来限制对该映射的访问:

private final Map<Class, Object> processorMap = new HashMap<Class, Object>();

public <T extends CtElement> void putProcessor(
    Class<T> elementClass, 
    AbstractProcessor<? extends T> processor
) {
     processorMap.put(elementClass, processor);
}

@SuppressWarnings("unchecked")
public <T extends CtElement> AbstractProcessor<? extends T> getProcessor(
    Class<T> elementClass,
) {
    return (AbstractProcessor<? extends T>) processorMap.get(elementClass);
}

现在,当您搜索处理器时,您可以使用此映射找到要调用的正确实现:

public void <T extends CtElement> process(T element) {
    getProcessor(element.getClass()).process(element);
}

您可能希望扩展它以允许每个类有多个实现,或者使用Class::isInstance 过滤element.getClass() 的所有有效处理器的processorMap,然后处理每个有效键。

【讨论】:

  • 我真正想做的是让访问者检查 Java 项目的 AST(这是 AbstractProcessor 所在的框架提供的内容)并获取所有带有特定注释的元素。所以 AnnotatedWithProcessor 会遍历 Java 项目,并对带有某个注解的代码元素进行处理。类型参数应指定我是否要使用附加了注释的类、方法等来执行流程。我也可以只检查元素的类型的过程方法,但想要更清洁
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多