Eclipse autocomplete (content assist) with facelets (jsf) and xhtml
Found the solution pretty quickly after asking the question (and an hour after I started attempting to solve it):
Window > Preferences > General > Content Types > Text > JSP > Add (xhtml)
Makes the files be treated as jsp ones. Thus when they are opened with the JSP editor, the autocomplete of any tag library that has its definitions in .tld
format (<h:
and <f
for example) works. Facelets, and facelets-only tags still don't work. Their .tld
equivalents should be added somewhere in the projects. Facelet's tld can be found here.
Another, a bit more complex solution is described here.
EL proposals / autocomplete / code assist in Facelets with Eclipse
Eclipse doesn't support this out the box. Even the support in JSP is very limited. Only the properties of <jsp:useBean>
and managed beans hardcoded as <managed-bean>
in faces-config.xml
are available by autocomplete. There are however plugins which supports EL autocomplete on @ManagedBean
and @Named
beans.
For example, the JBoss Tools plugin (specifically the CDI feature) which can be installed as described here: How do I Install JBoss AS / WildFly Server in Eclipse for Java EE.
(which has in its current 3.2.0 version unicode bugs, as you see above in the rightmost window)
You can even use Ctrl+Click on the managed bean name #{bean}
in an EL expression in Facelets file to navigate to the concrete backing bean class. You can also use Ctrl+Shift+G on the managed bean method in a backing bean class to find all references to the particular property or action in Facelets files.
The Aptana plugin is told to work fine for EL proposals in JSPs, but I am not sure for Facelets. I didn't had good experiences with installing and configuring the plugin for JSP some years ago.
See also:
- Properties of new tags using composite component are not displayed by Eclipse auto complete shortcurt
JSF editor autocomplete (xhtml) for STS 4
In Eclipse JSF is supported not via STS, but via the Eclipse WTP JavaServer Faces (JSF) Tools.
For Spring and JSF support install STS 4 into the Eclipse IDE for Enterprise Java Developers (which contains Eclipse JSF Tools) or install the Eclipse Java EE Developer Tools into an Eclipse IDE with STS 4 but without JSF support.
EL autocomplete / code assist with Eclipse and Spring 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.AbstractMemberDefinition
has 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: theA...$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
How to make Eclipse autocomplete work with JSF composite components in JAR?
Unfortunately support for JSF in Eclipse is not as comfortable as in NetBeans.
I prefer to use the RichFaces Tools plugin from jBoss (which works perfectly without RichFaces and with any container). You might give it a try.
Better support for JSF is considered to be available with the current eclipse release 'Juno' though I have not tried it yet.
Eclipse JSF content assist not working
I had the same problem with Kepler and solved the problem by
- installing JBoss Tools
- Right clicking the project > Configure -> Add JSF capabilities
Hope that helps others, too.
Related Topics
Using Ntlm Authentication in Java Applications
Hashcode and Equals for Hashset
Java - Regular Expression Finding Comments in Code
Why Doesn't Java.Util.Collection Implement the New Stream Interface
Calling Base Class Overridden Function from Base Class Method
Copy Directory from a Jar File
Production Settings File for Log4J
Adding Jradiobutton into Jtable
What Code Does the Compiler Generate for Autoboxing
How to Insert a Row Between Two Rows in an Existing Excel with Hssf (Apache Poi)
Java: Global Exception Handler
Why Should I Use Concurrent Characteristic in Parallel Stream with Collect
Why Functional Interfaces in Java 8 Have One Abstract Method
Is There a Commonly Used Rational Numbers Library in Java
How Can a Keylistener Detect Key Combinations (E.G., Alt + 1 + 1)