我深入研究了 JBoss 工具的实现,一个小小的改变让 Spring 用户感到高兴。
:-)
有一个基于 JSF 工具的解决方案(首先)和一个基于 CDI 工具的替代方案(之后)。
以下是基于jbosstools-4.5.2.Final使用插件文件org.jboss.tools.jsf_3.8.200.v20170908-0911.jar
但其他版本的更改应该相同或非常相似(相关源文件的最后更改是在 2011 年 12 月或 2012 年 9 月)。
班上org.jboss.tools.jsf.jsf2.bean.model.impl.AbstractMemberDefinition
必须在方法中扩展getManagedBeanAnnotation()
and isAnnotationPresent()
:
If @ManagedBean
没找到,那就再找@Controller
(应该在Spring中使用,所以@Service
JSF 中不提供等)。但这可以很容易地调整,请参阅以下来源中的评论。此外,Spring 使用value
注释属性而不是name
- 这是通过包装类解决的。
public boolean isAnnotationPresent(String annotationTypeName) {
//TW: added Spring annotations
boolean b = (getAnnotation(annotationTypeName) != null);
if (!b && JSF2Constants.MANAGED_BEAN_ANNOTATION_TYPE_NAME.equals(annotationTypeName)) {
b = (getAnnotation("org.springframework.stereotype.Controller") != null);
/* with support for all Spring annotations:
b = (getAnnotation("org.springframework.stereotype.Controller") != null
|| getAnnotation("org.springframework.stereotype.Service") != null
|| getAnnotation("org.springframework.stereotype.Repository") != null
|| getAnnotation("org.springframework.stereotype.Component") != null);
*/
}
return b;
}
public AnnotationDeclaration getManagedBeanAnnotation() {
AnnotationDeclaration ad = annotationsByType.get(JSF2Constants.MANAGED_BEAN_ANNOTATION_TYPE_NAME);
//TW: added Spring annotations
if (ad != null) return ad;
ad = annotationsByType.get("org.springframework.stereotype.Controller");
/* with support for all Spring annotations:
if (ad == null) ad = annotationsByType.get("org.springframework.stereotype.Service");
if (ad == null) ad = annotationsByType.get("org.springframework.stereotype.Repository");
if (ad == null) ad = annotationsByType.get("org.springframework.stereotype.Component");
*/
if (ad != null) {
// create wrapper to map "value" (used by Spring) to "name" (which is used by @ManageBean)
ad = new AnnotationDeclaration() {
private AnnotationDeclaration wrapped;
AnnotationDeclaration init(AnnotationDeclaration wrappedAD) {
this.wrapped = wrappedAD;
return this;
}
@Override
public Object getMemberValue(String name) {
Object val = wrapped.getMemberValue(name);
if (val == null && "name".equals(name)) {
val = wrapped.getMemberValue(null);
}
return val;
}
@Override
public Object getMemberValue(String name, boolean resolve) {
Object result = null;
if (resolve) {
result = this.getMemberConstantValue(name);
}
if (result == null) {
result = this.getMemberValue(name);
}
return result;
}
@Override
public void setDeclaration(IJavaAnnotation annotation) {
wrapped.setDeclaration(annotation);
}
@Override
public IJavaAnnotation getDeclaration() {
return wrapped.getDeclaration();
}
@Override
public IResource getResource() {
return wrapped.getResource();
}
@Override
public IMemberValuePair[] getMemberValuePairs() {
return wrapped.getMemberValuePairs();
}
@Override
public Object getMemberConstantValue(String name) {
return wrapped.getMemberConstantValue(name);
}
@Override
public Object getMemberDefaultValue(String name) {
return wrapped.getMemberDefaultValue(name);
}
@Override
public IMember getParentMember() {
return wrapped.getParentMember();
}
@Override
public String getTypeName() {
return wrapped.getTypeName();
}
@Override
public IType getType() {
return wrapped.getType();
}
@Override
public int getLength() {
return wrapped.getLength();
}
@Override
public int getStartPosition() {
return wrapped.getStartPosition();
}
@Override
public IAnnotationType getAnnotation() {
return wrapped.getAnnotation();
}
@Override
public IAnnotation getJavaAnnotation() {
return wrapped.getJavaAnnotation();
}
@Override
public IMember getSourceMember() {
return wrapped.getSourceMember();
}
@Override
public IJavaElement getSourceElement() {
return wrapped.getSourceElement();
}
}.init(ad); // class
}
return ad;
}
我在这里提供了两个编译好的类(主类+一个内部类)供直接下载:
AbstractMemberDefinition.class + AbstractMemberDefinition$1.class
我保证通过上述更改进行值得信赖的编译(即没有任何恶意代码或类似代码,您可以通过反编译进行检查CFR, Procyon, aged JAD or Eclipse-ECD) - 您可以直接使用它们或自己执行编译(顺便说一句:堆栈溢出是否提供文件附件?)
安装:
- 退出 Eclipse。
- 制作原始文件的备份副本
eclipse_home\plugins\org.jboss.tools.jsf_3.8.200.v20170908-0911.jar
(例如 *.jar_orig)。
- 将提供的类复制到
org.jboss.tools.jsf_3.8.200.v20170908-0911.jar\org\jboss\tools\jsf\jsf2\bean\model\impl
(例如,通过 Total Commander 或其他支持 zip/jar 处理的工具;您甚至可以使用 JDK 的 jar 工具)。注:A...$1.class
是一个新文件。
- 再次启动 Eclipse 并享受吧!
转到 JSF 页面并在后面键入 Ctrl+Space#{
获取 Bean 列表。会员自动完成功能也有效(之后#{beanName.
),甚至递归。
即使在 Bean 名称上按 Ctrl+单击或 F3 也可以!
注意:第一次自动完成调用需要几秒钟来进行初始 bean 发现。
顺便说一句:为此,有no需要激活项目的CDI支持! (构建速度更快,因为没有 CDI Builder 处于活动状态。)
或者,您可以延长JBoss 工具 CDI发现 Spring beans 的功能。它的工作原理相同,此外它们将通过 Ctrl+Alt+Z(工具栏按钮打开 CDI 命名 Bean).
注意:我没有检查如果非 CDI Spring bean 被发现为 CDI bean 是否有任何副作用!
为此,文件org.jboss.tools.cdi.internal.core.impl.definition.AbstractMemberDefinition
必须在方法中扩展getNamedAnnotation()
:
public AnnotationDeclaration getNamedAnnotation() {
AnnotationDeclaration ad = getAnnotation(CDIConstants.NAMED_QUALIFIER_TYPE_NAME);
//TW: added Spring annotations
if (ad != null) return ad;
ad = getAnnotation("org.springframework.stereotype.Controller");
/* add additional Spring annotations, if desired:
if (ad != null) return ad;
ad = getAnnotation("org.springframework.stereotype.Service");
if (ad != null) return ad;
ad = getAnnotation("org.springframework.stereotype.Repository");
if (ad != null) return ad;
ad = getAnnotation("org.springframework.stereotype.Component");
*/
return ad;
}
您必须复制编译的类(下载:CDI-AbstractMemberDefinition.class) into plugins\org.jboss.tools.cdi.core_1.8.201.v20171221-1913.jar\org\jboss\tools\cdi\internal\core\impl\definition
CDI 支持必须对该项目有效。
也许为 JBoss 工具项目工作的人可能会将此包含在官方插件中.
最好是提供一个首选项字符串,它允许添加任意注释 - 甚至可能是项目特定的设置。这将是一个通用的解决方案,并且没有可能存在政治接受问题的“官方 Spring 支持”。
See https://issues.jboss.org/browse/JBIDE-25748