I'm sort of testing/ correcting and old gradle project to build an RPM with a tool that automatizes the import of files to a server without doing it by hand.
However this tool requires a file that is used by this proprietary software and uses it do know which dirs and libs are needed to be used. And at this point is necessary to generate the RPM and copy the file by hand the the tool's bin folder and I wanted to incorporate that file into the RPM without passing the full path to the file since the software can be used by anyone and the dirs for the software might be different from environment to environment.
On of the classes has the following variables declared:
private static final String DB_USER = "db_user";
private static final String DB_PASSWORD = "db_password";
private static final String DB_URL = "db_url";
private static final String W_HOME = "w_home";
private static final String W_LOGIN = "w_login";
private static final String W_LOGIN_USERNAME = "username";
private static final String W_LOGIN_PASSWORD = "password";
private static final String W_SERVER_URL = "w_server_url";
The w_home is the path used to read where the software is installed and by using that variable in the build.gradle I could easily pass the folders and the file name and get it into the RPM package.
My question if its even possible to call java variables or the get of that variable into the build.gradle
Edit: adding the gradle task
task buildRpm(type: Rpm, overwrite: true, dependsOn: build) {
packageName = applicationName
release = rpm_release
arch = NOARCH
os = LINUX
epoch = git.head().time
summary = "Import"
license = 'Proprietary'
user User
permissionGroup Group
//THIS DIRECTORY SHOULD ALREADY BE PRESENT
into(Home){
addParentDirs = false
fileMode 0644
dirMode 0755
directory("${Home}/${ packageName }")
directory("${Home}/${ packageName }/lib")
directory("${Home}/${ packageName }/config")
directory("${Home}/${ packageName }/bin")
directory("${Home}/${ packageName }/logs", 0777)
from(jar.outputs.files) {
into "${ packageName }/lib"
}
from(configurations.runtime) {
into "${ packageName }/lib"
}
from('lib') {
into "${ packageName }/lib"
}
from('src/dist/config') {
exclude 'log4j2.xml'
into "${ packageName }/config"
}
from('src/dist/config/log4j2.xml') {
into "${ packageName }/config"
fileType CONFIG | NOREPLACE
}
from('out/scripts') {
into "${ packageName }/bin"
fileMode 0755
}
}
requires('java', '2000:1.8.0_121', GREATER | EQUAL)
}
If the class containing the constants is part of your project, one way to achieve your goal would be to dynamically load the output jar in your RPM generating task then extract the desired values via reflection :
// Put this in your RPM task
URL[] urls = [new URL("file:///" + jar.archivePath.absolutePath)]
def loader = new URLClassLoader(urls)
// className is the fully qualified name of the configuration class
Class<?> clazz = loader.loadClass(className)
def field = clazz.getDeclaredField("W_HOME")
field.setAccessible(true) // This is needed for private fields
String home = field.get(null)
Since your class has constants that are apparently intended to be used externally, there is no point in making them private.
Of course, you'll have to adapt the above snippet if you have some custom build chain that does not use the standard jar task.
Related
For unknown reason a java file in an android studio project
has a sub arrow to BuildConfig class from an other package of an other project
/**
* Automatically generated file. DO NOT MODIFY
*/
package alsayed.aly.maintenanceplaner;
public final class BuildConfig {
public static final boolean DEBUG = Boolean.parseBoolean("true");
public static final String APPLICATION_ID = "alsayed.aly.maintenanceplaner";
public static final String BUILD_TYPE = "debug";
public static final String FLAVOR = "";
public static final int VERSION_CODE = 1;
public static final String VERSION_NAME = "1.0";
}
I tried to revert it but it is not working as the file just created now.
At build time, Gradle generates the BuildConfig class so your app code can inspect information about the current build.
You can also add custom fields to the BuildConfig class from your Gradle build configuration file using the buildConfigField() method and access those values in your app's runtime code. Likewise, you can add app resource values with resValue().
android {
...
buildTypes {
release {
// These values are defined only for the release build, which
// is typically used for full builds and continuous builds.
buildConfigField("String", "BUILD_TIME", "\"${minutesSinceEpoch}\"")
resValue("string", "build_time", "${minutesSinceEpoch}")
...
}
debug {
// Use static values for incremental builds to ensure that
// resource files and BuildConfig aren't rebuilt with each run.
// If they were dynamic, they would prevent certain benefits of
// Instant Run as well as Gradle UP-TO-DATE checks.
buildConfigField("String", "BUILD_TIME", "\"0\"")
resValue("string", "build_time", "0")
}
}
}
In your app code, you can access the properties as follows:
Log.i(TAG, BuildConfig.BUILD_TIME);
Log.i(TAG, getString(R.string.build_time));
I'm currently developing on OS X and trying to load the librxtxSerial.jnilib with System.load(), which just doesn't work and always results in
java.lang.UnsatisfiedLinkError: no rxtxSerial in java.library.path thrown while loading gnu.io.RXTXCommDriver
When I place the lib in /Library/Java/Extensions everything works fine.
I have double checked paths and everything, but it just won't work with System.load when I remove the lib from /Library/Java/Extensions.
I want to bundle the jnilib with a distributable jar, that's why I want to load it programmatically.
Does anybody have an idea?
if you have this:
root:
main.jar
libjni.jnilib
And you run your code at the root directory, using command like:
java -jar main.jar
In this case, your loading code should be like:
System.load("libjni.jnilib");
But bot System.loadLibrary(), load is safer than loadLibrary.
It's recommended to pass the absolute path of your jni library to System.load.
I used something like this in my project:
/**
* To load the JNI library
* Created by ice1000 on 2017/1/6.
*
* #author ice1000
*/
#SuppressWarnings("WeakerAccess")
public final class Loader {
public final static String JNI_LIB_NAME;
private static boolean loaded = false;
/*
* maybe it's already loaded, so there should be a check
*/
static {
JNI_LIB_NAME = "libjni";
loadJni();
}
#NotNull
#Contract(pure = true)
private static String libraryName(#NonNls #NotNull String libName) {
String ___ = System.getProperty("os.name");
String fileName;
if (___.contains("Linux"))
fileName = libName + ".so";
else if (___.contains("Windows"))
fileName = libName + ".dll";
else // if (___.get("OSX"))
fileName = libName + ".dylib";
// else fileName = libName;
return new File(fileName).getAbsolutePath();
}
public static void loadJni() {
if (!loaded) {
System.load(libraryName(JNI_LIB_NAME));
loaded = true;
}
}
}
here's my working directory:
root:
javaClasses.jar
libjni.dll
libjni.so
libjni.dylib
Hope this can help you.
Make sure to put your library on LD_LIBRARY_PATH.
Take a look here for lots of JNI related samples written for macOS/Linux.
http://jnicookbook.owsiak.org
I suggest to start with supper simple Hello world app:
http://jnicookbook.owsiak.org/recipe-No-001/
You can take a look there how to develop with JNI for macOS using standard tools.
Hope this helps. Have fun with JNI.
I have a structure of old bean object in a dedicate package
I want to copy them to a test folder so when I update them I can ensure that new version are compatible with new one
To avoid any naming issue old bean will be rename during copy
This make the copy but the class cannot compile because className != filename
task saveOldBean(type: Copy) {
from('src/main/java/project/bean/') {
include '**/*Bean.java'
}
into 'src/test/java/project/bean/'
rename '(.*).java', '$1Old.java'
}
So i try to replace ClassName in file using same kind of feature (ie regexp)
task saveOldBean(type: Copy) {
from('src/main/java/project/bean/') {
include '**/(.*Bean).java'
filter(ReplaceTokens, tokens: [$1: $1Old])
}
into 'src/test/java/project/bean/'
rename '(.*).java', '$1Old.java'
}
This fails, so if you have any suggestion to make this "rename" works, you are welcome
after some tries here is an implementation
task backupBean(type: Copy) {
def TAG_PREVIOUS="Backup";
def newEnd = "${TAG_PREVIOUS}.java";
from('src/main/java') {
include '**/*Bean.java'
}
into 'src/test/java'
rename { String fileName ->
fileName.replace('.java', newEnd)
}
eachFile { FileCopyDetails fileInfo ->
def fileName = fileInfo.name;
def oldClassName = fileName.replace(newEnd, "");
def newClassName = fileName.substring(0, fileName.indexOf(".java"));
filter{ it.replaceAll("$oldClassName","${newClassName}")}
filter{ it.replaceAll("public final class","/*${version}*/\npublic final class")}
println "save [$oldClassName] to [$newClassName]"
}
}
I'm wondering if it is possible to retrieve, in runtime, a version number of a jar from which the class comes from?
I know its possible to find jar from which the class comes from:
MyClass.class.getProtectionDomain().getCodeSource().getLocation().getPath();
but what about a version?
(assuming its not in the file name:) )
Try this, it may be helpful:
String s = new String();
System.out.println(s.getClass().getPackage().getSpecificationVersion());
System.out.println(s.getClass().getPackage().getImplementationVersion());
Output:
1.7
1.7.0_25
import javax.mail.internet.InternetAddress;
/**
Display package name and version information for javax.mail.internet.
*/
public final class ReadVersion {
public static void main(String... aArgs){
ReadVersion readVersion = new ReadVersion();
readVersion.readVersionInfoInManifest();
}
public void readVersionInfoInManifest(){
InternetAddress object = new InternetAddress();
Package objPackage = object.getClass().getPackage();
//examine the package object
String name = objPackage.getSpecificationTitle();
String version = objPackage.getSpecificationVersion();
//some jars may use 'Implementation Version' entries in the manifest instead
System.out.println("Package name: " + name);
System.out.println("Package version: " + version);
}
}
Be careful using getPackage().getImplementationVersion/getSpecificationVersion()
getSpecificationVersion returns specVersion from Manifest.
Manifest is a property of a jar and is used in sun.misc.URLClassPath as
public Manifest getManifest() throws IOException {
SharedSecrets.javaUtilJarAccess().ensureInitialization(JarLoader.this.jar);
return JarLoader.this.jar.getManifest();
}
So in case somebody use your library as dependency for fat jar, it returns the version of Manifest for fat jar.
I have a "simple maven project" that contains a package with some custom annotated classes.
I'm currently developing a maven plugin that can scan my "simple project" for those annotated classes and then return their name and the associated package.
For exemple :
simple-project/src/main/java/myApp/domain/Entity.java with Entity annotated with #MyCustomAnnotation
and the "my-maven-plugin" project is declared in the "simple-project" pom.xml
So, if I run "mvn generator:myGoal" it should generate a file with this content : myApp.domain.Entity
I tried almost everything I found on the internet but nothing really worked.
Everytime I run my goal, my plugin scans for its own classes but not my simple-project classes.
Any help would be appreciated.
Thanks.
I found a solution.
I loop on the sourceDirectory with a recursive function to find all files.
Here is how I get the sourceDirectory from my mojo :
/**
* Project's source directory as specified in the POM.
*
* #parameter expression="${project.build.sourceDirectory}"
* #readonly
* #required
*/
private final File sourceDirectory = new File("");
fillListWithAllFilesRecursiveTask(sourceDirectory);
I get the path of those files and then I use com.google.code.javaparser to parse the associated FileInputStream.
public void fillListWithAllFilesRecursiveTask(final File root) {
CompilationUnit cu;
FileInputStream in;
try {
// we looped through root and we found a file (not a directory)
in = new FileInputStream(file);
cu = JavaParser.parse(in);
new MethodVisitor().visit(cu, file);
Finally, I extend the VoidVisitorAdapter to get Annotations and members...etc
private static class MethodVisitor extends VoidVisitorAdapter<File> {
#Override
public void visit(ClassOrInterfaceDeclaration n, File file) {
if (n.getAnnotations() != null) {
// store classes that are annotated
for (AnnotationExpr annotation : n.getAnnotations()) {
//here some logic
}
} ...