Correct way to use shaded jar as dependency - maven

I have a foo project which shades protobuf
<relocation>
<pattern>com.google</pattern>
<shadedPattern>shade.foo.com.google</shadedPattern>
</relocation>
<relocation>
<pattern>com.google.protobuf</pattern>
<shadedPattern>shade.foo.com.google.protobuf</shadedPattern>
</relocation>
Then I want to include the generated uber jar as depedency in another project bar.
com.google.protobuf.CodedInputStream input = com.google.protobuf.CodedInputStream.newInstance(buf);
com.google.protobuf.ExtensionRegistryLite extensionRegistry = com.google.protobuf.ExtensionRegistryLite.newInstance();
com.google.protobuf.Parser parserOk = com.bar.something.parser();
shade.foo.com.google.protobuf.Parser shadedParser = com.foo.somethinkg.parser();
input.readMessage(parserOk, extensionRegistry); // This is OK.
input.readMessage(shadedParser, extensionRegistry); // This throws error: Cannot resolve method 'readMessage'
So what's the correct way to reference methods from the shaded jar? Should I name all the reference starting with com.foo?

Related

How to Pass the features folder dynamically to a Jenkins->Maven->Testng Runner File

In my jenkins pipeline I am invoking my test like
"mvn test -Drun_location=US"
And my pom.xml file looks like this
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.16</version>
<configuration>
<systemPropertyVariables>
<run.location>${run_location}</run.location>
</systemPropertyVariables>
<suiteXmlFiles>
<suiteXmlFile>${basedir}/testng.xml</suiteXmlFile>
</suiteXmlFiles>
<skipTests>false</skipTests>
<testFailureIgnore>false</testFailureIgnore>
</configuration>
</plugin>
And my testng.xml file looks like this
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite>
<test>
<parameter name="location" value="${run_location}"/>
<classes>
<class name="com.test.Runner_Jenkins"/>
</classes>
</test>
</suite>
I need to pass this parameter to my runner file to set the feature directory dynamically. How do I accomplish this.
#CucumberOptions (
features = {"features/${run_location}"},
glue = "StepDefinitions"
)
There are two ways of achieving your requirement.
You could use the build parameters of Jenkins and pass your run_location. Then using the Execute Shell script option that runs before the maven build, you could use the sed command to add this parameter to your pom.xml file, feature file, and testng.xml file. sed command replaces the existing text with new text. You could search google about the usage of sed command.
The second option is to pass the run-location as a Jenkins build parameter. Then receive the build parameter inside your java code. Then add this run-location as a parameter to your testng xml file dynamically. This is called programmatic execution of testng. The below code will do this. The below code reads an existing testng XML file and adds a parameter based on your Jenkins input. In this way, you could receive this value inside any of your tests using the code mentioned below.
But this approach will not modify your pom.xml file and feature file. During the execution you have to figure out way to get this value to your code using java.
Programmatic execution of testng with dynamic jenkins parameter:
String run_location = System.getProperty("run_location");
TestNG tng = new TestNG();
File initialFile = new File("testng.xml");
InputStream inputStream = FileUtils.openInputStream(initialFile);
Parser p = new Parser(inputStream);
List<XmlSuite> suites = p.parseToList();
List<XmlSuite> modifiedSuites = new ArrayList<>();
for (XmlSuite suite : suites) {
XmlSuite modifiedSuite = new XmlSuite();
modifiedSuite.setParallel(suite.getParallel());
modifiedSuite.setThreadCount(deviceNames.size());
modifiedSuite.setName(suite.getName());
modifiedSuite.setListeners(suite.getListeners());
List<XmlTest> tests = suite.getTests();
for (XmlTest test : tests) {
for (int i = 0; i < deviceNames.size(); i++) {
XmlTest modifedtest = new XmlTest(modifiedSuite);
HashMap<String, String> parametersMap = new HashMap<>();
parametersMap.put("run_location", run_location);
modifedtest.setParameters(parametersMap);
modifedtest.setXmlClasses(test.getXmlClasses());
}
}
modifiedSuites.add(modifiedSuite);
}
inputStream.close();
tng.setXmlSuites(modifiedSuites);
tng.run();
Accessing the Parameter value inside your tests
#Test
#Parameters(value={"run_location"})
public void executeBeforeTest(String runlocation){
/**Your code goes her**/
}

