SCons not picking up all class files when creating a jar - java

SCons neophyte here. I am using it(version 2.0) to create a jar as follows:
compiled_classes = env.Java \
(target = compiled_classes_dir,
source = source_tld,
JAVAVERSION='1.6',
JAVACLASSPATH=['source_tld/libs/' +
file.name
for file in
Glob('source_tld/' +
'libs/*.jar')])
new_jar = env.Jar(target = jar_name,
source = compiled_classes_dir)
I am seeing an issue wherein class files belonging to classes that have inner classes(which when compiled into class files have a $ in the name) are not being handled properly i.e. they do not get included in the generated JAR. Any suggestions to address this would be greatly appreciated. TIA.
PS: This suggestion to add JAVAVERSION didn't seem to help.

Since SCons is incorrectly calculating the output classes I would suggest this workaround.
compiled_classes = env.Java \
(target = compiled_classes_dir,
source = source_tld,
JAVAVERSION='1.6',
JAVACLASSPATH=['source_tld/libs/' +
file.name
for file in
Glob('source_tld/' +
'libs/*.jar')])
#workaround to make sure classes are cleaned
env.Clean(compiled_classes, env.Dir(compiled_classes_dir))
# its important to set the JARCHDIR or the Jar command will not be run
# from the correct location if you want an executable Jar add the manifest here
new_jar = env.Jar(target = jar_name,
source = [compiled_classes_dir], JARCHDIR='$SOURCE')

Related

Include multiple source directories in Qt for Android

I want to include Java source code from multiple directories (which are shared between projects) in a Qt for Android project. On http://imaginativethinking.ca/what-the-heck-how-do-i-share-java-code-between-qt-android-projects/ an approach is described which copies the Java source files:
# This line makes sure my custom manifest file and project specific java code is copied to the android-build folder
ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android
# This is a custom variable which holds the path to my common Java code
# I use the $$system_path() qMake function to make sure that my directory separators are correct for the platform I'm compiling on as you need to use the correct separator in the Make file (i.e. \ for Windows and / for Linux)
commonAndroidFilesPath = $$system_path( $$PWD/../CommonLib/android-sources/src )
# This is a custom variable which holds the path to the src folder in the output directory. That is where they need to go for the ANT script to compile them.
androidBuildOutputDir = $$system_path( $$OUT_PWD/../android-build/src )
# Here is the magic, this is the actual copy command I want to run.
# Make has a platform agnostic copy command macro you can use which substitutes the correct copy command for the platform you are on: $(COPY_DIR)
copyCommonJavaFiles.commands = $(COPY_DIR) $${commonAndroidFilesPath} $${androidBuildOutputDir}
# I tack it on to the 'first' target which exists by default just because I know this will happen before the ANT script gets run.
first.depends = $(first) copyCommonJavaFiles
export(first.depends)
export(copyCommonJavaFiles.commands)
QMAKE_EXTRA_TARGETS += first copyCommonJavaFiles
With later Qt versions the code has to be changed to this:
commonAndroidFilesPath = $$system_path($$PWD/android/src)
androidBuildOutputDir = $$system_path($$OUT_PWD/../android-build)
createCommonJavaFilesDir.commands = $(MKDIR) $${androidBuildOutputDir}
copyCommonJavaFiles.commands = $(COPY_DIR) $${commonAndroidFilesPath} $${androidBuildOutputDir}
first.depends = $(first) createCommonJavaFilesDir copyCommonJavaFiles
export(first.depends)
export(createCommonJavaFilesDir.commands)
export(copyCommonJavaFiles.commands)
QMAKE_EXTRA_TARGETS += first createCommonJavaFilesDir copyCommonJavaFiles
Is this the standard way to go, or is there some built-in functionality for including multiple Java source directories in Qt for Android projects?
Regards,
A much cleaner solution is this one:
CONFIG += file_copies
COPIES += commonJavaFilesCopy
commonJavaFilesCopy.files = $$files($$system_path($$PWD/android/src))
commonJavaFilesCopy.path = $$OUT_PWD/android-build

How to get the right manifest from project with multiple modules? [JAVA]

