Linkage error in execution of custom (6.3) plugin (using java parser)

674 views
Skip to first unread message

Robert Willems of Brilman

unread,
Apr 8, 2017, 2:05:27 AM4/8/17
to SonarQube
Hi everybody,

i'm trying go get a new plugin working (analyzing package dependencies). That plugin uses the parsing functionality from the sonar Java plugin to analyze the source files.
So far so good; plugin is working in sonarqube server; however when running an analysis using the maven plugin a linkage error pops up.

I've tried a few things, but i'm kind of stumped by this error and was hoping somebody could point me in the right direction...

The source code for the project can be found at:

To reproduce the error:
- build and and deploy the plugin
- then configure a quality profile with the new rules
- configre a project with that quality profile
- run mvn -e sonar:sonar for that project

The exception:
[INFO] Sensor Package Analyzer Sensor (java) [packageanalyzer]
[INFO] JavaClasspath initialization
[INFO] JavaClasspath initialization (done) | time=12ms
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 10.343 s
[INFO] Finished at: 2017-04-08T07:50:59+02:00
[INFO] Final Memory: 66M/843M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.sonarsource.scanner.maven:sonar-maven-plugin:3.3.0.603:sonar (default-cli) on project sonar-packageanalyzer-plugin: Execution default-cli of goal org.sonarsource.scanner.maven:sonar-maven-plugin:3.3.0.603:sonar failed: An API incompatibility was encountered while executing org.sonarsource.scanner.maven:sonar-maven-plugin:3.3.0.603:sonar: java.lang.LinkageError: loader constraint violation: when resolving overridden method "org.sonar.java.resolve.TypeAndReferenceSolver.visitTypeArguments(Lorg/sonar/java/model/expression/TypeArgumentListTreeImpl;)V" the class loader (instance of org/sonar/classloader/ClassRealm) of the current class, org/sonar/java/resolve/TypeAndReferenceSolver, and its superclass loader (instance of org/sonar/classloader/ClassRealm), have different Class objects for the type org/sonar/java/model/expression/TypeArgumentListTreeImpl used in the signature
[ERROR] -----------------------------------------------------
[ERROR] realm =    plugin>org.codehaus.mojo:sonar-maven-plugin:3.3.0.603
[ERROR] strategy = org.codehaus.plexus.classworlds.strategy.SelfFirstStrategy
[ERROR] urls[0] = file:/C:/Users/Robert/.m2/repository/org/sonarsource/scanner/maven/sonar-maven-plugin/3.3.0.603/sonar-maven-plugin-3.3.0.603.jar
[ERROR] urls[1] = file:/C:/Users/Robert/.m2/repository/org/apache/maven/shared/maven-dependency-tree/2.2/maven-dependency-tree-2.2.jar
[ERROR] urls[2] = file:/C:/Users/Robert/.m2/repository/org/codehaus/plexus/plexus-component-annotations/1.5.5/plexus-component-annotations-1.5.5.jar
[ERROR] urls[3] = file:/C:/Users/Robert/.m2/repository/org/eclipse/aether/aether-util/0.9.0.M2/aether-util-0.9.0.M2.jar
[ERROR] urls[4] = file:/C:/Users/Robert/.m2/repository/org/sonatype/plexus/plexus-sec-dispatcher/1.4/plexus-sec-dispatcher-1.4.jar
[ERROR] urls[5] = file:/C:/Users/Robert/.m2/repository/org/sonatype/plexus/plexus-cipher/1.4/plexus-cipher-1.4.jar
[ERROR] urls[6] = file:/C:/Users/Robert/.m2/repository/org/codehaus/plexus/plexus-utils/3.0.22/plexus-utils-3.0.22.jar
[ERROR] urls[7] = file:/C:/Users/Robert/.m2/repository/org/sonarsource/scanner/api/sonar-scanner-api/2.9.0.887/sonar-scanner-api-2.9.0.887.jar
[ERROR] urls[8] = file:/C:/Users/Robert/.m2/repository/commons-lang/commons-lang/2.6/commons-lang-2.6.jar
[ERROR] urls[9] = file:/C:/Users/Robert/.m2/repository/com/google/code/findbugs/jsr305/2.0.3/jsr305-2.0.3.jar
[ERROR] Number of foreign imports: 1
[ERROR] import: Entry[import  from realm ClassRealm[project>nl.future-edge.sonarqube.plugins:sonar-packageanalyzer-plugin:1.0-SNAPSHOT, parent: ClassRealm[maven.api, parent: null]]]
[ERROR]
[ERROR] -----------------------------------------------------
[ERROR] -> [Help 1]
org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.sonarsource.scanner.maven:sonar-maven-plugin:3.3.0.603:sonar (default-cli) on project sonar-packageanalyzer-plugin: Execution default-cli of goal org.sonarsource.scanner.maven:sonar-maven-plugin:3.3.0.603:sonar failed: An API incompatibility was encountered while executing org.sonarsource.scanner.maven:sonar-maven-plugin:3.3.0.603:sonar: java.lang.LinkageError: loader constraint violation: when resolving overridden method "org.sonar.java.resolve.TypeAndReferenceSolver.visitTypeArguments(Lorg/sonar/java/model/expression/TypeArgumentListTreeImpl;)V" the class loader (instance of org/sonar/classloader/ClassRealm) of the current class, org/sonar/java/resolve/TypeAndReferenceSolver, and its superclass loader (instance of org/sonar/classloader/ClassRealm), have different Class objects for the type org/sonar/java/model/expression/TypeArgumentListTreeImpl used in the signature
-----------------------------------------------------
realm =    plugin>org.codehaus.mojo:sonar-maven-plugin:3.3.0.603
strategy = org.codehaus.plexus.classworlds.strategy.SelfFirstStrategy
urls[0] = file:/C:/Users/Robert/.m2/repository/org/sonarsource/scanner/maven/sonar-maven-plugin/3.3.0.603/sonar-maven-plugin-3.3.0.603.jar
urls[1] = file:/C:/Users/Robert/.m2/repository/org/apache/maven/shared/maven-dependency-tree/2.2/maven-dependency-tree-2.2.jar
urls[2] = file:/C:/Users/Robert/.m2/repository/org/codehaus/plexus/plexus-component-annotations/1.5.5/plexus-component-annotations-1.5.5.jar
urls[3] = file:/C:/Users/Robert/.m2/repository/org/eclipse/aether/aether-util/0.9.0.M2/aether-util-0.9.0.M2.jar
urls[4] = file:/C:/Users/Robert/.m2/repository/org/sonatype/plexus/plexus-sec-dispatcher/1.4/plexus-sec-dispatcher-1.4.jar
urls[5] = file:/C:/Users/Robert/.m2/repository/org/sonatype/plexus/plexus-cipher/1.4/plexus-cipher-1.4.jar
urls[6] = file:/C:/Users/Robert/.m2/repository/org/codehaus/plexus/plexus-utils/3.0.22/plexus-utils-3.0.22.jar
urls[7] = file:/C:/Users/Robert/.m2/repository/org/sonarsource/scanner/api/sonar-scanner-api/2.9.0.887/sonar-scanner-api-2.9.0.887.jar
urls[8] = file:/C:/Users/Robert/.m2/repository/commons-lang/commons-lang/2.6/commons-lang-2.6.jar
urls[9] = file:/C:/Users/Robert/.m2/repository/com/google/code/findbugs/jsr305/2.0.3/jsr305-2.0.3.jar
Number of foreign imports: 1
import: Entry[import  from realm ClassRealm[project>nl.future-edge.sonarqube.plugins:sonar-packageanalyzer-plugin:1.0-SNAPSHOT, parent: ClassRealm[maven.api, parent: null]]]

