KT-38450 Add functional interface converter to the NJ2K
- Enable custom compiler options for `AbstractNewJavaToKotlinConverterSingleFileTest` - ^KT-38450 Fixed
This commit is contained in:
committed by
Roman Golyshev
parent
50fc9d3692
commit
4436142f00
+12
-2
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
|
|||||||
import org.jetbrains.kotlin.idea.references.mainReference
|
import org.jetbrains.kotlin.idea.references.mainReference
|
||||||
import org.jetbrains.kotlin.idea.references.readWriteAccess
|
import org.jetbrains.kotlin.idea.references.readWriteAccess
|
||||||
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
||||||
|
import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor
|
||||||
import org.jetbrains.kotlin.idea.util.CommentSaver
|
import org.jetbrains.kotlin.idea.util.CommentSaver
|
||||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||||
@@ -42,6 +43,7 @@ import org.jetbrains.kotlin.psi.*
|
|||||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
|
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperInterfaces
|
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperInterfaces
|
||||||
|
import org.jetbrains.kotlin.resolve.sam.getSingleAbstractMethodOrNull
|
||||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||||
import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
|
import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
@@ -383,15 +385,18 @@ private class ConvertGettersAndSettersToPropertyStatefulProcessing(
|
|||||||
val realProperty = group.firstIsInstanceOrNull<RealProperty>()
|
val realProperty = group.firstIsInstanceOrNull<RealProperty>()
|
||||||
val name = realGetter?.name ?: realSetter?.name!!
|
val name = realGetter?.name ?: realSetter?.name!!
|
||||||
|
|
||||||
val superDeclarationOwner = (realGetter?.function ?: realSetter?.function)
|
val functionDescriptor = (realGetter?.function ?: realSetter?.function)
|
||||||
?.resolveToDescriptorIfAny(resolutionFacade)
|
?.resolveToDescriptorIfAny(resolutionFacade)
|
||||||
|
|
||||||
|
if (functionDescriptor != null && isSamDescriptor(functionDescriptor)) return@mapNotNull null
|
||||||
|
|
||||||
|
val superDeclarationOwner = functionDescriptor
|
||||||
?.overriddenDescriptors
|
?.overriddenDescriptors
|
||||||
?.firstOrNull()
|
?.firstOrNull()
|
||||||
?.findPsi()
|
?.findPsi()
|
||||||
?.safeAs<KtDeclaration>()
|
?.safeAs<KtDeclaration>()
|
||||||
?.containingClassOrObject
|
?.containingClassOrObject
|
||||||
|
|
||||||
collectingState.propertyNameToSuperType[superDeclarationOwner to name]
|
|
||||||
val type = collectingState.propertyNameToSuperType[superDeclarationOwner to name]
|
val type = collectingState.propertyNameToSuperType[superDeclarationOwner to name]
|
||||||
?: calculatePropertyType(
|
?: calculatePropertyType(
|
||||||
realGetter?.function,
|
realGetter?.function,
|
||||||
@@ -408,6 +413,11 @@ private class ConvertGettersAndSettersToPropertyStatefulProcessing(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun KtClassOrObject.isSamDescriptor(functionDescriptor: FunctionDescriptor): Boolean {
|
||||||
|
val classDescriptor = descriptor as? ClassDescriptor ?: return false
|
||||||
|
return getSingleAbstractMethodOrNull(classDescriptor) == functionDescriptor
|
||||||
|
}
|
||||||
|
|
||||||
private fun List<PropertyData>.filterGettersAndSetters(
|
private fun List<PropertyData>.filterGettersAndSetters(
|
||||||
klass: KtClassOrObject,
|
klass: KtClassOrObject,
|
||||||
factory: KtPsiFactory
|
factory: KtPsiFactory
|
||||||
|
|||||||
@@ -78,6 +78,8 @@ object ConversionsRunner {
|
|||||||
LiteralConversion(context),
|
LiteralConversion(context),
|
||||||
StaticMemberAccessConversion(context),
|
StaticMemberAccessConversion(context),
|
||||||
RemoveRedundantQualifiersForCallsConversion(context),
|
RemoveRedundantQualifiersForCallsConversion(context),
|
||||||
|
FunctionalInterfacesConverter(context),
|
||||||
|
|
||||||
FilterImportsConversion(context),
|
FilterImportsConversion(context),
|
||||||
MoveInitBlocksToTheEndConversion(context),
|
MoveInitBlocksToTheEndConversion(context),
|
||||||
AddElementsInfoConversion(context)
|
AddElementsInfoConversion(context)
|
||||||
|
|||||||
@@ -18,7 +18,8 @@ data class NewJ2kConverterContext(
|
|||||||
val inConversionContext: (PsiElement) -> Boolean,
|
val inConversionContext: (PsiElement) -> Boolean,
|
||||||
val importStorage: JKImportStorage,
|
val importStorage: JKImportStorage,
|
||||||
val elementsInfoStorage: JKElementInfoStorage,
|
val elementsInfoStorage: JKElementInfoStorage,
|
||||||
val externalCodeProcessor: NewExternalCodeProcessing
|
val externalCodeProcessor: NewExternalCodeProcessing,
|
||||||
|
val functionalInterfaceConversionEnabled: Boolean
|
||||||
) : ConverterContext {
|
) : ConverterContext {
|
||||||
val project: Project
|
val project: Project
|
||||||
get() = converter.project
|
get() = converter.project
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import com.intellij.openapi.progress.ProgressManager
|
|||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.openapi.util.Computable
|
import com.intellij.openapi.util.Computable
|
||||||
import com.intellij.psi.*
|
import com.intellij.psi.*
|
||||||
|
import org.jetbrains.kotlin.config.LanguageFeature
|
||||||
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
|
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
|
||||||
import org.jetbrains.kotlin.idea.project.languageVersionSettings
|
import org.jetbrains.kotlin.idea.project.languageVersionSettings
|
||||||
import org.jetbrains.kotlin.j2k.*
|
import org.jetbrains.kotlin.j2k.*
|
||||||
@@ -161,7 +162,8 @@ class NewJavaToKotlinConverter(
|
|||||||
inConversionContext,
|
inConversionContext,
|
||||||
importStorage,
|
importStorage,
|
||||||
JKElementInfoStorage(),
|
JKElementInfoStorage(),
|
||||||
externalCodeProcessing
|
externalCodeProcessing,
|
||||||
|
languageVersion.supportsFeature(LanguageFeature.FunctionalInterfaceConversion)
|
||||||
)
|
)
|
||||||
ConversionsRunner.doApply(asts.withIndex().mapNotNull { (i, ast) ->
|
ConversionsRunner.doApply(asts.withIndex().mapNotNull { (i, ast) ->
|
||||||
processor.updateState(i, 1, phaseDescription)
|
processor.updateState(i, 1, phaseDescription)
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.nj2k.conversions
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext
|
||||||
|
import org.jetbrains.kotlin.nj2k.annotationByFqName
|
||||||
|
import org.jetbrains.kotlin.nj2k.tree.*
|
||||||
|
|
||||||
|
private const val FUNCTIONAL_INTERFACE = "java.lang.FunctionalInterface"
|
||||||
|
|
||||||
|
internal class FunctionalInterfacesConverter(context: NewJ2kConverterContext) : RecursiveApplicableConversionBase(context) {
|
||||||
|
override fun applyToElement(element: JKTreeElement): JKTreeElement {
|
||||||
|
if (!context.functionalInterfaceConversionEnabled) return recurse(element)
|
||||||
|
if (element !is JKClass) return recurse(element)
|
||||||
|
if (element.classKind != JKClass.ClassKind.INTERFACE) return recurse(element)
|
||||||
|
if (element.inheritance.extends.isNotEmpty()) return recurse(element)
|
||||||
|
|
||||||
|
val functionalInterfaceMarker = element.annotationList.annotationByFqName(FUNCTIONAL_INTERFACE) ?: return recurse(element)
|
||||||
|
|
||||||
|
val samMethod = element.classBody.declarations.filterIsInstance<JKMethod>().singleOrNull { it.block is JKBodyStub }
|
||||||
|
if (samMethod == null || samMethod.typeParameterList.typeParameters.isNotEmpty()) return recurse(element)
|
||||||
|
|
||||||
|
element.otherModifierElements += JKOtherModifierElement(OtherModifier.FUN)
|
||||||
|
element.annotationList.annotations -= functionalInterfaceMarker
|
||||||
|
|
||||||
|
return recurse(element)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -34,6 +34,7 @@ enum class OtherModifier(override val text: String) : Modifier {
|
|||||||
SUSPEND("suspend"),
|
SUSPEND("suspend"),
|
||||||
TAILREC("tailrec"),
|
TAILREC("tailrec"),
|
||||||
VARARG("vararg"),
|
VARARG("vararg"),
|
||||||
|
FUN("fun"),
|
||||||
|
|
||||||
NATIVE("native"),
|
NATIVE("native"),
|
||||||
STATIC("static"),
|
STATIC("static"),
|
||||||
@@ -136,8 +137,8 @@ val JKModifierElement.modifier: Modifier
|
|||||||
|
|
||||||
inline fun JKModifiersListOwner.forEachModifier(action: (JKModifierElement) -> Unit) {
|
inline fun JKModifiersListOwner.forEachModifier(action: (JKModifierElement) -> Unit) {
|
||||||
safeAs<JKVisibilityOwner>()?.visibilityElement?.let(action)
|
safeAs<JKVisibilityOwner>()?.visibilityElement?.let(action)
|
||||||
safeAs<JKOtherModifiersOwner>()?.otherModifierElements?.forEach(action)
|
|
||||||
safeAs<JKModalityOwner>()?.modalityElement?.let(action)
|
safeAs<JKModalityOwner>()?.modalityElement?.let(action)
|
||||||
|
safeAs<JKOtherModifiersOwner>()?.otherModifierElements?.forEach(action)
|
||||||
safeAs<JKMutabilityOwner>()?.mutabilityElement?.let(action)
|
safeAs<JKMutabilityOwner>()?.mutabilityElement?.let(action)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
// RUNTIME_WITH_FULL_JDK
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface MyRunnable {
|
||||||
|
int getResult();
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
// RUNTIME_WITH_FULL_JDK
|
||||||
|
fun interface MyRunnable {
|
||||||
|
fun getResult(): Int
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// RUNTIME_WITH_FULL_JDK
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface MyRunnable {
|
||||||
|
int getResult();
|
||||||
|
|
||||||
|
default int getDoubleResult() {
|
||||||
|
return getResult() * 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
// RUNTIME_WITH_FULL_JDK
|
||||||
|
fun interface MyRunnable {
|
||||||
|
fun getResult(): Int
|
||||||
|
val doubleResult: Int
|
||||||
|
get() = getResult() * 2
|
||||||
|
}
|
||||||
Vendored
+5
@@ -0,0 +1,5 @@
|
|||||||
|
// RUNTIME_WITH_FULL_JDK
|
||||||
|
|
||||||
|
public interface MyRunnable {
|
||||||
|
int getResult();
|
||||||
|
}
|
||||||
+4
@@ -0,0 +1,4 @@
|
|||||||
|
// RUNTIME_WITH_FULL_JDK
|
||||||
|
interface MyRunnable {
|
||||||
|
val result: Int
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
// RUNTIME_WITH_FULL_JDK
|
||||||
|
|
||||||
|
// we intentionally do not convert interface to Kotlin fun interface
|
||||||
|
// if it inherits from some other interface, because it is hard to deal
|
||||||
|
// with default methods which were already converted to properties
|
||||||
|
// (and in kotlin fun interface cannot have abstract property)
|
||||||
|
|
||||||
|
public interface MyRunnableBase {
|
||||||
|
default int getValue() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface MyRunnable extends MyRunnableBase {
|
||||||
|
@Override
|
||||||
|
int getValue();
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
// RUNTIME_WITH_FULL_JDK
|
||||||
|
// we intentionally do not convert interface to Kotlin fun interface
|
||||||
|
// if it inherits from some other interface, because it is hard to deal
|
||||||
|
// with default methods which were already converted to properties
|
||||||
|
// (and in kotlin fun interface cannot have abstract property)
|
||||||
|
interface MyRunnableBase {
|
||||||
|
val value: Int
|
||||||
|
get() = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
interface MyRunnable : MyRunnableBase {
|
||||||
|
abstract override val value: Int
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
// RUNTIME_WITH_FULL_JDK
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface MyRunnable {
|
||||||
|
void run();
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
// RUNTIME_WITH_FULL_JDK
|
||||||
|
fun interface MyRunnable {
|
||||||
|
fun run()
|
||||||
|
}
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
public interface MyRunnable {
|
||||||
|
void run();
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
interface MyRunnable {
|
||||||
|
fun run()
|
||||||
|
}
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
// RUNTIME_WITH_FULL_JDK
|
||||||
|
// COMPILER_ARGUMENTS: -XXLanguage:-FunctionalInterfaceConversion
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface MyRunnable {
|
||||||
|
void run();
|
||||||
|
}
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
// RUNTIME_WITH_FULL_JDK
|
||||||
|
// COMPILER_ARGUMENTS: -XXLanguage:-FunctionalInterfaceConversion
|
||||||
|
@FunctionalInterface
|
||||||
|
interface MyRunnable {
|
||||||
|
fun run()
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
// RUNTIME_WITH_FULL_JDK
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface MyRunnable {
|
||||||
|
<T> void process(T t);
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
// RUNTIME_WITH_FULL_JDK
|
||||||
|
@FunctionalInterface
|
||||||
|
interface MyRunnable {
|
||||||
|
fun <T> process(t: T)
|
||||||
|
}
|
||||||
+12
-8
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.nj2k
|
|||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.psi.codeStyle.JavaCodeStyleSettings
|
import com.intellij.psi.codeStyle.JavaCodeStyleSettings
|
||||||
import org.jetbrains.kotlin.idea.j2k.IdeaJavaToKotlinServices
|
import org.jetbrains.kotlin.idea.j2k.IdeaJavaToKotlinServices
|
||||||
|
import org.jetbrains.kotlin.idea.test.withCustomCompilerOptions
|
||||||
import org.jetbrains.kotlin.j2k.AbstractJavaToKotlinConverterSingleFileTest
|
import org.jetbrains.kotlin.j2k.AbstractJavaToKotlinConverterSingleFileTest
|
||||||
import org.jetbrains.kotlin.j2k.ConverterSettings
|
import org.jetbrains.kotlin.j2k.ConverterSettings
|
||||||
import org.jetbrains.kotlin.nj2k.postProcessing.NewJ2kPostProcessor
|
import org.jetbrains.kotlin.nj2k.postProcessing.NewJ2kPostProcessor
|
||||||
@@ -16,15 +17,18 @@ import java.io.File
|
|||||||
|
|
||||||
abstract class AbstractNewJavaToKotlinConverterSingleFileTest : AbstractJavaToKotlinConverterSingleFileTest() {
|
abstract class AbstractNewJavaToKotlinConverterSingleFileTest : AbstractJavaToKotlinConverterSingleFileTest() {
|
||||||
override fun doTest(javaPath: String) {
|
override fun doTest(javaPath: String) {
|
||||||
val directory = File(javaPath).parentFile
|
val javaFile = File(javaPath)
|
||||||
val expectedFileName = "${File(javaPath).nameWithoutExtension}.external"
|
withCustomCompilerOptions(javaFile.readText(), project, module) {
|
||||||
val expectedFiles = directory.listFiles { _, name ->
|
val directory = javaFile.parentFile
|
||||||
name == "$expectedFileName.kt" || name == "$expectedFileName.java"
|
val expectedFileName = "${javaFile.nameWithoutExtension}.external"
|
||||||
}!!.filterNotNull()
|
val expectedFiles = directory.listFiles { _, name ->
|
||||||
for (expectedFile in expectedFiles) {
|
name == "$expectedFileName.kt" || name == "$expectedFileName.java"
|
||||||
addFile(expectedFile, dirName = null)
|
}!!.filterNotNull()
|
||||||
|
for (expectedFile in expectedFiles) {
|
||||||
|
addFile(expectedFile, dirName = null)
|
||||||
|
}
|
||||||
|
super.doTest(javaPath)
|
||||||
}
|
}
|
||||||
super.doTest(javaPath)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun compareResults(expectedFile: File, actual: String) {
|
override fun compareResults(expectedFile: File, actual: String) {
|
||||||
|
|||||||
+53
@@ -2583,6 +2583,59 @@ public class NewJavaToKotlinConverterSingleFileTestGenerated extends AbstractNew
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("nj2k/testData/newJ2k/functionalInterfaces")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class FunctionalInterfaces extends AbstractNewJavaToKotlinConverterSingleFileTest {
|
||||||
|
private void runTest(String testDataFilePath) throws Exception {
|
||||||
|
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("AbstractGetter1.java")
|
||||||
|
public void testAbstractGetter1() throws Exception {
|
||||||
|
runTest("nj2k/testData/newJ2k/functionalInterfaces/AbstractGetter1.java");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("AbstractGetter2.java")
|
||||||
|
public void testAbstractGetter2() throws Exception {
|
||||||
|
runTest("nj2k/testData/newJ2k/functionalInterfaces/AbstractGetter2.java");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("AbstractGetterNoFunctionalInterfaceAnnotation.java")
|
||||||
|
public void testAbstractGetterNoFunctionalInterfaceAnnotation() throws Exception {
|
||||||
|
runTest("nj2k/testData/newJ2k/functionalInterfaces/AbstractGetterNoFunctionalInterfaceAnnotation.java");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAllFilesPresentInFunctionalInterfaces() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("nj2k/testData/newJ2k/functionalInterfaces"), Pattern.compile("^([^\\.]+)\\.java$"), null, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("InterfacesHierarchy.java")
|
||||||
|
public void testInterfacesHierarchy() throws Exception {
|
||||||
|
runTest("nj2k/testData/newJ2k/functionalInterfaces/InterfacesHierarchy.java");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("MyRunnable.java")
|
||||||
|
public void testMyRunnable() throws Exception {
|
||||||
|
runTest("nj2k/testData/newJ2k/functionalInterfaces/MyRunnable.java");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("NoFunctionalInterfaceAnnotation.java")
|
||||||
|
public void testNoFunctionalInterfaceAnnotation() throws Exception {
|
||||||
|
runTest("nj2k/testData/newJ2k/functionalInterfaces/NoFunctionalInterfaceAnnotation.java");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("NoFunctionalInterfaceConversionEnabled.java")
|
||||||
|
public void testNoFunctionalInterfaceConversionEnabled() throws Exception {
|
||||||
|
runTest("nj2k/testData/newJ2k/functionalInterfaces/NoFunctionalInterfaceConversionEnabled.java");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("SamMethodWithGenerics.java")
|
||||||
|
public void testSamMethodWithGenerics() throws Exception {
|
||||||
|
runTest("nj2k/testData/newJ2k/functionalInterfaces/SamMethodWithGenerics.java");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("nj2k/testData/newJ2k/identifier")
|
@TestMetadata("nj2k/testData/newJ2k/identifier")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
Reference in New Issue
Block a user