I want to get to read from the Manifest of my Jar file to get the SVNVersion info from there and show it in the UI.
I work on a multi-module project that includes a client, a server running on tomcat, some modules of the client and its dependencies.
I wrote the code to access the current thread's manifest and get it's attributes.
Manifest mf = new Manifest();
mf.read(Thread.currentThread().getContextClassLoader().getResourceAsStream("META-INF/MANIFEST.MF"));
Attributes atts = mf.getMainAttributes();
System.out.println(atts.values());
System.out.println("Version: " + atts.getClass());
System.out.println("Revision: " + atts.get("SCM-Revision"));
String scm = (String) atts.get("SCM-Revision");
String revision = (String) atts.get("Revision-Number");
return revision + scm;
}
The only thing is that it gets Null values returned because it get's the manifest of a dependency from the local repository that doesn't have the information i need inside of it.
Is there a solution to my problem? to specify a module from the project in a way so it know's to get IT's jar's Manifest and not the one from the dependency?
Thank you!
(I deleted my previous answer because it was buggy and unaccurate)
This is the procedure I used to have to get the proper manifest from any class in the classpath: It consists of getting it through a specific URL:
private static URL getManifestUrlForClass(Class<?> cl)
throws MalformedURLException
{
URL url=cl.getResource(cl.getSimpleName() + ".class");
String s=url.toString();
return new URL(s.substring(0, s.length() - (cl.getName() + ".class").length()) + "META-INF/MANIFEST.MF");
To use it from your code, just replace the first line:
mf.read(getManifestUrlForClass(MyClass.class).openStream());
You get a null because manifests are disabled in maven by default and what you get are values from the Jdk (jar containing the Thread-classfile). You either read
this.getClass().getResourceAsStream("/META-INF/.../pom.properties")
or add the capability to create a manifest (depends on the modul packaging you have to pick the correct build-plugin for that).
Warning: "/META-INF/.../pom.properties" might have the same path in different Jars. Choose the Class first to determin what pom.properties you like to read.

How to set up classpath of JavaCompiler to multiple .jar files using wildcard

I am using JavaCompiler of javax.tools to compile some java code and I am trying to use wildcard in my classpath in order to include all the .jar files but I fail.
Here is my code:
String classpath = "C:\tomcat6\webapps\myapp/WEB-INF/lib/javax.ws.rs-api-2.0-m10.jar;"
+ "C:\\tomcat6\\webapps\\myapp/WEB-INF/lib/javax.persistence-2.1.0.jar";
Iterable<String> options = Arrays.asList("-d", classesBaseDir,
"-classpath", classpath);
JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager,
diagnostics, options, null, file);
boolean result = task.call();
The code above works just fine. But when I am trying to change the classpath to
String classpath = "C:\\tomcat6\\webapps\\myapp/WEB-INF/lib/*";
it fails with
compiler.err.doesnt.exist|package javax.ws.rs does not exist
...
symbol: class GET
location: class com.my.oasis.resources.TestClass
09/04/2014 14:27:09:030 | COMPILER_DIAGNOSTIC | compileResource() - compiler.err.cant.resolve.location|cannot find symbol
...
I have also tried the following alterations
String classpath = "\"C:\\tomcat6\\webapps\\myapp/WEB-INF/lib/*\"";
String classpath = "'C:\\tomcat6\\webapps\\myapp/WEB-INF/lib/*'";
but none of them worked. Any ideas?
Thanks
Note: the reason why the path includes slashes and backslashes is because the my program identifies the environment in runtime and auto completes the path.
Edit: I am using tomcat 6 and java 1.7.0_21
Wildcards: Since Java 1.6 wildcards are supported when using java/javaw/javac, more information: Windows/Solaris and Linux
example:
javac -cp "lib/*" Test.java
This uses all .jar files (not .class!) in the lib directory as classpath. This should not be confused with the *-expansion of your shell. -cp lib/* gets expanded to -cp lib/a.jar lib/b.jar which is not valid argument syntax. In order to avoid this you have to add quotation marks: -cp "lib/*"
The cause of your Problem: You are trying to call the Java compiler from source directly with its Java API. This source code does not contain the wildcard expansion.
The JDK ships with a wrapper binary (javac,javadoc,javah,javap are all the same binary) which does some things and finally calls the compiler task. This wrapper also expands the wildcards in your classpath and therefore the compiler task doesn't have to do this anymore (and it doesn't). See at Compiler Readme section "build -> Notes -> The launcher". Launcher sourcecode.
Solution:
A very poor solution would be to call javac through a Processbuilder. (This is not recommended since it is a complicated and error prone solution for a simple problem)
Expand the wildcards yourself:
example code:
String classpath = buildClassPath("lib/", "test/", "lib/*");
System.out.println(classpath);
// output: lib/;test/;lib/a.jar;lib/b.jar;
This function takes all classpath entries and builds one classpath. Classpath entries with a wildcard in it will get expanded.
/**
* This function builds a classpath from the passed Strings
*
* #param paths classpath elements
* #return returns the complete classpath with wildcards expanded
*/
private static String buildClassPath(String... paths) {
StringBuilder sb = new StringBuilder();
for (String path : paths) {
if (path.endsWith("*")) {
path = path.substring(0, path.length() - 1);
File pathFile = new File(path);
for (File file : pathFile.listFiles()) {
if (file.isFile() && file.getName().endsWith(".jar")) {
sb.append(path);
sb.append(file.getName());
sb.append(System.getProperty("path.separator"));
}
}
} else {
sb.append(path);
sb.append(System.getProperty("path.separator"));
}
}
return sb.toString();
}
Using backslashes or slashes makes no difference. But you obviously assume that the path is auto-globbed (like a normal command line would). This does not happen. So you run your compiler as you would with a command line arg of
-classpath 'C:\\tomcat6\\webapps\\myapp/WEB-INF/lib/*'
which is not what you want. You may look into the API docs for java.io.File.listFiles(FileFilter) or even java.nio.file.Files.walkFileTree(Path, FileVisitor) to gain a better understanding.
To expand a bit on that, when your shell sees C:\tomcat6\webapps\myapp/WEB-INF/lib/* it expands it into a space-separated list of whatever is in your WEB-INF/lib directory. This is called globbing, or since it's done automatically, auto-globbing.
Now Java doesn't do that, but you can build it yourself in a few lines of code:
StringBuilder sb = new StringBuilder();
String[] filenames = new File("C:\\tomcat6\\webapps\\myapp/WEB-INF/lib/").list();
for(int i = 0; i < filenames.length; i++) {
if(i > 0) sb.append(File.pathSeparatorChar); // separate with ':' or ';' on Win
sb.append(filenames[i]); // append the filename
}
Iterable<String> options = Arrays.asList("-d", classesBaseDir, "-cp", sb.toString())
...
Since Java1.7 you can also use Files.newDirectoryStream(Path) instead of list(File). With 1.8 you could even call join instead of joining manually.

Java : Where exactly the Properties would be configured?

Inside my Java class say Props.java File .
I have this static block as shown
static
{
instanceName = System.getProperty("bayer.instanceName");
systemPath = System.getProperty("bayer.home");
if (systemPath == null)
systemPath = ".";
propsFile = new File(System.getProperty("bayer.home") + File.separator + "bayer.properties");
}
Please tell me where this properties , bayer.instanceName and bayer.home would be defined ??
For more information i am using Apache Tomcat 6.0 server and Linux Environment .
System properties are set on the java command line using the -Dpropertyname=value syntax, for example:
java -cp someclasspath -Dbayer.instanceName=foo com.mycompany.MyClass
See this answer for more info.
Another standard location is
$TOMCAT_HOME/bin/setenv.sh
If you don't find them there do a grep bayer.home $TOMCAT_HOME/bin
Another resource to check are the init-scripts which depend on your system. See /etc/init.d.

Class path Error

Some Snippet of my code is shown as below;
String log4jConfigPath = FileUtil.getFilePathFromClasspath("log4j.properties");
if (null != log4jConfigPath) {
PropertyConfigurator.configureAndWatch(log4jConfigPath);
} else {
logger.warn("log4j.properties not found on classpath!");
}
Config config = Config.getConfig("crawler.properties");
String mode = config.getString("crawler.mode").toLowerCase();
I m getting an error for both the files "log4j.properties" and "crawler.properties" not found in class path..i have this files residing in folders in my projects..Can someone please tell me how to add this files to class path compiler looks for both this properties files.
Thanks;
The folder, that contains log4j.properties has to be added to the classpath, either relative to your current working directory or absolute:
/
+-project
+-src
| +-com
| +-example
| +-Hello
+-resource
+-log4j.properties
now, if you current directory is /project, then you have to run your app with
java -cp src;resource com.example.Hello # relative paths
java -cp /project/src;/project/resource com.example.Hello # absolute paths

Categories