Log4j Logger.getLogger(Class) throws NPE when running with jMockit and Cobertura - java

I have found a strange interaction between cobertura-maven-plugin 2.6 and jmockit 1.8. A particular pattern in our production code has a class with a lot of static methods that effectively wraps a different class that acts like a singleton. Writing unit tests for these classes went fine until I tried to run coverage reports with cobertura, when this error cropped up:
java.lang.ExceptionInInitializerError
at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:252)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:141)
at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:112)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:115)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75)
Caused by: java.lang.NullPointerException
at com.example.foo.MySingleton.<clinit>(MySingleton.java:7)
... 13 more
This then leads to a NoClassDefFoundError and being unable to initialize the singleton class. Here's a full SSCCE (the shortest I can get it down to) that replicates the error; line 7 of MySingleton is Logger.getLogger().
Here's the "singleton"...
package com.example.foo;
import org.apache.log4j.Logger;
public class MySingleton {
private static final Logger LOG = Logger.getLogger(MySingleton.class);
private boolean inited = false;
private Double d;
MySingleton() {
}
public boolean isInited() {
return inited;
}
public void start() {
inited = true;
}
public double getD() {
return d;
}
}
And the static class...
package com.example.foo;
import org.apache.log4j.Logger;
public class MyStatic {
private static final Logger LOGGER = Logger.getLogger(MyStatic.class);
private static MySingleton u = new MySingleton();
public static double getD() {
if (u.isInited()) {
return u.getD();
}
return 0.0;
}
}
And the test that breaks everything...
package com.example.foo;
import mockit.Expectations;
import mockit.Mocked;
import mockit.Tested;
import org.junit.Test;
public class MyStaticTest {
#Tested MyStatic myStatic;
#Mocked MySingleton single;
#Test
public void testThatBombs() {
new Expectations() {{
single.isInited(); result = true;
single.getD(); /*result = 1.2;*/
}};
// Deencapsulation.invoke(MyStatic.class, "getD");
MyStatic.getD();
}
}
And the maven pom:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example.foo</groupId>
<artifactId>test</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>Test</name>
<dependencies>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
<dependency>
<groupId>org.jmockit</groupId>
<artifactId>jmockit</artifactId>
<version>1.8</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<version>2.6</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
To summarize the summary: When running an ordinary unit test (mvn clean test), the above tests just fine; when run with cobertura (mvn clean cobertura:cobertura) it throws the nasty set of exceptions shown at the top. Obviously a bug somewhere, but whose?

The cause for this problem isn't so much a bug, but a lack of robustness in JMockit when mocking a class that contains a static initializer. The next version of JMockit (1.9) will be improved on this point (I already have a working solution).
Also, the problem would not have occurred if Cobertura marked its generated methods (four of them with names starting with "__cobertura_", added to every instrumented class) as "synthetic", so that JMockit would have ignored them when mocking a Cobertura-instrumented class. Anyway, fortunately this won't be necessary.
For now, there are two easy work-arounds which avoid the problem:
Make sure any class to be mocked was already initialized by the JVM by the time the test starts. This can be done by instantiating it or invoking a static method on it.
Declare the mock field or mock parameter as #Mocked(stubOutClassInitialization = true).
Both work-arounds prevent the NPE that would otherwise get thrown from inside the static class initializer, which is modified by Cobertura (to see these bytecode modifications, you can use the javap tool of the JDK, on classes under the target/generated-classes directory).

Related

Lombok not working in springboot application