-----------------------------------------------------

        at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:212)
        at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
        at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
        at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:116)
        at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:80)
        at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:51)
        at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:128)
        at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:307)
        at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:193)
        at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:106)
        at org.apache.maven.cli.MavenCli.execute(MavenCli.java:863)
        at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:288)
        at org.apache.maven.cli.MavenCli.main(MavenCli.java:199)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:289)
        at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:229)
        at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:415)
        at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:356)
Caused by: org.apache.maven.plugin.PluginExecutionException: Execution default-cli of goal org.sonarsource.scanner.maven:sonar-maven-plugin:3.3.0.603:sonar failed: An API incompatibility was encountered while executing org.sonarsource.scanner.maven:sonar-maven-plugin:3.3.0.603:sonar: java.lang.LinkageError: loader constraint violation: when resolving overridden method "org.sonar.java.resolve.TypeAndReferenceSolver.visitTypeArguments(Lorg/sonar/java/model/expression/TypeArgumentListTreeImpl;)V" the class loader (instance of org/sonar/classloader/ClassRealm) of the current class, org/sonar/java/resolve/TypeAndReferenceSolver, and its superclass loader (instance of org/sonar/classloader/ClassRealm), have different Class objects for the type org/sonar/java/model/expression/TypeArgumentListTreeImpl used in the signature
-----------------------------------------------------
realm =    plugin>org.codehaus.mojo:sonar-maven-plugin:3.3.0.603
strategy = org.codehaus.plexus.classworlds.strategy.SelfFirstStrategy
urls[0] = file:/C:/Users/Robert/.m2/repository/org/sonarsource/scanner/maven/sonar-maven-plugin/3.3.0.603/sonar-maven-plugin-3.3.0.603.jar
urls[1] = file:/C:/Users/Robert/.m2/repository/org/apache/maven/shared/maven-dependency-tree/2.2/maven-dependency-tree-2.2.jar
urls[2] = file:/C:/Users/Robert/.m2/repository/org/codehaus/plexus/plexus-component-annotations/1.5.5/plexus-component-annotations-1.5.5.jar
urls[3] = file:/C:/Users/Robert/.m2/repository/org/eclipse/aether/aether-util/0.9.0.M2/aether-util-0.9.0.M2.jar
urls[4] = file:/C:/Users/Robert/.m2/repository/org/sonatype/plexus/plexus-sec-dispatcher/1.4/plexus-sec-dispatcher-1.4.jar
urls[5] = file:/C:/Users/Robert/.m2/repository/org/sonatype/plexus/plexus-cipher/1.4/plexus-cipher-1.4.jar
urls[6] = file:/C:/Users/Robert/.m2/repository/org/codehaus/plexus/plexus-utils/3.0.22/plexus-utils-3.0.22.jar
urls[7] = file:/C:/Users/Robert/.m2/repository/org/sonarsource/scanner/api/sonar-scanner-api/2.9.0.887/sonar-scanner-api-2.9.0.887.jar
urls[8] = file:/C:/Users/Robert/.m2/repository/commons-lang/commons-lang/2.6/commons-lang-2.6.jar
urls[9] = file:/C:/Users/Robert/.m2/repository/com/google/code/findbugs/jsr305/2.0.3/jsr305-2.0.3.jar
Number of foreign imports: 1
import: Entry[import  from realm ClassRealm[project>nl.future-edge.sonarqube.plugins:sonar-packageanalyzer-plugin:1.0-SNAPSHOT, parent: ClassRealm[maven.api, parent: null]]]