How can I ensure that the right bytecode is available to my custom sonar plugin rule, so I don't get !unknown! for every type?

I've been attempting to write a custom rules plugin for Sonarqube ~5.4, and while I've gotten a few rules implemented and working, the ones that rely on types outside the standard libraries rely on various kinds of acrobatic string matching.
I'm using the sonar-packaging-maven-plugin to do the packaging:
<plugin>
<groupId>org.sonarsource.sonar-packaging-maven-plugin</groupId>
<artifactId>sonar-packaging-maven-plugin</artifactId>
<version>1.16</version>
<configuration>
<pluginClass>${project.groupId}.sonar.BravuraRulesPlugin</pluginClass>
<pluginKey>SonarPluginBravura</pluginKey>
<skipDependenciesPackaging>false</skipDependenciesPackaging>
<basePlugin>java</basePlugin>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>sonar-plugin</goal>
</goals>
</execution>
</executions>
</plugin>
And am running the various checks using the following helper extension (kotlin):
fun <T : JavaFileScanner> T.verify() {
val workDir = System.getProperty("user.dir");
val folder = Paths.get(workDir, "src/test/samples", this.javaClass.simpleName);
Files.list(folder).forEach { sample ->
try {
if (sample.toString().endsWith(".clean.java")) {
JavaCheckVerifier.verifyNoIssue(sample.toString(), this);
} else {
JavaCheckVerifier.verify(sample.toString(), this);
}
} catch (error: Exception) {
throw VerificationFailedException(sample, error);
}
}
};
class VerificationFailedException(path: Path, error: Exception)
: Exception("Failed to verify $path.", error);
I create an IssuableSubscriptionVisitor subclass for the rule, and visit Tree.Kind.METHOD_INVOCATION, looking for uses of a static MAX, MIN, ASC, or DESC sql builder method being passed an AutoLongColumn. This is to stop the identifier field being used for ordering purposes.
Unfortunately, even though I have the requisite library on the maven 'test' classpath, when I try and get any of the types, they just show as !unknown!.
override fun visitNode(tree: Tree) {
if (tree !is MethodInvocationTree) {
return;
}
val methodSelect = tree.methodSelect();
if (methodSelect !is IdentifierTree || methodSelect.name() !in setOf("MAX", "MIN", "ASC", "DESC")) {
return;
}
val firstArg = statement.arguments().first();
if (firstArg !is MethodInvocationTree) {
return;
}
val firstArgSelect = firstArg.methodSelect();
if (firstArgSelect !is MemberSelectExpressionTree) {
return;
}
if (firstArgSelect.type is UnknownType) {
throw TableFlipException("(ノಥ益ಥ)ノ ┻━┻");
}
// It never gets here.
}
I'm sure I'm missing some vital piece of the puzzle, and I'd appreciate if someone can tell me where I'm going wrong.
EDIT: I'm using org.sonarsource.java:sonar-java-plugin:3.14 for the analyser, and while I can't release all the code for the analysis target (commercial IP and all that), here's something structurally identical to the key part:
import static com.library.UtilClass.MAX;
...
query.SELECT(biggestId = MAX(address._id())) // Noncompliant
.FROM(address)
.WHERE(address.user_id().EQ(userId)
.AND(address.type_id().EQ(typeId)));
...
The type of address.id() is an com.library.Identifier that wraps a long. I'd like to be able to visit all the method invocations, check if they match com.library.UtilCLass.MAX, and if so, make sure that the first parameter isn't a com.library.Identifier. Without the type information, I have to do a regex match on _id method references, which is prone to potentially missing things.
So, turns out that the way to get the types available is by using maven (or whatever tool you're using) to copy the needed jars into a directory, then turn the lot into a list of files, and pass that to the test verifier.
For example, lets pretend we're trying to find usages of joda-time:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.10</version>
<executions>
<execution>
<id>copy-libs</id>
<phase>generate-test-resources</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.9.4</version>
</artifactItem>
</artifactItems>
</configuration>
</execution>
<executions>
</plugin>
This execution will put the joda-time jar into the target/dependency directory. Next, you make sure to enumerate the jars in that directory, and add them to your test verification (we're assuming you named your verifier 'JodaCheck'):
// Not at all necessary, but it makes the code later on a lot easier to read.
fun <T> Stream<T>.toList(): List<T> = this.collect({
mutableListOf()
}, { list, item ->
list.add(item)
}, { list, otherList ->
list.addAll(otherList)
})
...
val workDir = System.getProperty("user.dir")
val sampleFile = Paths.get(workDir, "src/test/samples/JodaSample.java").toString()
val dependencies = Files.list(Paths.get(workDir, "target/dependency"))
.map { it.toFile() }.toList()
JavaCheckVerifier.verify(sampleFile, JodaChecker(), dependencies)
Once you've done that, debugging through the tests will show that the joda-time classes are available during analysis.

Drools 6.4 KieScanner : How create and add Jar with rules in Maven?

I am a beginner with Drools and Maven and I am facing a problem to load rules with KieScanner.
The aim of the project is to be able to dynamically load rules in a permanent KieSession. I wonder if it is possible to manage rules with the KieFileSystem (not sure it is possible without a dispose of the session and starting another one leading to the lack of the previous inserted facts), but the good way is to use KieScanner.
It seems this requires the creation of a Jar containing the rules and having a Maven ID (ReleaseId), but I could not find detailed documentation about creation of these Jar files.
Which files shall be included in such a Jar ? DRL files, Pom.xml and manifest.mf ?
Where can this Jar file be added ? According to documentation it should not be added in the classpath when the detection of new issues of that file is necessary : "once a module is on the classpath, no other version may be loaded dynamically".
Is a Maven command needed ?
Can someone give me information on those points or give me a link where creation and deployment of such a Jar and its management in a KieScanner is described ? Thanks a lot.
Here is an example of a stateless kiesession using a kjar from a maven repository (code is in scala, but i am sure you'll get the idea of you primarily program in Java)
private val services = KieServices.Factory.get
private val releaseId = services.newReleaseId("com.piedpiper", "demo", "[1.0,2)")
private val kieContainer = services.newKieContainer(releaseId)
val kScanner = services.newKieScanner(kieContainer)
kScanner.start(2000L)
val kieSession = kieContainer.newStatelessKieSession("SimpleSession")
#tailrec
def check() {
val (aName, aAge) = scala.io.StdIn.readf2("{0} {1,number}")
val applicant = Applicant(name = aName.asInstanceOf[String], age = aAge.asInstanceOf[Long].toInt, pass = false)
kieSession.execute(applicant)
println(s"valid is ${applicant.pass}")
check()
}
check()
This looks for a kjar using maven with the gav com.piedpiper:demo:[1.0,2) (iow any version from 1.0 to 2 (non-inclusive). It checks every two seconds if a new version within that range is available.
The kjar contains the knowledge resources, the kmodule.xml etc (a proper kjar with the compiled rules using the kie-maven-plugin plugin-extension ). In this case it also contains the fact model (i would normally separate that out in a different maven artefact.)
The rule used in the example above is
rule "Is of valid age"
when
$a : Applicant( age > 13, pass==false )
then
modify($a){
pass = true
}
end
When changing the rule to for example > 15, it takes 2 seconds to become operational.
Here is an example to use MemoryFileSystem to create KJar and use it to create KieContainer
Input:
releaseId - Could be TimeStamp and UUID
ruleContentList - DRL file stringified list
public static final String IN_MEM_RULE_PATH = "src/main/resources/";
public static final String RULE_RESOURCE_TYPE = "drl";
public static byte[] createKJar(ReleaseId releaseId, List<String> ruleContentList) {
KieServices kieServices = KieServiceProvider.get();
KieFileSystem kfs = kieServices.newKieFileSystem();
kfs.generateAndWritePomXML(releaseId);
ruleContentList.forEach(drl -> kfs.write(IN_MEM_RULE_PATH + drl.hashCode() + "." + RULE_RESOURCE_TYPE, drl));
KieBuilder kb = kieServices.newKieBuilder(kfs).buildAll();
if (kb.getResults().hasMessages(Message.Level.ERROR)) {
for (Message result : kb.getResults().getMessages()) {
log.info("Error: " + result.getText());
}
throw new RegnatorException("Unable to create KJar for requested conditions resources", RegnatorError.ErrorCode.UNDEFINED);
}
InternalKieModule kieModule = (InternalKieModule) kieServices.getRepository().getKieModule(releaseId);
byte[] jar = kieModule.getBytes();
return jar;
}
Thanks a lot for your response raphaëλ. But my problem was rather building the jar before being able to use it in Java code.
This is how I could solve my problem.
Creation of a kjar file with the rules :
the file must contain :
file kmodule.xml in directory META-INF
file MANIFEST.MF in directory META-INF (not sure this is necessary...)
DRL files in same path than the one defined by their package (I have put the DRL files without compiling them before and they have been fired as expected)
a file pom.xml should be present for Maven but this has failed and I had to use an external pom.xml
command :
jar cvmf META-INF\MANIFEST.MF example-rules.jar META-INF* rules*
Example of file kmodule.xml :
<?xml version="1.0" encoding="UTF-8"?>
<kmodule xmlns="http://jboss.org/kie/6.0.0/kmodule">
<kbase name="base1" default="true" packages="rules">
<ksession name="session1" type="stateful" ="true"/>
</kbase>
</kmodule>
File MANIFEST.MF :
Manifest-Version: 1.0
Add kjar to Maven repository :
command :
mvn org.apache.maven.plugins:maven-install-plugin:2.5.2:install-file -Dfile=example-rules.jar -DpomFile=pom_jar.xml
file pom_jar.xml is used to define Maven references, example of such a file :
<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> test.example</groupId>
<artifactId>example-rules</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>example-rules</name>
<!-- Output to jar format -->
<packaging>jar</packaging>
</project>
Any comment is welcome.

How to make CodeNarc force maven build to fail

I'm trying to integrate CodeNarc into a maven based project and I've been running into problems.
I want to use a custom ruleset, and when a rule is violated, I'd like my maven build to fail.
How can I configure codenarc so that violations of rules lead to a failure when I run the following?
mvn clean install
Also, the documentation for configuring CodeNarc in a POM doesn't explain how to reference where my custom ruleset is. Any advice for how to set that up? Thanks!
When I run mvn clean install with the configurations below (I have a groovy file with blatant violations in accordance with my ruleset)
My build succeeds. :(
I tried referencing my own ruleset and no violations were being produced.
I took away a rulesetfiles property in the POM and it started producing violations.
(But I don't get to choose my own)
Anyone know how to make it actually read a custom rule set file? I tried with both xml and groovy.
Here's my ruleset and plugin config from my POM:
<ruleset xmlns="http://codenarc.org/ruleset/1.0";
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
xsi:schemaLocation="http://codenarc.org/ruleset/1.0 http://codenarc.org/ruleset-schema.xsd";
xsi:noNamespaceSchemaLocation="http://codenarc.org/ruleset-schema.xsd">;
<description>Dummy rule set</description>
<rule class='org.codenarc.rule.formatting.SpaceAfterIf'>
<property name='priority' value='1'/>
</rule>
<rule class='org.codenarc.rule.basic.EmptyIfStatement'>
<property name='priority' value='1'/>
</rule>
</ruleset>
I referenced this ruleset in my POM like this:
<groupId>org.codehaus.mojo</groupId>
<artifactId>codenarc-maven-plugin</artifactId>
<version>0.18-1</version>
<configuration>
<sourceDirectory>${basedir}/src/test/groovy</sourceDirectory>
<maxPriority1Violations>0</maxPriority1Violations>
<maxPriority2Violations>0</maxPriority2Violations>
<maxPriority3Violations>0</maxPriority3Violations>
<rulesetfiles>${basedir}/rulesets/ruleset.xml</rulesetfiles>
<xmlOutputDirectory>${basedir}/</xmlOutputDirectory>
</configuration>
<executions>
<execution>
<id>execution1</id>
<phase>install</phase>
<goals>
<goal>codenarc</goal>
</goals>
</execution>
</executions>
I was struggling with the same some time ago. I remember it was possible to run with maven properly but I don't have this config. Why? Because CodeNarc needs to compile your sources for purpuse of some rules execution. But codenarc maven plugin doesn't pass classpath and compilation was failing.
So I went for different approach which is running CodeNarc as a test source with ant task. It looks like:
import spock.lang.Specification
class GroovyCodeNarcStaticAnalysisRunner extends Specification {
private static final GROOVY_FILES = '**/*.groovy'
private static final ANALYSIS_SCOPE = 'src/main/groovy'
private static final RULESET_LOCATION = 'file:tools/static-analysis/codenarc.xml'
private static final HTML_REPORT_FILE = 'target/codenarc-result.html'
private static final XML_REPORT_FILE = 'target/codenarc-result.xml'
def 'Groovy code should meet coding standards'() {
given:
def ant = new AntBuilder()
ant.taskdef(name: 'codenarc', classname: 'org.codenarc.ant.CodeNarcTask')
expect:
ant.codenarc(
ruleSetFiles: RULESET_LOCATION,
maxPriority1Violations: 0,
maxPriority2Violations: 0,
maxPriority3Violations: 0)
{
fileset(dir: ANALYSIS_SCOPE) {
include(name: GROOVY_FILES)
}
report(type: 'text') {
option(name: 'writeToStandardOut', value: true)
}
report(type: 'xml') {
option(name: 'outputFile', value: XML_REPORT_FILE)
}
report(type: 'html') {
option(name: 'outputFile', value: HTML_REPORT_FILE)
}
}
}
}
You don't need to use Spock's Specification for that. Any test runner will do. On the maven side it's enough to make CodeNarc dependency configured with scope test.

how to get the super pom basedir in a child module pom?

I want to define a local repository in my maven project.
I've got a super pom and several child modules. My file structure is :
/root
/repository
/child
pom.xml
pom.xml
in my super pom I define :
<repository>
<id>my-local-repo</id>
<url>file://${basedir}/repository</url>
</repository>
The problem is that in my child pom, the repository defined in my super pom refers to /root/child/repository and so, dependencies cannot be found...
Is there a way to define a path always relative to the super pom ?
If not, what's the best way to solve the problem ?
In this case, at first you could try ${project.parent.basedir}.
As it seems it doesn't work, the simple(and native) way is use complete path (/root/...) or try relative path (../) instead of using ${basedir} variable.
But for me, a great solution would be externalize this configuration into a properties file.
You can use properties-maven-plugin ( http://mojo.codehaus.org/properties-maven-plugin/plugin-info.html ).
With this plugin, properties defined on the properties file can be read just like properties defined inside pom.xml.
From the plugin site:
If you have a properties file called teams.properties with this content:
toronto=raptors
miami=heat
Would be the same as declaring the following in your pom.xml:
<properties>
<toronto>raptors</toronto>
<miami>heat</miami>
</properties>
${project.parent.basedir} should do the job.
Or you can set the basedir-path of the root in a property, so it will be inherited. Something like this in the Parent
<properties>
<rootPath>${basedir}</rootPath>
</properties>
And in the Child
<repository>
<id>my-local-repo</id>
<url>file://${rootPath}/repository</url>
</repository>
I solved this many times with groovy plugin. Add a file called "basepath_marker" to your super pom's directory and add the following to your pom. You can access the property like this: ${base-path}. Read this blog post for more details.
Example:
...
<build>
<plugins>
<plugin>
<groupId>org.codehaus.gmaven</groupId>
<artifactId>groovy-maven-plugin</artifactId>
<executions>
<!-- set absolute base path from super pom -->
<execution>
<id>find-basepath</id>
<phase>validate</phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<source>
<![CDATA[
import java.io.File;
log.info('## define projects super pom absolute path through basepath_marker')
String p = "basepath_marker";
File f = null;
if( p != null ) {
def _max_child_poms = 0
while( _max_child_poms++ < 5 ) {
f = new File( p );
if( f.exists() ) {
break;
}
p = "../" + p;
}
}
if( f != null ) {
String basePath = f.getCanonicalPath();
basePath = basePath.substring( 0, basePath.lastIndexOf( File.separator ) );
project.properties['base-path'] = basePath.replace( '\\' , '/');
log.info(' - used base path = ' + project.properties['base-path'] );
} else {
log.error( 'Could not find basepath_marker marker file!' );
System.stop( 0 );
}
]]>
</source>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
...
I try ${basedir}/../ in child pom and it works.
${project.parent.basedir} can not be interpreted.
Also the solution as follow not work, seems ${basedir} is dynamic decided.
define a properties <rootPath> ${basedir} </rootPath> int your parent pom
use ${rootPath} in your child pom
In Parent pom -
Try to use relative path (../) instead of using ${basedir}

Resources