- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我有一个大型 wicket 组件库,这些组件使用自定义注释 @ReferencedResource
或另一个注释 @ReferencedResources
进行注释,具有 ReferencedResouce[] 值()
参数允许多个注释。
这是一个示例代码片段:
@ReferencedResources({
@ReferencedResource(value = Libraries.MOO_TOOLS, type = ResourceType.JAVASCRIPT),
@ReferencedResource(value = "behaviors/promoteSelectOptions", type = ResourceType.JAVASCRIPT) })
public class PromoteSelectOptionsBehavior extends AbstractBehavior{
...
}
到目前为止,我使用 apt检查引用的资源是否确实存在。例如。
@ReferencedResource(value = "behaviors/promoteSelectOptions",
type = ResourceType.JAVASCRIPT)
除非可以在类路径中找到文件 js/behaviors/promoteSelectOptions.js
,否则将导致编译失败。这部分工作得很好。
现在我也是 DRY 的粉丝,我想使用相同的注释在创建对象时将资源实际注入(inject)到对象中。我使用 AspectJ 实现了其中的一部分。
带注释的对象总是 Component 的任一实例或 AbstractBehavior .
对于组件来说,事情很简单,只需要在构造函数之后匹配即可。这是执行此操作的建议:
pointcut singleAnnotation() : @within(ReferencedResource);
pointcut multiAnnotation() : @within(ReferencedResources);
after() : execution(Component+.new(..)) && (singleAnnotation() || multiAnnotation()){
final Component component = (Component) thisJoinPoint.getTarget();
final Collection<ReferencedResource> resourceAnnotations =
// gather annotations from cache
this.getResourceAnnotations(component.getClass());
for(final ReferencedResource annotation : resourceAnnotations){
// helper utility that handles the creation of statements like
// component.add(JavascriptPackageResource.getHeaderContribution(path))
this.resourceInjector.inject(component, annotation);
}
}
但是,对于行为,我需要将资源附加到响应,而不是行为本身。以下是我使用的切入点:
pointcut renderHead(IHeaderResponse response) :
execution(* org.apache.wicket.behavior.AbstractBehavior+.renderHead(*))
&& args(response);
这里是建议:
before(final IHeaderResponse response) :
renderHead(response) && (multiAnnotation() || singleAnnotation()) {
final Collection<ReferencedResource> resourceAnnotations =
this.getResourceAnnotations(thisJoinPoint.getTarget().getClass());
for(final ReferencedResource resource : resourceAnnotations){
this.resourceInjector.inject(response, resource);
}
}
如果类重写 renderHead(response),这也能很好地工作方法,但在许多情况下,这并不是必需的,因为父类(super class)已经实现了基本功能,而子类仅添加了一些配置。因此,一种解决方案是让这些类定义如下方法:
@Override
public void renderHead(IHeaderResponse response){
super.renderHead(response);
}
我讨厌这个,因为这是死代码,但目前这是我看到的唯一可行的选项,所以我正在寻找其他解决方案。
编辑:
我已经使用 APT 和 sun javac 调用创建了一个可行的解决方案。然而,这会导致下一个问题:Running APT and AspectJ in the same project using maven .
无论如何,只要有空闲时间,我就会发布这个问题(或部分问题)的答案。
最佳答案
回答我自己的问题:
下面是插入 super 调用的相关代码:
这些字段都是在init(env)中初始化的或 process(annotations, roundEnv) :
private static Filer filer;
private static JavacProcessingEnvironment environment;
private static Messager messager;
private static Types types;
private static JavacElements elementUtils;
private Trees trees;
private TreeMaker treeMaker;
private IdentityHashMap<JCCompilationUnit, Void> compilationUnits;
private Map<String, JCCompilationUnit> typeMap;
如果具有注解的 AbstractBehavior
的子类型没有覆盖 renderHead(response)
方法,下面是调用的逻辑:
private void addMissingSuperCall(final TypeElement element){
final String className = element.getQualifiedName().toString();
final JCClassDecl classDeclaration =
// look up class declaration from a local map
this.findClassDeclarationForName(className);
if(classDeclaration == null){
this.error(element, "Can't find class declaration for " + className);
} else{
this.info(element, "Creating renderHead(response) method");
final JCTree extending = classDeclaration.extending;
if(extending != null){
final String p = extending.toString();
if(p.startsWith("com.myclient")){
// leave it alone, we'll edit the super class instead, if
// necessary
return;
} else{
// @formatter:off (turns off eclipse formatter if configured)
// define method parameter name
final com.sun.tools.javac.util.Name paramName =
elementUtils.getName("response");
// Create @Override annotation
final JCAnnotation overrideAnnotation =
this.treeMaker.Annotation(
Processor.buildTypeExpressionForClass(
this.treeMaker,
elementUtils,
Override.class
),
// with no annotation parameters
List.<JCExpression> nil()
);
// public
final JCModifiers mods =
this.treeMaker.Modifiers(Flags.PUBLIC,
List.of(overrideAnnotation));
// parameters:(final IHeaderResponse response)
final List<JCVariableDecl> params =
List.of(this.treeMaker.VarDef(this.treeMaker.Modifiers(Flags.FINAL),
paramName,
Processor.buildTypeExpressionForClass(this.treeMaker,
elementUtils,
IHeaderResponse.class),
null));
//method return type: void
final JCExpression returnType =
this.treeMaker.TypeIdent(TypeTags.VOID);
// super.renderHead(response);
final List<JCStatement> statements =
List.<JCStatement> of(
// Execute this:
this.treeMaker.Exec(
// Create a Method call:
this.treeMaker.Apply(
// (no generic type arguments)
List.<JCExpression> nil(),
// super.renderHead
this.treeMaker.Select(
this.treeMaker.Ident(
elementUtils.getName("super")
),
elementUtils.getName("renderHead")
),
// (response)
List.<JCExpression> of(this.treeMaker.Ident(paramName)))
)
);
// build code block from statements
final JCBlock body = this.treeMaker.Block(0, statements);
// build method
final JCMethodDecl methodDef =
this.treeMaker.MethodDef(
// public
mods,
// renderHead
elementUtils.getName("renderHead"),
// void
returnType,
// <no generic parameters>
List.<JCTypeParameter> nil(),
// (final IHeaderResponse response)
params,
// <no declared exceptions>
List.<JCExpression> nil(),
// super.renderHead(response);
body,
// <no default value>
null);
// add this method to the class tree
classDeclaration.defs =
classDeclaration.defs.append(methodDef);
// @formatter:on turn eclipse formatter on again
this.info(element,
"Created renderHead(response) method successfully");
}
}
}
}
关于java - AOP 或 APT 用于覆盖父类(super class)的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3652463/
我一直在尝试让 yum 在代理设置后面工作 导出 https_proxy、http_proxy 和 ftp_proxy。 这对 apt-get 或 yum 不起作用,但当我在 /etc/apt/apt
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 这个问题似乎不是关于 a specific programming problem, a software
为什么基于 Debian 的 Linux 发行版具有apt以及apt-get?apt是替换还是他们apt-get 有不同的目的?我们解释这两个命令之间的关系。 Debian 软件包管理系统 创建Lin
例如,当安装 lirc 包时,它会提供配置对话框屏幕。如何自动化以选择默认值(或可能提供特定值)并继续? 现在我有一个简单的脚本: #!/usr/bin/env python import a
我有一个 APT 处理器,在某些情况下会显示警告。我的项目正在使用 maven1 构建调用 ant:apt 如何让maven在满足警告条件时失败? (处理器可以修改) 谢谢。 最佳答案 注释处理器需要
我在 Windows 上使用 WSL。我无法使用 apt 或 apt-get 这是我在尝试使用 apt 或 apt-get 时收到的错误消息。 ~$ apt apt: error while load
我正在寻找一些命令行说明。我应该有带有 Python 2.7 的 Ubuntu Linux Server(为什么不能简单解释如何在你的 ULS 上获取 Python 2.7!)。 (编辑——显然 Py
当我尝试构建一个简单的docker映像时:。在Dockerfile中:。输出为:。我试过:。我之前构建了多个docker映像,一切都运行得很好。而现在,我总是会突然发现这个错误。
在 bash 脚本中,我想安装一个包。在理智地这样做之前,我需要检查是否没有其他 apt-get 实例。或 dpkg已经在工作。如果是这种情况,apt-get会失败,因为它已经锁定。 是否足以检查/v
这个问题有很多相关的问题,但没有一个回答我想知道的: 我通常是这样工作的: 安装 python 3.5+ sudo apt install virtualenv virtualenv -p/usr/b
我有一个很久以前安装的 Ubuntu 20.04。出于某种原因,即使我很确定我从未使用过它,我也安装了 OCaml。我试图通过卸载 OCaml sudo apt-get remove ocaml
我编写了一个 Ansible 剧本,其中包括运行 apt-get dist-upgrade。我确保在剧本的顶部有 become: true 和 become_user: root 以获得运行升级的 s
现在我的 Vagrantfile 中有以下内容: config.vm.provision :chef_solo do |chef| chef.cookbooks_path = "cookboo
我使用 gitlab ci 来构建 docker 镜像,我想安装 python。当我构建时,以下是我的 gitlab-ci.yml: image: docker:stable stages: -
我正在尝试在 Ubuntu 16.04 中启动此容器,步骤之一是:RUN apt update && apt install -y sudo 此步骤因暂时无法解析某些存储库而失败。这是此错误的输出:
我卡在了一个点上,我无法进步,很抱歉这个愚蠢的问题。我为此进行了很多搜索,但我不知道我错过了什么。请帮助我。 我研究了 python 中的模块和类。现在我想使用 python 和 apt 进行一些操作
在linux based os的某些软件安装中,我们有时使用apt update,有时使用apt-get update。 linux终端究竟如何理解apt only和apt-get的含义? 最佳答案
我正在编写 Puppet list ,以便在我的机器上安装大量软件。 许多软件包仅具有 PPA 中最新版本的二进制文件,例如名为 AutoKey 的非常方便的服务。 . 要安装此最新版本的软件包,必须
关闭。这个问题不满足Stack Overflow guidelines .它目前不接受答案。 想改善这个问题吗?更新问题,使其成为 on-topic对于堆栈溢出。 2年前关闭。 Improve thi
我正在编写我的 k8s 升级 ansible 剧本,其中我需要做 apt-mark unhold kubeadm .现在,我试图避免使用 ansible command或 shell调用模块apt如果
我是一名优秀的程序员,十分优秀!