-----------------------------------------------------

        at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:183)
        at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:207)
        ... 20 more
Caused by: org.apache.maven.plugin.PluginContainerException: An API incompatibility was encountered while executing org.sonarsource.scanner.maven:sonar-maven-plugin:3.3.0.603:sonar: java.lang.LinkageError: loader constraint violation: when resolving overridden method "org.sonar.java.resolve.TypeAndReferenceSolver.visitTypeArguments(Lorg/sonar/java/model/expression/TypeArgumentListTreeImpl;)V" the class loader (instance of org/sonar/classloader/ClassRealm) of the current class, org/sonar/java/resolve/TypeAndReferenceSolver, and its superclass loader (instance of org/sonar/classloader/ClassRealm), have different Class objects for the type org/sonar/java/model/expression/TypeArgumentListTreeImpl used in the signature
-----------------------------------------------------
realm =    plugin>org.codehaus.mojo:sonar-maven-plugin:3.3.0.603
strategy = org.codehaus.plexus.classworlds.strategy.SelfFirstStrategy
urls[0] = file:/C:/Users/Robert/.m2/repository/org/sonarsource/scanner/maven/sonar-maven-plugin/3.3.0.603/sonar-maven-plugin-3.3.0.603.jar
urls[1] = file:/C:/Users/Robert/.m2/repository/org/apache/maven/shared/maven-dependency-tree/2.2/maven-dependency-tree-2.2.jar
urls[2] = file:/C:/Users/Robert/.m2/repository/org/codehaus/plexus/plexus-component-annotations/1.5.5/plexus-component-annotations-1.5.5.jar
urls[3] = file:/C:/Users/Robert/.m2/repository/org/eclipse/aether/aether-util/0.9.0.M2/aether-util-0.9.0.M2.jar
urls[4] = file:/C:/Users/Robert/.m2/repository/org/sonatype/plexus/plexus-sec-dispatcher/1.4/plexus-sec-dispatcher-1.4.jar
urls[5] = file:/C:/Users/Robert/.m2/repository/org/sonatype/plexus/plexus-cipher/1.4/plexus-cipher-1.4.jar
urls[6] = file:/C:/Users/Robert/.m2/repository/org/codehaus/plexus/plexus-utils/3.0.22/plexus-utils-3.0.22.jar
urls[7] = file:/C:/Users/Robert/.m2/repository/org/sonarsource/scanner/api/sonar-scanner-api/2.9.0.887/sonar-scanner-api-2.9.0.887.jar
urls[8] = file:/C:/Users/Robert/.m2/repository/commons-lang/commons-lang/2.6/commons-lang-2.6.jar
urls[9] = file:/C:/Users/Robert/.m2/repository/com/google/code/findbugs/jsr305/2.0.3/jsr305-2.0.3.jar
Number of foreign imports: 1
import: Entry[import  from realm ClassRealm[project>nl.future-edge.sonarqube.plugins:sonar-packageanalyzer-plugin:1.0-SNAPSHOT, parent: ClassRealm[maven.api, parent: null]]]

