IntelliJ IDEA #ParametersAreNonnullByDefault for all subpackages - java

I use IntelliJ's null-checking mechanism to prevent nullpointer crashes.
I've successfully set up all Java method parameters to be #NonNull by default using this answer.
After creating package-info.java which is used to define package annotations in Java. All java files which are direct descendants of that package have methods with default #NonNull parameters in my Android Studio project.
The obvious problem is that I need to define #ParametersAreNonnullByDefault for all Java classes in that package i.e. including all subpackages.
How can I define #ParametersAreNonnullByDefault so that it propagates down to all subpackage java files? I want to have all of my internal code's method annotated with #NonNull by default.
/**
* File: package-info.java
* Make all method parameters #NonNull by default
*/
#ParametersAreNonnullByDefault
package com.intive.nearbyplaces.main;
import javax.annotation.ParametersAreNonnullByDefault;

The problem was that I couldn't force Android Studio to respect #ParametersAreNonnullByDefault in all subpackages (i.e. recursively for all java files in com.company.name)
I wrote a gradle script, however, to check whether package-info.java files are generated inside each of the subpackage folders and create it if necessary. The script runs just before assembleDebug task.
So it turns out it is possible to force #ParametersAreNonnullByDefault annotation on all java classes in your project.
Download the source here. Remember to replace line 19 with your package name.
Usage:
apply plugin: 'com.android.application'
apply from: 'nonnull.gradle'
android {
compileSdkVersion 24
buildToolsVersion "24.0.2"
[...]
}
Remember to include package-info.java files in .gitignore
//File: .gitignore
package-info.java
Checkstyle rule:
<module name="JavadocPackage"/>
checks whether package-info.java is included in each subpackage.
Source:
/**
* File: nonnull.gradle
*
* Generates package-info.java for appropriate packages
* inside src/main/java folder.
*
* This is a workaround to define #ParametersAreNonnullByDefault for all Java classes in a package
* i.e. including all subpackages (note: edit package name in line no. 19).
*/
task generateNonNullJavaFiles(dependsOn: "assembleDebug", type: Copy) {
group = "Copying"
description = "Generate package-info.java classes"
def infoFileContentHeader = getFileContentHeader();
def infoFileContentFooter = getFileContentFooter();
def sourceDir = file( "${projectDir}" + File.separatorChar + "src" + File.separatorChar +
"main" + File.separatorChar + "java" + File.separatorChar +
"com" + File.separatorChar + "company" + File.separatorChar + "name" )
sourceDir.eachDirRecurse { dir ->
def infoFilePath = dir.getAbsolutePath() + File.separatorChar + "package-info.java"
if (!file(infoFilePath).exists()) {
def infoFileContentPackage = getFileContentPackage(dir.getAbsolutePath());
new File(infoFilePath).write(infoFileContentHeader +
infoFileContentPackage + infoFileContentFooter)
println "[dir] " + infoFilePath + " created";
}
}
println "[SUCCESS] NonNull generator: package-info.java files checked"
}
def getFileContentPackage(path) {
def mainSrcPhrase = "src" + File.separatorChar + "main" + File.separatorChar +
"java" + File.separatorChar
def mainSrcPhraseIndex = path.indexOf(mainSrcPhrase)
def output = path.substring(mainSrcPhraseIndex)
// Win hotfix
if (System.properties['os.name'].toLowerCase().contains('windows')) {
output = output.replace("\\", "/")
mainSrcPhrase = mainSrcPhrase.replace("\\", "/")
}
return "package " + output.replaceAll(mainSrcPhrase, "").replaceAll(
"/", ".") + ";\n"
}
def getFileContentHeader() {
return "/** javadoc goes here \n */\n" +
"#ParametersAreNonnullByDefault\n" +
"#ReturnValuesAreNonnullByDefault\n"
}
def getFileContentFooter() {
return "\n" +
"import javax.annotation.ParametersAreNonnullByDefault;\n" +
"\n" +
"import edu.umd.cs.findbugs.annotations.ReturnValuesAreNonnullByDefault;"
}
Extended version which generates package info files for src main, test & androidTest folders can be found here.
Findbugs & Lint:
It does work with findbugs & lint.