I want to bean or inject logger so that I don't end up creating an object of logger in each and every class.
So I am trying to integrate Lombok which would help me to resolve lot of things including logger.
Here is my code:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import lombok.extern.slf4j.Slf4j;
#Slf4j
#SpringBootApplication
public class MyApplication {
private static final Logger logger = LoggerFactory.getLogger(MyApplication.class);
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
log.debug("Hello");
logger.info("Info log", MyApplication.class.getSimpleName());
}
}
But this is giving me error when I try to use log directly
IDE error -
log cannot be resolved
Console runtime error -
Exception in thread "main" java.lang.NullPointerException: Cannot
invoke "org.slf4j.Logger.info(String, Object)" because
"com.MyApplication .log" is null at
com.MyApplication.main(MyApplication .java:27)
Pom.xml
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
<version>2.4.5</version>
</dependency>
I have also installed lomback to my Eclipse IDE
Looks like you didn't install the Lombok plugin in your IDE.
Take a look at https://projectlombok.org/setup/overview under IDEs. There you can find instructions on how to install the plugin on most common used IDEs.
Also try to remove the logger from your code. This line:
private static final Logger logger = LoggerFactory.getLogger(MyApplication.class);
Because this is what lombok is adding at compile time. And you don't need the logging dependency because it's already part of spring-boot

groovy-eclipse-compiler compiles but javac compilation fails