-----------------------------------------------------

        at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:181)
        ... 21 more
Caused by: java.lang.LinkageError: loader constraint violation: when resolving overridden method "org.sonar.java.resolve.TypeAndReferenceSolver.visitTypeArguments(Lorg/sonar/java/model/expression/TypeArgumentListTreeImpl;)V" the class loader (instance of org/sonar/classloader/ClassRealm) of the current class, org/sonar/java/resolve/TypeAndReferenceSolver, and its superclass loader (instance of org/sonar/classloader/ClassRealm), have different Class objects for the type org/sonar/java/model/expression/TypeArgumentListTreeImpl used in the signature
        at org.sonar.java.resolve.SemanticModel.createFor(SemanticModel.java:61)
        at nl.futureedge.sonar.plugin.packageanalyzer.sensor.JavaSensor.buildModel(JavaSensor.java:63)
        at nl.futureedge.sonar.plugin.packageanalyzer.sensor.AbstractSensor.execute(AbstractSensor.java:29)
        at org.sonar.scanner.sensor.SensorWrapper.analyse(SensorWrapper.java:53)
        at org.sonar.scanner.phases.SensorsExecutor.executeSensor(SensorsExecutor.java:57)
        at org.sonar.scanner.phases.SensorsExecutor.execute(SensorsExecutor.java:49)
        at org.sonar.scanner.phases.AbstractPhaseExecutor.execute(AbstractPhaseExecutor.java:74)
        at org.sonar.scanner.scan.ModuleScanContainer.doAfterStart(ModuleScanContainer.java:175)
        at org.sonar.core.platform.ComponentContainer.startComponents(ComponentContainer.java:143)
        at org.sonar.core.platform.ComponentContainer.execute(ComponentContainer.java:128)
        at org.sonar.scanner.scan.ProjectScanContainer.scan(ProjectScanContainer.java:262)
        at org.sonar.scanner.scan.ProjectScanContainer.scanRecursively(ProjectScanContainer.java:257)
        at org.sonar.scanner.scan.ProjectScanContainer.doAfterStart(ProjectScanContainer.java:247)
        at org.sonar.core.platform.ComponentContainer.startComponents(ComponentContainer.java:143)
        at org.sonar.core.platform.ComponentContainer.execute(ComponentContainer.java:128)
        at org.sonar.scanner.task.ScanTask.execute(ScanTask.java:47)
        at org.sonar.scanner.task.TaskContainer.doAfterStart(TaskContainer.java:86)
        at org.sonar.core.platform.ComponentContainer.startComponents(ComponentContainer.java:143)
        at org.sonar.core.platform.ComponentContainer.execute(ComponentContainer.java:128)
        at org.sonar.scanner.bootstrap.GlobalContainer.executeTask(GlobalContainer.java:118)
        at org.sonar.batch.bootstrapper.Batch.executeTask(Batch.java:117)
        at org.sonarsource.scanner.api.internal.batch.BatchIsolatedLauncher.execute(BatchIsolatedLauncher.java:63)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.sonarsource.scanner.api.internal.IsolatedLauncherProxy.invoke(IsolatedLauncherProxy.java:60)
        at com.sun.proxy.$Proxy23.execute(Unknown Source)
        at org.sonarsource.scanner.api.EmbeddedScanner.doExecute(EmbeddedScanner.java:233)
        at org.sonarsource.scanner.api.EmbeddedScanner.runAnalysis(EmbeddedScanner.java:151)
        at org.sonarsource.scanner.maven.bootstrap.ScannerBootstrapper.execute(ScannerBootstrapper.java:77)
        at org.sonarsource.scanner.maven.SonarQubeMojo.execute(SonarQubeMojo.java:139)
        at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:134)
        ... 21 more
