diff --git a/j2k/src/org/jetbrains/kotlin/j2k/Converter.kt b/j2k/src/org/jetbrains/kotlin/j2k/Converter.kt index 530cad6904d..a421c248719 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/Converter.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/Converter.kt @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.j2k import com.intellij.openapi.project.Project import com.intellij.psi.* import com.intellij.psi.CommonClassNames.* +import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.util.InheritanceUtil import com.intellij.psi.util.PsiMethodUtil import com.intellij.psi.util.PsiTreeUtil @@ -67,7 +68,7 @@ class Converter private constructor( companion object { fun create(elementToConvert: PsiElement, settings: ConverterSettings, services: JavaToKotlinConverterServices, - inConversionScope: (PsiElement) -> Boolean, usageProcessingsCollector: (UsageProcessing) -> Unit): Converter { + inConversionScope: (PsiElement) -> Boolean, usageProcessingsCollector: (UsageProcessing) -> Unit): Converter { return Converter(elementToConvert, settings, inConversionScope, services, CommonState(usageProcessingsCollector), PersonalState(null)) } @@ -141,7 +142,7 @@ class Converter private constructor( commonState.postUnfoldActions.forEach { it() } } - fun deferredElement(generator: (CodeConverter) -> TResult): DeferredElement { + fun deferredElement(generator: (CodeConverter) -> TResult): DeferredElement { val element = DeferredElement(generator, personalState) commonState.deferredElements.add(element) return element @@ -309,7 +310,7 @@ class Converter private constructor( val setMethod = propertyInfo.setMethod //TODO: annotations from getter/setter? - val annotations = field?.let { convertAnnotations(it) } ?: Annotations.Empty + val annotations = field?.let { convertAnnotations(it) + specialAnnotationPropertyCases(it) } ?: Annotations.Empty val modifiers = propertyInfo.modifiers @@ -424,6 +425,24 @@ class Converter private constructor( } } + + private fun specialAnnotationPropertyCases(field: PsiField): Annotations { + val javaSerializableInterface = JavaPsiFacade.getInstance(project).findClass(CommonClassNames.JAVA_IO_SERIALIZABLE, field.resolveScope) + val output = mutableListOf() + if (javaSerializableInterface != null && + field.name == "serialVersionUID" && + field.hasModifierProperty(PsiModifier.FINAL) && + field.hasModifierProperty(PsiModifier.STATIC) && + field.containingClass?.isInheritor(javaSerializableInterface, false) ?: false + ) { + output.add(Annotation(Identifier.withNoPrototype("JvmStatic"), + listOf(), + newLineAfter = false).assignNoPrototype()) + } + + return Annotations(output) + } + private fun combinedNullability(vararg psiElements: PsiElement?): Nullability { val values = psiElements.filterNotNull().map { when (it) { @@ -537,7 +556,7 @@ class Converter private constructor( if (settings.openByDefault) { val isEffectivelyFinal = method.hasModifierProperty(PsiModifier.FINAL) || - containingClass != null && (containingClass.hasModifierProperty(PsiModifier.FINAL) || containingClass.isEnum) + containingClass != null && (containingClass.hasModifierProperty(PsiModifier.FINAL) || containingClass.isEnum) if (!isEffectivelyFinal && !modifiers.contains(Modifier.ABSTRACT) && !modifiers.isPrivate) { modifiers = modifiers.with(Modifier.OPEN) } @@ -611,9 +630,9 @@ class Converter private constructor( if (!isInOpenClass) return false if (modifiers.contains(Modifier.OVERRIDE) || modifiers.contains(Modifier.ABSTRACT)) return false if (settings.openByDefault) { - return !method.hasModifierProperty(PsiModifier.FINAL) - && !method.hasModifierProperty(PsiModifier.PRIVATE) - && !method.hasModifierProperty(PsiModifier.STATIC) + return !method.hasModifierProperty(PsiModifier.FINAL) + && !method.hasModifierProperty(PsiModifier.PRIVATE) + && !method.hasModifierProperty(PsiModifier.STATIC) } else { return referenceSearcher.hasOverrides(method) @@ -657,8 +676,8 @@ class Converter private constructor( private fun constructNestedClassReferenceIdentifier(psiClass: PsiClass, context: PsiElement): Identifier? { val outerClass = psiClass.containingClass if (outerClass != null - && !PsiTreeUtil.isAncestor(outerClass, context, true) - && !psiClass.isImported(context.containingFile as PsiJavaFile)) { + && !PsiTreeUtil.isAncestor(outerClass, context, true) + && !psiClass.isImported(context.containingFile as PsiJavaFile)) { val qualifier = constructNestedClassReferenceIdentifier(outerClass, context)?.name ?: outerClass.name!! return Identifier.withNoPrototype(Identifier.toKotlin(qualifier) + "." + Identifier.toKotlin(psiClass.name!!)) } diff --git a/j2k/testData/fileOrElement/annotations/serialVersionUID.java b/j2k/testData/fileOrElement/annotations/serialVersionUID.java new file mode 100644 index 00000000000..52faca91cf6 --- /dev/null +++ b/j2k/testData/fileOrElement/annotations/serialVersionUID.java @@ -0,0 +1,12 @@ + +import java.io.Serializable; + +public class Bar implements Serializable { + private static final long serialVersionUID = 0; + int foobar = 0; +} + +public class Foo { + private static final long serialVersionUID = 0; + int foobar = 0; +} \ No newline at end of file diff --git a/j2k/testData/fileOrElement/annotations/serialVersionUID.kt b/j2k/testData/fileOrElement/annotations/serialVersionUID.kt new file mode 100644 index 00000000000..cbd6e126919 --- /dev/null +++ b/j2k/testData/fileOrElement/annotations/serialVersionUID.kt @@ -0,0 +1,17 @@ +import java.io.Serializable + +class Bar : Serializable { + internal var foobar = 0 + + companion object { + @JvmStatic private val serialVersionUID: Long = 0 + } +} + +class Foo { + internal var foobar = 0 + + companion object { + private val serialVersionUID: Long = 0 + } +} \ No newline at end of file diff --git a/j2k/testData/fileOrElement/issues/kt-837.kt b/j2k/testData/fileOrElement/issues/kt-837.kt index fbe328f0161..1ffd30794ea 100644 --- a/j2k/testData/fileOrElement/issues/kt-837.kt +++ b/j2k/testData/fileOrElement/issues/kt-837.kt @@ -11,6 +11,6 @@ class Language(protected var code: String) : Serializable { companion object { var ENGLISH = Language("en") var SWEDISH = Language("sv") - private val serialVersionUID = -2442762969929206780L + @JvmStatic private val serialVersionUID = -2442762969929206780L } } \ No newline at end of file diff --git a/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterForWebDemoTestGenerated.java b/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterForWebDemoTestGenerated.java index 8455f79749d..470f37734ac 100644 --- a/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterForWebDemoTestGenerated.java +++ b/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterForWebDemoTestGenerated.java @@ -120,6 +120,12 @@ public class JavaToKotlinConverterForWebDemoTestGenerated extends AbstractJavaTo String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/annotations/primaryConstructorAnnotation.java"); doTest(fileName); } + + @TestMetadata("serialVersionUID.java") + public void testSerialVersionUID() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/annotations/serialVersionUID.java"); + doTest(fileName); + } } @TestMetadata("j2k/testData/fileOrElement/anonymousBlock") diff --git a/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterSingleFileTestGenerated.java b/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterSingleFileTestGenerated.java index f150c2838b9..76ed24158c3 100644 --- a/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterSingleFileTestGenerated.java +++ b/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterSingleFileTestGenerated.java @@ -120,6 +120,12 @@ public class JavaToKotlinConverterSingleFileTestGenerated extends AbstractJavaTo String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/annotations/primaryConstructorAnnotation.java"); doTest(fileName); } + + @TestMetadata("serialVersionUID.java") + public void testSerialVersionUID() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/annotations/serialVersionUID.java"); + doTest(fileName); + } } @TestMetadata("j2k/testData/fileOrElement/anonymousBlock")