My project builds successfully with groovy-eclipse-compiler, but fails without groovy-eclipse-compiler (using just javac). The build fails with an error message as given below (reported in a test class, while mocking an invocation)
java: reference to getFileResource is ambiguous
In order to debug the issue, I created a project with minimal files (given below). Though in project we have groovy source also, but I have not included them here to keep the code minimal.
The code is also pushed to git and is available at https://github.com/kaushalkumar/project-debug
My Doubt: The reported issue looks to be legitimate and I feel that groovy-eclipse-compiler must also fail, but it seems that the error is ignored. I am trying to understand what make groovy compiler to ignore it. Is it an issue in groovy compiler?
src/main/java/pkg1/IStrategy.java
package pkg1;
import java.util.Map;
public interface IStrategy {
Map<String, Object> getEnvMap();
}
src/main/java/pkg1/SharedResourceHelper.java
package pkg1;
import java.io.File;
import java.io.IOException;
import java.util.Map;
public class SharedResourceHelper {
public static File getFileResource(final String resourceName, final IStrategy strategy) throws IOException {
return getFileResource(resourceName, strategy.getEnvMap());
}
public static File getFileResource(final String resourceName, final Map<String, Object> envConfig) throws IOException {
return null;
}
}
src/test/java/pkg1/StrategyTest.java
package pkg1;
import pkg1.SharedResourceHelper;
import org.easymock.EasyMock;
import org.powermock.api.easymock.PowerMock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.junit.Test;
import org.powermock.modules.junit4.PowerMockRunner;
import org.junit.runner.RunWith;
import java.io.File;
#PrepareForTest({SharedResourceHelper.class})
#RunWith(PowerMockRunner.class)
public class StrategyTest {
#Test
#PrepareForTest({SharedResourceHelper.class})
public void testGetFileResource() throws Exception {
PowerMock.mockStatic(SharedResourceHelper.class);
EasyMock.expect(SharedResourceHelper.getFileResource(EasyMock.anyString(), EasyMock.anyObject())).andReturn(File.createTempFile("tmp", "s"));
// EasyMock.expect(SharedResourceHelper.getFileResource("test", null)).andReturn(File.createTempFile("tmp", "s"));
}
}
/pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>project.debug</groupId>
<artifactId>project</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-easymock</artifactId>
<version>2.0.7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>2.0.7</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<compilerId>groovy-eclipse-compiler</compilerId>
<source>1.8</source>
<target>1.8</target>
</configuration>
<dependencies>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-eclipse-compiler</artifactId>
<version>2.9.2-01</version>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-eclipse-batch</artifactId>
<version>2.4.3-01</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>
Java version - 1.8.0_231
Maven - 3.6.2
OS - Mac 10.15.6
groovy-eclipse-compiler - 2.9.2-01
groovy-eclipse-batch - 2.4.3-01
You reference "SharedResourceHelper.getFileResource(EasyMock.anyString(), EasyMock.anyObject())" is indeed ambiguous. If you add a typecast before "EasyMock.anyObject()" you could disambiguate. And EasyMock probably provides an "any" method that you can pass a type into as well.
groovy-eclipse-compiler is based upon ecj (eclipse compiler for java) and not javac, so there are bound to be differences. It may also be that ecj has a different default error/warning level for this particular case. If you feel this should be an error, you can file a JDT bug at bugs.eclipse.org.
eric-milles gave some direction to further explore this. His input is available at https://github.com/groovy/groovy-eclipse/issues/1157.
Based on his comment, we explored the history of https://github.com/groovy/groovy-eclipse/blob/master/extras/groovy-eclipse-batch-builder/build.properties and found that the compilation issue was between 2.4.12-01 (compilation works) and 2.4.12-02 (compilation breaks- as expected), which was part of release 2.9.2.
The change happened on Aug 10, 2017 (13c1c2a#diff-c8c111c3afb6080ae6b32148caaf6a0a), with comment as "Remove codehaus references". The jdt.patch.target was targeted for e44 which is Luna. This was same for both the files.
I invested some time in exploring https://github.com/eclipse/eclipse.jdt.core, to figure out how compiler behaviour could have altered, but could not get much. Though I am not very sure, but I feel that change in groovy-eclipse-batch (between 2.4.12-01 and 2.4.12-02) might be the cause of this.
Having invested this much time, I feel that it is not worth to further debug on this to figure out the root cause as the issue is already fixed in next version(s) [2.4.12-02 and beyond].

Getting a RootDoc in jdk11

I am trying to test out some code that works with Java Doc, it is used under the maven-javadoc-plugin. I am trying to get it to work under jdk11. I am after an implementation of RootDoc which I can use when running tests.
Currently the tests use EasyDoclet which gives me a RootDoc like so:
EasyDoclet easyDoclet = new EasyDoclet(new File("dir"), "com.foo.bar");
RootDoc rootDoc = easyDoclet.getRootDoc()
However I could not get this to work under jdk11.
The first issue I had was tools.jar is missing so I changed my pom.xml to have:
<dependency>
<groupId>org.seamless</groupId>
<artifactId>seamless-javadoc</artifactId>
<version>1.1.1</version>
<exclusions>
<exclusion>
<groupId>com.sun</groupId>
<artifactId>tools</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- maybe this will get what ever was in tools.jar -->
<dependency>
<groupId>com.github.olivergondza</groupId>
<artifactId>maven-jdk-tools-wrapper</artifactId>
<version>0.1</version>
</dependency>
This lead to many instances of:
java.lang.NoClassDefFoundError: com/sun/tools/javadoc/PublicMessager
The PublicMessager class seems to exist to make public some constructors, I am not sure why it exists under the com.sun.tools package. I tried to make a copy of this class:
public static class PublicMessager extends
com.sun.tools.javadoc.main.Messager {
public PublicMessager(Context context, String s) {
super(context, s);
}
public PublicMessager(Context context, String s, PrintWriter printWriter, PrintWriter printWriter1, PrintWriter printWriter2) {
super(context, s, printWriter, printWriter1, printWriter2);
}
}
And the error message changes to:
java.lang.IllegalAccessError: superclass access check failed: class com.fun.javadoc.FooBar$PublicMessager (in unnamed module #0x4abdb505) cannot access class com.sun.tools.javadoc.main.Messager (in module jdk.javadoc) because module jdk.javadoc does not export com.sun.tools.javadoc.main to unnamed module #0x4abdb50
I exposed jdk.javadoc to the unnamed module using:
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>-Dfile.encoding=UTF-8</argLine>
<argLine>--add-opens=jdk.javadoc/com.sun.tools.javadoc.main=ALL-UNNAMED</argLine>
</configuration>
</plugin>
</plugins>
</build>
This meant that my custom version of PublicMessager would no longer have the errors shown however the version from seamless under com.sun.tools could not be found. I made my own version of EasyDoclet which used my PublicMessager however it turned out that the following two classes are missing:
import com.sun.tools.javadoc.JavadocTool;
import com.sun.tools.javadoc.ModifierFilter;
At this point I am not sure what to do. halp!
Perhaps an alternative would be to instead find the jdk11 equivalent of RootDoc which I think is DocletEnvironment and then some how get an implementation of that, I have no idea how to get an implementation of DocletEnvironment.

Java Spring - how to inject #Value to a data object?

I have a data object (with getters\setter only) that needs to be aware of the Spring profile, i.e.
#Value("${spring.profiles.active}")
private String profile;
I added a logic to one of it's 'set' method that checks the profile, i.e.
public void setItem(Item msg) {
if (environmentProperties.isDevMode()) {
this.msg= msg;
}
}
since this class is often marshal\unmarhsalled externally, so, of course the #Value isn't being populated - sine I didn't use spring Autowire to create the class instance... I tried defined the class as component, and autowire to an external class that holds the profile #Value - but it doesn't work
I use spring 3.2 - with no XML definition.
any suggestions?
b.t.w.
that data-objects often wrapped inside an exception class - so when it's created the profile should also be known to the data-object...
thanks!
EDITED:
using ApplicationContextAware doesn't work - I get null the 'setApplicationContext' method is never invoked.
also trying to get context directly doesn't work - get null instead when using:
'ApplicationContext ctx = ContextLoader.getCurrentWebApplicationContext();'
FIXED:
I've eventually found an example how to access the context staticly from an external class:
#Configuration
public class ApplicationContextContainer implements ApplicationContextAware {
private static ApplicationContext CONTEXT;
/**
* This method is called from within the ApplicationContext once it is
* done starting up, it will stick a reference to itself into this bean.
*
* #param context a reference to the ApplicationContext.
*/
#Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
CONTEXT = context;
}
/**
* This is about the same as context.getBean("beanName"), except it has its
* own static handle to the Spring context, so calling this method statically
* will give access to the beans by name in the Spring application context.
* As in the context.getBean("beanName") call, the caller must cast to the
* appropriate target class. If the bean does not exist, then a Runtime error
* will be thrown.
*
* #param beanName the name of the bean to get.
* #return an Object reference to the named bean.
*/
public static Object getBean(String beanName) {
return CONTEXT.getBean(beanName);
}
If I understand you correctly you want to inject into Objects not managed by Spring, but created by some other code that internally calls new and returns objects e.g. a serialization framework.
To inject unmanaged Objects you will need to configure either load-time or compile-time weaving. Load-time weaving requires an agent argument and lib when you start your VM, some containers might do this for you.
Compile-time weaving requires the use of the AspectJ compiler.
Below you will find a complete example using Maven and Spring-Boot:
E.g. run it with:
mvn spring-boot:run -Drun.arguments="--spring.profiles.active=dev"
DemoApplication.java:
package com.example;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.aspectj.EnableSpringConfigured;
import org.springframework.stereotype.Component;
#SpringBootApplication
public class DemoApplication {
#EnableSpringConfigured
#ComponentScan("com.example")
public static class AppConfiguration {
#Value("${spring.profiles.active}")
String profile;
#Bean
public String profile() {
return profile;
}
}
#Configurable
public static class SomePojo {
#Autowired
private String profile;
public void print() {
System.out.println(this + "\t" + profile);
}
}
#Component
public static class Runner {
public void run() {
new SomePojo().print();
new SomePojo().print();
}
}
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args).getBean(Runner.class).run();
}
}
pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.3.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.8</version>
<configuration>
<complianceLevel>1.8</complianceLevel>
<aspectLibraries>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
</aspectLibraries>
</configuration>
<executions>
<execution>
<id>compile</id>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
From your description, you're trying to inject the property into POJO, which is used in marshalling. With this structure you may look for different workarounds with static-based/any other complex solutions.
I'd suggest to separate the bean which is used as POJO from the logic which depends on the property value. You can extract that logic to BeanService (which can be placed to Spring context) and handle it on that level, so that you separate the responsibility between Service and Data layers.
You're doing it wrong. Your code does not need to be aware of the profile. In your example, create a Message interface, and a number of bean implementations of this interface, one for each profile, each containing an appropriate message for that profile, and assign each one to a profile so that the bean is instantiated for that profile, and inject the instance into the class that needs the message.
So,
public interface Message { String getMessage(); }
#Profile("dev") #Component
public class DevMessage implements Message {
public String getMessage() { return "this is the dev message"; }
}
#Profile("prod") #Component
public class ProdMessage implements Message {
public String getMessage() { return "this is the production message"; }
}
If you prefer to describe your beans in your #Configuration class, you can mark a whole configuration with an #Profile, and have multiple configurations.
If you inject the Message instance into a class, you can call getMessage() on it. The profile will ensure that you have the appropriate implementation for your environment.
Edit:
I've just reread your question and realised that I've got this wrong. You have entity objects stored outside the application and instantiated through some code/framework. These aren't spring components, and so can't use the spring approach to dependency injection. In this case, don't use spring for them -- it doesn't work, doesn't have to work, and shouldn't work. If you haven't instantiated the object through spring, then it should have nothing to do with spring. I don't know your problem domain, but I've been using spring since it was invented and have never ever had to do this.