Related

How To Pass Variable To Pepper-Box Plain Text Config

I'm setting up my Pepper-Box Plain text Config to Pass variable using ${accountNumber}, ${{accountNumber}}, {{accountNumber}}, and using function to return string, but it didn't work.
This is my message to kafka :
{
"eventName": "OFFER",
"payload": {
"accountNumber": "${accountNumber}",
"Limit": 20000000
}
}
but the variable didn't pass, when I see the debug sampler, the accountNumber is pass.
I think there is mistake when I call the variable, but I try some techniques but it didnt work too.
The error Message when I try ${{accountNumber}} is :
symbol: method accountNumber()
location: class MessageIterator1566802574812
1 error
Uncaught Exception java.lang.ClassFormatError: Truncated class file. See log file for details.
It looks like a limitation of the plugin, you're basically limited to Schema Template Functions
Alternatively you can send a record to Kafka using JSR223 Sampler and the following Groovy code:
import org.apache.jmeter.threads.JMeterVariables
import org.apache.kafka.clients.producer.KafkaProducer
import org.apache.kafka.clients.producer.ProducerRecord
def kafkaProps = new Properties()
kafkaProps.put(org.apache.kafka.clients.producer.ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092")
kafkaProps.put(org.apache.kafka.clients.producer.ProducerConfig.CLIENT_ID_CONFIG, "KafkaExampleProducer")
kafkaProps.put(org.apache.kafka.clients.producer.ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, org.apache.kafka.common.serialization.LongSerializer.class.getName())
kafkaProps.put(org.apache.kafka.clients.producer.ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, org.apache.kafka.common.serialization.StringSerializer.class.getName())
def producer = new KafkaProducer<>(kafkaProps)
JMeterVariables vars = new JMeterVariables()
vars.put("accountNumber", "foo")
def record = new ProducerRecord<>("test", "{\n" +
" \"eventName\": \"OFFER\",\n" +
" \"payload\": {\n" +
" \"accountNumber\": \"" + vars.get("accountNumber") + "\",\n" +
" \"Limit\": 20000000\n" +
" }\n" +
"}")
producer.send(record)
More information: Apache Kafka - How to Load Test with JMeter

Gradle dependency resource access

How can I access resources from dependencies? I have something like this:
Wrapper project build.gradle
..
dependencies {
compile com.company:mysubproject1:2.0.1
compile com.company:mysubproject2:2.0.1
..
Those subprojects have some files in THEIR resource directories e.g. src/main/resources/liquibase/changelog.xml
There can be n of these subprojects and I need my gradle task to
pass through all dependencies and grab all changelog.xml files and create new file from them which will be later used.
It was actually not that hard:
doFirst {
println 'Generating master changelog...'
def changelogFiles = []
configurations.runtime.each {
def zip = new ZipFile(it)
def entries = zip.entries()
entries.findAll { entry -> entry.name.contains("liquibase") }
.findAll { entry -> entry =~ /changelog.xml/ }
.each { entry ->
changelogFiles.add(((ZipEntry) entry).name)
}
}
def resDir = sourceSets.main.output.resourcesDir.path + '/liquibase'
def changelogFile = new File("$resDir/changelog-master.xml")
changelogFile.write("<databaseChangeLog xmlns=\"http://www.liquibase.org/xml/ns/dbchangelog\"\n" +
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
" xsi:schemaLocation=\"http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-2.0.xsd\">\n\n")
changelogFiles.each {
println("Including $it to changelog.")
changelogFile << " <include file=\"classpath:$it\"/> \n"
}
changelogFile << "\n</databaseChangeLog>"
}
This code just loops through dependencies and digs up file paths for files named 'changelog.xml' and having 'liquibase' in path.
Possible issue would be if 2 dependecies had file with same name and path, I don't know what would be on classpath in that case.

How to provide python package path in Jython/Java code?

I have taken a written sample from this link to write my Python + Java integration code.
http://www.jython.org/jythonbook/en/1.0/JythonAndJavaIntegration.html
The code looks like below.
package org.jython.book.interfaces;
import org.jython.book.interfaces.JythonObjectFactory;
import org.python.core.Py;
import org.python.core.PyString;
import org.python.core.PySystemState;
public class Main {
public static void main(String args[]) {
String projDir = System.getProperty("user.dir");
String rootPath = projDir + "/src/org/jython/book/interfaces/";
String modulesDir = projDir + "/src/org/jython/book/interfaces/";
System.out.println("Project dir: " + projDir);
PySystemState sysSt = Py.getSystemState();
JythonObjectFactory factory = new JythonObjectFactory(sysSt, BuildingType.class, "Building", "Building");
BuildingType building = (BuildingType) factory.createObject();
building.setBuildingName("BUIDING-A");
building.setBuildingAddress("100 MAIN ST.");
building.setBuildingId(1);
System.out.println(building.getBuildingId() + " " +
building.getBuildingName() + " " +
building.getBuildingAddress());
}
}
When I run this code, it throws an error that it did not find the python module. I have kept the .py and .pyc files under the path provided as 'modulesDir'.
The literature says that "the requested module must be contained somewhere on the sys.path"; however, I did not understand how this can be set from this Java program. Can someone please provide some help?
Project dir: /Users/eclipsews/PythonJava
Exception in thread "main" ImportError: No module named Building
Hi found the answer to this issue!
Added the PySystemState.initialize method where I explicitly provide the "python.path" property, which is initialized to my project's path, where python modules are available.
private static Properties setDefaultPythonPath(Properties props) {
String pythonPathProp = props.getProperty("python.path");
String new_value;
if (pythonPathProp == null) {
new_value = System.getProperty("user.dir") + "/src/org/jython/book/interfaces/";
}
props.setProperty("python.path", new_value);
return props;
}
Properties props = setDefaultPythonPath(System.getProperties());
PySystemState.initialize( System.getProperties(), props, null );
This produces the correct output as follows:
module=<module 'Building' from '/Users/eclipsews/PythonJava/src/org/jython/book/interfaces/Building$py.class'>,class=<class 'Building.Buildin
g'>
1 BUIDING-A 100 MAIN ST.

Using a resource loader for FileWritingMessageHandler

When using a directory-expression for an <int-file:outbound-gateway> endpoint, the method below is called on org.springframework.integration.file.FileWritingMessageHandler:
private File evaluateDestinationDirectoryExpression(Message<?> message) {
final File destinationDirectory;
final Object destinationDirectoryToUse = this.destinationDirectoryExpression.getValue(
this.evaluationContext, message);
if (destinationDirectoryToUse == null) {
throw new IllegalStateException(String.format("The provided " +
"destinationDirectoryExpression (%s) must not resolve to null.",
this.destinationDirectoryExpression.getExpressionString()));
}
else if (destinationDirectoryToUse instanceof String) {
final String destinationDirectoryPath = (String) destinationDirectoryToUse;
Assert.hasText(destinationDirectoryPath, String.format(
"Unable to resolve destination directory name for the provided Expression '%s'.",
this.destinationDirectoryExpression.getExpressionString()));
destinationDirectory = new File(destinationDirectoryPath);
}
else if (destinationDirectoryToUse instanceof File) {
destinationDirectory = (File) destinationDirectoryToUse;
} else {
throw new IllegalStateException(String.format("The provided " +
"destinationDirectoryExpression (%s) must be of type " +
"java.io.File or be a String.", this.destinationDirectoryExpression.getExpressionString()));
}
validateDestinationDirectory(destinationDirectory, this.autoCreateDirectory);
return destinationDirectory;
}
Based on this code I see that if the directory to use evaluates to a String, it uses that String to create a new java.io.File object.
Is there a reason that a ResourceLoader couldn't/shouldn't be used instead of directly creating a new file?
I ask because my expression was evaluating to a String of the form 'file://path/to/file/' which of course is an invalid path for the java.io.File(String) constructor. I had assumed that Spring would treat the String the same way as it treats the directory attribute on <int-file:outbound-gateway> and pass it through a ResourceLoader.
Excerpt from my configuration file:
<int-file:outbound-gateway
request-channel="inputChannel"
reply-channel="updateTable"
directory-expression="
'${baseDirectory}'
+
T(java.text.MessageFormat).format('${dynamicPathPattern}', headers['Id'])
"
filename-generator-expression="headers.filename"
delete-source-files="true"/>
Where baseDirectory is a property that changes per-environment of the form 'file://hostname/some/path/'
There's no particular reason that this is the case, it probably just wasn't considered at the time of implementation.
The request sounds reasonable to me and will benefit others (even though you have found a work-around), by providing simpler syntax. Please open an 'Improvement' JIRA issue; thanks.
While not directly answering the question, I wanted to post the workaround that I used.
In my XML configuration, I changed the directory-expression to evaluate to a file through the DefaultResourceLoader instead of a String.
So this is what my new configuration looked like:
<int-file:outbound-gateway
request-channel="inputChannel"
reply-channel="updateTable"
directory-expression=" new org.springframework.core.io.DefaultResourceLoader().getResource(
'${baseDirectory}'
+
T(java.text.MessageFormat).format('${dynamicPathPattern}', headers['Id'])).getFile()
"
filename-generator-expression="headers.filename"
delete-source-files="true"/>

Jenkins/Hudson CLI API to modify the node labels using Groovy

Does anyone know how to modify the Jenkins/Hudson node labels in a non-manually way? I mean, thorough an API like the CLI API that this tool offers (without restarting Jenkins/Hudson of course).
My guess is that the best option is using a Groovy script to enter into the Jenkins/Hudson guts. Executing something like:
java -jar -s HUDSON_URL:8080 groovy /path/to/groovy.groovy
Being the content of that script something like:
for (aSlave in hudson.model.Hudson.instance.slaves) {
labels = aSlave.getAssignedLabels()
println labels
**aSlave.setLabel("blabla")** // this method doesn't exist, is there any other way???
}
Thanks in advance!
Victor
Note: the other answers are a bit old, so it could be that the API has appeared since then.
Node labels are accessed in the API as a single string, just like in the Configure screen.
To read and write labels: Node.getLabelString() and Node.setLabelString(String).
Note that you can get the effective labels as well via: Node.getAssignedLabels(), which returns a Collection of LabelAtom that includes dynamically computed labels such as the 'self-label' (representing the node name itself).
Last, these methods on the Node class are directly accessible from the slave objects also, e.g. as a System Groovy Script:
hudson = hudson.model.Hudson.instance
hudson.slaves.findAll { it.nodeName.equals("slave4") }.each { slave ->
print "Slave $slave.nodeName : Labels: $slave.labelString"
slave.labelString = slave.labelString + " " + "offline"
println " --> New labels: $slave.labelString"
}
hudson.save()
I've found a way to do this using the Groovy Postbuild Plugin.
I have a Jenkins job that takes a few parameters (NodeToUpdate, LabelName, DesiredState) and executes this content in the Groovy Postbuild Plugin:
nodeName = manager.envVars['NodeToUpdate']
labelName = manager.envVars['LabelName']
set = manager.envVars['DesiredState']
for (node in jenkins.model.Jenkins.instance.nodes) {
if (node.getNodeName().equals(nodeName)) {
manager.listener.logger.println("Found node to update: " + nodeName)
oldLabelString = node.getLabelString()
if (set.equals('true')) {
if (!oldLabelString.contains(labelName)) {
manager.listener.logger.println("Adding label '" + labelName + "' from node " + nodeName);
newLabelString = oldLabelString + " " + labelName
node.setLabelString(newLabelString)
node.save()
} else {
manager.listener.logger.println("Label '" + labelName + "' already exists on node " + nodeName)
}
}
else {
if (oldLabelString.contains(labelName)) {
manager.listener.logger.println("Removing label '" + labelName + "' from node " + nodeName)
newLabelString = oldLabelString.replaceAll(labelName, "")
node.setLabelString(newLabelString)
node.save()
} else {
manager.listener.logger.println("Label '" + labelName + "' doesn't exist on node " + nodeName)
}
}
}
}
I've not seen a way yet to change the slave label either.
I've taken to editing the main config.xml file and issuing a reload from the CLI.
This has it's own problems though - any jobs currently running are lost until the next jenkins restart - see https://issues.jenkins-ci.org/browse/JENKINS-3265

Categories

Resources