Spring Support: "Generate Dependency..." actions
#KT-11407 Fixed
This commit is contained in:
@@ -129,6 +129,7 @@ New features:
|
|||||||
- [KT-3741](https://youtrack.jetbrains.com/issue/KT-3741) Show Spring-specific line markers on Kotlin classes
|
- [KT-3741](https://youtrack.jetbrains.com/issue/KT-3741) Show Spring-specific line markers on Kotlin classes
|
||||||
- [KT-11406](https://youtrack.jetbrains.com/issue/KT-11406) Support Spring EL injections inside of Kotlin string literals
|
- [KT-11406](https://youtrack.jetbrains.com/issue/KT-11406) Support Spring EL injections inside of Kotlin string literals
|
||||||
- [KT-11604](https://youtrack.jetbrains.com/issue/KT-11604) Support "Configure Spring facet" inspection on Kotlin classes
|
- [KT-11604](https://youtrack.jetbrains.com/issue/KT-11604) Support "Configure Spring facet" inspection on Kotlin classes
|
||||||
|
- [KT-11407](https://youtrack.jetbrains.com/issue/KT-11407) Implemented "Generate Spring Dependency..." actions
|
||||||
|
|
||||||
Issues fixed:
|
Issues fixed:
|
||||||
|
|
||||||
|
|||||||
@@ -99,6 +99,7 @@ import org.jetbrains.kotlin.idea.refactoring.pushDown.AbstractPushDownTest
|
|||||||
import org.jetbrains.kotlin.idea.refactoring.rename.AbstractRenameTest
|
import org.jetbrains.kotlin.idea.refactoring.rename.AbstractRenameTest
|
||||||
import org.jetbrains.kotlin.idea.refactoring.safeDelete.AbstractSafeDeleteTest
|
import org.jetbrains.kotlin.idea.refactoring.safeDelete.AbstractSafeDeleteTest
|
||||||
import org.jetbrains.kotlin.idea.resolve.*
|
import org.jetbrains.kotlin.idea.resolve.*
|
||||||
|
import org.jetbrains.kotlin.idea.spring.tests.generate.AbstractGenerateSpringDependencyActionTest
|
||||||
import org.jetbrains.kotlin.idea.spring.tests.references.AbstractSpringReferenceCompletionHandlerTest
|
import org.jetbrains.kotlin.idea.spring.tests.references.AbstractSpringReferenceCompletionHandlerTest
|
||||||
import org.jetbrains.kotlin.idea.spring.tests.references.AbstractSpringReferenceCompletionTest
|
import org.jetbrains.kotlin.idea.spring.tests.references.AbstractSpringReferenceCompletionTest
|
||||||
import org.jetbrains.kotlin.idea.spring.tests.references.AbstractSpringReferenceNavigationTest
|
import org.jetbrains.kotlin.idea.spring.tests.references.AbstractSpringReferenceNavigationTest
|
||||||
@@ -814,6 +815,10 @@ fun main(args: Array<String>) {
|
|||||||
testClass<AbstractSpringReferenceNavigationTest>() {
|
testClass<AbstractSpringReferenceNavigationTest>() {
|
||||||
model("spring/core/references/navigation")
|
model("spring/core/references/navigation")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
testClass<AbstractGenerateSpringDependencyActionTest>() {
|
||||||
|
model("spring/core/generate", pattern = "^([\\w]+)\\.kt$", singleClass = true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
testGroup("idea/tests", "compiler/testData") {
|
testGroup("idea/tests", "compiler/testData") {
|
||||||
|
|||||||
+7
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.load.java.structure.impl.*
|
|||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.parameterIndex
|
||||||
import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolver
|
import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolver
|
||||||
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
|
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
|
||||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||||
@@ -82,6 +83,12 @@ fun PsiMember.getJavaOrKotlinMemberDescriptor(resolutionFacade: ResolutionFacade
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun PsiParameter.getParameterDescriptor(resolutionFacade: ResolutionFacade? = null): ValueParameterDescriptor? {
|
||||||
|
val method = declarationScope as? PsiMethod ?: return null
|
||||||
|
val methodDescriptor = method.getJavaMethodDescriptor(resolutionFacade) ?: return null
|
||||||
|
return methodDescriptor.valueParameters[parameterIndex()]
|
||||||
|
}
|
||||||
|
|
||||||
fun PsiClass.resolveToDescriptor(
|
fun PsiClass.resolveToDescriptor(
|
||||||
resolutionFacade: ResolutionFacade,
|
resolutionFacade: ResolutionFacade,
|
||||||
declarationTranslator: (KtClassOrObject) -> KtClassOrObject? = { it }
|
declarationTranslator: (KtClassOrObject) -> KtClassOrObject? = { it }
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.idea.core
|
|||||||
|
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||||
@@ -35,6 +36,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
|
|||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
||||||
import org.jetbrains.kotlin.resolve.scopes.utils.findClassifier
|
import org.jetbrains.kotlin.resolve.scopes.utils.findClassifier
|
||||||
|
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@@ -60,14 +62,18 @@ class CollectingNameValidator @JvmOverloads constructor(
|
|||||||
class NewDeclarationNameValidator(
|
class NewDeclarationNameValidator(
|
||||||
private val visibleDeclarationsContext: KtElement?,
|
private val visibleDeclarationsContext: KtElement?,
|
||||||
private val checkDeclarationsIn: Sequence<PsiElement>,
|
private val checkDeclarationsIn: Sequence<PsiElement>,
|
||||||
private val target: NewDeclarationNameValidator.Target
|
private val target: NewDeclarationNameValidator.Target,
|
||||||
|
private val excludedDeclarations: List<KtDeclaration> = emptyList()
|
||||||
) : (String) -> Boolean {
|
) : (String) -> Boolean {
|
||||||
|
constructor(container: PsiElement,
|
||||||
constructor(container: PsiElement, anchor: PsiElement?, target: NewDeclarationNameValidator.Target)
|
anchor: PsiElement?,
|
||||||
|
target: NewDeclarationNameValidator.Target,
|
||||||
|
excludedDeclarations: List<KtDeclaration> = emptyList())
|
||||||
: this(
|
: this(
|
||||||
(anchor ?: container).parentsWithSelf.firstIsInstanceOrNull<KtElement>(),
|
(anchor ?: container).parentsWithSelf.firstIsInstanceOrNull<KtElement>(),
|
||||||
anchor?.siblings() ?: container.allChildren,
|
anchor?.siblings() ?: container.allChildren,
|
||||||
target)
|
target,
|
||||||
|
excludedDeclarations)
|
||||||
|
|
||||||
enum class Target {
|
enum class Target {
|
||||||
VARIABLES,
|
VARIABLES,
|
||||||
@@ -88,6 +94,8 @@ class NewDeclarationNameValidator(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun notExcluded(it: DeclarationDescriptorWithSource) = it.source.getPsi() !in excludedDeclarations
|
||||||
|
|
||||||
private fun LexicalScope.hasConflict(name: Name): Boolean {
|
private fun LexicalScope.hasConflict(name: Name): Boolean {
|
||||||
fun DeclarationDescriptor.isVisible(): Boolean {
|
fun DeclarationDescriptor.isVisible(): Boolean {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
@@ -98,14 +106,15 @@ class NewDeclarationNameValidator(
|
|||||||
|
|
||||||
return when(target) {
|
return when(target) {
|
||||||
Target.VARIABLES ->
|
Target.VARIABLES ->
|
||||||
getAllAccessibleVariables(name).any { !it.isExtension && it.isVisible() }
|
getAllAccessibleVariables(name).any { !it.isExtension && it.isVisible() && notExcluded(it) }
|
||||||
Target.FUNCTIONS_AND_CLASSES ->
|
Target.FUNCTIONS_AND_CLASSES ->
|
||||||
getAllAccessibleFunctions(name).any { !it.isExtension && it.isVisible() } ||
|
getAllAccessibleFunctions(name).any { !it.isExtension && it.isVisible() && notExcluded(it) } ||
|
||||||
findClassifier(name, NoLookupLocation.FROM_IDE)?.let { it.isVisible() } ?: false
|
findClassifier(name, NoLookupLocation.FROM_IDE)?.let { it.isVisible() && notExcluded(it) } ?: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun KtNamedDeclaration.isConflicting(name: Name): Boolean {
|
private fun KtNamedDeclaration.isConflicting(name: Name): Boolean {
|
||||||
|
if (this in excludedDeclarations) return false
|
||||||
if (nameAsName != name) return false
|
if (nameAsName != name) return false
|
||||||
if (this is KtCallableDeclaration && receiverTypeReference != null) return false
|
if (this is KtCallableDeclaration && receiverTypeReference != null) return false
|
||||||
return when(target) {
|
return when(target) {
|
||||||
|
|||||||
@@ -22,4 +22,19 @@
|
|||||||
level="WARNING"
|
level="WARNING"
|
||||||
implementationClass="org.jetbrains.kotlin.idea.spring.inspections.KotlinSpringFacetCodeInspection"/>
|
implementationClass="org.jetbrains.kotlin.idea.spring.inspections.KotlinSpringFacetCodeInspection"/>
|
||||||
</extensions>
|
</extensions>
|
||||||
|
|
||||||
|
<actions>
|
||||||
|
<action id="Kotlin.Spring.Beans.Generate.Setter.Dependency.Action"
|
||||||
|
class="org.jetbrains.kotlin.idea.spring.generate.GenerateKotlinSpringBeanDependencyAction$Setter">
|
||||||
|
<add-to-group anchor="last" group-id="GenerateGroup"/>
|
||||||
|
</action>
|
||||||
|
<action id="Kotlin.Spring.Beans.Generate.Constructor.Dependency.Action"
|
||||||
|
class="org.jetbrains.kotlin.idea.spring.generate.GenerateKotlinSpringBeanDependencyAction$Constructor">
|
||||||
|
<add-to-group anchor="last" group-id="GenerateGroup"/>
|
||||||
|
</action>
|
||||||
|
<action id="Kotlin.Spring.Beans.Generate.Lateinit.Property.Dependency.Action"
|
||||||
|
class="org.jetbrains.kotlin.idea.spring.generate.GenerateKotlinSpringBeanDependencyAction$LateinitProperty">
|
||||||
|
<add-to-group anchor="last" group-id="GenerateGroup"/>
|
||||||
|
</action>
|
||||||
|
</actions>
|
||||||
</idea-plugin>
|
</idea-plugin>
|
||||||
+73
@@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.spring.generate
|
||||||
|
|
||||||
|
import com.intellij.openapi.editor.Editor
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.psi.PsiFile
|
||||||
|
import com.intellij.psi.xml.XmlFile
|
||||||
|
import com.intellij.spring.SpringBundle
|
||||||
|
import com.intellij.spring.SpringManager
|
||||||
|
import com.intellij.spring.model.actions.generate.GenerateSpringBeanDependenciesUtil
|
||||||
|
import com.intellij.spring.model.utils.SpringModelUtils
|
||||||
|
import icons.SpringApiIcons
|
||||||
|
import org.jetbrains.kotlin.asJava.toLightClass
|
||||||
|
import org.jetbrains.kotlin.idea.actions.generate.KotlinGenerateActionBase
|
||||||
|
import org.jetbrains.kotlin.idea.editor.BatchTemplateRunner
|
||||||
|
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
|
||||||
|
import org.jetbrains.kotlin.psi.KtClass
|
||||||
|
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||||
|
|
||||||
|
abstract class GenerateKotlinSpringBeanDependencyAction(
|
||||||
|
text: String,
|
||||||
|
private val injectionKind: SpringDependencyInjectionKind
|
||||||
|
) : KotlinGenerateActionBase() {
|
||||||
|
class Constructor: GenerateKotlinSpringBeanDependencyAction(
|
||||||
|
SpringBundle.message("action.Spring.Beans.Generate.Constructor.Dependency.Action.text"),
|
||||||
|
SpringDependencyInjectionKind.CONSTRUCTOR
|
||||||
|
)
|
||||||
|
class Setter: GenerateKotlinSpringBeanDependencyAction(
|
||||||
|
SpringBundle.message("action.Spring.Beans.Generate.Setter.Dependency.Action.text"),
|
||||||
|
SpringDependencyInjectionKind.SETTER
|
||||||
|
)
|
||||||
|
class LateinitProperty: GenerateKotlinSpringBeanDependencyAction(
|
||||||
|
"Spring 'lateinit' Dependency...",
|
||||||
|
SpringDependencyInjectionKind.LATEINIT_PROPERTY
|
||||||
|
)
|
||||||
|
|
||||||
|
init {
|
||||||
|
templatePresentation.text = text
|
||||||
|
templatePresentation.icon = SpringApiIcons.Spring
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isValidForClass(targetClass: KtClassOrObject): Boolean {
|
||||||
|
if (targetClass !is KtClass || targetClass.isInterface() || targetClass.isEnum() || targetClass.fqName == null) return false
|
||||||
|
val lightClass = targetClass.toLightClass() ?: return false
|
||||||
|
val module = GenerateSpringBeanDependenciesUtil.getSpringModule(lightClass) ?: return false
|
||||||
|
return SpringManager.getInstance(module.project).getCombinedModel(module).configFiles.any { it is XmlFile }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun invoke(project: Project, editor: Editor, file: PsiFile) {
|
||||||
|
val klass = getTargetClass(editor, file) as? KtClass ?: return
|
||||||
|
val lightClass = klass.toLightClass() ?: return
|
||||||
|
val springModel = SpringModelUtils.getInstance().getPsiClassSpringModel(lightClass)
|
||||||
|
val templates = project.executeWriteCommand<List<BatchTemplateRunner>>("") {
|
||||||
|
generateDependenciesFor(springModel, lightClass, injectionKind)
|
||||||
|
}
|
||||||
|
templates.forEach { it.runTemplates() }
|
||||||
|
}
|
||||||
|
}
|
||||||
+497
@@ -0,0 +1,497 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.spring.generate
|
||||||
|
|
||||||
|
import com.intellij.codeInsight.lookup.LookupElement
|
||||||
|
import com.intellij.codeInsight.lookup.LookupElementBuilder
|
||||||
|
import com.intellij.codeInsight.template.Expression
|
||||||
|
import com.intellij.codeInsight.template.ExpressionContext
|
||||||
|
import com.intellij.codeInsight.template.TemplateBuilderImpl
|
||||||
|
import com.intellij.codeInsight.template.TextResult
|
||||||
|
import com.intellij.codeInspection.SmartHashMap
|
||||||
|
import com.intellij.openapi.application.ApplicationManager
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.util.Key
|
||||||
|
import com.intellij.psi.*
|
||||||
|
import com.intellij.psi.codeStyle.CodeStyleManager
|
||||||
|
import com.intellij.psi.util.PropertyUtil
|
||||||
|
import com.intellij.psi.util.PsiTypesUtil
|
||||||
|
import com.intellij.spring.CommonSpringModel
|
||||||
|
import com.intellij.spring.model.CommonSpringBean
|
||||||
|
import com.intellij.spring.model.SpringBeanPointer
|
||||||
|
import com.intellij.spring.model.SpringModelSearchParameters
|
||||||
|
import com.intellij.spring.model.actions.generate.GenerateSpringBeanDependenciesUtil
|
||||||
|
import com.intellij.spring.model.actions.generate.GenerateSpringBeanDependenciesUtil.*
|
||||||
|
import com.intellij.spring.model.actions.generate.SpringBeanClassMember
|
||||||
|
import com.intellij.spring.model.highlighting.SpringConstructorArgResolveUtil
|
||||||
|
import com.intellij.spring.model.utils.SpringBeanCoreUtils
|
||||||
|
import com.intellij.spring.model.utils.SpringBeanUtils
|
||||||
|
import com.intellij.spring.model.utils.SpringModelSearchers
|
||||||
|
import com.intellij.spring.model.utils.SpringModelUtils
|
||||||
|
import com.intellij.spring.model.xml.DomSpringBean
|
||||||
|
import com.intellij.spring.model.xml.beans.Beans
|
||||||
|
import com.intellij.spring.model.xml.beans.SpringBean
|
||||||
|
import com.intellij.util.IncorrectOperationException
|
||||||
|
import com.intellij.util.xml.DomElement
|
||||||
|
import com.intellij.util.xml.DomUtil
|
||||||
|
import org.jetbrains.annotations.NotNull
|
||||||
|
import org.jetbrains.annotations.TestOnly
|
||||||
|
import org.jetbrains.kotlin.asJava.KtLightClass
|
||||||
|
import org.jetbrains.kotlin.asJava.KtLightMethod
|
||||||
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.*
|
||||||
|
import org.jetbrains.kotlin.idea.completion.BasicLookupElementFactory
|
||||||
|
import org.jetbrains.kotlin.idea.completion.InsertHandlerProvider
|
||||||
|
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
|
||||||
|
import org.jetbrains.kotlin.idea.core.NewDeclarationNameValidator
|
||||||
|
import org.jetbrains.kotlin.idea.core.getOrCreateCompanionObject
|
||||||
|
import org.jetbrains.kotlin.idea.editor.BatchTemplateRunner
|
||||||
|
import org.jetbrains.kotlin.idea.util.CallType
|
||||||
|
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||||
|
import org.jetbrains.kotlin.idea.util.ShortenReferences
|
||||||
|
import org.jetbrains.kotlin.load.java.propertyNameBySetMethodName
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
import org.jetbrains.kotlin.types.expressions.TypeReconstructionUtil
|
||||||
|
import org.jetbrains.kotlin.utils.SmartList
|
||||||
|
import org.jetbrains.kotlin.utils.ifEmpty
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
// TODO: GenerateSpringBeanDependenciesUtil.ensureFileWritable() is not accessible here
|
||||||
|
private fun DomElement.ensureFileWritable() = ensureFileWritable(DomUtil.getFile(this).virtualFile, manager.project)
|
||||||
|
|
||||||
|
// TODO: GenerateSpringBeanDependenciesUtil.getReferenceName() is not accessible here
|
||||||
|
private fun getReferencedName(currentBean: SpringBean, bean: SpringBeanPointer<CommonSpringBean>): String? {
|
||||||
|
val model = SpringModelUtils.getInstance().getSpringModel(currentBean)
|
||||||
|
return SpringBeanCoreUtils.getReferencedName(bean, model.allCommonBeans)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: GenerateSpringBeanDependenciesUtil.getExistedSetter() is not accessible here
|
||||||
|
private fun getExistedSetter(currentBeanClass: PsiClass, setterPsiClass: PsiClass): PsiMethod? {
|
||||||
|
val psiClassType = JavaPsiFacade.getInstance(setterPsiClass.project).elementFactory.createType(setterPsiClass)
|
||||||
|
return currentBeanClass.allMethods.firstOrNull {
|
||||||
|
PropertyUtil.isSimplePropertySetter(it) && it.parameterList.parameters.first().type.isAssignableFrom(psiClassType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: GenerateSpringBeanDependenciesUtil.findConstructor() is not accessible here
|
||||||
|
private fun findConstructor(constructors: Array<PsiMethod>, psiParameterTypes: List<PsiType>): PsiMethod? {
|
||||||
|
return constructors.firstOrNull {
|
||||||
|
val parameters = it.parameterList.parameters
|
||||||
|
if (it.parameterList.parametersCount != psiParameterTypes.size) return@firstOrNull false
|
||||||
|
(psiParameterTypes zip parameters).all { it.first.isAssignableFrom(it.second.type) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: GenerateSpringBeanDependenciesUtil.findExistedConstructor() is not accessible here
|
||||||
|
private fun findExistedConstructor(
|
||||||
|
currentBean: SpringBean,
|
||||||
|
currentBeanClass: PsiClass,
|
||||||
|
candidateParameterClasses: Array<out PsiClass>
|
||||||
|
): PsiMethod? {
|
||||||
|
val constructors = SpringConstructorArgResolveUtil.findMatchingMethods(currentBean)
|
||||||
|
for (candidateBeanClass in candidateParameterClasses) {
|
||||||
|
for (constructor in constructors) {
|
||||||
|
val psiParameterTypes = SmartList<PsiType>().apply {
|
||||||
|
constructor.parameterList.parameters.mapTo(this) { it.type }
|
||||||
|
add(PsiTypesUtil.getClassType(candidateBeanClass))
|
||||||
|
}
|
||||||
|
findConstructor(currentBeanClass.constructors, psiParameterTypes)?.let { return it }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: GenerateSpringBeanDependenciesUtil.createSpringBean() is not accessible here
|
||||||
|
private fun createSpringBean(parentBeans: Beans, psiClass: PsiClass): SpringBean? {
|
||||||
|
if (!((parentBeans as DomElement)).ensureFileWritable()) return null
|
||||||
|
|
||||||
|
return parentBeans.addBean().apply {
|
||||||
|
clazz.stringValue = psiClass.qualifiedName
|
||||||
|
id.stringValue = SpringBeanCoreUtils.suggestBeanNames(this).firstOrNull() ?: ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun SpringBean.getFactoryFunctionName(factoryBeanClass: KtClass): String {
|
||||||
|
factoryMethod.stringValue?.let { if (!it.isBlank()) return it }
|
||||||
|
|
||||||
|
val existingNames = factoryBeanClass.declarations.mapNotNull { if (it is KtFunction || it is KtClassOrObject) it.name else null }
|
||||||
|
return KotlinNameSuggester.suggestNameByName("create${beanClass!!.name}") { it !in existingNames }
|
||||||
|
}
|
||||||
|
|
||||||
|
private val PsiClass.defaultTypeText: String
|
||||||
|
get() {
|
||||||
|
val qName = qualifiedName ?: return "Any"
|
||||||
|
val typeParameters = typeParameters
|
||||||
|
if (typeParameters.isEmpty()) return qName
|
||||||
|
return TypeReconstructionUtil.getTypeNameAndStarProjectionsString(qName, typeParameters.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createSettable(
|
||||||
|
candidateBean: SpringBeanPointer<CommonSpringBean>,
|
||||||
|
currentBeanClass: KtLightClass,
|
||||||
|
candidateBeanClasses: Array<out PsiClass>,
|
||||||
|
injectionKind: SpringDependencyInjectionKind
|
||||||
|
): KtNamedDeclaration {
|
||||||
|
val project = currentBeanClass.project
|
||||||
|
val psiFactory = KtPsiFactory(project)
|
||||||
|
val beanName = candidateBean.name
|
||||||
|
try {
|
||||||
|
val candidateClass = candidateBeanClasses.first()
|
||||||
|
val propertyName = if (beanName != null && KotlinNameSuggester.isIdentifier(beanName)) beanName else candidateClass.name!!
|
||||||
|
|
||||||
|
val prototype: KtNamedDeclaration = when (injectionKind) {
|
||||||
|
SpringDependencyInjectionKind.SETTER -> {
|
||||||
|
psiFactory.createFunction("fun set${propertyName.capitalize()}(${propertyName.decapitalize()}: ${candidateClass.defaultTypeText}) { }")
|
||||||
|
}
|
||||||
|
|
||||||
|
SpringDependencyInjectionKind.LATEINIT_PROPERTY -> {
|
||||||
|
psiFactory.createProperty("lateinit var ${propertyName.decapitalize()}: ${candidateClass.defaultTypeText}")
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> error("Unexpected injection kind: $injectionKind")
|
||||||
|
}
|
||||||
|
return currentBeanClass.kotlinOrigin!!.addDeclaration(prototype).apply { ShortenReferences.DEFAULT.process(this) }
|
||||||
|
}
|
||||||
|
catch (e: IncorrectOperationException) {
|
||||||
|
throw RuntimeException(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getSuggestedNames(
|
||||||
|
beanPointer: SpringBeanPointer<CommonSpringBean>,
|
||||||
|
declaration: KtCallableDeclaration,
|
||||||
|
getType: CallableDescriptor.() -> KotlinType?
|
||||||
|
): Collection<String> {
|
||||||
|
val names = LinkedHashSet<String>()
|
||||||
|
|
||||||
|
val validator = NewDeclarationNameValidator(declaration.parent, null, NewDeclarationNameValidator.Target.VARIABLES, listOf(declaration))
|
||||||
|
|
||||||
|
SpringBeanUtils.getInstance()
|
||||||
|
.findBeanNames(beanPointer.springBean)
|
||||||
|
.asSequence()
|
||||||
|
.filter { KotlinNameSuggester.isIdentifier(it) }
|
||||||
|
.mapTo(names) { KotlinNameSuggester.suggestNameByName(it, validator) }
|
||||||
|
|
||||||
|
(declaration.resolveToDescriptor() as CallableDescriptor).getType()?.let {
|
||||||
|
names += KotlinNameSuggester.suggestNamesByType(it, validator)
|
||||||
|
}
|
||||||
|
|
||||||
|
return names
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun TemplateBuilderImpl.appendVariableTemplate(
|
||||||
|
variable: KtCallableDeclaration,
|
||||||
|
candidateBeanClasses: Array<out PsiClass>,
|
||||||
|
computeSuggestions: (() -> Collection<String>)?
|
||||||
|
) {
|
||||||
|
if (computeSuggestions != null) {
|
||||||
|
val suggestedNames = computeSuggestions()
|
||||||
|
val defaultName = variable.name ?: ""
|
||||||
|
val nameExpression = object : Expression() {
|
||||||
|
override fun calculateResult(context: ExpressionContext) = TextResult(defaultName)
|
||||||
|
|
||||||
|
override fun calculateQuickResult(context: ExpressionContext) = calculateResult(context)
|
||||||
|
|
||||||
|
override fun calculateLookupItems(context: ExpressionContext): Array<LookupElement>? {
|
||||||
|
PsiDocumentManager.getInstance(context.project).commitAllDocuments()
|
||||||
|
return suggestedNames.map { LookupElementBuilder.create(it) }.toTypedArray()
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
replaceElement(variable.nameIdentifier, "names", nameExpression, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
val superTypeVariants = getSuperTypeVariants(candidateBeanClasses)
|
||||||
|
if (superTypeVariants.size > 1) {
|
||||||
|
val lookupFactory = BasicLookupElementFactory(variable.project, InsertHandlerProvider(CallType.TYPE) { emptyList() })
|
||||||
|
val typeReferenceExpression = object : Expression() {
|
||||||
|
override fun calculateResult(context: ExpressionContext) = TextResult(candidateBeanClasses.first().qualifiedName ?: "")
|
||||||
|
|
||||||
|
override fun calculateQuickResult(context: ExpressionContext) = calculateResult(context)
|
||||||
|
|
||||||
|
override fun calculateLookupItems(context: ExpressionContext): Array<LookupElement>? {
|
||||||
|
return superTypeVariants
|
||||||
|
.mapTo(LinkedHashSet()) { lookupFactory.createLookupElementForJavaClass(it, qualifyNestedClasses = true) }
|
||||||
|
.toTypedArray()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
replaceElement(variable.typeReference, "type", typeReferenceExpression, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun BatchTemplateRunner.addCreateFunctionTemplate(
|
||||||
|
function: KtFunction,
|
||||||
|
candidateBeanClasses: Map<Int, Array<out PsiClass>>,
|
||||||
|
dependency: SpringBeanPointer<CommonSpringBean>
|
||||||
|
) {
|
||||||
|
val parameterList = function.valueParameterList!!
|
||||||
|
val builder = TemplateBuilderImpl(parameterList)
|
||||||
|
addTemplateFactory(parameterList) {
|
||||||
|
for ((paramIndex, candidateBeanClassesForParam) in candidateBeanClasses) {
|
||||||
|
builder.appendVariableTemplate(function.valueParameters[paramIndex], candidateBeanClassesForParam) {
|
||||||
|
getSuggestedNames(dependency, function) { valueParameters[paramIndex].type }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.buildInlineTemplate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun BatchTemplateRunner.addCreatePropertyTemplate(property: KtProperty, candidateBeanClasses: Array<out PsiClass>) {
|
||||||
|
val builder = TemplateBuilderImpl(property)
|
||||||
|
addTemplateFactory(property) {
|
||||||
|
builder.appendVariableTemplate(property, candidateBeanClasses, null)
|
||||||
|
builder.buildInlineTemplate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun BatchTemplateRunner.addCreateFunctionTemplate(
|
||||||
|
function: KtFunction,
|
||||||
|
paramIndex: Int,
|
||||||
|
candidateBeanClasses: Array<out PsiClass>,
|
||||||
|
dependency: SpringBeanPointer<CommonSpringBean>
|
||||||
|
) {
|
||||||
|
addCreateFunctionTemplate(function, mapOf(paramIndex to candidateBeanClasses), dependency)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getOrCreateSetter(
|
||||||
|
candidateBean: SpringBeanPointer<CommonSpringBean>,
|
||||||
|
currentBeanClass: KtLightClass,
|
||||||
|
candidateBeanClasses: Array<out PsiClass>,
|
||||||
|
templatesHolder: BatchTemplateRunner,
|
||||||
|
injectionKind: SpringDependencyInjectionKind
|
||||||
|
): PsiNamedElement? {
|
||||||
|
for (candidateBeanClass in candidateBeanClasses) {
|
||||||
|
getExistedSetter(currentBeanClass, candidateBeanClass)?.let { return it }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ensureFileWritable(currentBeanClass)) return null
|
||||||
|
val settable = createSettable(candidateBean, currentBeanClass, candidateBeanClasses, injectionKind)
|
||||||
|
when (settable) {
|
||||||
|
is KtNamedFunction -> templatesHolder.addCreateFunctionTemplate(settable, 0, candidateBeanClasses, candidateBean)
|
||||||
|
is KtProperty -> templatesHolder.addCreatePropertyTemplate(settable, candidateBeanClasses)
|
||||||
|
}
|
||||||
|
|
||||||
|
return settable
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createSetterDependency(
|
||||||
|
currentBean: SpringBean,
|
||||||
|
dependency: SpringBeanPointer<CommonSpringBean>,
|
||||||
|
injectionKind: SpringDependencyInjectionKind
|
||||||
|
): BatchTemplateRunner? {
|
||||||
|
val templatesHolder = BatchTemplateRunner(currentBean.manager.project)
|
||||||
|
val currentBeanClass = currentBean.beanClass as? KtLightClass ?: return null
|
||||||
|
val candidateBeanClasses = dependency.effectiveBeanType.ifEmpty { return null }
|
||||||
|
val setter = getOrCreateSetter(dependency, currentBeanClass, candidateBeanClasses, templatesHolder, injectionKind) ?: return null
|
||||||
|
currentBean.addProperty().apply {
|
||||||
|
name.ensureXmlElementExists()
|
||||||
|
name.stringValue = when (setter) {
|
||||||
|
is PsiMethod, is KtFunction -> propertyNameBySetMethodName(Name.identifier(setter.name!!), false)!!.asString()
|
||||||
|
else -> setter.name
|
||||||
|
}
|
||||||
|
refAttr.setStringValue(getReferencedName(currentBean, dependency))
|
||||||
|
}
|
||||||
|
return templatesHolder
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addConstructorParameter(
|
||||||
|
currentBeanClass: KtLightClass,
|
||||||
|
candidateBeanClass: PsiClass,
|
||||||
|
constructor: KtFunction
|
||||||
|
) {
|
||||||
|
val psiFactory = KtPsiFactory(currentBeanClass)
|
||||||
|
|
||||||
|
val validator = NewDeclarationNameValidator(constructor, null, NewDeclarationNameValidator.Target.VARIABLES)
|
||||||
|
val resolutionFacade = currentBeanClass.kotlinOrigin!!.getResolutionFacade()
|
||||||
|
val defaultType = (candidateBeanClass.getJavaOrKotlinMemberDescriptor(resolutionFacade) as ClassDescriptor).defaultType
|
||||||
|
val name = KotlinNameSuggester.suggestNamesByType(defaultType, validator).first()
|
||||||
|
|
||||||
|
val parameter = psiFactory.createParameter("$name: ${candidateBeanClass.defaultTypeText}")
|
||||||
|
constructor.getValueParameterList()!!.addParameter(parameter).apply { ShortenReferences.DEFAULT.process(this) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findProperConstructorAndAddParameter(
|
||||||
|
currentBean: SpringBean,
|
||||||
|
dependency: SpringBeanPointer<CommonSpringBean>,
|
||||||
|
currentBeanClass: KtLightClass,
|
||||||
|
candidateBeanClass: PsiClass,
|
||||||
|
holder: BatchTemplateRunner
|
||||||
|
): PsiMethod? {
|
||||||
|
val lightConstructor = currentBean.resolvedConstructorArgs.resolvedMethod as? KtLightMethod ?: return null
|
||||||
|
val constructorOrigin = lightConstructor.kotlinOrigin
|
||||||
|
val properConstructor = when (constructorOrigin) {
|
||||||
|
is KtFunction -> constructorOrigin
|
||||||
|
is KtClass -> constructorOrigin.createPrimaryConstructorIfAbsent()
|
||||||
|
else -> return null
|
||||||
|
}
|
||||||
|
addConstructorParameter(currentBeanClass, candidateBeanClass, properConstructor)
|
||||||
|
holder.addCreateFunctionTemplate(properConstructor, properConstructor.getValueParameters().lastIndex, arrayOf(candidateBeanClass), dependency)
|
||||||
|
return lightConstructor
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createConstructorWithTemplate(
|
||||||
|
currentBean: SpringBean,
|
||||||
|
dependency: SpringBeanPointer<CommonSpringBean>,
|
||||||
|
templatesHolder: BatchTemplateRunner
|
||||||
|
) {
|
||||||
|
val beanClass = currentBean.beanClass as? KtLightClass ?: return
|
||||||
|
val ktBeanClass = beanClass.kotlinOrigin as? KtClass ?: return
|
||||||
|
|
||||||
|
try {
|
||||||
|
val psiFactory = KtPsiFactory(beanClass)
|
||||||
|
val factoryFunction = when {
|
||||||
|
currentBean.factoryBean.exists() -> {
|
||||||
|
// TODO: Support non-Kotlin factory beans
|
||||||
|
val factoryClass = currentBean.factoryBean.value?.beanClass as? KtLightClass ?: return
|
||||||
|
val ktFactoryClass = factoryClass.kotlinOrigin as? KtClass ?: return
|
||||||
|
val funName = currentBean.getFactoryFunctionName(ktFactoryClass)
|
||||||
|
val funText = "fun $funName(): ${beanClass.defaultTypeText} {\n return null \n}"
|
||||||
|
ktFactoryClass.addDeclaration(psiFactory.createFunction(funText))
|
||||||
|
}
|
||||||
|
currentBean.factoryMethod.exists() -> {
|
||||||
|
val funName = currentBean.getFactoryFunctionName(ktBeanClass)
|
||||||
|
val funText = "@JvmStatic fun $funName(): ${beanClass.defaultTypeText} {\n return null \n}"
|
||||||
|
ktBeanClass.getOrCreateCompanionObject().addDeclaration(psiFactory.createFunction(funText))
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
if (ktBeanClass.hasPrimaryConstructor() || ktBeanClass.getSecondaryConstructors().isNotEmpty()) {
|
||||||
|
ktBeanClass.addDeclaration(psiFactory.createSecondaryConstructor("constructor()"))
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ktBeanClass.createPrimaryConstructorIfAbsent()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} as KtFunction
|
||||||
|
|
||||||
|
ShortenReferences.DEFAULT.process(factoryFunction)
|
||||||
|
|
||||||
|
val dummyMethod = JavaPsiFacade.getElementFactory(beanClass.project).createMethod("foo", PsiType.VOID)
|
||||||
|
dummyMethod.containingFile.moduleInfo = ktBeanClass.getModuleInfo()
|
||||||
|
SpringConstructorArgResolveUtil.suggestParamsForConstructorArgs(currentBean).forEach { dummyMethod.parameterList.add(it) }
|
||||||
|
|
||||||
|
val parameterList = factoryFunction.valueParameterList!!
|
||||||
|
val indexOffset = parameterList.parameters.size
|
||||||
|
val candidateClassMap = SmartHashMap<Int, Array<PsiClass>>()
|
||||||
|
val resolutionFacade = ktBeanClass.getResolutionFacade()
|
||||||
|
for ((i, psiParam) in dummyMethod.parameterList.parameters.withIndex()) {
|
||||||
|
val descriptor = psiParam.getParameterDescriptor(resolutionFacade)!!
|
||||||
|
val ktParameter = psiFactory.createParameter(
|
||||||
|
"${psiParam.name}: ${IdeDescriptorRenderers.SOURCE_CODE_NOT_NULL_TYPE_APPROXIMATION.renderType(descriptor.type)}"
|
||||||
|
)
|
||||||
|
parameterList.addParameter(ktParameter)
|
||||||
|
(psiParam.type as? PsiClassType)?.resolve()?.let { candidateClassMap[i + indexOffset] = arrayOf(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
templatesHolder.addCreateFunctionTemplate(factoryFunction, candidateClassMap, dependency)
|
||||||
|
}
|
||||||
|
catch (e: IncorrectOperationException) {
|
||||||
|
throw RuntimeException(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createConstructorDependency(
|
||||||
|
currentBean: SpringBean,
|
||||||
|
dependency: SpringBeanPointer<CommonSpringBean>
|
||||||
|
): BatchTemplateRunner? {
|
||||||
|
val templatesHolder = BatchTemplateRunner(currentBean.manager.project)
|
||||||
|
val currentBeanClass = currentBean.beanClass as? KtLightClass ?: return null
|
||||||
|
val candidateBeanClasses = dependency.effectiveBeanType.ifEmpty { return null }
|
||||||
|
var existedConstructor = findExistedConstructor(currentBean, currentBeanClass, candidateBeanClasses)
|
||||||
|
if (existedConstructor == null) {
|
||||||
|
if (!ensureFileWritable(currentBeanClass)) return null
|
||||||
|
existedConstructor = findProperConstructorAndAddParameter(currentBean, dependency, currentBeanClass, candidateBeanClasses.first(), templatesHolder)
|
||||||
|
}
|
||||||
|
|
||||||
|
val newConstructorArg = currentBean.addConstructorArg()
|
||||||
|
newConstructorArg.refAttr.stringValue = getReferencedName(currentBean, dependency)
|
||||||
|
if (existedConstructor == null && SpringConstructorArgResolveUtil.findMatchingMethods(currentBean).isEmpty()) {
|
||||||
|
createConstructorWithTemplate(currentBean, dependency, templatesHolder)
|
||||||
|
}
|
||||||
|
|
||||||
|
return templatesHolder
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateDependency(
|
||||||
|
springBean: SpringBean,
|
||||||
|
dependency: SpringBeanPointer<CommonSpringBean>,
|
||||||
|
injectionKind: SpringDependencyInjectionKind
|
||||||
|
): BatchTemplateRunner? {
|
||||||
|
return if (injectionKind.isSetter) {
|
||||||
|
createSetterDependency(springBean, dependency, injectionKind)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
createConstructorDependency(springBean, dependency)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class SpringDependencyInjectionKind(val isSetter: Boolean) {
|
||||||
|
CONSTRUCTOR(false),
|
||||||
|
SETTER(true),
|
||||||
|
LATEINIT_PROPERTY(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
@set:TestOnly
|
||||||
|
var Project.beanFilter: (SpringBeanPointer<CommonSpringBean>) -> Boolean
|
||||||
|
by NotNullableUserDataProperty(Key.create("BEAN_CHOOSER")) { true }
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private fun chooseDependentBeans(
|
||||||
|
candidates: Set<SpringBeanClassMember>,
|
||||||
|
project: Project,
|
||||||
|
isSetterDependency: Boolean
|
||||||
|
): List<SpringBeanPointer<CommonSpringBean>> {
|
||||||
|
return if (ApplicationManager.getApplication().isUnitTestMode) {
|
||||||
|
candidates.map { it.springBean }.filter(project.beanFilter)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
GenerateSpringBeanDependenciesUtil.chooseDependentBeans(candidates, project, isSetterDependency)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun generateDependenciesFor(
|
||||||
|
springModel: CommonSpringModel,
|
||||||
|
klass: KtLightClass,
|
||||||
|
injectionKind: SpringDependencyInjectionKind
|
||||||
|
): List<BatchTemplateRunner> {
|
||||||
|
val project = klass.project
|
||||||
|
val isSetter = injectionKind.isSetter
|
||||||
|
|
||||||
|
SpringModelSearchers
|
||||||
|
.findBeans(springModel, SpringModelSearchParameters.byClass(klass))
|
||||||
|
.asSequence()
|
||||||
|
.map { it.springBean }
|
||||||
|
.filterIsInstance<SpringBean>()
|
||||||
|
.firstOrNull { acceptBean(it, false) }
|
||||||
|
?.let { springBean ->
|
||||||
|
if (!springBean.ensureFileWritable()) return emptyList()
|
||||||
|
if (springBean.beanClass == null) return emptyList()
|
||||||
|
val dependencies = chooseDependentBeans(getCandidates(springBean, isSetter), project, isSetter)
|
||||||
|
return dependencies.mapNotNull { generateDependency(springBean, it, injectionKind) }
|
||||||
|
}
|
||||||
|
|
||||||
|
val dependencies = chooseDependentBeans(getCandidates(springModel, klass, isSetter), project, isSetter)
|
||||||
|
val beanXml = dependencies.singleOrNull()?.springBean as? DomSpringBean ?: return emptyList()
|
||||||
|
val beansXml = beanXml.getParentOfType(Beans::class.java, false) ?: return emptyList()
|
||||||
|
val newBean = createSpringBean(beansXml, klass) ?: return emptyList()
|
||||||
|
|
||||||
|
return dependencies.mapNotNull { generateDependency(newBean, it, injectionKind) }
|
||||||
|
}
|
||||||
+68
@@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.spring.tests.generate
|
||||||
|
|
||||||
|
import com.intellij.openapi.util.io.FileUtil
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
|
import com.intellij.util.PathUtil
|
||||||
|
import junit.framework.TestCase
|
||||||
|
import org.jetbrains.kotlin.idea.codeInsight.generate.AbstractCodeInsightActionTest
|
||||||
|
import org.jetbrains.kotlin.idea.spring.generate.beanFilter
|
||||||
|
import org.jetbrains.kotlin.idea.spring.tests.SpringTestFixtureExtension
|
||||||
|
import org.jetbrains.kotlin.idea.test.TestFixtureExtension
|
||||||
|
import org.jetbrains.kotlin.test.InTextDirectivesUtils
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
abstract class AbstractGenerateSpringDependencyActionTest : AbstractCodeInsightActionTest() {
|
||||||
|
private var configFile: VirtualFile? = null
|
||||||
|
private var configFilePath: String? = null
|
||||||
|
|
||||||
|
override fun setUp() {
|
||||||
|
super.setUp()
|
||||||
|
TestFixtureExtension.loadFixture<SpringTestFixtureExtension>(myModule)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun configureExtra(mainFilePath: String, mainFileText: String) {
|
||||||
|
configFilePath = InTextDirectivesUtils.findStringWithPrefixes(mainFileText, "// CONFIG_FILE: ")?.let {
|
||||||
|
"${PathUtil.getParentPath(mainFilePath)}/$it"
|
||||||
|
} ?: mainFilePath
|
||||||
|
val springFileSet = TestFixtureExtension
|
||||||
|
.getFixture<SpringTestFixtureExtension>()!!
|
||||||
|
.configureFileSet(myFixture, listOf(configFilePath!!))
|
||||||
|
if (configFilePath != mainFilePath) {
|
||||||
|
configFile = springFileSet.files.single().file!!
|
||||||
|
}
|
||||||
|
|
||||||
|
val beansToChoose = InTextDirectivesUtils.findListWithPrefixes(mainFileText, "// CHOOSE_BEAN: ")
|
||||||
|
project.beanFilter = { it.name in beansToChoose }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun checkExtra() {
|
||||||
|
configFile?.let {
|
||||||
|
myFixture.openFileInEditor(it)
|
||||||
|
val afterFile = File("$configFilePath.after")
|
||||||
|
TestCase.assertTrue(afterFile.exists())
|
||||||
|
myFixture.checkResult(FileUtil.loadFile(afterFile, true))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun tearDown() {
|
||||||
|
configFile = null
|
||||||
|
TestFixtureExtension.unloadFixture<SpringTestFixtureExtension>()
|
||||||
|
super.tearDown()
|
||||||
|
}
|
||||||
|
}
|
||||||
+67
@@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.spring.tests.generate;
|
||||||
|
|
||||||
|
import com.intellij.testFramework.TestDataPath;
|
||||||
|
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
|
||||||
|
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
||||||
|
import org.jetbrains.kotlin.test.TestMetadata;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
|
||||||
|
@SuppressWarnings("all")
|
||||||
|
@TestMetadata("idea/testData/spring/core/generate")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public class GenerateSpringDependencyActionTestGenerated extends AbstractGenerateSpringDependencyActionTest {
|
||||||
|
public void testAllFilesPresentInGenerate() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentInSingleGeneratedClass(this.getClass(), new File("idea/testData/spring/core/generate"), Pattern.compile("^([\\w]+)\\.kt$"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("beanDependenciesByXml/firstConstructor.kt")
|
||||||
|
public void testBeanDependenciesByXml_FirstConstructor() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/spring/core/generate/beanDependenciesByXml/firstConstructor.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("beanDependenciesByXml/primaryConstructorAddParam.kt")
|
||||||
|
public void testBeanDependenciesByXml_PrimaryConstructorAddParam() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/spring/core/generate/beanDependenciesByXml/primaryConstructorAddParam.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("beanDependenciesByXml/property.kt")
|
||||||
|
public void testBeanDependenciesByXml_Property() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/spring/core/generate/beanDependenciesByXml/property.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("beanDependenciesByXml/secondaryConstructorAddParam.kt")
|
||||||
|
public void testBeanDependenciesByXml_SecondaryConstructorAddParam() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/spring/core/generate/beanDependenciesByXml/secondaryConstructorAddParam.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("beanDependenciesByXml/setter.kt")
|
||||||
|
public void testBeanDependenciesByXml_Setter() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/spring/core/generate/beanDependenciesByXml/setter.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.editor
|
||||||
|
|
||||||
|
import com.intellij.codeInsight.template.Template
|
||||||
|
import com.intellij.codeInsight.template.TemplateEditingAdapter
|
||||||
|
import com.intellij.codeInsight.template.TemplateManager
|
||||||
|
import com.intellij.openapi.application.ApplicationManager
|
||||||
|
import com.intellij.openapi.editor.Editor
|
||||||
|
import com.intellij.openapi.fileEditor.FileEditorManager
|
||||||
|
import com.intellij.openapi.fileEditor.OpenFileDescriptor
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.psi.PsiDocumentManager
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.SmartPsiElementPointer
|
||||||
|
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class BatchTemplateRunner(private val project: Project) {
|
||||||
|
private val elementsAndFactories = ArrayList<Pair<SmartPsiElementPointer<*>, () -> Template?>>()
|
||||||
|
|
||||||
|
fun addTemplateFactory(element: PsiElement, factory: () -> Template?) {
|
||||||
|
elementsAndFactories.add(element.createSmartPointer() to factory)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun runTemplates() {
|
||||||
|
runTemplates(elementsAndFactories.iterator())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getEditor(pointer: SmartPsiElementPointer<*>): Editor? {
|
||||||
|
val element = pointer.element ?: return null
|
||||||
|
val virtualFile = element.containingFile?.virtualFile ?: return null
|
||||||
|
val descriptor = OpenFileDescriptor(project, virtualFile, element.textRange.startOffset)
|
||||||
|
return FileEditorManager.getInstance(project).openTextEditor(descriptor, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun runTemplates(iterator: Iterator<Pair<SmartPsiElementPointer<*>, () -> Template?>>) {
|
||||||
|
if (!iterator.hasNext()) return
|
||||||
|
|
||||||
|
val manager = TemplateManager.getInstance(project)
|
||||||
|
project.executeWriteCommand("") {
|
||||||
|
val (pointer, factory) = iterator.next()
|
||||||
|
|
||||||
|
val editor = getEditor(pointer) ?: return@executeWriteCommand
|
||||||
|
PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.document)
|
||||||
|
val template = factory() ?: return@executeWriteCommand
|
||||||
|
manager.startTemplate(
|
||||||
|
editor,
|
||||||
|
template,
|
||||||
|
object : TemplateEditingAdapter() {
|
||||||
|
override fun templateFinished(template: Template?, brokenOff: Boolean) {
|
||||||
|
if (brokenOff) return
|
||||||
|
ApplicationManager.getApplication().invokeLater { runTemplates(iterator) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -118,6 +118,7 @@ fun createSpacingBuilder(settings: CodeStyleSettings): KotlinSpacingBuilder {
|
|||||||
between(ENUM_ENTRY, SEMICOLON).spaces(0)
|
between(ENUM_ENTRY, SEMICOLON).spaces(0)
|
||||||
|
|
||||||
beforeInside(FUN, TokenSet.create(BODY, CLASS_BODY)).lineBreakInCode()
|
beforeInside(FUN, TokenSet.create(BODY, CLASS_BODY)).lineBreakInCode()
|
||||||
|
beforeInside(SECONDARY_CONSTRUCTOR, TokenSet.create(BODY, CLASS_BODY)).lineBreakInCode()
|
||||||
beforeInside(CLASS, TokenSet.create(BODY, CLASS_BODY)).lineBreakInCode()
|
beforeInside(CLASS, TokenSet.create(BODY, CLASS_BODY)).lineBreakInCode()
|
||||||
beforeInside(OBJECT_DECLARATION, TokenSet.create(BODY, CLASS_BODY)).lineBreakInCode()
|
beforeInside(OBJECT_DECLARATION, TokenSet.create(BODY, CLASS_BODY)).lineBreakInCode()
|
||||||
before(PROPERTY).lineBreakInCode()
|
before(PROPERTY).lineBreakInCode()
|
||||||
|
|||||||
+3
-1
@@ -64,6 +64,7 @@ import javax.swing.*;
|
|||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.event.ItemEvent;
|
import java.awt.event.ItemEvent;
|
||||||
import java.awt.event.ItemListener;
|
import java.awt.event.ItemListener;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class MoveKotlinNestedClassesToUpperLevelDialog extends MoveDialogBase {
|
public class MoveKotlinNestedClassesToUpperLevelDialog extends MoveDialogBase {
|
||||||
@@ -202,7 +203,8 @@ public class MoveKotlinNestedClassesToUpperLevelDialog extends MoveDialogBase {
|
|||||||
Function1<String, Boolean> validator =
|
Function1<String, Boolean> validator =
|
||||||
innerClassBody != null
|
innerClassBody != null
|
||||||
? new NewDeclarationNameValidator(innerClassBody, (PsiElement) null,
|
? new NewDeclarationNameValidator(innerClassBody, (PsiElement) null,
|
||||||
NewDeclarationNameValidator.Target.VARIABLES)
|
NewDeclarationNameValidator.Target.VARIABLES,
|
||||||
|
Collections.<KtDeclaration>emptyList())
|
||||||
: new CollectingNameValidator();
|
: new CollectingNameValidator();
|
||||||
List<String> suggestions = KotlinNameSuggester.INSTANCE.suggestNamesByType(getOuterInstanceType(), validator, "outer");
|
List<String> suggestions = KotlinNameSuggester.INSTANCE.suggestNamesByType(getOuterInstanceType(), validator, "outer");
|
||||||
parameterField.setSuggestions(ArrayUtil.toStringArray(suggestions));
|
parameterField.setSuggestions(ArrayUtil.toStringArray(suggestions));
|
||||||
|
|||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
default-init-method="myDefaultInitMethod"
|
||||||
|
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||||
|
<bean id="fooBean" class="a.FooBean" factory-bean="fooFactoryBean" factory-method="create"/>
|
||||||
|
<bean id="fooFactoryBean" class="a.FooFactoryBean"/>
|
||||||
|
<bean id="barBean" class="a.BarBean"/>
|
||||||
|
</beans>
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
default-init-method="myDefaultInitMethod"
|
||||||
|
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||||
|
<bean id="fooBean" class="a.FooBean" factory-bean="fooFactoryBean" factory-method="create">
|
||||||
|
<constructor-arg ref="barBean"/>
|
||||||
|
</bean>
|
||||||
|
<bean id="fooFactoryBean" class="a.FooFactoryBean"/>
|
||||||
|
<bean id="barBean" class="a.BarBean"/>
|
||||||
|
</beans>
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
// ACTION_CLASS: org.jetbrains.kotlin.idea.spring.generate.GenerateKotlinSpringBeanDependencyAction$Constructor
|
||||||
|
// CONFIG_FILE: factoryMethod-config.xml
|
||||||
|
// CHOOSE_BEAN: barBean
|
||||||
|
package a
|
||||||
|
|
||||||
|
open class FooBean {<caret>
|
||||||
|
}
|
||||||
|
|
||||||
|
open class FooFactoryBean {
|
||||||
|
open fun create(barBean: BarBean) = FooBean()
|
||||||
|
}
|
||||||
|
|
||||||
|
open class BarBean
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
// ACTION_CLASS: org.jetbrains.kotlin.idea.spring.generate.GenerateKotlinSpringBeanDependencyAction$Constructor
|
||||||
|
// CONFIG_FILE: factoryMethod-config.xml
|
||||||
|
// CHOOSE_BEAN: barBean
|
||||||
|
package a
|
||||||
|
|
||||||
|
open class FooBean {<caret>
|
||||||
|
}
|
||||||
|
|
||||||
|
open class FooFactoryBean {
|
||||||
|
open fun create() = FooBean()
|
||||||
|
}
|
||||||
|
|
||||||
|
open class BarBean
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
default-init-method="myDefaultInitMethod"
|
||||||
|
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||||
|
<bean id="fooBean" class="a.FooBean" factory-method="create" />
|
||||||
|
<bean id="barBean" class="a.BarBean"/>
|
||||||
|
</beans>
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
default-init-method="myDefaultInitMethod"
|
||||||
|
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||||
|
<bean id="fooBean" class="a.FooBean" factory-method="create">
|
||||||
|
<constructor-arg ref="barBean"/>
|
||||||
|
</bean>
|
||||||
|
<bean id="barBean" class="a.BarBean"/>
|
||||||
|
</beans>
|
||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
// ACTION_CLASS: org.jetbrains.kotlin.idea.spring.generate.GenerateKotlinSpringBeanDependencyAction$Constructor
|
||||||
|
// CONFIG_FILE: factoryMethod-config.xml
|
||||||
|
// CHOOSE_BEAN: barBean
|
||||||
|
package a
|
||||||
|
|
||||||
|
open class FooBean {
|
||||||
|
companion object {
|
||||||
|
@JvmStatic fun create(barBean: BarBean): FooBean {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open class BarBean
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
// ACTION_CLASS: org.jetbrains.kotlin.idea.spring.generate.GenerateKotlinSpringBeanDependencyAction$Constructor
|
||||||
|
// CONFIG_FILE: factoryMethod-config.xml
|
||||||
|
// CHOOSE_BEAN: barBean
|
||||||
|
package a
|
||||||
|
|
||||||
|
open class FooBean {<caret>
|
||||||
|
}
|
||||||
|
|
||||||
|
open class BarBean
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
default-init-method="myDefaultInitMethod"
|
||||||
|
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||||
|
<bean id="fooBean" class="a.FooBean"/>
|
||||||
|
<bean id="barBean" class="a.BarBean"/>
|
||||||
|
</beans>
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
default-init-method="myDefaultInitMethod"
|
||||||
|
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||||
|
<bean id="fooBean" class="a.FooBean">
|
||||||
|
<constructor-arg ref="barBean"/>
|
||||||
|
</bean>
|
||||||
|
<bean id="barBean" class="a.BarBean"/>
|
||||||
|
</beans>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// ACTION_CLASS: org.jetbrains.kotlin.idea.spring.generate.GenerateKotlinSpringBeanDependencyAction$Constructor
|
||||||
|
// CONFIG_FILE: firstConstructor-config.xml
|
||||||
|
// CHOOSE_BEAN: barBean
|
||||||
|
package a
|
||||||
|
|
||||||
|
open class FooBean {<caret>
|
||||||
|
}
|
||||||
|
|
||||||
|
open class BarBean
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
// ACTION_CLASS: org.jetbrains.kotlin.idea.spring.generate.GenerateKotlinSpringBeanDependencyAction$Constructor
|
||||||
|
// CONFIG_FILE: firstConstructor-config.xml
|
||||||
|
// CHOOSE_BEAN: barBean
|
||||||
|
package a
|
||||||
|
|
||||||
|
open class FooBean(barBean: BarBean) {
|
||||||
|
}
|
||||||
|
|
||||||
|
open class BarBean
|
||||||
Vendored
+11
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
default-init-method="myDefaultInitMethod"
|
||||||
|
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||||
|
<bean id="fooBean" class="a.FooBean">
|
||||||
|
<constructor-arg ref="barBean"/>
|
||||||
|
</bean>
|
||||||
|
<bean id="barBean" class="a.BarBean"/>
|
||||||
|
<bean id="bazBean" class="a.BazBean"/>
|
||||||
|
</beans>
|
||||||
idea/testData/spring/core/generate/beanDependenciesByXml/primaryConstructorAddParam-config.xml.after
Vendored
+12
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
default-init-method="myDefaultInitMethod"
|
||||||
|
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||||
|
<bean id="fooBean" class="a.FooBean">
|
||||||
|
<constructor-arg ref="barBean"/>
|
||||||
|
<constructor-arg ref="bazBean"/>
|
||||||
|
</bean>
|
||||||
|
<bean id="barBean" class="a.BarBean"/>
|
||||||
|
<bean id="bazBean" class="a.BazBean"/>
|
||||||
|
</beans>
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
// ACTION_CLASS: org.jetbrains.kotlin.idea.spring.generate.GenerateKotlinSpringBeanDependencyAction$Constructor
|
||||||
|
// CONFIG_FILE: primaryConstructorAddParam-config.xml
|
||||||
|
// CHOOSE_BEAN: bazBean
|
||||||
|
package a
|
||||||
|
|
||||||
|
open class FooBean(barBean: BarBean) {<caret>
|
||||||
|
}
|
||||||
|
|
||||||
|
open class BarBean
|
||||||
|
|
||||||
|
open class BazBean
|
||||||
Vendored
+11
@@ -0,0 +1,11 @@
|
|||||||
|
// ACTION_CLASS: org.jetbrains.kotlin.idea.spring.generate.GenerateKotlinSpringBeanDependencyAction$Constructor
|
||||||
|
// CONFIG_FILE: primaryConstructorAddParam-config.xml
|
||||||
|
// CHOOSE_BEAN: bazBean
|
||||||
|
package a
|
||||||
|
|
||||||
|
open class FooBean(barBean: BarBean, bazBean: BazBean) {
|
||||||
|
}
|
||||||
|
|
||||||
|
open class BarBean
|
||||||
|
|
||||||
|
open class BazBean
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
default-init-method="myDefaultInitMethod"
|
||||||
|
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||||
|
<bean id="fooBean" class="a.FooBean"/>
|
||||||
|
<bean id="barBean" class="a.BarBean"/>
|
||||||
|
</beans>
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
default-init-method="myDefaultInitMethod"
|
||||||
|
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||||
|
<bean id="fooBean" class="a.FooBean">
|
||||||
|
<property name="barBean" ref="barBean"/>
|
||||||
|
</bean>
|
||||||
|
<bean id="barBean" class="a.BarBean"/>
|
||||||
|
</beans>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// ACTION_CLASS: org.jetbrains.kotlin.idea.spring.generate.GenerateKotlinSpringBeanDependencyAction$LateinitProperty
|
||||||
|
// CONFIG_FILE: property-config.xml
|
||||||
|
// CHOOSE_BEAN: barBean
|
||||||
|
package a
|
||||||
|
|
||||||
|
open class FooBean {<caret>
|
||||||
|
}
|
||||||
|
|
||||||
|
open class BarBean
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// ACTION_CLASS: org.jetbrains.kotlin.idea.spring.generate.GenerateKotlinSpringBeanDependencyAction$LateinitProperty
|
||||||
|
// CONFIG_FILE: property-config.xml
|
||||||
|
// CHOOSE_BEAN: barBean
|
||||||
|
package a
|
||||||
|
|
||||||
|
open class FooBean {
|
||||||
|
lateinit var barBean: BarBean
|
||||||
|
}
|
||||||
|
|
||||||
|
open class BarBean
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
default-init-method="myDefaultInitMethod"
|
||||||
|
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||||
|
<bean id="fooBean" class="a.FooBean"/>
|
||||||
|
<bean id="barBean" class="a.BarBean"/>
|
||||||
|
</beans>
|
||||||
Vendored
+8
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
default-init-method="myDefaultInitMethod"
|
||||||
|
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||||
|
<bean id="fooBean" class="a.FooBean"/>
|
||||||
|
<bean id="barBean" class="a.BarBean"/>
|
||||||
|
</beans>
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
// ACTION_CLASS: org.jetbrains.kotlin.idea.spring.generate.GenerateKotlinSpringBeanDependencyAction$Constructor
|
||||||
|
// CONFIG_FILE: secondaryConstructor-config.xml
|
||||||
|
// CHOOSE_BEAN: barBean
|
||||||
|
package a
|
||||||
|
|
||||||
|
open class FooBean(n: Int) {
|
||||||
|
<caret>
|
||||||
|
}
|
||||||
|
|
||||||
|
open class BarBean
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
// ACTION_CLASS: org.jetbrains.kotlin.idea.spring.generate.GenerateKotlinSpringBeanDependencyAction$Constructor
|
||||||
|
// CONFIG_FILE: secondaryConstructor-config.xml
|
||||||
|
// CHOOSE_BEAN: barBean
|
||||||
|
package a
|
||||||
|
|
||||||
|
open class FooBean(n: Int) {<caret>
|
||||||
|
}
|
||||||
|
|
||||||
|
open class BarBean
|
||||||
Vendored
+11
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
default-init-method="myDefaultInitMethod"
|
||||||
|
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||||
|
<bean id="fooBean" class="a.FooBean">
|
||||||
|
<constructor-arg ref="barBean"/>
|
||||||
|
</bean>
|
||||||
|
<bean id="barBean" class="a.BarBean"/>
|
||||||
|
<bean id="bazBean" class="a.BazBean"/>
|
||||||
|
</beans>
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
default-init-method="myDefaultInitMethod"
|
||||||
|
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||||
|
<bean id="fooBean" class="a.FooBean">
|
||||||
|
<constructor-arg ref="barBean"/>
|
||||||
|
<constructor-arg ref="bazBean"/>
|
||||||
|
</bean>
|
||||||
|
<bean id="barBean" class="a.BarBean"/>
|
||||||
|
<bean id="bazBean" class="a.BazBean"/>
|
||||||
|
</beans>
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
// ACTION_CLASS: org.jetbrains.kotlin.idea.spring.generate.GenerateKotlinSpringBeanDependencyAction$Constructor
|
||||||
|
// CONFIG_FILE: secondaryConstructorAddParam-config.xml
|
||||||
|
// CHOOSE_BEAN: bazBean
|
||||||
|
package a
|
||||||
|
|
||||||
|
open class FooBean(n: Int) {
|
||||||
|
constructor(barBean: BarBean): this(1)<caret>
|
||||||
|
}
|
||||||
|
|
||||||
|
open class BarBean
|
||||||
|
|
||||||
|
open class BazBean
|
||||||
Vendored
+12
@@ -0,0 +1,12 @@
|
|||||||
|
// ACTION_CLASS: org.jetbrains.kotlin.idea.spring.generate.GenerateKotlinSpringBeanDependencyAction$Constructor
|
||||||
|
// CONFIG_FILE: secondaryConstructorAddParam-config.xml
|
||||||
|
// CHOOSE_BEAN: bazBean
|
||||||
|
package a
|
||||||
|
|
||||||
|
open class FooBean(n: Int) {
|
||||||
|
constructor(barBean: BarBean, bazBean: BazBean): this(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
open class BarBean
|
||||||
|
|
||||||
|
open class BazBean
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
default-init-method="myDefaultInitMethod"
|
||||||
|
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||||
|
<bean id="fooBean" class="a.FooBean"/>
|
||||||
|
<bean id="barBean" class="a.BarBean"/>
|
||||||
|
</beans>
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
default-init-method="myDefaultInitMethod"
|
||||||
|
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||||
|
<bean id="fooBean" class="a.FooBean">
|
||||||
|
<property name="barBean" ref="barBean"/>
|
||||||
|
</bean>
|
||||||
|
<bean id="barBean" class="a.BarBean"/>
|
||||||
|
</beans>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// ACTION_CLASS: org.jetbrains.kotlin.idea.spring.generate.GenerateKotlinSpringBeanDependencyAction$Setter
|
||||||
|
// CONFIG_FILE: setter-config.xml
|
||||||
|
// CHOOSE_BEAN: barBean
|
||||||
|
package a
|
||||||
|
|
||||||
|
open class FooBean {<caret>
|
||||||
|
}
|
||||||
|
|
||||||
|
open class BarBean
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
// ACTION_CLASS: org.jetbrains.kotlin.idea.spring.generate.GenerateKotlinSpringBeanDependencyAction$Setter
|
||||||
|
// CONFIG_FILE: setter-config.xml
|
||||||
|
// CHOOSE_BEAN: barBean
|
||||||
|
package a
|
||||||
|
|
||||||
|
open class FooBean {
|
||||||
|
fun setBarBean(barBean: BarBean) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open class BarBean
|
||||||
+11
@@ -37,6 +37,14 @@ abstract class AbstractCodeInsightActionTest : KotlinLightCodeInsightFixtureTest
|
|||||||
return Class.forName(actionClassName).newInstance() as CodeInsightAction
|
return Class.forName(actionClassName).newInstance() as CodeInsightAction
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected open fun configureExtra(mainFilePath: String, mainFileText: String) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open fun checkExtra() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
protected open fun testAction(action: AnAction, forced: Boolean): Presentation {
|
protected open fun testAction(action: AnAction, forced: Boolean): Presentation {
|
||||||
val e = TestActionEvent(action)
|
val e = TestActionEvent(action)
|
||||||
action.beforeActionPerformedUpdate(e)
|
action.beforeActionPerformedUpdate(e)
|
||||||
@@ -65,6 +73,7 @@ abstract class AbstractCodeInsightActionTest : KotlinLightCodeInsightFixtureTest
|
|||||||
.forEach {
|
.forEach {
|
||||||
myFixture.configureByFile(File(rootDir, it).path.replace(File.separator, "/"))
|
myFixture.configureByFile(File(rootDir, it).path.replace(File.separator, "/"))
|
||||||
}
|
}
|
||||||
|
configureExtra(path, fileText)
|
||||||
myFixture.configureByFile(path)
|
myFixture.configureByFile(path)
|
||||||
|
|
||||||
val action = createAction(fileText)
|
val action = createAction(fileText)
|
||||||
@@ -83,6 +92,8 @@ abstract class AbstractCodeInsightActionTest : KotlinLightCodeInsightFixtureTest
|
|||||||
val afterFile = File("$path.after")
|
val afterFile = File("$path.after")
|
||||||
TestCase.assertTrue(afterFile.exists())
|
TestCase.assertTrue(afterFile.exists())
|
||||||
myFixture.checkResult(FileUtil.loadFile(afterFile, true))
|
myFixture.checkResult(FileUtil.loadFile(afterFile, true))
|
||||||
|
|
||||||
|
checkExtra()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (e: CommonRefactoringUtil.RefactoringErrorHintException) {
|
catch (e: CommonRefactoringUtil.RefactoringErrorHintException) {
|
||||||
|
|||||||
Reference in New Issue
Block a user