I’m trying to restore the project Scala IDE to make it work on a more recent technical environment, i.e. Eclipse 2024-03, JDK17, and Scala 2.12.19.
I’m launching the test suite of this eclipse plugin project with org.eclipse.tycho:tycho-surefire-plugin:4.0.7:test
.
The configuration of the tycho-surefire-plugin
is :
<pluginManagement>
<plugins>
<plugin>
<groupId>org.eclipse.tycho</groupId>
<artifactId>tycho-surefire-plugin</artifactId>
<configuration>
<useUIHarness>false</useUIHarness>
<useUIThread>false</useUIThread>
<systemProperties combine.children="append">
<aj.weaving.verbose>true</aj.weaving.verbose>
<org.aspectj.weaver.showWeaveInfo>true</org.aspectj.weaver.showWeaveInfo>
<org.aspectj.osgi.verbose>true</org.aspectj.osgi.verbose>
</systemProperties>
<frameworkExtensions>
<frameworkExtension>
<groupId>p2.osgi.bundle</groupId>
<artifactId>org.eclipse.equinox.weaving.hook</artifactId>
<version>${weaving.hook.plugin.version}</version>
</frameworkExtension>
</frameworkExtensions>
<bundleStartLevel>
<bundle>
<id>org.eclipse.equinox.weaving.aspectj</id>
<level>2</level>
<autoStart>true</autoStart>
</bundle>
</bundleStartLevel>
<argLine>${tycho.test.jvmArgs}</argLine>
</configuration>
</plugin>
</plugins>
</pluginManagement>
The root project defines properties :
<weaving.hook.plugin.version>1.4.0.v20240213-1357</weaving.hook.plugin.version>
<tycho.test.weaving>-XX:+UnlockDiagnosticVMOptions -Dosgi.classloader.lock=classname</tycho.test.weaving>
<tycho.test.addOpens>--add-opens java.base/java.lang=ALL-UNNAMED</tycho.test.addOpens>
<tycho.test.jvmArgs>${tycho.test.addOpens} -Xmx2048m -Dsdtcore.headless -Dsdtcore.notimeouts -DretryFlakyTests=true ${tycho.test.weaving}</tycho.test.jvmArgs>
The tycho-surefire-plugin
launched the following java command:
C:UsersnicolDownloadsjdk-17.0.4_windows-x64_binjdk-17.0.4binjava.exe -Dosgi.noShutdown=false -Dosgi.os=win32 -Dosgi.ws=win32 -Dosgi.arch=x86_64 --add-opens java.base/java.lang=ALL-UNNAMED -Xmx2048m -Dsdtcore.headless -Dsdtcore.notimeouts -DretryFlakyTests=true -XX:+UnlockDiagnosticVMOptions -Dosgi.classloader.lock=classname -Dosgi.clean=true -Daj.weaving.verbose=true -Dorg.aspectj.osgi.verbose=true -Dorg.aspectj.weaver.showWeaveInfo=true -jar C:Usersnicol.m2repositoryp2osgibundleorg.eclipse.equinox.launcher1.6.700.v20240213-1244org.eclipse.equinox.launcher-1.6.700.v20240213-1244.jar -data C:Usersnicolgitscala-ideorg.scala-ide.sdt.core.teststargetworkdata -install C:Usersnicolgitscala-ideorg.scala-ide.sdt.core.teststargetwork -configuration C:Usersnicolgitscala-ideorg.scala-ide.sdt.core.teststargetworkconfiguration -application org.eclipse.tycho.surefire.osgibooter.headlesstest -testproperties C:Usersnicolgitscala-ideorg.scala-ide.sdt.core.teststargetsurefire.properties
One of the test classes is :
package org.scalaide.core.testsetup
import org.eclipse.core.resources.IFile
import org.eclipse.core.resources.IncrementalProjectBuilder
import org.eclipse.core.runtime.NullProgressMonitor
import org.eclipse.core.runtime.Path
import org.eclipse.jdt.core.ICompilationUnit
import org.eclipse.jdt.core.IPackageFragmentRoot
import org.eclipse.jdt.core.IProblemRequestor
import org.eclipse.jdt.core.JavaCore
import org.eclipse.jdt.core.WorkingCopyOwner
import org.eclipse.text.edits.ReplaceEdit
import org.junit.Assert.assertNotNull
import org.mockito.Mockito.mock
import org.mockito.Mockito.when
import org.scalaide.core.compiler.InteractiveCompilationUnit
import org.scalaide.core.internal.jdt.model.ScalaCompilationUnit
import org.scalaide.core.internal.jdt.model.ScalaSourceFile
import org.scalaide.core.IScalaProject
import org.scalaide.core.internal.project.ScalaProject
/** Base class for setting up tests that depend on a project found in the test-workspace.
*
* Subclass this class with an `object'. The initialization will copy the given project
* from test-workspace to the target workspace, and retrieve the 'src/' package root in
* `srcPackageRoot'.
*
* Reference the object form your test, so that the constructor is called and the project
* setup.
*
* Example: `object HyperlinkDetectorTests extends TestProjectSetup("hyperlinks")'
*
*/
class TestProjectSetup(projectName: String, srcRoot: String = "/%s/src/", val bundleName: String = "org.scala-ide.sdt.core.tests") extends ProjectBuilder {
private[core] lazy val internalProject: ScalaProject = BlockingProgressMonitor.waitUntilDone {
SDTTestUtils.internalSetupProject(projectName, bundleName)(_)
}
/** The ScalaProject corresponding to projectName, after copying to the test workspace. */
override lazy val project: IScalaProject = internalProject
/** The package root corresponding to /src inside the project. */
lazy val srcPackageRoot: IPackageFragmentRoot = {
val javaProject = JavaCore.create(project.underlying)
javaProject.open(null)
javaProject.findPackageFragmentRoot(new Path(srcRoot.format(projectName)))
}
assertNotNull(srcPackageRoot)
srcPackageRoot.open(null)
def file(path: String): IFile = {
project.underlying.getFile(path)
}
/** Return the compilation unit corresponding to the given path, relative to the src folder.
* for example: "scala/collection/Map.scala"
*/
def compilationUnit(path: String): ICompilationUnit = {
val segments = path.split("/")
srcPackageRoot.getPackageFragment(segments.init.mkString(".")).getCompilationUnit(segments.last)
}
/** Return a sequence of compilation units corresponding to the given paths. */
def compilationUnits(paths: String*): Seq[ICompilationUnit] =
paths.map(compilationUnit)
/** Return a sequence of Scala compilation units corresponding to the given paths. */
def scalaCompilationUnits(paths: String*): Seq[ScalaSourceFile] =
paths.map(scalaCompilationUnit)
/** Return the Scala compilation unit corresponding to the given path, relative to the src folder.
* for example: "scala/collection/Map.scala".
*/
def scalaCompilationUnit(path: String): ScalaSourceFile =
compilationUnit(path).asInstanceOf[ScalaSourceFile]
def createSourceFile(packageName: String, unitName: String)(contents: String): ScalaSourceFile = {
val pack = SDTTestUtils.createSourcePackage(packageName)(project)
SDTTestUtils.createCompilationUnit(pack, unitName, contents).asInstanceOf[ScalaSourceFile]
}
def reload(unit: InteractiveCompilationUnit): Unit = {
// first, 'open' the file by telling the compiler to load it
unit.withSourceFile { (src, compiler) =>
compiler.askReload(List(unit)).get
}
}
def parseAndEnter(unit: InteractiveCompilationUnit): Unit = {
unit.withSourceFile { (src, compiler) =>
val dummy = new compiler.Response[compiler.Tree]
compiler.askParsedEntered(src, false, dummy)
dummy.get
}
}
def findMarker(marker: String) = SDTTestUtils.findMarker(marker)
/** Emulate the opening of a scala source file (i.e., it tries to
* reproduce the steps performed by JDT when opening a file in an editor).
*
* @param srcPath the path to the scala source file
* */
def open(srcPath: String): ScalaSourceFile = {
val unit = scalaCompilationUnit(srcPath)
openWorkingCopyFor(unit)
reload(unit)
unit
}
/** Open a working copy of the passed `unit` */
private def openWorkingCopyFor(unit: ScalaSourceFile): Unit = {
val requestor = mock(classOf[IProblemRequestor])
// the requestor must be active, or unit.getWorkingCopy won't trigger the Scala
// structure builder
when(requestor.isActive()).thenReturn(true)
val owner = new WorkingCopyOwner() {
override def getProblemRequestor(unit: org.eclipse.jdt.core.ICompilationUnit): IProblemRequestor = requestor
}
// this will trigger the Scala structure builder
unit.getWorkingCopy(owner, new NullProgressMonitor)
}
/** Wait until the passed `unit` is entirely typechecked. */
def waitUntilTypechecked(unit: ScalaCompilationUnit): Unit = {
// give a chance to the background compiler to report the error
unit.withSourceFile { (source, compiler) =>
compiler.askLoadedTyped(source, true).get // wait until unit is typechecked
}
}
/** Open the passed `source` and wait until it has been fully typechecked.*/
def openAndWaitUntilTypechecked(source: ScalaSourceFile): Unit = {
val sourcePath = source.getPath()
val projectSrcPath = project.underlying.getFullPath() append "src"
val path = sourcePath.makeRelativeTo(projectSrcPath)
open(path.toOSString())
waitUntilTypechecked(source)
}
/**
* Allows to modify sources in test workspace.
*
* @param compilationUnitPath path to file which we'll change
* @param lineNumber line which will be removed (line numbers start from 1)
* @param newLine code inserted in place of line with lineNumber
*/
def modifyLine(compilationUnitPath: String, lineNumber: Int, newLine: String): Unit = {
val lineIndex = lineNumber - 1
val cu = compilationUnit(compilationUnitPath)
val code = cu.getSource
val lines = code.split('n').toList
val newLines = lines.updated(lineIndex, newLine)
val newCode = newLines.mkString("n")
val textEdit = new ReplaceEdit(0, code.length(), newCode)
cu.applyTextEdit(textEdit, new NullProgressMonitor)
cu.save(new NullProgressMonitor, true)
}
/**
* Be aware that it can be heavy. Moreover, it's needed to ensure that
* events are already properly propagated after the build.
*/
def buildIncrementally(): Unit =
project.underlying.build(IncrementalProjectBuilder.INCREMENTAL_BUILD, new NullProgressMonitor)
}
The stacktrace corresponding to that test is :
scala.reflect.internal.MissingRequirementError: object java.lang.Object in compiler mirror not found.
at scala.reflect.internal.MissingRequirementError$.signal(MissingRequirementError.scala:24)
at scala.reflect.internal.MissingRequirementError$.notFound(MissingRequirementError.scala:25)
at scala.reflect.internal.Mirrors$RootsBase.$anonfun$getModuleOrClass$5(Mirrors.scala:61)
at scala.reflect.internal.Mirrors$RootsBase.getModuleOrClass(Mirrors.scala:61)
at scala.reflect.internal.Mirrors$RootsBase.getModuleOrClass(Mirrors.scala:51)
at scala.reflect.internal.Mirrors$RootsBase.getRequiredClass(Mirrors.scala:51)
at scala.reflect.internal.Definitions$DefinitionsClass.ObjectClass$lzycompute(Definitions.scala:301)
at scala.reflect.internal.Definitions$DefinitionsClass.ObjectClass(Definitions.scala:301)
at scala.reflect.internal.Definitions$DefinitionsClass.init(Definitions.scala:1511)
at scala.tools.nsc.Global$Run.<init>(Global.scala:1225)
at scala.tools.nsc.interactive.Global$TyperRun.<init>(Global.scala:1323)
at scala.tools.nsc.interactive.Global.newTyperRun(Global.scala:1346)
at scala.tools.nsc.interactive.Global.<init>(Global.scala:294)
at org.scalaide.core.internal.compiler.ScalaPresentationCompiler.<init>(ScalaPresentationCompiler.scala:55)
at org.scalaide.core.internal.compiler.PresentationCompilerProxy.liftedTree1$1(PresentationCompilerProxy.scala:156)
at org.scalaide.core.internal.compiler.PresentationCompilerProxy.create(PresentationCompilerProxy.scala:153)
at org.scalaide.core.internal.compiler.PresentationCompilerProxy.initialize(PresentationCompilerProxy.scala:118)
at org.scalaide.core.internal.compiler.PresentationCompilerProxy.obtainPc$1(PresentationCompilerProxy.scala:80)
at org.scalaide.core.internal.compiler.PresentationCompilerProxy.internal(PresentationCompilerProxy.scala:100)
at org.scalaide.core.internal.compiler.PresentationCompilerProxy.apply(PresentationCompilerProxy.scala:58)
at org.scalaide.core.compiler.InteractiveCompilationUnit.withSourceFile(InteractiveCompilationUnit.scala:201)
at org.scalaide.core.compiler.InteractiveCompilationUnit.withSourceFile$(InteractiveCompilationUnit.scala:200)
at org.scalaide.core.internal.jdt.model.ScalaSourceFile.withSourceFile(ScalaSourceFile.scala:70)
at org.scalaide.core.testsetup.TestProjectSetup.reload(TestProjectSetup.scala:88)
at org.scalaide.core.completion.CompletionTests.t1001218(CompletionTests.scala:161)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:27)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:316)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeWithRerun(JUnit4Provider.java:240)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:214)
at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:155)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.apache.maven.surefire.api.util.ReflectionUtils.invokeMethodWithArray2(ReflectionUtils.java:137)
at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:148)
at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:88)
at org.eclipse.tycho.surefire.osgibooter.OsgiSurefireBooter.run(OsgiSurefireBooter.java:140)
at org.eclipse.tycho.surefire.osgibooter.HeadlessTestApplication.start(HeadlessTestApplication.java:29)
at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:208)
at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:143)
at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:109)
at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:439)
at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:271)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:651)
at org.eclipse.equinox.launcher.Main.basicRun(Main.java:588)
at org.eclipse.equinox.launcher.Main.run(Main.java:1459)
at org.eclipse.equinox.launcher.Main.main(Main.java:1432)
The target-platform-configuration
uses a target-platform file target-platform-2.12.target
:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?pde version="3.8"?>
<target name="target-platform">
<locations>
<location includeDependencyDepth="none" includeSource="true"
missingManifest="generate" type="Maven">
<dependencies>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>2.12.19</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-compiler</artifactId>
<version>2.12.19</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-reflect</artifactId>
<version>2.12.19</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.scala-refactoring</groupId>
<artifactId>org.scala-refactoring.library_2.12.2</artifactId>
<version>0.13.0</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.scalariform</groupId>
<artifactId>scalariform_2.12</artifactId>
<version>0.2.10</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.scala-lang.modules</groupId>
<artifactId>scala-xml_2.12</artifactId>
<version>2.3.0</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.scala-ide</groupId>
<artifactId>org.scala-ide.zinc.compiler.bridge</artifactId>
<version>4.7.1-SNAPSHOT</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.scala-ide</groupId>
<artifactId>org.scala-ide.zinc.library</artifactId>
<version>4.7.1-SNAPSHOT</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.fusesource.jansi</groupId>
<artifactId>jansi</artifactId>
<version>2.4.1</version>
<type>jar</type>
</dependency>
</dependencies>
</location>
<location includeAllPlatforms="false" includeConfigurePhase="true" includeMode="planner" includeSource="true" type="InstallableUnit">
<repository location="https://download.eclipse.org/releases/2024-03"/>
<unit id="org.apache.ant" version="0.0.0"/>
</location>
</locations>
</target>
I tried to do minimalist example without tycho/osgi and I didn’t have any issue with it :
import scala.tools.nsc.Global
import scala.tools.nsc.Settings
// Define the ScalaCompiler class with an integrated main method
object ScalaCompiler {
// Method to compile a specified Scala file
def compileScalaFile(fileName: String): Unit = {
val settings = new Settings()
settings.usejavacp.value = true
settings.withErrorFn(err => println(s"error while compiling: $err"))
val compiler = new Global(settings)
val run = new compiler.Run
val sourceFiles = run.compile(List(fileName))
}
// Main method as the entry point
def main(args: Array[String]): Unit = {
if (args.length > 0) {
compileScalaFile(args(0))
} else {
println("No filename provided. Usage: scala ScalaCompiler <filename>")
}
}
}
class Test {
println ("Hello World!")
}
This worked without any errors :
scalac ScalaCompiler.scala
java -cp .;.m2repositoryorgscala-langscala-library2.12.19scala-library-2.12.19.jar;.m2repositoryorgscala-langscala-compiler2.12.19scala-compiler-2.12.19.jar;.m2repositoryorgscala-langscala-reflect2.12.19scala-reflect-2.12.19.jar ScalaCompiler Test.scala
I suspect there is something with the OSGi
environment that prevents java.lang.Object
from being visible by the scala compiler.