NoClassDefFoundError com.google.common.collect.Iterables on custom plugin deploy

I'm trying to write a plugin to perform some custom Java checks.
The checks are pretty simple and all look similar to this:
#ActivatedByDefault
#SqaleConstantRemediation("1h")
#SqaleSubCharacteristic(SECURITY_FEATURES)
#Rule(name = "Methods annotated with #RequestMapping should also have #PreAuthorize annotation", priority = CRITICAL)
public class RequestMappingHasPreAuthorizeAnnotationCheck extends MethodVisitor {
#Override
public void visitMethod(MethodTree methodTree) {
if (hasRequestMappingButNotPreAuthorize(methodTree.modifiers())) {
reportIssue(methodTree,
"Methods annotated with #RequestMapping should also be annotated with #PreAuthorize");
}
}
private static boolean hasRequestMappingButNotPreAuthorize(ModifiersTree modifiers) {
return isAnnotatedWith(modifiers, REQUEST_MAPPING) && !isAnnotatedWith(modifiers, PRE_AUTHORIZE);
}
Relevant part of pom.xml:
<packaging>sonar-plugin</packaging>
<dependencies>
<dependency>
<groupId>org.sonarsource.java</groupId>
<artifactId>java-checks</artifactId>
<version>3.9</version>
</dependency>
<dependency>
<groupId>org.sonarsource.sonarqube</groupId>
<artifactId>sonar-plugin-api</artifactId>
<version>5.3</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.sonarsource.sonar-packaging-maven-plugin</groupId>
<artifactId>sonar-packaging-maven-plugin</artifactId>
<version>1.15</version>
<extensions>true</extensions>
<configuration>
<pluginClass>com.company.sonar.security.RestSecurityPlugin</pluginClass>
<pluginDescription>Verifies security annotations</pluginDescription>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.sonar</groupId>
<artifactId>sonar-dev-maven-plugin</artifactId>
<version>1.8</version>
</plugin>
</plugins>
</build>
When I build with
mvn clean package
it generates my snapshot jar in target, but displays this (along w/ similar messages for other libraries):
[WARNING] com.google.guava:guava:jar:10.0.1:compile is provided by SonarQube plugin API and will not be packaged in your plugin
When I try to deploy it to my local test sonar server using
mvn sonar-dev:upload -DsonarHome=~/sonarqube-5.3
I get the folowing (snipped) stack trace:
Java::JavaLang::NoClassDefFoundError (com/google/common/collect/Iterables):
org.sonar.squidbridge.annotations.AnnotationBasedRulesDefinition.addRuleClasses(AnnotationBasedRulesDefinition.java:90)
org.sonar.squidbridge.annotations.AnnotationBasedRulesDefinition.addRuleClasses(AnnotationBasedRulesDefinition.java:86)
org.sonar.squidbridge.annotations.AnnotationBasedRulesDefinition.load(AnnotationBasedRulesDefinition.java:75)
com.company.sonar.security.RestSecurityRulesDefinition.define(RestSecurityRulesDefinition.java:25)
org.sonar.server.rule.RuleDefinitionsLoader.load(RuleDefinitionsLoader.java:54)
org.sonar.server.rule.RegisterRules.start(RegisterRules.java:100)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:497)
org.picocontainer.lifecycle.ReflectionLifecycleStrategy.invokeMethod(ReflectionLifecycleStrategy.java:110)
org.picocontainer.lifecycle.ReflectionLifecycleStrategy.start(ReflectionLifecycleStrategy.java:89)
org.sonar.core.platform.ComponentContainer$1.start(ComponentContainer.java:291)
org.picocontainer.injectors.AbstractInjectionFactory$LifecycleAdapter.start(AbstractInjectionFactory.java:84)
org.picocontainer.behaviors.AbstractBehavior.start(AbstractBehavior.java:169)
org.picocontainer.behaviors.Stored$RealComponentLifecycle.start(Stored.java:132)
org.picocontainer.behaviors.Stored.start(Stored.java:110)
org.picocontainer.DefaultPicoContainer.potentiallyStartAdapter(DefaultPicoContainer.java:1016)
org.picocontainer.DefaultPicoContainer.startAdapters(DefaultPicoContainer.java:1009)
org.picocontainer.DefaultPicoContainer.start(DefaultPicoContainer.java:767)
org.sonar.core.platform.ComponentContainer.startComponents(ComponentContainer.java:131)
org.sonar.server.platform.platformlevel.PlatformLevel.start(PlatformLevel.java:84)
org.sonar.server.platform.platformlevel.PlatformLevelStartup.access$001(PlatformLevelStartup.java:45)
org.sonar.server.platform.platformlevel.PlatformLevelStartup$1.doPrivileged(PlatformLevelStartup.java:82)
org.sonar.server.user.DoPrivileged.execute(DoPrivileged.java:45)
org.sonar.server.platform.platformlevel.PlatformLevelStartup.start(PlatformLevelStartup.java:78)
org.sonar.server.platform.Platform.executeStartupTasks(Platform.java:197)
org.sonar.server.platform.Platform.restart(Platform.java:141)
org.sonar.server.platform.Platform.restart(Platform.java:125)
org.sonar.server.platform.ws.RestartAction.handle(RestartAction.java:63)
org.sonar.server.ws.WebServiceEngine.execute(WebServiceEngine.java:85)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
(snip)
The RestSecurityRulesDefinition class looks like this:
public class RestSecurityRulesDefinition implements RulesDefinition {
#Override
public void define(Context context) {
NewRepository repository = context.createRepository("rest-security", "java").setName("rest-security");
#SuppressWarnings("rawtypes")
List<Class> ruleClasses = new ArrayList<>();
ruleClasses.add(PreAuthorizeInfoCheck.class);
ruleClasses.add(RequestMappingHasPartnerSecuredAnnotationCheck.class);
ruleClasses.add(RequestMappingHasPreAuthorizeAnnotationCheck.class);
ruleClasses.add(RequestMappingHasTimedAnnotationCheck.class);
ruleClasses.add(RestControllerWithExceptionHandlerAnnotationCheck.class);
// exception gets thrown on the following line
AnnotationBasedRulesDefinition.load(repository, "java", ruleClasses);
repository.done();
}
Server is freshly downloaded 5.3 with sonar.web.dev=true.
Any help on what I might be missing?

Categories