在Eclipse中,JSF / EL的自动完成仅适用于旧版@ManagedBean
或CDI bean(@Named
),至少在使用JBoss工具插件时是这样的。
另请参阅:EL proposals / autocomplete / code assist in Facelets with Eclipse或Eclipse autocomplete (content assist) with facelets (jsf) and xhtml或Content Assist for JSF2 + CDI (weld) beans + Eclipse Helios
=>总结起来:
- 安装JBoss工具JSF + CDI(http://download.jboss.org/jbosstools/oxygen/stable/updates/,JBoss Web和Java EE / JBoss Tools JSF + Visual Page Editor + 上下文和依赖注入工具);
- 在项目属性中:删除Project Facets /“JavaServer Faces”,这样非常慢的Eclipse JSF-autocompleter将不使用,激活CDI / CDI支持。
但是使用Spring时没有任何支持,即@Controller
或@Component
通常,您现在应该使用完全支持所有JSF范围的CDI bean,但您可能有原因或现有项目可能使用Spring。
另请参阅:Moving JSF Managed Beans to Spring beans或https://www.beyondjava.net/blog/integrate-jsf-2-spring-3-nicely/
那么,如何支持Spring Web bean的JSF / EL自动完成?
答案 0 :(得分:1)
我深入研究了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()
中扩展课程isAnnotationPresent()
:
如果找不到@ManagedBean
,那么还要查找@Controller
(应该在Spring中使用,因此JSF中不提供@Service
等)。但这可能很容易调整,请参阅以下来源中的评论。另外,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,年龄JAD或Eclipse-ECD进行检查 - 您可以直接使用它们或自己执行编译(BTW:堆栈溢出是否提供文件附件?)
安装:
eclipse_home\plugins\org.jboss.tools.jsf_3.8.200.v20170908-0911.jar
org.jboss.tools.jsf_3.8.200.v20170908-0911.jar\org\jboss\tools\jsf\jsf2\bean\model\impl
(例如,通过Total Commander或支持zip / jar处理的其他工具;您甚至可以使用JDKs jar工具)。注意:A...$1.class
是一个新文件。 转到JSF页面并在#{
后键入Ctrl + Space以获取bean列表。会员自动完成工作(#{beanName.
之后),甚至递归
即使按住Ctrl +单击或bean名称上的F3也可以!
注意:第一次自动完成调用需要几秒钟才能获得初始bean。
BTW:为此,没有需要为项目激活CDI支持! (然后构建更快,因为没有CDI Builder处于活动状态。)
或者,您可以扩展 JBoss工具CDI 功能来发现Spring bean。它的工作方式相同,另外它们将按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)复制到plugins\org.jboss.tools.cdi.core_1.8.201.v20171221-1913.jar\org\jboss\tools\cdi\internal\core\impl\definition
CDI支持必须对项目有效。
也许为JBoss工具项目工作的人可能会将其包含在官方插件中。
最好的方法是提供一个首选项String,它允许添加任意注释 - 甚至可能是项目特定的设置。这将是一个通用的解决方案,而不是正式的Spring支持"可能有政治接受问题
见https://issues.jboss.org/browse/JBIDE-25748
答案 1 :(得分:0)
我尝试了由@Thies解释的第一个解决方案,它仍然适用于org.jboss.tools.jsf_3.8.500.v20200930-0907.jar
。实际上,这是我发现从xhtml文件访问Spring Bean(具有@Component
等)的唯一方法。我希望他为.class
文件提供对所有Spring注释的支持,而不仅仅是@Controller
的支持,但后来我意识到我可以为每个人做。因此,我下载了源代码,并重新编译了这两个类以提供@Component
支持和其他Spring注释。我也想添加重新编译文件所需的详细步骤,以使像我这样的经验不足的编码人员也可以这么做。 :)
我在全新安装的“ Eclipse JEE 2020-09 R Win32 x86_64”和空的Maven存储库上尝试了所有操作。下面的大写信息是我第一次做错了然后纠正的事情,因此,我希望您不要再重复浪费时间的错误。 :)
在开始由@Thies解释的第一个解决方案之前:
<your-eclipse-workspace>\jbosstools-javaee-master\jsf\plugins\org.jboss.tools.jsf\
文件夹。然后点击'Finish'“按钮。等待Eclipse完成其工作,不要尝试匆匆忙忙,只需等待。:)它将下载总计的Maven依赖项。 20-25 MB。<your-eclipse-workspace>\jbosstools-javaee-master\jsf\plugins\org.jboss.tools.jsf\src\org\jboss\tools\jsf\jsf2\bean\model\impl\AbstractMemberDefinition.java
文件(在Eclipse项目中找到它)并执行@Thies建议的更改,作为对先前post的第一个解决方案。但这一次通过支持所有Spring注释进行更改。 :)看到他注释掉的代码,并根据需要进行更新。可能是这样的:import org.eclipse.jdt.core.IMember;
import org.eclipse.jdt.core.IMemberValuePair;
import org.jboss.tools.common.java.IAnnotationType;
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
|| 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");
if (ad == null) ad = annotationsByType.get("org.springframework.stereotype.Component");
if (ad == null) ad = annotationsByType.get("org.springframework.stereotype.Service");
if (ad == null) ad = annotationsByType.get("org.springframework.stereotype.Repository");
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
和<your-eclipse-workspace>\jbosstools-javaee-master\jsf\plugins\org.jboss.tools.jsf\target\classes\org\jboss\tools\jsf\jsf2\bean\model\impl
文件。这是我编译为支持4个spring注释的AbstractMemberDefinition.class和AbstractMemberDefinition$1.class文件; @Component
,@Service
,@Repository
和@Controller
。我希望他们可以为某人节省一些时间。
我希望将来有人发布https://issues.jboss.org/browse/JBIDE-25748的结果,而由于我们的懒惰,我们回想起这些日子以及我们所做的所有编码,我们会很开心。 :)