Eclipse自动完成/代码辅助Eclipse和Spring Beans

时间:2018-02-22 17:29:59

标签: spring eclipse jsf autocomplete el

在Eclipse中,JSF / EL的自动完成仅适用于旧版@ManagedBean或CDI bean(@Named),至少在使用JBoss工具插件时是这样的。
另请参阅:EL proposals / autocomplete / code assist in Facelets with EclipseEclipse autocomplete (content assist) with facelets (jsf) and xhtmlContent 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 beanshttps://www.beyondjava.net/blog/integrate-jsf-2-spring-3-nicely/

那么,如何支持Spring Web bean的JSF / EL自动完成?

2 个答案:

答案 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.AbstractMemberDefinitiongetManagedBeanAnnotation()中扩展课程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
我保证一个值得信赖的编译只有上面的更改(即没有任何恶意代码或类似的,您可以通过反编译CFRProcyon,年龄JADEclipse-ECD进行检查 - 您可以直接使用它们或自己执行编译(BTW:堆栈溢出是否提供文件附件?)

安装:

  • 退出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处理的其他工具;您甚至可以使用JDKs jar工具)。注意:A...$1.class是一个新文件。
  • 再次启动Eclipse并享受!

转到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解释的第一个解决方案之前:

  1. 仅将' JBoss Tools JSF' 添加到Eclipse。 此步骤必须为第一步,因为编译过程(后续步骤)要求在此步骤中安装一些常用的库。您不需要安装任何版本的STS(Spring Tools Suite)。不要使用“ Eclipse Marketplace”,它只会使您感到困惑。
    • 使用Eclipse主菜单中的“帮助”>“安装新软件...”
    • 点击'添加...'按钮,添加
    • 'JBoss Tools'存储库。我将其命名为'JBoss Tools',我的位置网址为 http://download.jboss.org/jbosstools/photon/stable/updates/ 。单击“更新站点” 标签下的 https://tools.jboss.org/downloads/jbosstools/ 上的“下载” 按钮后,我发现了该URL。
    • 在下拉框中选择存储库后,仅查找并检查'JBoss Tools JSF'(位于'JBoss WEB和Java EE开发'树),然后按照说明进行操作。 Eclipse会在必要时自动安装其依赖项,因此您无需选中任何其他复选框,只需选中1。
    • Eclipse将请求安装'Jboss Tools JSF'的权限,因为Eclipse不信任'JBoss Tools'存储库。无论如何安装,然后按照安装结束时的要求重新启动Eclipse。
  2. 从GitHub here下载最新的'javaee'项目源代码。将其下载为zip归档文件(我们将不使用全部文件),将'jbosstools-javaee-master'文件夹解压缩到您的日食工作区中但不要全部导入 。这是没有必要的,并且会花费一些时间。继续阅读:
    • 在Eclipse上,选择“文件”>“导入...”
    • “导入” 窗口中,仅浏览和选择<your-eclipse-workspace>\jbosstools-javaee-master\jsf\plugins\org.jboss.tools.jsf\ 文件夹。然后点击'Finish'“按钮。等待Eclipse完成其工作,不要尝试匆匆忙忙,只需等待。:)它将下载总计的Maven依赖项。 20-25 MB。
    • 根据需要安装任何东西(例如“ tycho”插件)。按照Eclipse的说明进行操作。即使Eclipse不信任它们,也无论如何都要安装。如果需要,请重新启动Eclipse。
    • 等待Eclipse自动启动任何正在进行的操作。检查Eclipse的'Progress'视图,以查看是否有任何正在进行的操作。
  3. 在Eclipse的“项目资源管理器” 视图上,右键单击该项目('org.jboss.tools.jsf'项目)。然后选择'Maven'->'Update Project',以确保一切正常。
  4. 在Eclipse主菜单上,找到'Project'->'Clean'以打开'Clean'窗口。确保仅选择“ org.jboss.tools.jsf”项目,并且“仅构建选定的项目” 选项处于活动状态以节省时间(假设工作空间中还有其他不相关的项目)给我们)。然后点击'Clean'按钮并等待eclipse清除重建项目。
  5. 找到<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;
}
  1. 重复步骤4。 (在Eclipse主菜单上,执行'Project'>'Clean',然后等待Eclipse重建)
  2. 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文件。
  3. 退出Eclipse并从上一个@Thies上的post的第一个解决方案开始执行“安装”步骤。我使用“ 7-Zip”来打开和更新所有ZIP和JAR归档文件,因为它是免费的且易于使用。

这是我编译为支持4个spring注释的AbstractMemberDefinition.classAbstractMemberDefinition$1.class文件; @Component@Service@Repository@Controller。我希望他们可以为某人节省一些时间。

我希望将来有人发布https://issues.jboss.org/browse/JBIDE-25748的结果,而由于我们的懒惰,我们回想起这些日子以及我们所做的所有编码,我们会很开心。 :)