diff --git a/java/java-impl/resources/META-INF/JavaPlugin.xml b/java/java-impl/resources/META-INF/JavaPlugin.xml
index 6e96860c16a8..81912631cacf 100644
--- a/java/java-impl/resources/META-INF/JavaPlugin.xml
+++ b/java/java-impl/resources/META-INF/JavaPlugin.xml
@@ -1497,6 +1497,7 @@
+
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/JavaGenerateConstructorCompletionCommand.kt b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/JavaGenerateConstructorCompletionCommand.kt
new file mode 100644
index 000000000000..85ea2af76513
--- /dev/null
+++ b/java/java-impl/src/com/intellij/codeInsight/completion/commands/impl/JavaGenerateConstructorCompletionCommand.kt
@@ -0,0 +1,126 @@
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.codeInsight.completion.commands.impl
+
+import com.intellij.codeInsight.CodeInsightBundle
+import com.intellij.codeInsight.completion.command.CommandCompletionProviderContext
+import com.intellij.codeInsight.completion.command.CommandProvider
+import com.intellij.codeInsight.completion.command.CompletionCommand
+import com.intellij.codeInsight.completion.command.getCommandContext
+import com.intellij.codeInsight.daemon.impl.quickfix.AddDefaultConstructorFix
+import com.intellij.codeInsight.daemon.impl.quickfix.AddMethodFix
+import com.intellij.codeInsight.generation.ClassMember
+import com.intellij.codeInsight.generation.GenerateConstructorHandler
+import com.intellij.codeInsight.generation.GenerationInfo
+import com.intellij.codeInsight.generation.PsiMethodMember
+import com.intellij.codeInsight.intention.preview.IntentionPreviewInfo
+import com.intellij.java.JavaBundle
+import com.intellij.modcommand.ActionContext
+import com.intellij.modcommand.ModCommandExecutor
+import com.intellij.openapi.editor.Editor
+import com.intellij.psi.*
+import com.intellij.psi.util.TypeConversionUtil
+import com.intellij.psi.util.parentOfType
+import org.jetbrains.annotations.Nls
+
+public class JavaGenerateConstructorCompletionCommandProvider : CommandProvider {
+ private fun findContext(context: CommandCompletionProviderContext): PsiClass? {
+ val element = getCommandContext(context.offset, context.psiFile) ?: return null
+ val containingClass = element.parentOfType() ?: return null
+ if (containingClass.isInterface || containingClass.isRecord || containingClass is PsiImplicitClass) return null
+ if (element is PsiIdentifier && element.parent is PsiClass) return element.parent as PsiClass
+ if (!(element is PsiWhiteSpace && element.text.contains("\n"))) return null
+ return element.parentOfType()
+ }
+
+ override fun getCommands(context: CommandCompletionProviderContext): List {
+ val clazz = findContext(context) ?: return emptyList()
+ val result = mutableListOf()
+ if (clazz.constructors.none { it.parameters.isEmpty() }) {
+ result.add(object : CompletionCommand() {
+ private val fix = AddDefaultConstructorFix(clazz, PsiModifier.PUBLIC)
+
+ override val presentableName: @Nls String
+ get() = CodeInsightBundle.message("command.completion.generate.text", JavaBundle.message("command.completion.generate.no.args.constructor.text"))
+
+ override fun execute(offset: Int, psiFile: PsiFile, editor: Editor?) {
+ val actionContext = ActionContext.from(editor, psiFile)
+ ModCommandExecutor.executeInteractively(actionContext, presentableName, editor) {
+ fix.perform(actionContext)
+ }
+ }
+
+ override fun getPreview(): IntentionPreviewInfo {
+ val actionContext = ActionContext.from(context.editor, context.psiFile)
+ return fix.generatePreview(actionContext)
+ }
+ })
+ }
+
+ val handler = object : GenerateConstructorHandler() {
+ public override fun getAllOriginalMembers(aClass: PsiClass?): Array? {
+ return super.getAllOriginalMembers(aClass)
+ }
+
+ public override fun generateMemberPrototypes(aClass: PsiClass?, members: Array?): List {
+ return super.generateMemberPrototypes(aClass, members)
+ }
+ }
+ var members = handler.getAllOriginalMembers(clazz) ?: return result
+ if (members.isEmpty()) return result
+
+ //let's simplify condition, because it can be quite tricky to find out whether there is a constructor with the same arguments or
+ //which super constructor should be called
+ val superClass = clazz.superClass
+ if ((clazz.constructors.none { it.parameters.size == members.size } &&
+ (superClass == null ||
+ superClass.constructors.isEmpty() ||
+ superClass.constructors.any { it.parameters.isEmpty() })) ||
+ canUseSuperConstructor(superClass, clazz, members)) {
+ val superConstructors = superClass?.constructors
+ if (superConstructors?.size == 1) {
+ val substitutor = TypeConversionUtil.getSuperClassSubstitutor(superClass, clazz, PsiSubstitutor.EMPTY)
+ val superConstructor = PsiMethodMember(superConstructors[0], substitutor)
+ members = arrayOf(superConstructor, *members)
+ }
+ val prototypes = handler.generateMemberPrototypes(clazz, members)
+ if (prototypes.size == 1) {
+ val generationInfo = prototypes[0]
+ val text = (generationInfo?.psiMember as? PsiMethod)?.text ?: return result
+ result.add(object : CompletionCommand() {
+ private val fix = AddMethodFix(text, clazz)
+
+ override val presentableName: @Nls String
+ get() = CodeInsightBundle.message("command.completion.generate.text", JavaBundle.message("command.completion.generate.all.args.constructor.text"))
+
+ override fun execute(offset: Int, psiFile: PsiFile, editor: Editor?) {
+ val actionContext = ActionContext.from(editor, psiFile)
+ ModCommandExecutor.executeInteractively(actionContext, presentableName, editor) {
+ fix.perform(actionContext)
+ }
+ }
+
+ override fun getPreview(): IntentionPreviewInfo {
+ val actionContext = ActionContext.from(context.editor, context.psiFile)
+ return fix.generatePreview(actionContext)
+ }
+ })
+ }
+ }
+
+ return result
+ }
+
+ private fun canUseSuperConstructor(
+ superClass: PsiClass?,
+ clazz: PsiClass,
+ members: Array,
+ ): Boolean {
+ if (superClass == null) return false
+ if (superClass.constructors.size != 1) return false
+ val method = superClass.constructors[0]
+ val targetSize = members.size + method.parameters.size
+ return clazz.constructors.none {
+ it.parameters.size == targetSize
+ }
+ }
+}
\ No newline at end of file
diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/commands/JavaCommandsCompletionGenerateConstructorsTest.kt b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/commands/JavaCommandsCompletionGenerateConstructorsTest.kt
new file mode 100644
index 000000000000..b6a4621aac03
--- /dev/null
+++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/commands/JavaCommandsCompletionGenerateConstructorsTest.kt
@@ -0,0 +1,114 @@
+// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.java.codeInsight.completion.commands
+
+import com.intellij.codeInsight.completion.LightFixtureCompletionTestCase
+import com.intellij.ide.highlighter.JavaFileType
+import com.intellij.openapi.application.impl.NonBlockingReadActionImpl
+import com.intellij.openapi.util.registry.Registry
+import com.intellij.testFramework.NeedsIndex
+
+@NeedsIndex.SmartMode(reason = "it requires highlighting")
+class JavaCommandsCompletionGenerateConstructorsTest : LightFixtureCompletionTestCase() {
+
+ override fun setUp() {
+ super.setUp()
+ Registry.get("ide.completion.command.enabled").setValue(false, getTestRootDisposable())
+ Registry.get("ide.completion.command.force.enabled").setValue(true, getTestRootDisposable())
+ }
+
+ fun testGenerateNoArgsConstructor() {
+ myFixture.configureByText(JavaFileType.INSTANCE, """
+ class A {
+ int a;
+ g
+ }
+ """.trimIndent())
+ val elements = myFixture.completeBasic()
+ selectItem(elements.first { element -> element.lookupString.contains("Generate 'No-Args Constructor'", ignoreCase = true) })
+ NonBlockingReadActionImpl.waitForAsyncTaskCompletion()
+ myFixture.checkResult("""
+ class A {
+ int a;
+
+ public A() {
+ }
+ }""".trimIndent())
+ }
+
+ fun testGenerateAllArgsConstructor() {
+ myFixture.configureByText(JavaFileType.INSTANCE, """
+ class A {
+ int a;
+ g
+ }
+ """.trimIndent())
+ val elements = myFixture.completeBasic()
+ selectItem(elements.first { element -> element.lookupString.contains("Generate 'All-Args Constructor'", ignoreCase = true) })
+ NonBlockingReadActionImpl.waitForAsyncTaskCompletion()
+ myFixture.checkResult("""
+ class A {
+ int a;
+
+ public A(int a) {
+ this.a = a;
+ }
+ }""".trimIndent())
+ }
+
+ fun testGenerateAllArgsConstructorWithSuper() {
+ myFixture.configureByText(JavaFileType.INSTANCE, """
+ class A extends B{
+ int a;
+ g
+ }
+
+ class B {
+ public B(T a){}
+ }
+ """.trimIndent())
+ val elements = myFixture.completeBasic()
+ selectItem(elements.first { element -> element.lookupString.contains("Generate 'All-Args Constructor'", ignoreCase = true) })
+ NonBlockingReadActionImpl.waitForAsyncTaskCompletion()
+ myFixture.checkResult("""
+ class A extends B{
+ int a;
+
+ public A(String a, int a1) {
+ super(a);
+ this.a = a1;
+ }
+ }
+
+ class B {
+ public B(T a){}
+ }""".trimIndent())
+ }
+
+ fun testNoGenerateNoArgsConstructor() {
+ myFixture.configureByText(JavaFileType.INSTANCE, """
+ class A {
+ public A(){}
+ int a;
+ g
+ }
+ """.trimIndent())
+ val elements = myFixture.completeBasic()
+ assertNull(elements.firstOrNull { element -> element.lookupString.contains("Generate 'No-Args Constructor'", ignoreCase = true) })
+ }
+
+ fun testNoGenerateAllArgsConstructor() {
+ myFixture.configureByText(JavaFileType.INSTANCE, """
+ class A extends B{
+ int a;
+ g
+ }
+
+ class B {
+ public B(int a){}
+ public B(String a){}
+ }
+ """.trimIndent())
+ val elements = myFixture.completeBasic()
+ assertNull(elements.firstOrNull { element -> element.lookupString.contains("Generate 'All-Args Constructor'", ignoreCase = true) })
+ }
+}
\ No newline at end of file
diff --git a/java/openapi/resources/messages/JavaBundle.properties b/java/openapi/resources/messages/JavaBundle.properties
index 849e5d4875b6..5345c8b46301 100644
--- a/java/openapi/resources/messages/JavaBundle.properties
+++ b/java/openapi/resources/messages/JavaBundle.properties
@@ -1954,6 +1954,8 @@ command.completion.getters.and.setters.text=Getters and Setters
command.completion.generate.getter.setter=Generate 'Getter' and 'Setter'
command.completion.generate.getter=Generate 'Getter'
command.completion.generate.setter=Generate 'Setter'
+command.completion.generate.no.args.constructor.text=No-Args Constructor
+command.completion.generate.all.args.constructor.text=All-Args Constructor
advanced.setting.java.show.irrelevant.templates.in.source.roots=Show irrelevant New File templates in Java source roots
java.test.use.wall.time=Use Wall Time