This is an automated email from the ASF dual-hosted git repository. lukaszlenart pushed a commit to branch fix/nullability-npe-warnings in repository https://gitbox.apache.org/repos/asf/struts-intellij-plugin.git
commit 8689f9fc9c2dc6c2758923a902b3bcb2c27fc386 Author: Lukasz Lenart <[email protected]> AuthorDate: Tue Feb 24 10:44:57 2026 +0100 fix: resolve 21 critical nullability/NPE warnings from Qodana CI Add null guards and fix nullable annotations across 15 files to prevent potential runtime NPE crashes identified by Qodana static analysis: - ResultNode: replace FileTypes.UNKNOWN.getIcon() with AllIcons.FileTypes.Unknown - Struts2GlobalVariableProvider (freemarker): null-guard action.getXmlTag() - ActionPathResultContributor: null-guard action.getXmlTag() in getVariants() - ActionChainOrRedirectResultContributor: same pattern in getVariants() - GoToActionSymbolProvider: null-guard action.getXmlTag() in addItems() - ResultActionPropertyReferenceProvider: null-guard result.getXmlTag(), simplify dead Math.max() - StrutsConstantValueReference: null-guard getErrorMessage() return - CreateValidationXmlIntention: null-guard action.getName().getStringValue() - ExtendableClassConverterSpringContributor: null-guard getPossibleSubClasses() - ConstantValueConverterImpl: null-guard domElement.getXmlTag() - HardcodedActionUrlInspection: assert buildTag result non-null - ValidatorManagerImpl: null-guard clazz.getName() - GotoRelatedActionProvider: null-guard pathReference.resolve() - StrutsConventionImplicitUsageProvider: null-guard psiClass.getName() - StrutsDataModel: fix @Nullable to @NotNull on createGroupNodeRealizer() 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> --- .../StrutsConventionImplicitUsageProvider.java | 119 ++++---- .../constant/ConstantValueConverterImpl.java | 33 +-- .../ActionChainOrRedirectResultContributor.java | 186 ++++++------- .../impl/path/ActionPathResultContributor.java | 242 ++++++++--------- .../dom/validator/ValidatorManagerImpl.java | 238 ++++++++-------- .../freemarker/Struts2GlobalVariableProvider.java | 205 +++++++------- .../gotosymbol/GoToActionSymbolProvider.java | 68 ++--- .../gotosymbol/GotoRelatedActionProvider.java | 100 +++---- .../intellij/struts2/graph/StrutsDataModel.java | 262 +++++++++--------- .../intellij/struts2/graph/beans/ResultNode.java | 48 ++-- .../code/CreateValidationXmlIntention.java | 300 ++++++++++----------- .../inspection/HardcodedActionUrlInspection.java | 1 + .../ResultActionPropertyReferenceProvider.java | 148 +++++----- .../web/StrutsConstantValueReference.java | 223 +++++++-------- .../ExtendableClassConverterSpringContributor.java | 199 +++++++------- 15 files changed, 1199 insertions(+), 1173 deletions(-) diff --git a/src/main/java/com/intellij/struts2/annotators/StrutsConventionImplicitUsageProvider.java b/src/main/java/com/intellij/struts2/annotators/StrutsConventionImplicitUsageProvider.java index 35d5ca4..ba54aa4 100644 --- a/src/main/java/com/intellij/struts2/annotators/StrutsConventionImplicitUsageProvider.java +++ b/src/main/java/com/intellij/struts2/annotators/StrutsConventionImplicitUsageProvider.java @@ -29,76 +29,77 @@ import org.jetbrains.annotations.Nullable; */ public class StrutsConventionImplicitUsageProvider implements ImplicitUsageProvider { - @Override - public boolean isImplicitUsage(@NotNull PsiElement element) { - if (element instanceof PsiClass) { - return isConventionActionClass((PsiClass)element); + @Override + public boolean isImplicitUsage(@NotNull PsiElement element) { + if (element instanceof PsiClass) { + return isConventionActionClass((PsiClass) element); + } + + if (element instanceof PsiMethod psiMethod) { + if (!checkMethod(psiMethod)) { + return false; + } + + return isAnnotatedWithAction(psiMethod) || + isConventionActionClass(psiMethod.getContainingClass()); + } + return false; } - if (element instanceof PsiMethod psiMethod) { - if (!checkMethod(psiMethod)) { + @Override + public boolean isImplicitRead(@NotNull PsiElement element) { return false; - } - - return isAnnotatedWithAction(psiMethod) || - isConventionActionClass(psiMethod.getContainingClass()); - } - return false; - } - - @Override - public boolean isImplicitRead(@NotNull PsiElement element) { - return false; - } - - @Override - public boolean isImplicitWrite(@NotNull PsiElement element) { - return false; - } - - private static boolean checkMethod(PsiMethod psiMethod) { - return psiMethod.hasModifierProperty(PsiModifier.PUBLIC) && - !psiMethod.isConstructor() && - !psiMethod.hasModifierProperty(PsiModifier.STATIC) && - !psiMethod.hasModifierProperty(PsiModifier.ABSTRACT); - } - - private static boolean isAnnotatedWithAction(PsiModifierListOwner psiModifierListOwner) { - return AnnotationUtil.isAnnotated(psiModifierListOwner, StrutsConventionConstants.ACTION, 0); - } - - private static boolean isConventionActionClass(@Nullable PsiClass psiClass) { - if (psiClass == null || - psiClass.isInterface() || - psiClass.isEnum() || - psiClass.isAnnotationType() || - !psiClass.hasModifierProperty(PsiModifier.PUBLIC) || - psiClass.hasModifierProperty(PsiModifier.ABSTRACT)) { - return false; } - if (isAnnotatedWithAction(psiClass)) { - return true; + @Override + public boolean isImplicitWrite(@NotNull PsiElement element) { + return false; } - if (AnnotationUtil.isAnnotated(psiClass, StrutsConventionConstants.ACTIONS, 0)) { - return true; + private static boolean checkMethod(PsiMethod psiMethod) { + return psiMethod.hasModifierProperty(PsiModifier.PUBLIC) && + !psiMethod.isConstructor() && + !psiMethod.hasModifierProperty(PsiModifier.STATIC) && + !psiMethod.hasModifierProperty(PsiModifier.ABSTRACT); } - if (!isConventionPluginPresent(psiClass)) { - return false; + private static boolean isAnnotatedWithAction(PsiModifierListOwner psiModifierListOwner) { + return AnnotationUtil.isAnnotated(psiModifierListOwner, StrutsConventionConstants.ACTION, 0); } - if (StringUtil.endsWith(psiClass.getName(), "Action")) { - return true; + private static boolean isConventionActionClass(@Nullable PsiClass psiClass) { + if (psiClass == null || + psiClass.isInterface() || + psiClass.isEnum() || + psiClass.isAnnotationType() || + !psiClass.hasModifierProperty(PsiModifier.PUBLIC) || + psiClass.hasModifierProperty(PsiModifier.ABSTRACT)) { + return false; + } + + if (isAnnotatedWithAction(psiClass)) { + return true; + } + + if (AnnotationUtil.isAnnotated(psiClass, StrutsConventionConstants.ACTIONS, 0)) { + return true; + } + + if (!isConventionPluginPresent(psiClass)) { + return false; + } + + final String className = psiClass.getName(); + if (className != null && StringUtil.endsWith(className, "Action")) { + return true; + } + + return InheritanceUtil.isInheritor(psiClass, StrutsConstants.XWORK_ACTION_CLASS); } - return InheritanceUtil.isInheritor(psiClass, StrutsConstants.XWORK_ACTION_CLASS); - } - - private static boolean isConventionPluginPresent(PsiElement element) { - final PsiClass conventionService = JavaPsiFacade.getInstance(element.getProject()). - findClass(StrutsConventionConstants.CONVENTIONS_SERVICE, element.getResolveScope()); - return conventionService != null; - } + private static boolean isConventionPluginPresent(PsiElement element) { + final PsiClass conventionService = JavaPsiFacade.getInstance(element.getProject()). + findClass(StrutsConventionConstants.CONVENTIONS_SERVICE, element.getResolveScope()); + return conventionService != null; + } } diff --git a/src/main/java/com/intellij/struts2/dom/struts/constant/ConstantValueConverterImpl.java b/src/main/java/com/intellij/struts2/dom/struts/constant/ConstantValueConverterImpl.java index 30bb89c..a6a20a1 100644 --- a/src/main/java/com/intellij/struts2/dom/struts/constant/ConstantValueConverterImpl.java +++ b/src/main/java/com/intellij/struts2/dom/struts/constant/ConstantValueConverterImpl.java @@ -29,21 +29,24 @@ import org.jetbrains.annotations.Nullable; */ public class ConstantValueConverterImpl extends ConstantValueConverter { - @Override - @Nullable - public Converter<?> getConverter(@NotNull final GenericDomValue domElement) { - final Constant constant = (Constant) domElement.getParent(); - assert constant != null; - - final String constantName = constant.getName().getStringValue(); - if (StringUtil.isEmpty(constantName)) { - return null; + @Override + @Nullable + public Converter<?> getConverter(@NotNull final GenericDomValue domElement) { + final Constant constant = (Constant) domElement.getParent(); + assert constant != null; + + final String constantName = constant.getName().getStringValue(); + if (StringUtil.isEmpty(constantName)) { + return null; + } + + final XmlTag xmlTag = domElement.getXmlTag(); + if (xmlTag == null) { + return null; + } + final StrutsConstantManager constantManager = StrutsConstantManager.getInstance(xmlTag.getProject()); + + return constantManager.findConverter(xmlTag, StrutsConstantKey.create(constantName)); } - final XmlTag xmlTag = domElement.getXmlTag(); - final StrutsConstantManager constantManager = StrutsConstantManager.getInstance(xmlTag.getProject()); - - return constantManager.findConverter(xmlTag, StrutsConstantKey.create(constantName)); - } - } \ No newline at end of file diff --git a/src/main/java/com/intellij/struts2/dom/struts/impl/path/ActionChainOrRedirectResultContributor.java b/src/main/java/com/intellij/struts2/dom/struts/impl/path/ActionChainOrRedirectResultContributor.java index 9f6f869..6117607 100644 --- a/src/main/java/com/intellij/struts2/dom/struts/impl/path/ActionChainOrRedirectResultContributor.java +++ b/src/main/java/com/intellij/struts2/dom/struts/impl/path/ActionChainOrRedirectResultContributor.java @@ -45,111 +45,113 @@ import java.util.Objects; */ public class ActionChainOrRedirectResultContributor extends StrutsResultContributor { - @Override - public boolean matchesResultType(@NotNull @NonNls final String resultType) { - return ResultTypeResolver.isChainOrRedirectType(resultType); - } - - @Override - public boolean createReferences(@NotNull final PsiElement psiElement, - final @NotNull List<PsiReference> references, - final boolean soft) { - final StrutsModel model = StrutsManager.getInstance(psiElement.getProject()) - .getModelByFile((XmlFile) psiElement.getContainingFile()); - if (model == null) { - return false; + @Override + public boolean matchesResultType(@NotNull @NonNls final String resultType) { + return ResultTypeResolver.isChainOrRedirectType(resultType); } - final String currentPackage = getNamespace(psiElement); - if (currentPackage == null) { - return false; - } + @Override + public boolean createReferences(@NotNull final PsiElement psiElement, + final @NotNull List<PsiReference> references, + final boolean soft) { + final StrutsModel model = StrutsManager.getInstance(psiElement.getProject()) + .getModelByFile((XmlFile) psiElement.getContainingFile()); + if (model == null) { + return false; + } - final PsiReference chainReference = new ActionChainReference((XmlTag) psiElement, currentPackage, model); - references.add(chainReference); - return true; - } + final String currentPackage = getNamespace(psiElement); + if (currentPackage == null) { + return false; + } - @Override - @Nullable - public PathReference getPathReference(@NotNull final String path, @NotNull final PsiElement element) { - return createDefaultPathReference(path, element, Struts2Icons.Action); - } + final PsiReference chainReference = new ActionChainReference((XmlTag) psiElement, currentPackage, model); + references.add(chainReference); + return true; + } + @Override + @Nullable + public PathReference getPathReference(@NotNull final String path, @NotNull final PsiElement element) { + return createDefaultPathReference(path, element, Struts2Icons.Action); + } - private static final class ActionChainReference extends PsiReferenceBase<XmlTag> implements EmptyResolveMessageProvider { - private final String currentPackage; - private final StrutsModel model; + private static final class ActionChainReference extends PsiReferenceBase<XmlTag> implements EmptyResolveMessageProvider { - private ActionChainReference(final XmlTag psiElement, - final String currentPackage, - final StrutsModel model) { - super(psiElement, true); - this.currentPackage = currentPackage; - this.model = model; - } + private final String currentPackage; + private final StrutsModel model; - @Override - public PsiElement resolve() { - final XmlTagValue tagValue = myElement.getValue(); - final String path = PathReference.trimPath(tagValue.getText()); - - // use given namespace or current if none given - final int namespacePrefixIndex = path.lastIndexOf("/"); - final String namespace; - if (namespacePrefixIndex != -1) { - namespace = path.substring(0, namespacePrefixIndex); - } else { - namespace = currentPackage; - } - - final String strippedPath = path.substring(namespacePrefixIndex != -1 ? namespacePrefixIndex + 1 : 0); - final List<Action> actions = model.findActionsByName(strippedPath, namespace); - if (actions.size() == 1) { - final Action action = actions.get(0); - return action.getXmlTag(); - } - - return null; - } + private ActionChainReference(final XmlTag psiElement, + final String currentPackage, + final StrutsModel model) { + super(psiElement, true); + this.currentPackage = currentPackage; + this.model = model; + } - @Override - public Object @NotNull [] getVariants() { - final List<Action> allActions = model.getActionsForNamespace(null); - final List<LookupElementBuilder> variants = new ArrayList<>(allActions.size()); - for (final Action action : allActions) { - final String actionPath = action.getName().getStringValue(); - if (actionPath != null) { - final boolean isInCurrentPackage = Objects.equals(action.getNamespace(), currentPackage); - - // prepend package-name if not default ("/") or "current" package - final String actionNamespace = action.getNamespace(); - final String fullPath; - if (!Objects.equals(actionNamespace, StrutsPackage.DEFAULT_NAMESPACE) && - !isInCurrentPackage) { - fullPath = actionNamespace + "/" + actionPath; - } else { - fullPath = actionPath; - } - - final LookupElementBuilder builder = LookupElementBuilder.create(action.getXmlTag(), fullPath) - .withBoldness(isInCurrentPackage) - .withIcon(Struts2Icons.Action) - .withTypeText(action.getNamespace()); - variants.add(builder); + @Override + public PsiElement resolve() { + final XmlTagValue tagValue = myElement.getValue(); + final String path = PathReference.trimPath(tagValue.getText()); + + // use given namespace or current if none given + final int namespacePrefixIndex = path.lastIndexOf("/"); + final String namespace; + if (namespacePrefixIndex != -1) { + namespace = path.substring(0, namespacePrefixIndex); + } else { + namespace = currentPackage; + } + + final String strippedPath = path.substring(namespacePrefixIndex != -1 ? namespacePrefixIndex + 1 : 0); + final List<Action> actions = model.findActionsByName(strippedPath, namespace); + if (actions.size() == 1) { + final Action action = actions.get(0); + return action.getXmlTag(); + } + + return null; } - } - return ArrayUtil.toObjectArray(variants); - } + @Override + public Object @NotNull [] getVariants() { + final List<Action> allActions = model.getActionsForNamespace(null); + final List<LookupElementBuilder> variants = new ArrayList<>(allActions.size()); + for (final Action action : allActions) { + final String actionPath = action.getName().getStringValue(); + if (actionPath != null) { + final boolean isInCurrentPackage = Objects.equals(action.getNamespace(), currentPackage); + + // prepend package-name if not default ("/") or "current" package + final String actionNamespace = action.getNamespace(); + final String fullPath; + if (!Objects.equals(actionNamespace, StrutsPackage.DEFAULT_NAMESPACE) && + !isInCurrentPackage) { + fullPath = actionNamespace + "/" + actionPath; + } else { + fullPath = actionPath; + } + + final XmlTag actionTag = action.getXmlTag(); + if (actionTag == null) continue; + final LookupElementBuilder builder = LookupElementBuilder.create(actionTag, fullPath) + .withBoldness(isInCurrentPackage) + .withIcon(Struts2Icons.Action) + .withTypeText(action.getNamespace()); + variants.add(builder); + } + } + + return ArrayUtil.toObjectArray(variants); + } - @NotNull - @Override - public String getUnresolvedMessagePattern() { - return "Cannot resolve Action '" + getValue() + "'"; - } + @NotNull + @Override + public String getUnresolvedMessagePattern() { + return "Cannot resolve Action '" + getValue() + "'"; + } - } + } } diff --git a/src/main/java/com/intellij/struts2/dom/struts/impl/path/ActionPathResultContributor.java b/src/main/java/com/intellij/struts2/dom/struts/impl/path/ActionPathResultContributor.java index dad762b..0e1ac24 100644 --- a/src/main/java/com/intellij/struts2/dom/struts/impl/path/ActionPathResultContributor.java +++ b/src/main/java/com/intellij/struts2/dom/struts/impl/path/ActionPathResultContributor.java @@ -49,142 +49,144 @@ import java.util.Objects; */ public class ActionPathResultContributor extends StrutsResultContributor { - @Override - public boolean matchesResultType(@NotNull @NonNls final String resultType) { - return ResultTypeResolver.isDispatchType(resultType); - } - - @Override - public boolean createReferences(@NotNull final PsiElement psiElement, - final @NotNull List<PsiReference> references, - final boolean soft) { - final StrutsModel model = StrutsManager.getInstance(psiElement.getProject()) - .getModelByFile((XmlFile) psiElement.getContainingFile()); - if (model == null) { - return false; + @Override + public boolean matchesResultType(@NotNull @NonNls final String resultType) { + return ResultTypeResolver.isDispatchType(resultType); } - final String currentPackage = getNamespace(psiElement); - if (currentPackage == null) { - return false; - } + @Override + public boolean createReferences(@NotNull final PsiElement psiElement, + final @NotNull List<PsiReference> references, + final boolean soft) { + final StrutsModel model = StrutsManager.getInstance(psiElement.getProject()) + .getModelByFile((XmlFile) psiElement.getContainingFile()); + if (model == null) { + return false; + } - final TextRange rangeInElement = ElementManipulators.getValueTextRange(psiElement); - final String fullPath = psiElement.getText(); - final String trimmedPath = rangeInElement.substring(fullPath); - final TextRange trimmedPathRange = TextRange.from(rangeInElement.getStartOffset(), - PathReference.trimPath(trimmedPath).length()); + final String currentPackage = getNamespace(psiElement); + if (currentPackage == null) { + return false; + } - final PsiReference actionReference = new ActionPathReference((XmlTag) psiElement, - trimmedPathRange, - currentPackage, - model); + final TextRange rangeInElement = ElementManipulators.getValueTextRange(psiElement); + final String fullPath = psiElement.getText(); + final String trimmedPath = rangeInElement.substring(fullPath); + final TextRange trimmedPathRange = TextRange.from(rangeInElement.getStartOffset(), + PathReference.trimPath(trimmedPath).length()); - references.add(actionReference); - return false; - } + final PsiReference actionReference = new ActionPathReference((XmlTag) psiElement, + trimmedPathRange, + currentPackage, + model); - @Override - @Nullable - public PathReference getPathReference(@NotNull final String path, @NotNull final PsiElement element) { - return createDefaultPathReference(path, element, Struts2Icons.Action); - } + references.add(actionReference); + return false; + } + @Override + @Nullable + public PathReference getPathReference(@NotNull final String path, @NotNull final PsiElement element) { + return createDefaultPathReference(path, element, Struts2Icons.Action); + } - private static final class ActionPathReference extends PsiReferenceBase<XmlTag> { - private final String currentPackage; - private final StrutsModel model; + private static final class ActionPathReference extends PsiReferenceBase<XmlTag> { - private ActionPathReference(final XmlTag psiElement, - final TextRange textRange, - final String currentPackage, - final StrutsModel model) { - super(psiElement, textRange, true); - this.currentPackage = currentPackage; - this.model = model; - } + private final String currentPackage; + private final StrutsModel model; - private List<String> getActionExtensions() { - return StrutsConstantHelper.getActionExtensions(myElement); - } + private ActionPathReference(final XmlTag psiElement, + final TextRange textRange, + final String currentPackage, + final StrutsModel model) { + super(psiElement, textRange, true); + this.currentPackage = currentPackage; + this.model = model; + } - @Override - public PsiElement resolve() { - final String path = getCanonicalText(); - - int extensionIndex = -1; - for (final String actionExtension : getActionExtensions()) { - extensionIndex = path.lastIndexOf(actionExtension); - if (extensionIndex != -1) { - break; + private List<String> getActionExtensions() { + return StrutsConstantHelper.getActionExtensions(myElement); } - } - if (extensionIndex == -1) { - return null; - } - - // use given namespace or current if none given - final int namespacePrefixIndex = path.lastIndexOf("/"); - final String namespace; - if (namespacePrefixIndex != -1) { - namespace = path.substring(0, namespacePrefixIndex); - } else { - namespace = currentPackage; - } - - // "/XX/" behind ".extension" --> not parseable - if (namespacePrefixIndex > extensionIndex) { - return null; - } - - final String strippedPath = path.substring(namespacePrefixIndex != -1 ? namespacePrefixIndex + 1 : 0, - extensionIndex); - final List<Action> actions = model.findActionsByName(strippedPath, namespace); - if (actions.size() == 1) { - final Action action = actions.get(0); - return action.getXmlTag(); - } - - return null; - } - @Override - public Object @NotNull [] getVariants() { - final List<String> extensions = getActionExtensions(); - if (extensions.isEmpty()) { - return ArrayUtilRt.EMPTY_OBJECT_ARRAY; - } - - final String firstExtension = extensions.get(0); - - final List<Action> allActions = model.getActionsForNamespace(null); - final List<LookupElementBuilder> variants = new ArrayList<>(allActions.size()); - for (final Action action : allActions) { - final String actionPath = action.getName().getStringValue(); - if (actionPath != null) { - final boolean isInCurrentPackage = Objects.equals(action.getNamespace(), currentPackage); - - // prepend package-name if not default ("/") or "current" package - final String actionNamespace = action.getNamespace(); - final String fullPath; - if (!Objects.equals(actionNamespace, StrutsPackage.DEFAULT_NAMESPACE) && - !isInCurrentPackage) { - fullPath = actionNamespace + "/" + actionPath + firstExtension; - } else { - fullPath = actionPath + firstExtension; - } - - final LookupElementBuilder builder = LookupElementBuilder.create(action.getXmlTag(), fullPath) - .withBoldness(isInCurrentPackage) - .withIcon(Struts2Icons.Action) - .withTypeText(action.getNamespace()); - variants.add(builder); + @Override + public PsiElement resolve() { + final String path = getCanonicalText(); + + int extensionIndex = -1; + for (final String actionExtension : getActionExtensions()) { + extensionIndex = path.lastIndexOf(actionExtension); + if (extensionIndex != -1) { + break; + } + } + if (extensionIndex == -1) { + return null; + } + + // use given namespace or current if none given + final int namespacePrefixIndex = path.lastIndexOf("/"); + final String namespace; + if (namespacePrefixIndex != -1) { + namespace = path.substring(0, namespacePrefixIndex); + } else { + namespace = currentPackage; + } + + // "/XX/" behind ".extension" --> not parseable + if (namespacePrefixIndex > extensionIndex) { + return null; + } + + final String strippedPath = path.substring(namespacePrefixIndex != -1 ? namespacePrefixIndex + 1 : 0, + extensionIndex); + final List<Action> actions = model.findActionsByName(strippedPath, namespace); + if (actions.size() == 1) { + final Action action = actions.get(0); + return action.getXmlTag(); + } + + return null; } - } - return ArrayUtil.toObjectArray(variants); + @Override + public Object @NotNull [] getVariants() { + final List<String> extensions = getActionExtensions(); + if (extensions.isEmpty()) { + return ArrayUtilRt.EMPTY_OBJECT_ARRAY; + } + + final String firstExtension = extensions.get(0); + + final List<Action> allActions = model.getActionsForNamespace(null); + final List<LookupElementBuilder> variants = new ArrayList<>(allActions.size()); + for (final Action action : allActions) { + final String actionPath = action.getName().getStringValue(); + if (actionPath != null) { + final boolean isInCurrentPackage = Objects.equals(action.getNamespace(), currentPackage); + + // prepend package-name if not default ("/") or "current" package + final String actionNamespace = action.getNamespace(); + final String fullPath; + if (!Objects.equals(actionNamespace, StrutsPackage.DEFAULT_NAMESPACE) && + !isInCurrentPackage) { + fullPath = actionNamespace + "/" + actionPath + firstExtension; + } else { + fullPath = actionPath + firstExtension; + } + + final XmlTag actionTag = action.getXmlTag(); + if (actionTag == null) continue; + final LookupElementBuilder builder = LookupElementBuilder.create(actionTag, fullPath) + .withBoldness(isInCurrentPackage) + .withIcon(Struts2Icons.Action) + .withTypeText(action.getNamespace()); + variants.add(builder); + } + } + + return ArrayUtil.toObjectArray(variants); + } } - } } diff --git a/src/main/java/com/intellij/struts2/dom/validator/ValidatorManagerImpl.java b/src/main/java/com/intellij/struts2/dom/validator/ValidatorManagerImpl.java index 539787c..933877b 100644 --- a/src/main/java/com/intellij/struts2/dom/validator/ValidatorManagerImpl.java +++ b/src/main/java/com/intellij/struts2/dom/validator/ValidatorManagerImpl.java @@ -39,10 +39,12 @@ import com.intellij.util.containers.ContainerUtil; import com.intellij.util.xml.DomFileElement; import com.intellij.util.xml.DomManager; import com.intellij.util.xml.DomService; + import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; + import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -52,144 +54,148 @@ import org.jetbrains.annotations.Nullable; */ public class ValidatorManagerImpl extends ValidatorManager { - @NonNls - private static final String VALIDATORS_XML = "validators.xml"; - - @NonNls - private static final String VALIDATORS_DEFAULT_XML = "default.xml"; + @NonNls + private static final String VALIDATORS_XML = "validators.xml"; - @Override - public boolean isValidatorsFile(@NotNull final XmlFile xmlFile) { - return DomManager.getDomManager(xmlFile.getProject()).getFileElement(xmlFile, Validators.class) != null; - } + @NonNls + private static final String VALIDATORS_DEFAULT_XML = "default.xml"; - @Nullable - private static DomFileElement<ValidatorsConfig> getValidatorsConfigFileElement(@NotNull final XmlFile xmlFile) { - return DomManager.getDomManager(xmlFile.getProject()).getFileElement(xmlFile, ValidatorsConfig.class); - } - - @Override - public boolean isCustomValidatorConfigFile(@NotNull final PsiFile psiFile) { - return !Objects.equals(psiFile.getName(), VALIDATORS_DEFAULT_XML); - } - - @Override - public List<ValidatorConfig> getValidators(@NotNull final Module module) { - final XmlFile validatorsFile = getValidatorConfigFile(module); - if (validatorsFile == null) { - return Collections.emptyList(); + @Override + public boolean isValidatorsFile(@NotNull final XmlFile xmlFile) { + return DomManager.getDomManager(xmlFile.getProject()).getFileElement(xmlFile, Validators.class) != null; } - final DomFileElement<ValidatorsConfig> validatorsConfigElement = getValidatorsConfigFileElement(validatorsFile); - if (validatorsConfigElement == null) { - return Collections.emptyList(); + @Nullable + private static DomFileElement<ValidatorsConfig> getValidatorsConfigFileElement(@NotNull final XmlFile xmlFile) { + return DomManager.getDomManager(xmlFile.getProject()).getFileElement(xmlFile, ValidatorsConfig.class); } - final List<ValidatorConfig> validatorConfigs = validatorsConfigElement.getRootElement().getValidatorConfigs(); - if (!isCustomValidatorConfigFile(validatorsFile)) { - return validatorConfigs; + @Override + public boolean isCustomValidatorConfigFile(@NotNull final PsiFile psiFile) { + return !Objects.equals(psiFile.getName(), VALIDATORS_DEFAULT_XML); } - // add validators from default.xml for Struts > 2.0.8 - final String version = StrutsVersionDetector.detectStrutsVersion(module); - if (StringUtil.compareVersionNumbers(version, "2.0.8") == 1) { - final XmlFile defaultValidatorFile = findDefaultValidatorsFile(module); - if (defaultValidatorFile != null) { - final DomFileElement<ValidatorsConfig> fileElement = getValidatorsConfigFileElement(defaultValidatorFile); - if (fileElement == null) { - return validatorConfigs; + @Override + public List<ValidatorConfig> getValidators(@NotNull final Module module) { + final XmlFile validatorsFile = getValidatorConfigFile(module); + if (validatorsFile == null) { + return Collections.emptyList(); + } + + final DomFileElement<ValidatorsConfig> validatorsConfigElement = getValidatorsConfigFileElement(validatorsFile); + if (validatorsConfigElement == null) { + return Collections.emptyList(); } - final List<ValidatorConfig> defaultValidators = fileElement.getRootElement().getValidatorConfigs(); + final List<ValidatorConfig> validatorConfigs = validatorsConfigElement.getRootElement().getValidatorConfigs(); + if (!isCustomValidatorConfigFile(validatorsFile)) { + return validatorConfigs; + } - final List<ValidatorConfig> allValidatorConfigs = new ArrayList<>(defaultValidators); - allValidatorConfigs.addAll(validatorConfigs); // custom overrides defaults - return allValidatorConfigs; - } - } + // add validators from default.xml for Struts > 2.0.8 + final String version = StrutsVersionDetector.detectStrutsVersion(module); + if (StringUtil.compareVersionNumbers(version, "2.0.8") == 1) { + final XmlFile defaultValidatorFile = findDefaultValidatorsFile(module); + if (defaultValidatorFile != null) { + final DomFileElement<ValidatorsConfig> fileElement = getValidatorsConfigFileElement(defaultValidatorFile); + if (fileElement == null) { + return validatorConfigs; + } + + final List<ValidatorConfig> defaultValidators = fileElement.getRootElement().getValidatorConfigs(); + + final List<ValidatorConfig> allValidatorConfigs = new ArrayList<>(defaultValidators); + allValidatorConfigs.addAll(validatorConfigs); // custom overrides defaults + return allValidatorConfigs; + } + } - return validatorConfigs; - } - - @Override - @Nullable - public XmlFile getValidatorConfigFile(@NotNull final Module module) { - final Project project = module.getProject(); - final PsiManager psiManager = PsiManager.getInstance(project); - - final VirtualFile validatorsVirtualFile = - ResourceFileUtil.findResourceFileInScope(VALIDATORS_XML, project, - GlobalSearchScope.moduleRuntimeScope(module, false)); - - if (validatorsVirtualFile != null) { - final PsiFile file = psiManager.findFile(validatorsVirtualFile); - if (file != null && - getValidatorsConfigFileElement((XmlFile) file) != null) { - return (XmlFile) file; - } + return validatorConfigs; } - return findDefaultValidatorsFile(module); - } + @Override + @Nullable + public XmlFile getValidatorConfigFile(@NotNull final Module module) { + final Project project = module.getProject(); + final PsiManager psiManager = PsiManager.getInstance(project); + + final VirtualFile validatorsVirtualFile = + ResourceFileUtil.findResourceFileInScope(VALIDATORS_XML, project, + GlobalSearchScope.moduleRuntimeScope(module, false)); + + if (validatorsVirtualFile != null) { + final PsiFile file = psiManager.findFile(validatorsVirtualFile); + if (file != null && + getValidatorsConfigFileElement((XmlFile) file) != null) { + return (XmlFile) file; + } + } - @NotNull - @Override - public List<XmlFile> findValidationFilesFor(@NotNull final PsiClass clazz) { - final PsiFile psiFile = clazz.getContainingFile().getOriginalFile(); - final PsiDirectory containingDirectory = psiFile.getContainingDirectory(); - if (containingDirectory == null) { - return Collections.emptyList(); + return findDefaultValidatorsFile(module); } - final PsiPackage containingPackage = JavaDirectoryService.getInstance().getPackage(containingDirectory); - if (containingPackage == null) { - return Collections.emptyList(); - } + @NotNull + @Override + public List<XmlFile> findValidationFilesFor(@NotNull final PsiClass clazz) { + final PsiFile psiFile = clazz.getContainingFile().getOriginalFile(); + final PsiDirectory containingDirectory = psiFile.getContainingDirectory(); + if (containingDirectory == null) { + return Collections.emptyList(); + } - final PackageScope searchScope = new PackageScope(containingPackage, false, true); - final List<DomFileElement<Validators>> validationRoots = - DomService.getInstance().getFileElements(Validators.class, clazz.getProject(), searchScope); - - final List<DomFileElement<Validators>> filtered = - ContainerUtil.filter(validationRoots, validatorDomFileElement -> { - final String fileName = validatorDomFileElement.getFile().getName(); - return StringUtil.startsWith(fileName, clazz.getName()); - }); - - return ContainerUtil.map(filtered, DomFileElement::getFile); - } - - /** - * Find {@code com/opensymphony/xwork2/validator/validators/default.xml} from {@code xwork.jar}. - * - * @param module Current module. - * @return {@code null} if not found. - */ - @Nullable - private static XmlFile findDefaultValidatorsFile(final Module module) { - final Project project = module.getProject(); - - final PsiClass emailValidatorClass = JavaPsiFacade.getInstance(project).findClass( - "com.opensymphony.xwork2.validator.validators.EmailValidator", - GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module, false)); - if (emailValidatorClass == null) { - return null; - } + final PsiPackage containingPackage = JavaDirectoryService.getInstance().getPackage(containingDirectory); + if (containingPackage == null) { + return Collections.emptyList(); + } + + final PackageScope searchScope = new PackageScope(containingPackage, false, true); + final List<DomFileElement<Validators>> validationRoots = + DomService.getInstance().getFileElements(Validators.class, clazz.getProject(), searchScope); + + final String className = clazz.getName(); + if (className == null) { + return Collections.emptyList(); + } + final List<DomFileElement<Validators>> filtered = + ContainerUtil.filter(validationRoots, validatorDomFileElement -> { + final String fileName = validatorDomFileElement.getFile().getName(); + return StringUtil.startsWith(fileName, className); + }); - final VirtualFile file = PsiUtilCore.getVirtualFile(emailValidatorClass); - if (file == null || - file.getFileSystem() != JarFileSystem.getInstance()) { - return null; + return ContainerUtil.map(filtered, DomFileElement::getFile); } - // go up one level to ../validators/ - final VirtualFile parent = file.getParent(); - assert parent != null : "error walking up to parent from EmailValidator.class, xwork JAR file=" + file; + /** + * Find {@code com/opensymphony/xwork2/validator/validators/default.xml} from {@code xwork.jar}. + * + * @param module Current module. + * @return {@code null} if not found. + */ + @Nullable + private static XmlFile findDefaultValidatorsFile(final Module module) { + final Project project = module.getProject(); + + final PsiClass emailValidatorClass = JavaPsiFacade.getInstance(project).findClass( + "com.opensymphony.xwork2.validator.validators.EmailValidator", + GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module, false)); + if (emailValidatorClass == null) { + return null; + } + + final VirtualFile file = PsiUtilCore.getVirtualFile(emailValidatorClass); + if (file == null || + file.getFileSystem() != JarFileSystem.getInstance()) { + return null; + } - final VirtualFile vfDefaultXml = parent.findChild(VALIDATORS_DEFAULT_XML); - assert vfDefaultXml != null : "VF for default.xml null, parent=" + parent; + // go up one level to ../validators/ + final VirtualFile parent = file.getParent(); + assert parent != null : "error walking up to parent from EmailValidator.class, xwork JAR file=" + file; - return (XmlFile) PsiManager.getInstance(project).findFile(vfDefaultXml); - } + final VirtualFile vfDefaultXml = parent.findChild(VALIDATORS_DEFAULT_XML); + assert vfDefaultXml != null : "VF for default.xml null, parent=" + parent; + + return (XmlFile) PsiManager.getInstance(project).findFile(vfDefaultXml); + } } \ No newline at end of file diff --git a/src/main/java/com/intellij/struts2/freemarker/Struts2GlobalVariableProvider.java b/src/main/java/com/intellij/struts2/freemarker/Struts2GlobalVariableProvider.java index ba748f1..f83f985 100644 --- a/src/main/java/com/intellij/struts2/freemarker/Struts2GlobalVariableProvider.java +++ b/src/main/java/com/intellij/struts2/freemarker/Struts2GlobalVariableProvider.java @@ -34,6 +34,7 @@ import com.intellij.jsp.JspManager; import com.intellij.psi.util.PsiTypesUtil; import com.intellij.psi.xml.XmlDocument; import com.intellij.psi.xml.XmlFile; +import com.intellij.psi.xml.XmlTag; import com.intellij.struts2.StrutsConstants; import com.intellij.struts2.StrutsIcons; import com.intellij.struts2.dom.struts.action.Action; @@ -54,122 +55,124 @@ import java.util.Collections; import java.util.List; final class Struts2GlobalVariableProvider extends FtlGlobalVariableProvider { - @Override - @NotNull - public List<? extends FtlVariable> getGlobalVariables(final FtlFile file) { - final Module module = ModuleUtilCore.findModuleForPsiElement(file); - if (module == null) { - return Collections.emptyList(); - } + @Override + @NotNull + public List<? extends FtlVariable> getGlobalVariables(final FtlFile file) { + final Module module = ModuleUtilCore.findModuleForPsiElement(file); + if (module == null) { + return Collections.emptyList(); + } - if (StrutsFacet.getInstance(module) == null) { - return Collections.emptyList(); - } + if (StrutsFacet.getInstance(module) == null) { + return Collections.emptyList(); + } - final List<FtlVariable> result = new ArrayList<>(); - result.add(new MyFtlLightVariable("stack", file, (FtlType) null)); - result.add(new MyFtlLightVariable("response", file, WebCommonClassNames.JAVAX_HTTP_SERVLET_RESPONSE)); - result.add(new MyFtlLightVariable("res", file, WebCommonClassNames.JAVAX_HTTP_SERVLET_RESPONSE)); - result.add(new MyFtlLightVariable("request", file, WebCommonClassNames.JAVAX_HTTP_SERVLET_REQUEST)); - result.add(new MyFtlLightVariable("req", file, WebCommonClassNames.JAVAX_HTTP_SERVLET_REQUEST)); - result.add(new MyFtlLightVariable("session", file, WebCommonClassNames.JAVAX_HTTP_SESSION)); - result.add(new MyFtlLightVariable("application", file, WebCommonClassNames.JAVAX_SERVLET_CONTEXT)); - result.add(new MyFtlLightVariable("base", file, CommonClassNames.JAVA_LANG_STRING)); - - installTaglibSupport(result, module, - StrutsConstants.TAGLIB_STRUTS_UI_URI, StrutsConstants.TAGLIB_STRUTS_UI_PREFIX); - installTaglibSupport(result, module, - StrutsConstants.TAGLIB_JQUERY_PLUGIN_URI, StrutsConstants.TAGLIB_JQUERY_PLUGIN_PREFIX); - installTaglibSupport(result, module, - StrutsConstants.TAGLIB_JQUERY_RICHTEXT_PLUGIN_URI, StrutsConstants.TAGLIB_JQUERY_RICHTEXT_PLUGIN_PREFIX); - installTaglibSupport(result, module, - StrutsConstants.TAGLIB_JQUERY_CHART_PLUGIN_URI, StrutsConstants.TAGLIB_JQUERY_CHART_PLUGIN_PREFIX); - installTaglibSupport(result, module, - StrutsConstants.TAGLIB_JQUERY_TREE_PLUGIN_URI, StrutsConstants.TAGLIB_JQUERY_TREE_PLUGIN_PREFIX); - installTaglibSupport(result, module, - StrutsConstants.TAGLIB_JQUERY_GRID_PLUGIN_URI, StrutsConstants.TAGLIB_JQUERY_GRID_PLUGIN_PREFIX); - installTaglibSupport(result, module, - StrutsConstants.TAGLIB_JQUERY_MOBILE_PLUGIN_URI, StrutsConstants.TAGLIB_JQUERY_MOBILE_PLUGIN_PREFIX); - installTaglibSupport(result, module, - StrutsConstants.TAGLIB_BOOTSTRAP_PLUGIN_URI, StrutsConstants.TAGLIB_BOOTSTRAP_PLUGIN_PREFIX); - - final Processor<Action> processor = action -> { - final PsiClass actionClass = action.searchActionClass(); - if (actionClass != null) { - for (final Result result1 : action.getResults()) { - final ResultType resultType = result1.getEffectiveResultType(); - if (resultType != null && - FreeMarkerStrutsResultContributor.FREEMARKER.equals(resultType.getName().getStringValue())) { - final PathReference reference = result1.getValue(); - final PsiElement target = reference == null ? null : reference.resolve(); - if (target != null && - (file.getManager().areElementsEquivalent(file, target) || - file.getManager().areElementsEquivalent(file.getOriginalFile(), target))) { - final PsiClassType actionType = PsiTypesUtil.getClassType(actionClass); - final FtlPsiType ftlPsiType = FtlPsiType.wrap(actionType); - result.add(new MyFtlLightVariable("", action.getXmlTag(), ftlPsiType)); - result.add(new MyFtlLightVariable("action", action.getXmlTag(), ftlPsiType)); - return false; // stop after first match + final List<FtlVariable> result = new ArrayList<>(); + result.add(new MyFtlLightVariable("stack", file, (FtlType) null)); + result.add(new MyFtlLightVariable("response", file, WebCommonClassNames.JAVAX_HTTP_SERVLET_RESPONSE)); + result.add(new MyFtlLightVariable("res", file, WebCommonClassNames.JAVAX_HTTP_SERVLET_RESPONSE)); + result.add(new MyFtlLightVariable("request", file, WebCommonClassNames.JAVAX_HTTP_SERVLET_REQUEST)); + result.add(new MyFtlLightVariable("req", file, WebCommonClassNames.JAVAX_HTTP_SERVLET_REQUEST)); + result.add(new MyFtlLightVariable("session", file, WebCommonClassNames.JAVAX_HTTP_SESSION)); + result.add(new MyFtlLightVariable("application", file, WebCommonClassNames.JAVAX_SERVLET_CONTEXT)); + result.add(new MyFtlLightVariable("base", file, CommonClassNames.JAVA_LANG_STRING)); + + installTaglibSupport(result, module, + StrutsConstants.TAGLIB_STRUTS_UI_URI, StrutsConstants.TAGLIB_STRUTS_UI_PREFIX); + installTaglibSupport(result, module, + StrutsConstants.TAGLIB_JQUERY_PLUGIN_URI, StrutsConstants.TAGLIB_JQUERY_PLUGIN_PREFIX); + installTaglibSupport(result, module, + StrutsConstants.TAGLIB_JQUERY_RICHTEXT_PLUGIN_URI, StrutsConstants.TAGLIB_JQUERY_RICHTEXT_PLUGIN_PREFIX); + installTaglibSupport(result, module, + StrutsConstants.TAGLIB_JQUERY_CHART_PLUGIN_URI, StrutsConstants.TAGLIB_JQUERY_CHART_PLUGIN_PREFIX); + installTaglibSupport(result, module, + StrutsConstants.TAGLIB_JQUERY_TREE_PLUGIN_URI, StrutsConstants.TAGLIB_JQUERY_TREE_PLUGIN_PREFIX); + installTaglibSupport(result, module, + StrutsConstants.TAGLIB_JQUERY_GRID_PLUGIN_URI, StrutsConstants.TAGLIB_JQUERY_GRID_PLUGIN_PREFIX); + installTaglibSupport(result, module, + StrutsConstants.TAGLIB_JQUERY_MOBILE_PLUGIN_URI, StrutsConstants.TAGLIB_JQUERY_MOBILE_PLUGIN_PREFIX); + installTaglibSupport(result, module, + StrutsConstants.TAGLIB_BOOTSTRAP_PLUGIN_URI, StrutsConstants.TAGLIB_BOOTSTRAP_PLUGIN_PREFIX); + + final Processor<Action> processor = action -> { + final PsiClass actionClass = action.searchActionClass(); + if (actionClass != null) { + for (final Result result1 : action.getResults()) { + final ResultType resultType = result1.getEffectiveResultType(); + if (resultType != null && + FreeMarkerStrutsResultContributor.FREEMARKER.equals(resultType.getName().getStringValue())) { + final PathReference reference = result1.getValue(); + final PsiElement target = reference == null ? null : reference.resolve(); + if (target != null && + (file.getManager().areElementsEquivalent(file, target) || + file.getManager().areElementsEquivalent(file.getOriginalFile(), target))) { + final XmlTag actionTag = action.getXmlTag(); + if (actionTag == null) return false; + final PsiClassType actionType = PsiTypesUtil.getClassType(actionClass); + final FtlPsiType ftlPsiType = FtlPsiType.wrap(actionType); + result.add(new MyFtlLightVariable("", actionTag, ftlPsiType)); + result.add(new MyFtlLightVariable("action", actionTag, ftlPsiType)); + return false; // stop after first match + } + } + } } - } - } - } - return true; - }; + return true; + }; - for (final StrutsModel model : StrutsManager.getInstance(file.getProject()).getAllModels(module)) { - model.processActions(processor); - } - return result; - } - - private static void installTaglibSupport(@NotNull final List<FtlVariable> result, - @NotNull final Module module, - @NotNull @NonNls final String taglibUri, - @NotNull @NonNls final String taglibPrefix) { - final XmlFile xmlFile = JspManager.getInstance(module.getProject()).getTldFileByUri(taglibUri, module, null); - if (xmlFile == null) { - return; + for (final StrutsModel model : StrutsManager.getInstance(file.getProject()).getAllModels(module)) { + model.processActions(processor); + } + return result; } - final XmlDocument document = xmlFile.getDocument(); - if (document == null) { - return; - } + private static void installTaglibSupport(@NotNull final List<FtlVariable> result, + @NotNull final Module module, + @NotNull @NonNls final String taglibUri, + @NotNull @NonNls final String taglibPrefix) { + final XmlFile xmlFile = JspManager.getInstance(module.getProject()).getTldFileByUri(taglibUri, module, null); + if (xmlFile == null) { + return; + } - final XmlNSDescriptor descriptor = (XmlNSDescriptor) document.getMetaData(); - if (descriptor == null) { - return; - } + final XmlDocument document = xmlFile.getDocument(); + if (document == null) { + return; + } - PsiElement declaration = descriptor.getDeclaration(); - if (declaration == null) { - declaration = xmlFile; - } + final XmlNSDescriptor descriptor = (XmlNSDescriptor) document.getMetaData(); + if (descriptor == null) { + return; + } - result.add(new MyFtlLightVariable(taglibPrefix, declaration, new FtlXmlNamespaceType(descriptor))); - } + PsiElement declaration = descriptor.getDeclaration(); + if (declaration == null) { + declaration = xmlFile; + } + result.add(new MyFtlLightVariable(taglibPrefix, declaration, new FtlXmlNamespaceType(descriptor))); + } - private static final class MyFtlLightVariable extends FtlLightVariable { - private MyFtlLightVariable(@NotNull @NonNls final String name, - @NotNull final PsiElement parent, - @Nullable final FtlType type) { - super(name, parent, type); - } + private static final class MyFtlLightVariable extends FtlLightVariable { - private MyFtlLightVariable(@NotNull @NonNls final String name, - @NotNull final PsiElement parent, - @NotNull @NonNls final String psiType) { - super(name, parent, psiType); - } + private MyFtlLightVariable(@NotNull @NonNls final String name, + @NotNull final PsiElement parent, + @Nullable final FtlType type) { + super(name, parent, type); + } - @Override - public Icon getIcon(final boolean open) { - return StrutsIcons.STRUTS_VARIABLE; + private MyFtlLightVariable(@NotNull @NonNls final String name, + @NotNull final PsiElement parent, + @NotNull @NonNls final String psiType) { + super(name, parent, psiType); + } + + @Override + public Icon getIcon(final boolean open) { + return StrutsIcons.STRUTS_VARIABLE; + } } - } } \ No newline at end of file diff --git a/src/main/java/com/intellij/struts2/gotosymbol/GoToActionSymbolProvider.java b/src/main/java/com/intellij/struts2/gotosymbol/GoToActionSymbolProvider.java index 08a8f2a..6a7bd91 100644 --- a/src/main/java/com/intellij/struts2/gotosymbol/GoToActionSymbolProvider.java +++ b/src/main/java/com/intellij/struts2/gotosymbol/GoToActionSymbolProvider.java @@ -20,6 +20,7 @@ import com.intellij.navigation.NavigationItem; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.struts2.Struts2Icons; +import com.intellij.psi.xml.XmlTag; import com.intellij.struts2.dom.struts.action.Action; import com.intellij.struts2.dom.struts.model.StrutsManager; import com.intellij.struts2.dom.struts.model.StrutsModel; @@ -38,44 +39,47 @@ import java.util.Set; */ public class GoToActionSymbolProvider extends GoToSymbolProvider { - @Override - protected boolean acceptModule(final Module module) { - return StrutsFacet.getInstance(module) != null; - } - @NotNull - @Override - protected Collection<Module> calcAcceptableModules(@NotNull Project project) { - return ProjectFacetManager.getInstance(project).getModulesWithFacet(StrutsFacet.FACET_TYPE_ID); - } + @Override + protected boolean acceptModule(final Module module) { + return StrutsFacet.getInstance(module) != null; + } - @Override - protected void addNames(@NotNull final Module module, final Set<String> result) { - final StrutsModel strutsModel = StrutsManager.getInstance(module.getProject()).getCombinedModel(module); - if (strutsModel == null) { - return; + @NotNull + @Override + protected Collection<Module> calcAcceptableModules(@NotNull Project project) { + return ProjectFacetManager.getInstance(project).getModulesWithFacet(StrutsFacet.FACET_TYPE_ID); } - strutsModel.processActions(action -> { - result.add(action.getName().getStringValue()); - return true; - }); - } + @Override + protected void addNames(@NotNull final Module module, final Set<String> result) { + final StrutsModel strutsModel = StrutsManager.getInstance(module.getProject()).getCombinedModel(module); + if (strutsModel == null) { + return; + } - @Override - protected void addItems(@NotNull final Module module, final String name, final List<NavigationItem> result) { - final StrutsModel strutsModel = StrutsManager.getInstance(module.getProject()).getCombinedModel(module); - if (strutsModel == null) { - return; + strutsModel.processActions(action -> { + result.add(action.getName().getStringValue()); + return true; + }); } - final List<Action> actions = strutsModel.findActionsByName(name, null); - for (final Action action : actions) { - final NavigationItem item = createNavigationItem(action.getXmlTag(), - action.getName().getStringValue() + - " [" + action.getNamespace() + "]", - Struts2Icons.Action); - result.add(item); + @Override + protected void addItems(@NotNull final Module module, final String name, final List<NavigationItem> result) { + final StrutsModel strutsModel = StrutsManager.getInstance(module.getProject()).getCombinedModel(module); + if (strutsModel == null) { + return; + } + + final List<Action> actions = strutsModel.findActionsByName(name, null); + for (final Action action : actions) { + final XmlTag tag = action.getXmlTag(); + if (tag == null) continue; + final NavigationItem item = createNavigationItem(tag, + action.getName().getStringValue() + + " [" + action.getNamespace() + "]", + Struts2Icons.Action); + result.add(item); + } } - } } diff --git a/src/main/java/com/intellij/struts2/gotosymbol/GotoRelatedActionProvider.java b/src/main/java/com/intellij/struts2/gotosymbol/GotoRelatedActionProvider.java index df9646a..03a543f 100644 --- a/src/main/java/com/intellij/struts2/gotosymbol/GotoRelatedActionProvider.java +++ b/src/main/java/com/intellij/struts2/gotosymbol/GotoRelatedActionProvider.java @@ -39,69 +39,69 @@ import java.util.*; * @author Yann Cébron */ final class GotoRelatedActionProvider extends GotoRelatedProvider { - // TODO restrict to "realistic" results - private static final Set<String> SUPPORTED_EXTENSIONS = CollectionFactory.createFilePathSet(Arrays.asList("ftl", "htm", "html", "jsp", "jspx", "txt", "vm")); + // TODO restrict to "realistic" results + private static final Set<String> SUPPORTED_EXTENSIONS = CollectionFactory.createFilePathSet(Arrays.asList("ftl", "htm", "html", "jsp", "jspx", "txt", "vm")); - @NotNull - @Override - public List<? extends GotoRelatedItem> getItems(@NotNull final PsiElement psiElement) { - PsiFile psiFile = psiElement.getContainingFile(); - if (psiFile == null) return Collections.emptyList(); + @NotNull + @Override + public List<? extends GotoRelatedItem> getItems(@NotNull final PsiElement psiElement) { + PsiFile psiFile = psiElement.getContainingFile(); + if (psiFile == null) return Collections.emptyList(); - final PsiFile containingFile = psiFile.getOriginalFile(); - final String filename = containingFile.getName(); + final PsiFile containingFile = psiFile.getOriginalFile(); + final String filename = containingFile.getName(); - final String extension = FileUtilRt.getExtension(filename); - if (!SUPPORTED_EXTENSIONS.contains(extension)) { - return Collections.emptyList(); - } + final String extension = FileUtilRt.getExtension(filename); + if (!SUPPORTED_EXTENSIONS.contains(extension)) { + return Collections.emptyList(); + } - final StrutsManager strutsManager = StrutsManager.getInstance(psiElement.getProject()); - final StrutsModel strutsModel = strutsManager.getCombinedModel(psiElement); - if (strutsModel == null) { - return Collections.emptyList(); - } + final StrutsManager strutsManager = StrutsManager.getInstance(psiElement.getProject()); + final StrutsModel strutsModel = strutsManager.getCombinedModel(psiElement); + if (strutsModel == null) { + return Collections.emptyList(); + } - final List<PsiFile> allFiles = containingFile.getViewProvider().getAllFiles(); + final List<PsiFile> allFiles = containingFile.getViewProvider().getAllFiles(); - final Set<Action> actions = new HashSet<>(); - final List<GotoRelatedItem> items = new ArrayList<>(); - strutsModel.processActions(action -> { - for (final Result result : action.getResults()) { + final Set<Action> actions = new HashSet<>(); + final List<GotoRelatedItem> items = new ArrayList<>(); + strutsModel.processActions(action -> { + for (final Result result : action.getResults()) { - final PathReference pathReference = result.getValue(); - if (pathReference == null) { - continue; - } + final PathReference pathReference = result.getValue(); + if (pathReference == null) { + continue; + } - final String path = pathReference.getPath(); - if (!path.endsWith(filename)) { - continue; - } + final String path = pathReference.getPath(); + if (!path.endsWith(filename)) { + continue; + } - final PsiElement resolve = pathReference.resolve(); - if (ContainerUtil.find(allFiles, resolve) == null) { - continue; - } + final PsiElement resolve = pathReference.resolve(); + if (resolve == null || ContainerUtil.find(allFiles, resolve) == null) { + continue; + } - if (!actions.contains(action)) { - items.add(new DomGotoRelatedItem(action)); - actions.add(action); - } + if (!actions.contains(action)) { + items.add(new DomGotoRelatedItem(action)); + actions.add(action); + } - final PsiClass actionClass = action.searchActionClass(); - if (actionClass == null) { - continue; - } + final PsiClass actionClass = action.searchActionClass(); + if (actionClass == null) { + continue; + } - final PsiMethod actionMethod = action.searchActionMethod(); - items.add(new GotoRelatedItem(actionMethod != null ? actionMethod : actionClass)); - } + final PsiMethod actionMethod = action.searchActionMethod(); + items.add(new GotoRelatedItem(actionMethod != null ? actionMethod : actionClass)); + } - return true; - }); + return true; + }); - return items; - } + return items; + } } \ No newline at end of file diff --git a/src/main/java/com/intellij/struts2/graph/StrutsDataModel.java b/src/main/java/com/intellij/struts2/graph/StrutsDataModel.java index 4c633c0..86bdbb8 100644 --- a/src/main/java/com/intellij/struts2/graph/StrutsDataModel.java +++ b/src/main/java/com/intellij/struts2/graph/StrutsDataModel.java @@ -46,163 +46,163 @@ import java.util.*; */ public class StrutsDataModel extends GraphDataModel<BasicStrutsNode, BasicStrutsEdge> { - private final Set<BasicStrutsNode> myNodes = new HashSet<>(); - private final Set<BasicStrutsEdge> myEdges = new HashSet<>(); - - private final Map<PsiFile, NodesGroup> myGroups = new HashMap<>(); - - private final Project myProject; - private final XmlFile myFile; - - @NonNls - private static final String UNKNOWN = "???"; - - public StrutsDataModel(final XmlFile file) { - myFile = file; - myProject = file.getProject(); - } - - @Override - @NotNull - public Collection<BasicStrutsNode> getNodes() { - refreshDataModel(); - return myNodes; - } - - @Override - @NotNull - public Collection<BasicStrutsEdge> getEdges() { - return myEdges; - } - - @Override - @NotNull - public BasicStrutsNode getSourceNode(final BasicStrutsEdge edge) { - return edge.getSource(); - } - - @Override - @NotNull - public BasicStrutsNode getTargetNode(final BasicStrutsEdge edge) { - return edge.getTarget(); - } - - @Override - @NotNull - public String getNodeName(final BasicStrutsNode node) { - return node.getName(); - } - - @Override - @NotNull - public String getEdgeName(final BasicStrutsEdge edge) { - return edge.getName(); - } - - @Override - public BasicStrutsEdge createEdge(@NotNull final BasicStrutsNode from, @NotNull final BasicStrutsNode to) { - return null; - } - - @Override - public void dispose() { - } - - private void refreshDataModel() { - myNodes.clear(); - myEdges.clear(); - updateDataModel(); - } - - @Override - public NodeGroupDescriptor getGroup(final BasicStrutsNode basicStrutsNode) { - if (isGroupElements()) { - final XmlElement xmlElement = basicStrutsNode.getIdentifyingElement().getXmlElement(); - assert xmlElement != null; - return myGroups.get(xmlElement.getContainingFile()); + private final Set<BasicStrutsNode> myNodes = new HashSet<>(); + private final Set<BasicStrutsEdge> myEdges = new HashSet<>(); + + private final Map<PsiFile, NodesGroup> myGroups = new HashMap<>(); + + private final Project myProject; + private final XmlFile myFile; + + @NonNls + private static final String UNKNOWN = "???"; + + public StrutsDataModel(final XmlFile file) { + myFile = file; + myProject = file.getProject(); } - return super.getGroup(basicStrutsNode); - } + @Override + @NotNull + public Collection<BasicStrutsNode> getNodes() { + refreshDataModel(); + return myNodes; + } - private void addNode(final BasicStrutsNode node) { - if (!node.getIdentifyingElement().isValid()) { - return; + @Override + @NotNull + public Collection<BasicStrutsEdge> getEdges() { + return myEdges; } - myNodes.add(node); + @Override + @NotNull + public BasicStrutsNode getSourceNode(final BasicStrutsEdge edge) { + return edge.getSource(); + } - if (isGroupElements()) { - final XmlElement element = node.getIdentifyingElement().getXmlElement(); - assert element != null; - final PsiFile file = element.getContainingFile(); - if (file != null && !myGroups.containsKey(file)) { - final String name = file.getName(); + @Override + @NotNull + public BasicStrutsNode getTargetNode(final BasicStrutsEdge edge) { + return edge.getTarget(); + } - final BasicNodesGroup group = new BasicNodesGroup(name) { + @Override + @NotNull + public String getNodeName(final BasicStrutsNode node) { + return node.getName(); + } - @Override - public @Nullable GroupNodeRealizer createGroupNodeRealizer() { - final GroupNodeRealizer groupNodeRealizer = super.createGroupNodeRealizer(); - assert groupNodeRealizer != null; + @Override + @NotNull + public String getEdgeName(final BasicStrutsEdge edge) { + return edge.getName(); + } - final NodeLabel nodeLabel = groupNodeRealizer.getLabel(); - nodeLabel.setText(" " + getGroupName()); - nodeLabel.setModel(NodeLabel.INTERNAL); - nodeLabel.setPosition(NodeLabel.TOP_RIGHT); + @Override + public BasicStrutsEdge createEdge(@NotNull final BasicStrutsNode from, @NotNull final BasicStrutsNode to) { + return null; + } - return groupNodeRealizer; - } - }; + @Override + public void dispose() { + } - // collapse all other files - group.setClosed(file != myFile); + private void refreshDataModel() { + myNodes.clear(); + myEdges.clear(); + updateDataModel(); + } - myGroups.put(file, group); + @Override + public NodeGroupDescriptor getGroup(final BasicStrutsNode basicStrutsNode) { + if (isGroupElements()) { + final XmlElement xmlElement = basicStrutsNode.getIdentifyingElement().getXmlElement(); + assert xmlElement != null; + return myGroups.get(xmlElement.getContainingFile()); + } - } + return super.getGroup(basicStrutsNode); } - } - // TODO configurable? - private boolean isGroupElements() { - return true; - } + private void addNode(final BasicStrutsNode node) { + if (!node.getIdentifyingElement().isValid()) { + return; + } + + myNodes.add(node); - private void addEdge(final BasicStrutsEdge edge) { - if (!edge.getSource().getIdentifyingElement().isValid() || - !edge.getTarget().getIdentifyingElement().isValid()) { - return; + if (isGroupElements()) { + final XmlElement element = node.getIdentifyingElement().getXmlElement(); + assert element != null; + final PsiFile file = element.getContainingFile(); + if (file != null && !myGroups.containsKey(file)) { + final String name = file.getName(); + + final BasicNodesGroup group = new BasicNodesGroup(name) { + + @Override + public @NotNull GroupNodeRealizer createGroupNodeRealizer() { + final GroupNodeRealizer groupNodeRealizer = super.createGroupNodeRealizer(); + assert groupNodeRealizer != null; + + final NodeLabel nodeLabel = groupNodeRealizer.getLabel(); + nodeLabel.setText(" " + getGroupName()); + nodeLabel.setModel(NodeLabel.INTERNAL); + nodeLabel.setPosition(NodeLabel.TOP_RIGHT); + + return groupNodeRealizer; + } + }; + + // collapse all other files + group.setClosed(file != myFile); + + myGroups.put(file, group); + + } + } } - myEdges.add(edge); - } + // TODO configurable? + private boolean isGroupElements() { + return true; + } + + private void addEdge(final BasicStrutsEdge edge) { + if (!edge.getSource().getIdentifyingElement().isValid() || + !edge.getTarget().getIdentifyingElement().isValid()) { + return; + } - private void updateDataModel() { - final StrutsModel model = StrutsManager.getInstance(myProject).getModelByFile(myFile); - if (model == null) { - return; + myEdges.add(edge); } - for (final StrutsPackage strutsPackage : model.getStrutsPackages()) { - for (final Action action : strutsPackage.getActions()) { - final ActionNode actionNode = new ActionNode(action, action.getName().getStringValue()); - addNode(actionNode); + private void updateDataModel() { + final StrutsModel model = StrutsManager.getInstance(myProject).getModelByFile(myFile); + if (model == null) { + return; + } - for (final Result result : action.getResults()) { - final PathReference pathReference = result.getValue(); - final String path = pathReference != null ? pathReference.getPath() : UNKNOWN; + for (final StrutsPackage strutsPackage : model.getStrutsPackages()) { + for (final Action action : strutsPackage.getActions()) { + final ActionNode actionNode = new ActionNode(action, action.getName().getStringValue()); + addNode(actionNode); - final ResultNode resultNode = new ResultNode(result, path); - addNode(resultNode); + for (final Result result : action.getResults()) { + final PathReference pathReference = result.getValue(); + final String path = pathReference != null ? pathReference.getPath() : UNKNOWN; - final String resultName = result.getName().getStringValue(); - addEdge(new BasicStrutsEdge(actionNode, resultNode, resultName != null ? resultName : Result.DEFAULT_NAME)); + final ResultNode resultNode = new ResultNode(result, path); + addNode(resultNode); + + final String resultName = result.getName().getStringValue(); + addEdge(new BasicStrutsEdge(actionNode, resultNode, resultName != null ? resultName : Result.DEFAULT_NAME)); + } + + } } - } } - } - } \ No newline at end of file diff --git a/src/main/java/com/intellij/struts2/graph/beans/ResultNode.java b/src/main/java/com/intellij/struts2/graph/beans/ResultNode.java index 612c2bc..c13ab9d 100644 --- a/src/main/java/com/intellij/struts2/graph/beans/ResultNode.java +++ b/src/main/java/com/intellij/struts2/graph/beans/ResultNode.java @@ -14,7 +14,7 @@ */ package com.intellij.struts2.graph.beans; -import com.intellij.openapi.fileTypes.FileTypes; +import com.intellij.icons.AllIcons; import com.intellij.openapi.paths.PathReference; import com.intellij.struts2.dom.struts.action.Result; import org.jetbrains.annotations.NotNull; @@ -28,32 +28,32 @@ import javax.swing.*; */ public class ResultNode extends BasicStrutsNode<Result> { - private static final Icon UNKNOWN_RESULT_ICON = FileTypes.UNKNOWN.getIcon(); + private static final Icon UNKNOWN_RESULT_ICON = AllIcons.FileTypes.Unknown; - public ResultNode(@NotNull final Result identifyingElement, - @NotNull final String path) { - super(identifyingElement, path); - } - - @Override - @NotNull - public Icon getIcon() { - final Result result = getIdentifyingElement(); - if (!result.isValid()) { - return UNKNOWN_RESULT_ICON; - } - - final PathReference pathReference = result.getValue(); - if (pathReference == null) { - return UNKNOWN_RESULT_ICON; + public ResultNode(@NotNull final Result identifyingElement, + @NotNull final String path) { + super(identifyingElement, path); } - if (pathReference.resolve() == null) { - return UNKNOWN_RESULT_ICON; + @Override + @NotNull + public Icon getIcon() { + final Result result = getIdentifyingElement(); + if (!result.isValid()) { + return UNKNOWN_RESULT_ICON; + } + + final PathReference pathReference = result.getValue(); + if (pathReference == null) { + return UNKNOWN_RESULT_ICON; + } + + if (pathReference.resolve() == null) { + return UNKNOWN_RESULT_ICON; + } + + final Icon pathReferenceIcon = pathReference.getIcon(); + return pathReferenceIcon != null ? pathReferenceIcon : UNKNOWN_RESULT_ICON; } - final Icon pathReferenceIcon = pathReference.getIcon(); - return pathReferenceIcon != null ? pathReferenceIcon : UNKNOWN_RESULT_ICON; - } - } \ No newline at end of file diff --git a/src/main/java/com/intellij/struts2/intentions/code/CreateValidationXmlIntention.java b/src/main/java/com/intellij/struts2/intentions/code/CreateValidationXmlIntention.java index 5106af0..fe9b023 100644 --- a/src/main/java/com/intellij/struts2/intentions/code/CreateValidationXmlIntention.java +++ b/src/main/java/com/intellij/struts2/intentions/code/CreateValidationXmlIntention.java @@ -62,175 +62,175 @@ import java.util.List; */ public class CreateValidationXmlIntention extends PsiElementBaseIntentionAction implements Iconable { - @NotNull - @Override - public String getText() { - return "Create validation.xml"; - } - - @Override - public boolean isAvailable(@NotNull final Project project, - final Editor editor, - @NotNull final PsiElement psiElement) { - final PsiClass clazz = findActionClass(psiElement); - if (clazz == null) { - return false; + @NotNull + @Override + public String getText() { + return "Create validation.xml"; } - // short exit if Struts Facet not present - final Module module = ModuleUtilCore.findModuleForPsiElement(clazz); - if (module == null || - StrutsFacet.getInstance(module) == null) { - return false; - } + @Override + public boolean isAvailable(@NotNull final Project project, + final Editor editor, + @NotNull final PsiElement psiElement) { + final PsiClass clazz = findActionClass(psiElement); + if (clazz == null) { + return false; + } - final List<Action> actions = getActionsForClazz(project, clazz, module); - if (actions.isEmpty()) { - return false; - } + // short exit if Struts Facet not present + final Module module = ModuleUtilCore.findModuleForPsiElement(clazz); + if (module == null || + StrutsFacet.getInstance(module) == null) { + return false; + } - final List<XmlFile> files = ValidatorManager.getInstance(psiElement.getProject()).findValidationFilesFor(clazz); - return files.isEmpty() || - files.size() != actions.size(); - } + final List<Action> actions = getActionsForClazz(project, clazz, module); + if (actions.isEmpty()) { + return false; + } - private static List<Action> getActionsForClazz(final Project project, final PsiClass clazz, final Module module) { - final StrutsModel model = StrutsManager.getInstance(project).getCombinedModel(module); - if (model == null || !model.isActionClass(clazz)) { - return Collections.emptyList(); + final List<XmlFile> files = ValidatorManager.getInstance(psiElement.getProject()).findValidationFilesFor(clazz); + return files.isEmpty() || + files.size() != actions.size(); } - return model.findActionsByClass(clazz); - } - - @NotNull - @Override - public String getFamilyName() { - return getText(); - } - - @Override - public Icon getIcon(final int flags) { - return Struts2Icons.Action; - } - - @Override - public void invoke(@NotNull final Project project, - final Editor editor, - @NotNull final PsiElement element) throws IncorrectOperationException { - final PsiClass actionClass = findActionClass(element); - assert actionClass != null : element; - - final List<Action> filteredActions = getActionsWithoutValidation(actionClass); - if (filteredActions.size() > 1) { - final ListPopupStep<Action> step = - new BaseListPopupStep<>("Choose action mapping", filteredActions) { - - @Override - public Icon getIconFor(final Action value) { - return Struts2Icons.Action; - } - - @NotNull - @Override - public String getTextFor(final Action value) { - return value.getName().getStringValue() + " (" + value.getMethod().getStringValue() + ")"; - } - - @Override - public PopupStep onChosen(final Action selectedValue, final boolean finalChoice) { - final String path = selectedValue.getName().getStringValue(); - WriteCommandAction.writeCommandAction(project).run(() -> createValidationXml(project, actionClass, path)); - return FINAL_CHOICE; - } - }; - JBPopupFactory.getInstance().createListPopup(step).showInBestPositionFor(editor); - return; + private static List<Action> getActionsForClazz(final Project project, final PsiClass clazz, final Module module) { + final StrutsModel model = StrutsManager.getInstance(project).getCombinedModel(module); + if (model == null || !model.isActionClass(clazz)) { + return Collections.emptyList(); + } + + return model.findActionsByClass(clazz); } - createValidationXml(project, actionClass, filteredActions.get(0).getName().getStringValue()); - } - - private static void createValidationXml(final Project project, - final PsiClass actionClass, - @Nullable final String path) { - final PsiManager manager = PsiManager.getInstance(project); - final String actionClassQualifiedName = actionClass.getQualifiedName(); - assert actionClassQualifiedName != null; - - final PackageWrapper targetPackage = - new PackageWrapper(manager, StringUtil.getPackageName(actionClassQualifiedName)); - - final Module module = ModuleUtilCore.findModuleForPsiElement(actionClass); - assert module != null; - final List<VirtualFile> sourceRoots = ModuleRootManager.getInstance(module).getSourceRoots(JavaModuleSourceRootTypes.PRODUCTION); - final VirtualFile sourceRoot = sourceRoots.size() == 1 ? sourceRoots.get(0) : - CommonMoveClassesOrPackagesUtil.chooseSourceRoot(targetPackage, - sourceRoots, - manager.findDirectory(sourceRoots.get(0))); - if (sourceRoot == null) { - return; + @NotNull + @Override + public String getFamilyName() { + return getText(); } - final PsiDirectory directory = manager.findDirectory(sourceRoot); - assert directory != null : sourceRoot.getPresentableUrl(); + @Override + public Icon getIcon(final int flags) { + return Struts2Icons.Action; + } - final FileTemplateManager templateManager = FileTemplateManager.getInstance(project); - final FileTemplate validationTemplate = templateManager.getJ2eeTemplate(StrutsFileTemplateGroupDescriptorFactory.VALIDATION_XML); + @Override + public void invoke(@NotNull final Project project, + final Editor editor, + @NotNull final PsiElement element) throws IncorrectOperationException { + final PsiClass actionClass = findActionClass(element); + assert actionClass != null : element; + + final List<Action> filteredActions = getActionsWithoutValidation(actionClass); + if (filteredActions.size() > 1) { + final ListPopupStep<Action> step = + new BaseListPopupStep<>("Choose action mapping", filteredActions) { + + @Override + public Icon getIconFor(final Action value) { + return Struts2Icons.Action; + } + + @NotNull + @Override + public String getTextFor(final Action value) { + return value.getName().getStringValue() + " (" + value.getMethod().getStringValue() + ")"; + } + + @Override + public PopupStep onChosen(final Action selectedValue, final boolean finalChoice) { + final String path = selectedValue.getName().getStringValue(); + WriteCommandAction.writeCommandAction(project).run(() -> createValidationXml(project, actionClass, path)); + return FINAL_CHOICE; + } + }; + JBPopupFactory.getInstance().createListPopup(step).showInBestPositionFor(editor); + return; + } - final PsiDirectory packageDirectoryInSourceRoot = CommonJavaRefactoringUtil.createPackageDirectoryInSourceRoot(targetPackage, sourceRoot); - try { - final String filename = - path == null ? actionClass.getName() + "-validation.xml" : actionClass.getName() + "-" + path + "-validation.xml"; - final PsiElement psiElement = FileTemplateUtil.createFromTemplate(validationTemplate, filename, null, packageDirectoryInSourceRoot); - NavigationUtil.activateFileWithPsiElement(psiElement, true); + createValidationXml(project, actionClass, filteredActions.get(0).getName().getStringValue()); } - catch (Exception e) { - throw new IncorrectOperationException("error creating validation.xml", (Throwable)e); - } - } - - private static List<Action> getActionsWithoutValidation(final PsiClass actionClass) { - final Project project = actionClass.getProject(); - final List<Action> actions = getActionsForClazz(project, - actionClass, - ModuleUtilCore.findModuleForPsiElement(actionClass)); - - final List<XmlFile> files = ValidatorManager.getInstance(project).findValidationFilesFor(actionClass); - return ContainerUtil.filter(actions, action -> { - final String path = action.getName().getStringValue(); - for (final XmlFile file : files) { - if (file.getName().contains(path)) { - return false; + + private static void createValidationXml(final Project project, + final PsiClass actionClass, + @Nullable final String path) { + final PsiManager manager = PsiManager.getInstance(project); + final String actionClassQualifiedName = actionClass.getQualifiedName(); + assert actionClassQualifiedName != null; + + final PackageWrapper targetPackage = + new PackageWrapper(manager, StringUtil.getPackageName(actionClassQualifiedName)); + + final Module module = ModuleUtilCore.findModuleForPsiElement(actionClass); + assert module != null; + final List<VirtualFile> sourceRoots = ModuleRootManager.getInstance(module).getSourceRoots(JavaModuleSourceRootTypes.PRODUCTION); + final VirtualFile sourceRoot = sourceRoots.size() == 1 ? sourceRoots.get(0) : + CommonMoveClassesOrPackagesUtil.chooseSourceRoot(targetPackage, + sourceRoots, + manager.findDirectory(sourceRoots.get(0))); + if (sourceRoot == null) { + return; } - } - return true; - }); - } - - @Nullable - private static PsiClass findActionClass(final PsiElement psiElement) { - if (!(psiElement instanceof PsiIdentifier)) { - return null; - } - final PsiElement parent = psiElement.getParent(); - if (!(parent instanceof PsiClass clazz)) { - return null; - } + final PsiDirectory directory = manager.findDirectory(sourceRoot); + assert directory != null : sourceRoot.getPresentableUrl(); + + final FileTemplateManager templateManager = FileTemplateManager.getInstance(project); + final FileTemplate validationTemplate = templateManager.getJ2eeTemplate(StrutsFileTemplateGroupDescriptorFactory.VALIDATION_XML); - if (clazz.getNameIdentifier() != psiElement) { - return null; + final PsiDirectory packageDirectoryInSourceRoot = CommonJavaRefactoringUtil.createPackageDirectoryInSourceRoot(targetPackage, sourceRoot); + try { + final String filename = + path == null ? actionClass.getName() + "-validation.xml" : actionClass.getName() + "-" + path + "-validation.xml"; + final PsiElement psiElement = FileTemplateUtil.createFromTemplate(validationTemplate, filename, null, packageDirectoryInSourceRoot); + NavigationUtil.activateFileWithPsiElement(psiElement, true); + } catch (Exception e) { + throw new IncorrectOperationException("error creating validation.xml", (Throwable) e); + } } - // do not run on non-public, abstract classes or interfaces - if (clazz.isInterface() || - clazz.isAnnotationType() || - !clazz.hasModifierProperty(PsiModifier.PUBLIC) || - clazz.hasModifierProperty(PsiModifier.ABSTRACT)) { - return null; + private static List<Action> getActionsWithoutValidation(final PsiClass actionClass) { + final Project project = actionClass.getProject(); + final List<Action> actions = getActionsForClazz(project, + actionClass, + ModuleUtilCore.findModuleForPsiElement(actionClass)); + + final List<XmlFile> files = ValidatorManager.getInstance(project).findValidationFilesFor(actionClass); + return ContainerUtil.filter(actions, action -> { + final String path = action.getName().getStringValue(); + if (path == null) return true; + for (final XmlFile file : files) { + if (file.getName().contains(path)) { + return false; + } + } + return true; + }); } - return clazz; - } + @Nullable + private static PsiClass findActionClass(final PsiElement psiElement) { + if (!(psiElement instanceof PsiIdentifier)) { + return null; + } + + final PsiElement parent = psiElement.getParent(); + if (!(parent instanceof PsiClass clazz)) { + return null; + } + + if (clazz.getNameIdentifier() != psiElement) { + return null; + } + + // do not run on non-public, abstract classes or interfaces + if (clazz.isInterface() || + clazz.isAnnotationType() || + !clazz.hasModifierProperty(PsiModifier.PUBLIC) || + clazz.hasModifierProperty(PsiModifier.ABSTRACT)) { + return null; + } + + return clazz; + } } diff --git a/src/main/java/com/intellij/struts2/jsp/inspection/HardcodedActionUrlInspection.java b/src/main/java/com/intellij/struts2/jsp/inspection/HardcodedActionUrlInspection.java index 7af9d1a..9ffed32 100644 --- a/src/main/java/com/intellij/struts2/jsp/inspection/HardcodedActionUrlInspection.java +++ b/src/main/java/com/intellij/struts2/jsp/inspection/HardcodedActionUrlInspection.java @@ -203,6 +203,7 @@ public class HardcodedActionUrlInspection extends XmlSuppressableInspectionTool while (indent.length() < start - lineStart) indent += " "; Pair<String, String> tag_var = buildTag(prefix, url, indent, inline, myActionExtension); + assert tag_var != null; String tag = tag_var.getFirst(); String var = tag_var.getSecond(); diff --git a/src/main/java/com/intellij/struts2/reference/ResultActionPropertyReferenceProvider.java b/src/main/java/com/intellij/struts2/reference/ResultActionPropertyReferenceProvider.java index 76a2bfd..655b50e 100644 --- a/src/main/java/com/intellij/struts2/reference/ResultActionPropertyReferenceProvider.java +++ b/src/main/java/com/intellij/struts2/reference/ResultActionPropertyReferenceProvider.java @@ -18,6 +18,7 @@ package com.intellij.struts2.reference; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; +import com.intellij.psi.xml.XmlTag; import com.intellij.struts2.dom.struts.action.Action; import com.intellij.struts2.dom.struts.action.Result; import com.intellij.struts2.reference.common.BeanPropertyPathReference; @@ -34,77 +35,80 @@ import org.jetbrains.annotations.NotNull; */ public class ResultActionPropertyReferenceProvider extends PsiReferenceProvider { - private static final String EXPRESSION_START = "${"; - private static final String EXPRESSION_END = "}"; - - @Override - public PsiReference @NotNull [] getReferencesByElement(@NotNull final PsiElement psiElement, - @NotNull final ProcessingContext processingContext) { - final Result result = (Result)DomUtil.getDomElement(psiElement); - assert result != null : psiElement.getText(); - final Action action = result.getParentOfType(Action.class, true); - assert action != null : psiElement.getText(); - final PsiClass actionClass = action.searchActionClass(); - if (actionClass == null) { - return PsiReference.EMPTY_ARRAY; + private static final String EXPRESSION_START = "${"; + private static final String EXPRESSION_END = "}"; + + @Override + public PsiReference @NotNull [] getReferencesByElement(@NotNull final PsiElement psiElement, + @NotNull final ProcessingContext processingContext) { + final Result result = (Result) DomUtil.getDomElement(psiElement); + assert result != null : psiElement.getText(); + final Action action = result.getParentOfType(Action.class, true); + assert action != null : psiElement.getText(); + final PsiClass actionClass = action.searchActionClass(); + if (actionClass == null) { + return PsiReference.EMPTY_ARRAY; + } + + final XmlTag xmlTag = result.getXmlTag(); + if (xmlTag == null) { + return PsiReference.EMPTY_ARRAY; + } + final int tagValueStartOffset = ElementManipulators.getOffsetInElement(xmlTag); + PsiReference[] references = new PsiReference[1]; + + final String stringValue = result.getStringValue(); + if (!StringUtil.isNotEmpty(stringValue)) { + return PsiReference.EMPTY_ARRAY; + } + + final String resultText = StringUtil.replace(stringValue, "&", "&"); + final int lastExpressionEnd = resultText.length(); + + int startOffset = 0; + while (startOffset < lastExpressionEnd) { + startOffset = resultText.indexOf(EXPRESSION_START, startOffset); + if (startOffset == -1) { + break; + } + + startOffset += EXPRESSION_START.length(); + final int closingBraceIdx = resultText.indexOf(EXPRESSION_END, startOffset); + final int length = (closingBraceIdx != -1 ? closingBraceIdx : resultText.length()) - startOffset; + + final String expressionString = resultText.substring(startOffset, startOffset + length); + + // we only "fake" OGNL here, skip method call expressions for now + if (StringUtil.containsChar(expressionString, '(')) { + continue; + } + + final BeanPropertyPathReferenceSet propertyPathReferenceSet = + new BeanPropertyPathReferenceSet(expressionString, + psiElement, + startOffset, + '.', + actionClass, + true) { + + // CTOR creates references eagerly, so we have to subclass here + @Override + public boolean isSoft() { + return false; + } + + @NotNull + @Override + protected BeanPropertyPathReference createReference(final TextRange range, final int index) { + final TextRange shift = TextRange.from(range.getStartOffset() + tagValueStartOffset, + range.getLength()); // shift range to XmlTag value range + return createBeanPropertyPathReference(shift, index); + } + }; + + references = ArrayUtil.mergeArrays(references, propertyPathReferenceSet.getPsiReferences()); + } + + return references; } - - final int tagValueStartOffset = ElementManipulators.getOffsetInElement(result.getXmlTag()); - PsiReference[] references = new PsiReference[1]; - - final String stringValue = result.getStringValue(); - if (!StringUtil.isNotEmpty(stringValue)) { - return PsiReference.EMPTY_ARRAY; - } - - final String resultText = StringUtil.replace(stringValue, "&", "&"); - final int lastExpressionEnd = Math.max(resultText.length(), // missing '}' - resultText.lastIndexOf(EXPRESSION_START)); - - int startOffset = 0; - while (startOffset < lastExpressionEnd) { - startOffset = resultText.indexOf(EXPRESSION_START, startOffset); - if (startOffset == -1) { - break; - } - - startOffset += EXPRESSION_START.length(); - final int closingBraceIdx = resultText.indexOf(EXPRESSION_END, startOffset); - final int length = (closingBraceIdx != -1 ? closingBraceIdx : resultText.length()) - startOffset; - - final String expressionString = resultText.substring(startOffset, startOffset + length); - - // we only "fake" OGNL here, skip method call expressions for now - if (StringUtil.containsChar(expressionString, '(')) { - continue; - } - - final BeanPropertyPathReferenceSet propertyPathReferenceSet = - new BeanPropertyPathReferenceSet(expressionString, - psiElement, - startOffset, - '.', - actionClass, - true) { - - // CTOR creates references eagerly, so we have to subclass here - @Override - public boolean isSoft() { - return false; - } - - @NotNull - @Override - protected BeanPropertyPathReference createReference(final TextRange range, final int index) { - final TextRange shift = TextRange.from(range.getStartOffset() + tagValueStartOffset, - range.getLength()); // shift range to XmlTag value range - return createBeanPropertyPathReference(shift, index); - } - }; - - references = ArrayUtil.mergeArrays(references, propertyPathReferenceSet.getPsiReferences()); - } - - return references; - } } \ No newline at end of file diff --git a/src/main/java/com/intellij/struts2/reference/web/StrutsConstantValueReference.java b/src/main/java/com/intellij/struts2/reference/web/StrutsConstantValueReference.java index 45ff9b6..ce2e587 100644 --- a/src/main/java/com/intellij/struts2/reference/web/StrutsConstantValueReference.java +++ b/src/main/java/com/intellij/struts2/reference/web/StrutsConstantValueReference.java @@ -43,138 +43,139 @@ import java.util.*; */ class StrutsConstantValueReference extends PsiReferenceBase<XmlTag> implements EmptyResolveMessageProvider { - @Nullable - private final Pair<DomElement, Converter> elementConverterPair; - - StrutsConstantValueReference(@NotNull final XmlTag xmlTag) { - super(xmlTag, false); - elementConverterPair = getElementConverterPair(); - } - - @Override - public PsiElement resolve() { - if (elementConverterPair == null) { - return myElement; - } - - final Converter converter = elementConverterPair.getSecond(); - final ConvertContext convertContext = ConvertContextFactory.createConvertContext(elementConverterPair.first); + @Nullable + private final Pair<DomElement, Converter> elementConverterPair; - // additional variants (String only) - if (converter instanceof ResolvingConverter) { - final Set additionalVariants = ((ResolvingConverter<?>) converter).getAdditionalVariants(convertContext); - if (additionalVariants.contains(getValue())) { - return myElement; - } + StrutsConstantValueReference(@NotNull final XmlTag xmlTag) { + super(xmlTag, false); + elementConverterPair = getElementConverterPair(); } - // "normal" reference - final Object resolveObject = converter.fromString(getValue(), convertContext); - if (resolveObject == null) { - return null; - } + @Override + public PsiElement resolve() { + if (elementConverterPair == null) { + return myElement; + } - // DomElement - if (resolveObject instanceof DomElement) { - return ((DomElement) resolveObject).getXmlTag(); - } + final Converter converter = elementConverterPair.getSecond(); + final ConvertContext convertContext = ConvertContextFactory.createConvertContext(elementConverterPair.first); - // fake self-reference (e.g. String value from Converter) - if (!(resolveObject instanceof PsiElement)) { - return myElement; - } + // additional variants (String only) + if (converter instanceof ResolvingConverter) { + final Set additionalVariants = ((ResolvingConverter<?>) converter).getAdditionalVariants(convertContext); + if (additionalVariants.contains(getValue())) { + return myElement; + } + } - // "real" reference - return (PsiElement) resolveObject; - } + // "normal" reference + final Object resolveObject = converter.fromString(getValue(), convertContext); + if (resolveObject == null) { + return null; + } - @Override - @NotNull - public String getUnresolvedMessagePattern() { - assert elementConverterPair != null; + // DomElement + if (resolveObject instanceof DomElement) { + return ((DomElement) resolveObject).getXmlTag(); + } - return elementConverterPair.second - .getErrorMessage(getValue(), ConvertContextFactory.createConvertContext(elementConverterPair.first)); - } + // fake self-reference (e.g. String value from Converter) + if (!(resolveObject instanceof PsiElement)) { + return myElement; + } - @Override - @SuppressWarnings({"unchecked"}) - public Object @NotNull [] getVariants() { - if (elementConverterPair == null) { - return ArrayUtilRt.EMPTY_OBJECT_ARRAY; + // "real" reference + return (PsiElement) resolveObject; } - final Converter converter = elementConverterPair.second; - if (!(converter instanceof ResolvingConverter resolvingConverter)) { - return ArrayUtilRt.EMPTY_OBJECT_ARRAY; + @Override + @NotNull + public String getUnresolvedMessagePattern() { + assert elementConverterPair != null; + + final String msg = elementConverterPair.second + .getErrorMessage(getValue(), ConvertContextFactory.createConvertContext(elementConverterPair.first)); + return msg != null ? msg : "Cannot resolve '" + getValue() + "'"; } - // merge "normal" + additional variants - final DomElement paramValueElement = elementConverterPair.first; - final ConvertContext convertContext = ConvertContextFactory.createConvertContext(paramValueElement); + @Override + @SuppressWarnings({"unchecked"}) + public Object @NotNull [] getVariants() { + if (elementConverterPair == null) { + return ArrayUtilRt.EMPTY_OBJECT_ARRAY; + } - // wrap explicitly for empty list - final Collection converterVariants = new ArrayList(resolvingConverter.getVariants(convertContext)); + final Converter converter = elementConverterPair.second; + if (!(converter instanceof ResolvingConverter resolvingConverter)) { + return ArrayUtilRt.EMPTY_OBJECT_ARRAY; + } - final Collection variants; - if (!converterVariants.isEmpty() && - converterVariants.iterator().next() instanceof DomElement) { - variants = Arrays.asList(ElementPresentationManager.getInstance().createVariants(converterVariants)); - } else { - variants = converterVariants; - } + // merge "normal" + additional variants + final DomElement paramValueElement = elementConverterPair.first; + final ConvertContext convertContext = ConvertContextFactory.createConvertContext(paramValueElement); + + // wrap explicitly for empty list + final Collection converterVariants = new ArrayList(resolvingConverter.getVariants(convertContext)); - variants.addAll(resolvingConverter.getAdditionalVariants(convertContext)); - - // add custom created references - if (resolvingConverter instanceof CustomReferenceConverter) { - final PsiReference[] references = ((CustomReferenceConverter) resolvingConverter). - createReferences((GenericDomValue) paramValueElement, - myElement, - convertContext); - for (final PsiReference customReference : references) { - if (customReference instanceof JavaClassReference javaClassReference) { - @NotNull List<String> names = javaClassReference.getSuperClasses(); - PsiElement context = javaClassReference.getCompletionContext(); - if (!names.isEmpty() && context instanceof PsiPackage) { - javaClassReference.processSubclassVariants((PsiPackage)context, ArrayUtil.toStringArray(names), element -> variants.add(element)); - continue; - } + final Collection variants; + if (!converterVariants.isEmpty() && + converterVariants.iterator().next() instanceof DomElement) { + variants = Arrays.asList(ElementPresentationManager.getInstance().createVariants(converterVariants)); + } else { + variants = converterVariants; + } + + variants.addAll(resolvingConverter.getAdditionalVariants(convertContext)); + + // add custom created references + if (resolvingConverter instanceof CustomReferenceConverter) { + final PsiReference[] references = ((CustomReferenceConverter) resolvingConverter). + createReferences((GenericDomValue) paramValueElement, + myElement, + convertContext); + for (final PsiReference customReference : references) { + if (customReference instanceof JavaClassReference javaClassReference) { + @NotNull List<String> names = javaClassReference.getSuperClasses(); + PsiElement context = javaClassReference.getCompletionContext(); + if (!names.isEmpty() && context instanceof PsiPackage) { + javaClassReference.processSubclassVariants((PsiPackage) context, ArrayUtil.toStringArray(names), element -> variants.add(element)); + continue; + } + } + Collections.addAll(variants, customReference.getVariants()); + } } - Collections.addAll(variants, customReference.getVariants()); - } - } - return ArrayUtil.toObjectArray(variants); - } - - /** - * Gets the DomElement and corresponding converter. - * - * @return {@code null} on errors or if one of both could not be resolved. - */ - @Nullable - private Pair<DomElement, Converter> getElementConverterPair() { - final DomElement paramValueElement = DomUtil.getDomElement(myElement); - assert paramValueElement != null; - - final DomElement domElement = paramValueElement.getParent(); - assert domElement instanceof CommonParamValue; - - final CommonParamValue initParamElement = (CommonParamValue) domElement; - final String paramName = initParamElement.getParamName().getStringValue(); - if (StringUtil.isEmpty(paramName)) { - return null; + return ArrayUtil.toObjectArray(variants); } - final StrutsConstantManager constantManager = StrutsConstantManager.getInstance(myElement.getProject()); + /** + * Gets the DomElement and corresponding converter. + * + * @return {@code null} on errors or if one of both could not be resolved. + */ + @Nullable + private Pair<DomElement, Converter> getElementConverterPair() { + final DomElement paramValueElement = DomUtil.getDomElement(myElement); + assert paramValueElement != null; + + final DomElement domElement = paramValueElement.getParent(); + assert domElement instanceof CommonParamValue; + + final CommonParamValue initParamElement = (CommonParamValue) domElement; + final String paramName = initParamElement.getParamName().getStringValue(); + if (StringUtil.isEmpty(paramName)) { + return null; + } - final Converter converter = constantManager.findConverter(myElement, StrutsConstantKey.create(paramName)); - if (converter == null) { - return null; - } + final StrutsConstantManager constantManager = StrutsConstantManager.getInstance(myElement.getProject()); - return Pair.create(paramValueElement, converter); - } + final Converter converter = constantManager.findConverter(myElement, StrutsConstantKey.create(paramName)); + if (converter == null) { + return null; + } + + return Pair.create(paramValueElement, converter); + } } \ No newline at end of file diff --git a/src/main/java/com/intellij/struts2/spring/ExtendableClassConverterSpringContributor.java b/src/main/java/com/intellij/struts2/spring/ExtendableClassConverterSpringContributor.java index 53effd6..06ee8ef 100644 --- a/src/main/java/com/intellij/struts2/spring/ExtendableClassConverterSpringContributor.java +++ b/src/main/java/com/intellij/struts2/spring/ExtendableClassConverterSpringContributor.java @@ -46,120 +46,119 @@ import java.util.stream.Collectors; * @author Yann Cébron */ final class ExtendableClassConverterSpringContributor - extends ExtendableClassConverter.ExtendableClassConverterContributor { - - @Override - @NotNull - public String getTypeName() { - return StrutsBundle.message("dom.extendable.class.converter.type.spring"); - } - - /** - * Checks if struts2-spring-plugin is present in current module. - * - * @param convertContext Current context. - * @return true if yes. - */ - @Override - public boolean isSuitable(@NotNull final ConvertContext convertContext) { - if (!SpringCommonUtils.isSpringConfigured(convertContext.getModule())) return false; - - return DomJavaUtil.findClass(StrutsConstants.SPRING_OBJECT_FACTORY_CLASS, convertContext.getInvocationElement()) != null; - } - - @Override - public PsiReference @NotNull [] getReferences(@NotNull final ConvertContext convertContext, - @NotNull final PsiElement psiElement, - @NotNull final ExtendClass extendClass) { - return new PsiReference[]{new SpringBeanReference((XmlAttributeValue)psiElement, - convertContext.getModule(), - extendClass)}; - } - - - // TODO provide QuickFix to create Spring bean? - private static final class SpringBeanReference extends PsiReferenceBase<XmlAttributeValue> { - - private final Module module; - private final ExtendClass extendClass; - - private SpringBeanReference(final XmlAttributeValue element, - final Module module, - final ExtendClass extendClass) { - super(element, true); - this.module = module; - this.extendClass = extendClass; - } + extends ExtendableClassConverter.ExtendableClassConverterContributor { + @Override @NotNull - private SpringModel getSpringModel() { - return SpringManager.getInstance(module.getProject()).getCombinedModel(module); + public String getTypeName() { + return StrutsBundle.message("dom.extendable.class.converter.type.spring"); } + /** + * Checks if struts2-spring-plugin is present in current module. + * + * @param convertContext Current context. + * @return true if yes. + */ @Override - public PsiElement resolve() { - final String beanName = myElement.getValue(); - if (StringUtil.isEmpty(beanName)) { - return null; - } - - final SpringModel springModel = getSpringModel(); - final SpringBeanPointer<?> springBean = SpringModelSearchers.findBean(springModel, beanName); - if (springBean == null) { - return null; - } - - if (springBean.isAbstract()) { - return null; - } - - return springBean.getBeanClass(); + public boolean isSuitable(@NotNull final ConvertContext convertContext) { + if (!SpringCommonUtils.isSpringConfigured(convertContext.getModule())) return false; + + return DomJavaUtil.findClass(StrutsConstants.SPRING_OBJECT_FACTORY_CLASS, convertContext.getInvocationElement()) != null; } @Override - public Object @NotNull [] getVariants() { - final SpringModel springModel = getSpringModel(); + public PsiReference @NotNull [] getReferences(@NotNull final ConvertContext convertContext, + @NotNull final PsiElement psiElement, + @NotNull final ExtendClass extendClass) { + return new PsiReference[]{new SpringBeanReference((XmlAttributeValue) psiElement, + convertContext.getModule(), + extendClass)}; + } - final @Nullable Set<PsiClass> subClasses = getPossibleSubClasses(); - final Collection<SpringBeanPointer<?>> list = new ArrayList<>(); - if (subClasses.size() > 0) { - for (PsiClass subClass : subClasses) { - list.addAll(SpringModelSearchers.findBeans(springModel, SpringModelSearchParameters.byClass(subClass).withInheritors())); + // TODO provide QuickFix to create Spring bean? + private static final class SpringBeanReference extends PsiReferenceBase<XmlAttributeValue> { + + private final Module module; + private final ExtendClass extendClass; + + private SpringBeanReference(final XmlAttributeValue element, + final Module module, + final ExtendClass extendClass) { + super(element, true); + this.module = module; + this.extendClass = extendClass; } - } - else { - list.addAll(springModel.getAllCommonBeans()); - } - - final List<LookupElement> variants = new ArrayList<>(list.size()); - for (final SpringBeanPointer<?> bean : list) { - if (bean.isAbstract()) { - continue; + + @NotNull + private SpringModel getSpringModel() { + return SpringManager.getInstance(module.getProject()).getCombinedModel(module); } - ContainerUtil.addIfNotNull(variants, SpringConverterUtil.createCompletionVariant(bean)); - } + @Override + public PsiElement resolve() { + final String beanName = myElement.getValue(); + if (StringUtil.isEmpty(beanName)) { + return null; + } - return variants.toArray(LookupElement.EMPTY_ARRAY); - } + final SpringModel springModel = getSpringModel(); + final SpringBeanPointer<?> springBean = SpringModelSearchers.findBean(springModel, beanName); + if (springBean == null) { + return null; + } - /** - * Determines a possible subclass for the current reference element. - * - * @return Subclass the Spring bean reference must implement or {@code null} if no subclass defined. - */ - @Nullable - private Set<PsiClass> getPossibleSubClasses() { - final String[] subClassName = extendClass.value(); - if (subClassName.length == 0) { - return null; - } - return Arrays.stream(subClassName) - .map(s -> JavaPsiFacade.getInstance(module.getProject()) - .findClass(s, GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module, false))) - .filter(Objects::nonNull) - .collect(Collectors.toSet()); + if (springBean.isAbstract()) { + return null; + } + + return springBean.getBeanClass(); + } + + @Override + public Object @NotNull [] getVariants() { + final SpringModel springModel = getSpringModel(); + + final @Nullable Set<PsiClass> subClasses = getPossibleSubClasses(); + + final Collection<SpringBeanPointer<?>> list = new ArrayList<>(); + if (subClasses != null && !subClasses.isEmpty()) { + for (PsiClass subClass : subClasses) { + list.addAll(SpringModelSearchers.findBeans(springModel, SpringModelSearchParameters.byClass(subClass).withInheritors())); + } + } else { + list.addAll(springModel.getAllCommonBeans()); + } + + final List<LookupElement> variants = new ArrayList<>(list.size()); + for (final SpringBeanPointer<?> bean : list) { + if (bean.isAbstract()) { + continue; + } + + ContainerUtil.addIfNotNull(variants, SpringConverterUtil.createCompletionVariant(bean)); + } + + return variants.toArray(LookupElement.EMPTY_ARRAY); + } + + /** + * Determines a possible subclass for the current reference element. + * + * @return Subclass the Spring bean reference must implement or {@code null} if no subclass defined. + */ + @Nullable + private Set<PsiClass> getPossibleSubClasses() { + final String[] subClassName = extendClass.value(); + if (subClassName.length == 0) { + return null; + } + return Arrays.stream(subClassName) + .map(s -> JavaPsiFacade.getInstance(module.getProject()) + .findClass(s, GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module, false))) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + } } - } } \ No newline at end of file