[ERROR]
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:


I've tried to set the client first classloader (no change in error)
I've tried to set the java-frontend dependency to provided (noclassdeffound error, so the dependency does not seem to be implicit in the classpath)

Any help would be greatly appreciated!

Regards,
Robert

Robert Willems of Brilman

unread,
Apr 8, 2017, 1:56:54 PM4/8/17
to SonarQube
I've tracked down the classes that seems to be the problem:

Adding this in the execution of the sensor:

private void debug() {
LOGGER.info("TypeArgumentListTreeImpl location: {}", org.sonar.java.model.expression.TypeArgumentListTreeImpl.class.getProtectionDomain().getCodeSource().getLocation());
LOGGER.info("BaseTreeVisitor location: {}", org.sonar.plugins.java.api.tree.BaseTreeVisitor.class.getProtectionDomain().getCodeSource().getLocation());
LOGGER.info("TypeAndReferenceSolver location: {}", org.sonar.java.resolve.TypeAndReferenceSolver.class.getProtectionDomain().getCodeSource().getLocation());
LOGGER.info("JavaParser location: {}", org.sonar.java.ast.parser.JavaParser.class.getProtectionDomain().getCodeSource().getLocation());
}

Results in:

[INFO] TypeArgumentListTreeImpl location: file:/C:/Users/Robert/.sonar/cache/8e3188b106fb125b083463aa8e6df9d4/sonar-packageanalyzer-plugin-1.0-SNAPSHOT.jar_unzip/META-INF/lib/java-frontend-4.7.1.9272.jar
[INFO] BaseTreeVisitor location: file:/C:/Users/Robert/.sonar/cache/5f15eeda65525868f4f4c920de0c4eb1/sonar-java-plugin-4.7.0.9212.jar_unzip/META-INF/lib/java-frontend-4.7.0.9212.jar
[INFO] TypeAndReferenceSolver location: file:/C:/Users/Robert/.sonar/cache/8e3188b106fb125b083463aa8e6df9d4/sonar-packageanalyzer-plugin-1.0-SNAPSHOT.jar_unzip/META-INF/lib/java-frontend-4.7.1.9272.jar
[INFO] JavaParser location: file:/C:/Users/Robert/.sonar/cache/8e3188b106fb125b083463aa8e6df9d4/sonar-packageanalyzer-plugin-1.0-SNAPSHOT.jar_unzip/META-INF/lib/java-frontend-4.7.1.9272.jar


