EL自动完成/代码辅助与Eclipse和Spring Beans [英] EL autocomplete / code assist with Eclipse and Spring Beans

查看:98
本文介绍了EL自动完成/代码辅助与Eclipse和Spring Beans的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Eclipse中,至少在使用JBoss工具插件时,JSF/EL的自动完成功能仅适用于旧版@ManagedBean或CDI bean(@Named).
另请参见:  EL提案/自动完成/使用Eclipse在Facelets中进行代码辅助 或  带有facelets(jsf)的Eclipse自动完成(内容辅助)和xhtml  或  针对JSF2 + CDI(焊接)bean + Eclipse Helios的内容辅助
=>总结:
-安装JBoss工具JSF + CDI( http://download.jboss.org/jbosstools /oxygen/stable/updates/,JBoss Web和Java EE/ JBoss工具JSF + 可视页面编辑器 + 上下文和依赖性注入工具);
-在项目属性中:删除Project Facets/"JavaServer Faces",以便将使用非常慢的Eclipse JSF-autocompleter, 激活CDI/CDI支持.

但是使用Spring时不支持,即@Controller@Component.
通常,您应该现在使用对所有JSF范围具有完全支持的CDI bean,但是您可能有理由或现有项目可能使用Spring.
另请参见:  将JSF托管Bean迁移到Spring Bean  或  https://www.beyondjava.net/blog/integrate -jsf-2-spring-3-nicely/

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

解决方案

我研究了JBoss工具的实现,并且进行了微小的更改使Spring用户感到高兴.
:-)
有一个基于JSF工具的解决方案(第一个),另一个基于CDI工具的解决方案(其后).

以下内容基于jbosstools-4.5.2.Final,使用插件文件org.jboss.tools.jsf_3.8.200.v20170908-0911.jar
但是更改应该与其他版本相同或非常相似(相关源文件的最后更改早于2011年12月或2012年9月).

必须在方法getManagedBeanAnnotation()isAnnotationPresent()中扩展类org.jboss.tools.jsf.jsf2.bean.model.impl.AbstractMemberDefinition:

如果未找到@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 + CFR Procyon ,年龄 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.之后)也可以使用,甚至是递归的.
甚至Ctrl + click或F3都可以使用bean名称! 注意:第一次的自动完成调用需要几秒钟的时间才能完成初始bean的转移.

顺便说一句:为此,不需要 激活该项目的CDI支持! (由于没有CDI Builder处于活动状态,因此构建起来要快得多.)


或者,您可以扩展 JBoss工具CDI 功能以发现Spring Bean.它的工作原理相同,此外,它们将用Ctrl + Alt + Z列出(工具栏按钮打开名为Bean的CDI ).
注意:如果非CDI Spring豆被发现为CDI豆,我没有检查是否有任何副作用!

为此,必须在方法getNamedAnnotation()中扩展文件org.jboss.tools.cdi.internal.core.impl.definition.AbstractMemberDefinition:

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工具项目工作的人可能会将其包含在官方插件中.
最好是提供一个首选项字符串,该字符串允许添加任意注释-甚至是项目特定的设置.这样,这将是一个通用解决方案,并且没有可能存在政治接受问题的官方Spring支持".
参见 https://issues.jboss.org/browse/JBIDE-25748

In Eclipse, auto-complete for JSF / EL only works for legacy @ManagedBean or CDI beans (@Named), at least when using the JBoss tools plugin.
See also:   EL proposals / autocomplete / code assist in Facelets with Eclipse   or   Eclipse autocomplete (content assist) with facelets (jsf) and xhtml   or   Content Assist for JSF2 + CDI (weld) beans + Eclipse Helios
=> Summing-up:
- install JBoss tools JSF + CDI (http://download.jboss.org/jbosstools/oxygen/stable/updates/, JBoss Web and Java EE / JBoss Tools JSF + Visual Page Editor + Contexts and Dependency Injection Tools);
- in project properties: remove Project Facets/"JavaServer Faces" so the very slow Eclipse JSF-autocompleter will not be used,   activate CDI / CDI support.

But there is no support when using Spring, i.e. @Controller or @Component.
Typically, you should use CDI beans with full support for all JSF scopes now, but you may have your reasons or an existing project may use Spring.
See also:   Moving JSF Managed Beans to Spring beans   or   https://www.beyondjava.net/blog/integrate-jsf-2-spring-3-nicely/

So, how to support JSF/EL auto-complete for Spring web beans?

解决方案

I digged into the JBoss tools implementation and a small change makes Spring users happy.
:-)
There is a solution based on the JSF tools (first) and an alternative based on the CDI tools (afterwards).

The following is based on jbosstools-4.5.2.Final using the plugin file org.jboss.tools.jsf_3.8.200.v20170908-0911.jar
But the changes should be the same or very similar for other versions (the relevant source files have their last changes back in Dec 2011 or Sept 2012).

The class org.jboss.tools.jsf.jsf2.bean.model.impl.AbstractMemberDefinitionhas to be extended in the methods getManagedBeanAnnotation() and isAnnotationPresent():

If @ManagedBean is not found, then also look for @Controller (which should be used in Spring, so @Service etc. is not offered in JSF). But this may easily be adjusted, see comments in the following source. Additionally, Spring uses the value annotation attribute instead of name - this is solved via a wrapper class.

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;
}

I offer the two compiled classes (main + one inner class) here for direct download:
AbstractMemberDefinition.class + AbstractMemberDefinition$1.class
I promise a trustworthy compile with just above changes (i.e. without any malicious code or similar, you may check via a decompile with CFR, Procyon, aged JAD or Eclipse-ECD) - you may use them directly or perform the compile by yourself (BTW: Does stack overflow offer file attachments?)

Installation:

  • Exit Eclipse.
  • Make a backup copy of the original file
    eclipse_home\plugins\org.jboss.tools.jsf_3.8.200.v20170908-0911.jar
    (e.g. as *.jar_orig).
  • Copy the provided classes into org.jboss.tools.jsf_3.8.200.v20170908-0911.jar\org\jboss\tools\jsf\jsf2\bean\model\impl (e.g. via Total Commander or another tool supporting zip/jar handling; you may even use JDKs jar tool). Note: the A...$1.class is a new file.
  • Start Eclipse again and enjoy!

Go to a JSF page and Type Ctrl+Space after #{ to get a list of beans. Member auto-completion works, too (after #{beanName.), even recursive.
Even Ctrl+click or F3 on the bean name works!
Note: the first auto-completion call needs some seconds for the initial bean disovery.

BTW: For this, there is no need to activate CDI support for the project! (Build is quicker then because no CDI Builder is active.)


Alternatively, you may extend the JBoss tools CDI feature to discover Spring beans. It works the same and additionally they will be listed with Ctrl+Alt+Z (toolbar button Open CDI Named Bean).
Note: I did not check if there are any side effects if the non-CDI Spring beans are discovered as CDI beans!

For this, the file org.jboss.tools.cdi.internal.core.impl.definition.AbstractMemberDefinition has to be extended in the method 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;
}

You have to copy the compiled class (download: 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 support has to be active for the project.


Maybe someone working for the JBoss tools project may include this in the offical plugin.
Best would be to offer a preferences String, that allows to add arbitrary annotations - maybe even a project specific setting. This would then be a generic solution and no "offical Spring support" which might have political acceptance issues.
See https://issues.jboss.org/browse/JBIDE-25748

这篇关于EL自动完成/代码辅助与Eclipse和Spring Beans的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