diff --git a/enterprise/web.jsf.editor/src/org/netbeans/modules/web/jsf/editor/el/JsfELVariableResolver.java b/enterprise/web.jsf.editor/src/org/netbeans/modules/web/jsf/editor/el/JsfELVariableResolver.java index 8c5288cbcc79..c6861023d58e 100644 --- a/enterprise/web.jsf.editor/src/org/netbeans/modules/web/jsf/editor/el/JsfELVariableResolver.java +++ b/enterprise/web.jsf.editor/src/org/netbeans/modules/web/jsf/editor/el/JsfELVariableResolver.java @@ -207,7 +207,7 @@ public void run(ResultIterator resultIterator) throws Exception { public List getBeansInScope(String scope, Snapshot snapshot, ResolverContext context) { List result = new ArrayList<>(); for (FacesManagedBean bean : getJsfManagedBeans(snapshot.getSource().getFileObject(), context)) { - if(bean.getManagedBeanClass() != null && bean.getManagedBeanName() == null) { + if(bean.getManagedBeanClass() != null && bean.getManagedBeanName() != null) { if (scope.equals(bean.getManagedBeanScopeString())) { result.add(VariableInfo.createResolvedVariable(bean.getManagedBeanName(), bean.getManagedBeanClass())); } diff --git a/enterprise/web.jsf.editor/src/org/netbeans/modules/web/jsf/editor/el/WebBeansELVariableResolver.java b/enterprise/web.jsf.editor/src/org/netbeans/modules/web/jsf/editor/el/WebBeansELVariableResolver.java index beafc9ef848a..c7236a57316e 100644 --- a/enterprise/web.jsf.editor/src/org/netbeans/modules/web/jsf/editor/el/WebBeansELVariableResolver.java +++ b/enterprise/web.jsf.editor/src/org/netbeans/modules/web/jsf/editor/el/WebBeansELVariableResolver.java @@ -23,12 +23,12 @@ import java.util.Collections; import java.util.LinkedList; import java.util.List; +import java.util.Locale; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel; -import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelException; import org.netbeans.modules.parsing.api.Snapshot; import org.netbeans.modules.web.beans.api.model.WebBeansModel; import org.netbeans.modules.web.el.spi.ELVariableResolver; @@ -50,7 +50,7 @@ public final class WebBeansELVariableResolver implements ELVariableResolver { @Override public FieldInfo getInjectableField(String beanName, FileObject target, ResolverContext context) { for (WebBean bean : getWebBeans(target, context)) { - if (beanName.equals(bean.getName())) { + if (beanName.equals(bean.name())) { return new FieldInfo(bean.getEnclodingClass(), bean.getBeanClassName()); } } @@ -61,7 +61,7 @@ public FieldInfo getInjectableField(String beanName, FileObject target, Resolver public String getBeanName(String clazz, FileObject target, ResolverContext context) { for (WebBean bean : getWebBeans(target, context)) { if (clazz.equals(bean.getBeanClassName())) { - return bean.getName(); + return bean.name(); } } return null; @@ -77,7 +77,7 @@ public List getManagedBeans(FileObject target, ResolverContext con List beans = getWebBeans(target, context); List result = new ArrayList<>(beans.size()); for (WebBean bean : beans) { - result.add(VariableInfo.createResolvedVariable(bean.getName(), bean.getBeanClassName())); + result.add(VariableInfo.createResolvedVariable(bean.name(), bean.getBeanClassName())); } return result; } @@ -89,7 +89,13 @@ public List getVariables(Snapshot snapshot, int offset, ResolverCo @Override public List getBeansInScope(String scope, Snapshot snapshot, ResolverContext context) { - return Collections.emptyList(); + List beans = getWebBeans(snapshot.getSource().getFileObject(), context); + // bean's scope is CDI FQDN (eg. "jakarta.enterprise.context.RequestScoped") + // the received scope filter, instead, is the simple name (eg. "request") + return beans.stream() + .filter(bean -> bean.scope() != null && bean.scope().toLowerCase(Locale.ROOT).contains(scope)) + .map(bean -> VariableInfo.createResolvedVariable(bean.name(), bean.getBeanClassName())) + .toList(); } @Override @@ -119,13 +125,11 @@ private static List getNamedBeans(MetadataModel webBeans //filter out null elements - probably a WebBeansModel bug, //happens under some circumstances when renaming/deleting beans if (e != null) { - webBeans.add(new WebBean(e, metadata.getName(e))); + webBeans.add(new WebBean(e, metadata.getName(e), metadata.getScope(e))); } } return webBeans; }); - } catch (MetadataModelException ex) { - Exceptions.printStackTrace(ex); } catch (IOException ex) { Exceptions.printStackTrace(ex); } @@ -133,39 +137,23 @@ private static List getNamedBeans(MetadataModel webBeans return Collections.emptyList(); } - private static final class WebBean { - - private final Element element; - private final String name; - - private WebBean(Element element, String name) { - this.element = element; - this.name = name; - } - - private Element getElement() { - return element; - } + private record WebBean(Element element, String name, String scope) { public String getBeanClassName() { - if (getElement() instanceof ExecutableElement methodElement) { + if (element instanceof ExecutableElement methodElement) { String returnType = methodElement.getReturnType().toString(); int genericOffset = returnType.indexOf('<'); return genericOffset == -1 ? returnType : returnType.substring(0, genericOffset); } else { - return getElement().asType().toString(); + return element.asType().toString(); } } - public String getName() { - return name; - } - private String getEnclodingClass() { - if (getElement() instanceof ExecutableElement methodElement) { + if (element instanceof ExecutableElement methodElement) { return methodElement.getEnclosingElement().asType().toString(); } else { - return getElement().asType().toString(); + return element.asType().toString(); } } } diff --git a/enterprise/web.jsf.editor/test/unit/data/testWebProject/src/java/beans/SessionBean.java b/enterprise/web.jsf.editor/test/unit/data/testWebProject/src/java/beans/SessionBean.java new file mode 100644 index 000000000000..fd480bbe8301 --- /dev/null +++ b/enterprise/web.jsf.editor/test/unit/data/testWebProject/src/java/beans/SessionBean.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package beans; + +import javax.faces.bean.ManagedBean; +import javax.faces.bean.SessionScoped; + +@ManagedBean(name="SessionBean") +@SessionScoped +public class SessionBean { + +} diff --git a/enterprise/web.jsf.editor/test/unit/src/org/netbeans/modules/web/jsf/editor/el/JsfELVariableResolverTest.java b/enterprise/web.jsf.editor/test/unit/src/org/netbeans/modules/web/jsf/editor/el/JsfELVariableResolverTest.java new file mode 100644 index 000000000000..31047011e916 --- /dev/null +++ b/enterprise/web.jsf.editor/test/unit/src/org/netbeans/modules/web/jsf/editor/el/JsfELVariableResolverTest.java @@ -0,0 +1,137 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.web.jsf.editor.el; + +import java.io.IOException; +import java.util.List; + +import org.netbeans.modules.parsing.api.Snapshot; +import org.netbeans.modules.web.el.spi.ELVariableResolver; +import org.netbeans.modules.web.el.spi.ResolverContext; +import org.netbeans.modules.web.jsf.editor.TestBaseForTestProject; +import org.openide.filesystems.FileObject; + +public class JsfELVariableResolverTest extends TestBaseForTestProject { + + private final JsfELVariableResolver variableResolver = new JsfELVariableResolver(); + private final ResolverContext resolverContext = new ResolverContext(); + + public JsfELVariableResolverTest(String name) { + super(name); + } + + private String getTestFilePath() { + return "testWebProject/web/test.xhtml"; + } + + private FileObject getTestFileObject() throws IOException { + return getWorkFile(getTestFilePath()); + } + + public void testGetInjectableField() throws Exception { + ELVariableResolver.FieldInfo fieldInfoMBean = variableResolver.getInjectableField("MBean", getTestFileObject(), resolverContext); + assertNotNull(fieldInfoMBean); + assertEquals("beans.MBean", fieldInfoMBean.getType()); + assertEquals("beans.MBean", fieldInfoMBean.getEnclosingClass()); + ELVariableResolver.FieldInfo fieldInfoNull = variableResolver.getInjectableField("NonExistingBean", getTestFileObject(), resolverContext); + assertNull(fieldInfoNull); + } + + public void testGetBeanName() throws Exception { + String mBeanBeanName = variableResolver.getBeanName("beans.MBean", getTestFileObject(), resolverContext); + assertEquals("MBean", mBeanBeanName); + String invalidBeanName = variableResolver.getBeanName("not.existent.Class", getTestFileObject(), resolverContext); + assertNull(invalidBeanName); + } + + public void testGetManagedBeans() throws Exception { + List beans = variableResolver.getManagedBeans(getTestFileObject(), resolverContext); + assertNotNull(beans); + List beanNames = beans.stream().map(v -> v.name).toList(); + assertTrue(beanNames.contains("MBean")); + assertTrue(beanNames.contains("SessionBean")); + } + + public void testGetVariables() throws Exception { + ParseResultInfo parseResult = parse(getTestFilePath()); + Snapshot snapshot = parseResult.topLevelSnapshot; + assertNotNull(snapshot); + + List variablesAtStart = variableResolver.getVariables(snapshot, 0, resolverContext); + assertNotNull(variablesAtStart); + assertTrue(variablesAtStart.isEmpty()); + + List variablesInsideTable = variableResolver.getVariables(snapshot, 500, resolverContext); + assertNotNull(variablesInsideTable); + assertEquals(1, variablesInsideTable.size()); + ELVariableResolver.VariableInfo var = variablesInsideTable.get(0); + assertEquals("prop", var.name); + assertEquals("#{ProductMB.all}", var.expression); + assertNull(var.clazz); + + // TODO getVariables should be empty after the end of the table + } + + public void testGetRawObjectProperties() throws Exception { + ParseResultInfo parseResult = parse("testWebProject/web/resources/ezcomp/test.xhtml"); + Snapshot snapshot = parseResult.topLevelSnapshot; + assertNotNull(snapshot); + + List emptyVariables = variableResolver.getRawObjectProperties("invalid", snapshot, resolverContext); + assertNotNull(emptyVariables); + assertTrue(emptyVariables.isEmpty()); + + List ccVariables = variableResolver.getRawObjectProperties("cc", snapshot, resolverContext); + assertNotNull(ccVariables); + List ccVariablesNames = ccVariables.stream().map(v -> v.name).toList(); + assertTrue(ccVariablesNames.contains("id")); + assertTrue(ccVariablesNames.contains("rendered")); + assertTrue(ccVariablesNames.contains("attrs")); + + List attrVariables = variableResolver.getRawObjectProperties("attrs", snapshot, resolverContext); + assertNotNull(attrVariables); + List attrVariablesName = attrVariables.stream().map(v -> v.name).toList(); + assertTrue(attrVariablesName.contains("id")); + assertTrue(attrVariablesName.contains("rendered")); + assertTrue(attrVariablesName.contains("testAttr")); + } + + public void testGetBeansInScope() throws Exception { + ParseResultInfo parseResult = parse(getTestFilePath()); + Snapshot snapshot = parseResult.topLevelSnapshot; + assertNotNull(snapshot); + + List invalidScopeBeans = variableResolver.getBeansInScope("invalid", snapshot, resolverContext); + assertNotNull(invalidScopeBeans); + assertTrue(invalidScopeBeans.isEmpty()); + + List requestBeans = variableResolver.getBeansInScope("request", snapshot, resolverContext); + assertNotNull(requestBeans); + List requestBeanNames = requestBeans.stream().map(v -> v.name).toList(); + assertTrue(requestBeanNames.contains("MBean")); + assertFalse(requestBeanNames.contains("SessionBean")); + + List sessionBeans = variableResolver.getBeansInScope("session", snapshot, resolverContext); + assertNotNull(sessionBeans); + List sessionBeanNames = sessionBeans.stream().map(v -> v.name).toList(); + assertFalse(sessionBeanNames.contains("MBean")); + assertTrue(sessionBeanNames.contains("SessionBean")); + } + +}