Note the BaseTreeVisitor class seems to be loaded from another plugin. Does this mean the classloading for plugins is not supposed to be 'seperate' for each plugin?

Robert Willems of Brilman

unread,
Apr 8, 2017, 2:30:08 PM4/8/17
to SonarQube
Putting the plugin within the classloader of the Java plugin (setting <basePlugin>java</basePlugin> in the configuration) seem to resolve the problem at bit...
However it makes the dependency very brittle...

I'm compiling with version 4.7.1, but when i ran the plugin within the classloader of 4.2.1 (which we currently
use at work) it broke because the classes were incompatible:

Caused by: java.lang.NoSuchMethodError: org.sonar.java.ast.parser.JavaParser.createParser()Lcom/sonar/sslr/api/typed/ActionParser;
        at nl.futureedge.sonar.plugin.packageanalyzer.sensor.JavaSensor.buildModel(JavaSensor.java:53)
        at nl.futureedge.sonar.plugin.packageanalyzer.sensor.AbstractSensor.execute(AbstractSensor.java:29)
        at org.sonar.scanner.sensor.SensorWrapper.analyse(SensorWrapper.java:53)
        at org.sonar.scanner.phases.SensorsExecutor.executeSensor(SensorsExecutor.java:57)

It also crashes SonarQube (during the startup of the compute engine) on a nullpointer when the base plugin is not installed:

2017.04.08 20:27:29 INFO  ce[][o.s.c.c.CePluginRepository] Load plugins
2017.04.08 20:27:29 ERROR ce[][o.s.ce.app.CeServer] Compute Engine startup failed
java.lang.NullPointerException: null
at org.sonar.core.platform.PluginLoader.basePluginKey(PluginLoader.java:176)
at org.sonar.core.platform.PluginLoader.defineClassloaders(PluginLoader.java:85)
at org.sonar.core.platform.PluginLoader.load(PluginLoader.java:71)
at org.sonar.ce.container.CePluginRepository.start(CePluginRepository.java:71)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.picocontainer.lifecycle.ReflectionLifecycleStrategy.invokeMethod(ReflectionLifecycleStrategy.java:110)
at org.picocontainer.lifecycle.ReflectionLifecycleStrategy.start(ReflectionLifecycleStrategy.java:89)
at org.sonar.core.platform.ComponentContainer$1.start(ComponentContainer.java:321)

The documentation also states:
If specified, then the plugin is executed in the same classloader as basePlugin. That is mainly used when extending rules of a rule engine plugin.

So for my usage i don't really think this is the right way to go....

Robert Willems of Brilman

unread,
Apr 8, 2017, 4:17:42 PM4/8/17
to SonarQube
Currently i've decided to lookup the MANIFEST.MF file of the plugin, parse the Plugin-Dependencies entry and construct a ClassWorlds classloader from that to separate the plugin from the rest of the code. However this doesn't feel right and is a lot of work that will be akward in unittesting...

Hopefully somebody has a better idea...

Simon Brandhof

unread,
Apr 10, 2017, 11:45:28 AM4/10/17
to Robert Willems of Brilman, SonarQube
Hi Robert,

In the current state the artifact java-frontend can't be considered as a library and can't be embedded in a plugin. You should use the API published by the Java plugin to benefit from the package org.sonar.plugins.java.api. The other packages prefixed by org.sonar.java should not be used.
As a consequence the dependency on java-frontend should be defined with scope "provided" and the Java plugin should be available at runtime.

Does it help ?

Regards


On Sat, 8 Apr 2017 at 22:17 Robert Willems of Brilman <robert.wille...@gmail.com> wrote:
Currently i've decided to lookup the MANIFEST.MF file of the plugin, parse the Plugin-Dependencies entry and construct a ClassWorlds classloader from that to separate the plugin from the rest of the code. However this doesn't feel right and is a lot of work that will be akward in unittesting...

Hopefully somebody has a better idea...

--
You received this message because you are subscribed to the Google Groups "SonarQube" group.
To unsubscribe from this group and stop receiving emails from it, send an email to sonarqube+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/sonarqube/06d2ebe9-2b6c-4922-a545-826b8ee8a018%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
--
Simon BRANDHOF | SonarSource
Tech Lead & Co-Founder
http://twitter.com/SimonBrandhof

Robert Willems of Brilman

unread,
Apr 10, 2017, 12:51:15 PM4/10/17
to SonarQube, robert.wille...@gmail.com
Hi Simon,

thank you for the reply. Unfortunately this doesn't help me as the published API doesn't support my use case (it only allows adding checks that work on one file).

Currently i've designed the plugin to parse all source (ideally it would support more languages than only Java) files to build a plugin specific model.
The plugin then does some language agnostic analysis on the model and reports issues based on this analysis.
The parts of the java-frontend i would like to reuse are the AST (JavaParser) and the SemanticModel, but those are not exposed in the org.sonar.plugins.java.api package.
Maybe the language support could be refactored out of the checks artifact? That would support this use case and would make the AST reusable.

As for progress on my direct problem, i've succeeded in setting up a classworld realm (using the system loader, only loading the plugin jars and importing only parts of the base plugin api 
to communicate) to separate the model loading from the rest of the plugin. This is currently working (the AST works, i think the SemanticModel still needs work) and allows me to use the 
Java language that is configured in the SonarQube plugin. I'm looking forward to a discussion when i have the plugin completed and post a RFF ;-)

Regards,
Robert

Simon Brandhof

unread,
Apr 10, 2017, 1:50:10 PM4/10/17
to Robert Willems of Brilman, SonarQube
As for progress on my direct problem, i've succeeded in setting up a classworld realm (using the system loader, only loading the plugin jars and importing only parts of the base plugin api 
to communicate) to separate the model loading from the rest of the plugin. This is currently working (the AST works, i think the SemanticModel still needs work) and allows me to use the 

I don't recommend at all to go into this direction. Classloaders should not be hacked. That may lead to unexpected behaviors in some scanners. 
Did you try to simply shade and relocate the java-frontend classes ?

Robert Willems of Brilman

unread,
Apr 10, 2017, 2:47:43 PM4/10/17
to SonarQube, robert.wille...@gmail.com
Lol,

a prime example of how my mind selected a difficult solution while other more simple solutions also exist.
Extracting and relocation the needed classes would lead to the same result... i've never done that so it didn't cross my mind...

Good suggestion... this will make my tests easier aswell...

Regards,
Robert

Simon Brandhof

unread,
Apr 10, 2017, 3:13:19 PM4/10/17
to Robert Willems of Brilman, SonarQube
As you never did that, here is an example: https://github.com/SonarSource/sonarqube/blob/master/sonar-plugin-api/pom.xml#L168-L203 :-)
Hope it helps.

--
You received this message because you are subscribed to the Google Groups "SonarQube" group.
To unsubscribe from this group and stop receiving emails from it, send an email to sonarqube+...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Robert Willems of Brilman

unread,
Apr 10, 2017, 3:14:49 PM4/10/17
to SonarQube, robert.wille...@gmail.com
Thanks... found the plugin, i'll have a look at the example... 

Nicolas Peru

unread,
Apr 11, 2017, 1:29:48 AM4/11/17
to Robert Willems of Brilman, SonarQube
Hi Robert, 

I am bit curious as to why you can't code your usecase as CustomCheck as the AST and the semantic information are available from a custom rule. 
if your issue is to get packages and imports from a compilation unit you could perfectly do that from a custom check (you can't do cross file but your custom check can have a state).
Or is your problem about the order in which the files are scanned ? 
All in all : Could you detail your usecase ? 

A bit of warning also : Using classes like SemanticModel is at your own risk, we may remove that class without warning between minor version (as it is not part of any API) resulting in breaking your plugin.
Cheers 


For more options, visit https://groups.google.com/d/optout.
--
Nicolas PERU | SonarSource
Senior Developer
http://sonarsource.com

Robert Willems of Brilman

unread,
Apr 12, 2017, 9:30:36 AM4/12/17
to SonarQube, robert.wille...@gmail.com
Hi Nicolas,

my checks depend on having the complete model analysed as a whole.

In steps this is what i do:

1. Setup the model
2. Parse all source files and collect data from those source files in the model
3. Analyse the model to compute numbers for the rules
4. Loop over the model and execute rules (the model contains references to where to register issues)

I intentionally split the language specific step out of the others, because in future i want to support the same rules on different languages.

I'm also planning on adding metrics, but i'm not too sure about those, as Ann pointed out (in a discussion about the predecessor of this plugin)
that there is an anti-pattern in having metrics and rules that point to the same number.

At this moment i'm seeing the following problems in the steps with the current api to do this in JavaChecks:

1 and 2. Nothing much, however i don't like mixing state and functionality in a check.
3 and 4. There is no signal i can use to signal the scanning is complete and to do my own analysis and execute my own set of rules.
Metrics. The API does not allow to register metrics

I think it could be resolved with the following changes:

1 and 2. Allow custom values in the JavaScannerContext (maybe a map where multiple plugins can store their state).
   My checks wouldn't be checks though, just processors...
3 and 4. Not a real good idea, maybe a listener that can be called; should have access to the JavaScannerContext
Metrics. The JavaFileScannerContext should expose the SensorContext

Hope this explains my usecase...

Regards,
Robert

Nicolas Peru

unread,
Apr 12, 2017, 10:16:20 AM4/12/17
to Robert Willems of Brilman, SonarQube
Hi Robert ,

AFAI understand step 2 could be totally covered using a custom rule. There's nothing preventing you to store information out of scanning file from a custom rule.

So if I am correct what you are lacking is more a "callback" once your custom rule (which will allow you to have access to parsing and semantic) has scanned all files ? 

Cheers, 


For more options, visit https://groups.google.com/d/optout.

Robert Willems of Brilman

unread,
Apr 12, 2017, 3:30:30 PM4/12/17
to SonarQube
Hi Nicolas,

Yes that would make it possible. A custom rule would be the 'collector'. The callback would make it possible to execute the analysis and the checks.

How do you suppose the data collected would be collected 'in' the rule and passed to the callback? A ThreadLocal or something like that? I suppose
in the future the filescanner would become multithreaded to speed it up and parse files parallel; so that is why i proposed to put the data in the context.

Regards,
Robert

Nicolas Peru

unread,
May 10, 2017, 10:31:18 AM5/10/17
to Robert Willems of Brilman, SonarQube
Hi, 

For the time being I am sorry to let you know that we have no plan nor desire to implement such feature as this is a corner case for us. 
So, sorry but you are indeed back to square one and Simon solution's might be the way to go by shading and relocating classes. 

Cheers, 

--
You received this message because you are subscribed to the Google Groups "SonarQube" group.
To unsubscribe from this group and stop receiving emails from it, send an email to sonarqube+...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.
--
Nicolas Peru | SonarSource

Robert Willems of Brilman

unread,
May 17, 2017, 7:38:39 AM5/17/17
to SonarQube, robert.wille...@gmail.com
Hi Nicolas,

thank you for the feedback. I understand the cornercase from your point of view ;-).
I've already tried the approach Simon suggested and have a working version of the plugin.

Regards,
Robert
Reply all
Reply to author
Forward
0 new messages