building Java classes from two directories using SCons - java

I have a project that has some android specific code and desktop specific code. Since Java does not have something like #ifdef I place the os specific code in its own directory. something like this
project
+-- common
| +-- src
| +-- com
| +-- example
| +-- common1.java
| +-- common2.java
+-- desktop
| +-- src
| +-- com
| +-- example
| +-- platform.java
+-- android
| +-- src
| +-- com
| +-- example
| +-- platform.java
Depending on which platform the code is being built for the code from desktop or android is included in the build.
however I am having difficulty building this with SCons
example snippet from SCons build script
#target contains the platform we are building on
if target in ['windows', 'linux']:
java_class_out = env.Java(target='classes', source=['desktop/src', 'common/src'])
jar_out = env.Jar(target='myOutput.jar', source=java_class_out);
when run this will look something like the following:
javac -d classes -sourcepath common/src common/src/com/example/common1.java common/src/com/example/common2.java
javac -d classes -sourcepath desktop/src desktop/src/com/example/platform.java
desktop/src/com/example/platform.java:42: error: cannot find symbol
The cannot find symbol error is repeated for every symbol that is in platform that came from common1.java or common2.java
I tried to pass in an array of all of the java files:
Updated snippet from SCons build script.
#target contains the platform we are building on
if target in ['windows', 'linux']:
java_files = ['desktop/src/com/example/platform.java',
'common/src/com/example/common1.java',
'common/src/com/example/common2.java']
java_class_out = env.Java(target='classes', source=java_files)
jar_out = env.Jar(target='myOutput.jar', source=java_class_out);
this results in output similar to this:
javac -d classes -sourcepath common/src/com/example common/src/com/example/common1.java
javac -d classes -sourcepath common/src/com/example common/src/com/example/common2.java
javac -d classes -sourcepath desktop/src desktop/src/com/example/platform.java
desktop/src/com/example/platform.java:42: error: cannot find symbol
What I want SCons to do is output something similar to this:
javac -d classes -sourcepath common/src -sourcepath desktop/src common/src/com/example/common1.java common/src/com/example/common2.java desktop/src/com/example/platform.java
There was a thread on the Scons-users mailing list asking almost this exact question but no solution was given.
Full email chain that I could find with google:
https://pairlist4.pair.net/pipermail/scons-users/2016-February/004609.html
Anyone know how to get Scons to do what I need? Unfortunately I am stuck with SCons for building.

SCons is clever enough to add the source folder for your call to the Java() method as default parameter to the -sourcepath option. But if you simply say
env.Java(target='classes', source=['desktop/src', 'common/src'])
this will internally result in two separate calls, having the effect of:
env.Java(target='classes', source=['desktop/src'])
env.Java(target='classes', source=['common/src'])
. That's why you always just get one path, but not the other with your approach.
Instead, you have to use the provided JAVASOURCEPATH variable (please search our User Guide, there is only one occurrence) to specify the list of folders that should be searched for class or interface definitions.
Either
env.Append(JAVASOURCEPATH=['desktop/src', 'common/src'])
env.Java(target='classes', source=['desktop/src', 'common/src'])
or
env.Java('classes', 'desktop/src', JAVASOURCEPATH=['common/src'])
env.Java('classes', 'common/src', JAVASOURCEPATH=['desktop/src'])
should do the trick. Note, how I omitted the source/target specifiers in the last code snippet for brevity, but explicitly naming the parameters should work too.

Related

How can the Java compiler know were are the packages I create?

I was wondering if there is any way that allow us to import packages in a class using a relative path.
To set an analogy, in html you can use a relative path to set an hyperlink.
For example, given this Files Structure:
Folder: "A"
|
|____________ Folder: "B"
| |
| |
| |
| |_________ File html: "Link.html"
|
|
|
|________ File html: "Index.html"
So, in the file "Link.html" I can set this Hyperlink:
<!DOCTYPE html>
<html>
<head>
<title>Link</title>
</head>
<body>
<main>
<h1>You are in the file "Link"</h1>
<!--This would be the hyperlink-->
Go to Index
</main>
</body>
</html>
My question is:
Could I create a package for example in folder "B" and import the class from that folder "B" in a java file which would be in folder "A"?
I mean without using "classpath" (I don't say without using "sourcepath" too, because I'm not sure about how it works).
Folder: "A"
|
|____________ Folder: "B"
| |
| |
| |
| |_________ File Java: "Example.java"
|
|
|
|________ File Java: "Main.Java"
Moreover, could I set an absolute path in a java file directly to import a package without having to tell the compiler, manually, where the packages are through classpath? (Like in html?)
I mean something like this example but when importing a package in java:
Go to Index
Thanks in advance ;)
I was wondering if there is any way that allow us to import packages in a class using a relative path.
No. Java doesn't support that. Package names are fully qualified when you define them and fully qualified when you use them.
My question is: Could I create a package for example in folder "B" and import the class from that folder "B" in a java file which would be in folder "A"?
For the OpenJDK Java tool chain, and anything else that uses the same class resolution mechanisms1, the folder name structure must map to the package structure. So assuming that the folder above A is the root of your (source or binary) class folder tree, then your Main.java file needs a package declaration
package A;
and your Example.java file needs a package declaration:
package A.B;
(Note that case is significant, and package names A and B are a Java style violation.)
Class Example can import Main and vice versa, but they must use the fully qualified package names to do that; i.e.
import A.Main;
import A.B.Example;
Q: Can you trick the compiler / runtime by having a class / package naming scheme that doesn't correspond to the file / folder structure?
A: No. Either the Java compiler or runtime will fail to find classes or it will detect that there is a mismatch a class's fully qualified and the place where it was found. In both cases you will get an error.
Q: Can you import by file pathname?
A: No. The Java language doesn't permit this. Just ... no.
I mean without using "classpath" (I don't say without using "sourcepath" too, because I'm not sure about how it works).
That doesn't make sense. You cannot "not use" a classpath. If there is no classpath, the Java tools cannot find your code. There is always a classpath ... even if it is just the current directory; i.e. ".".
1 - As far as I am aware, this covers all current practical Java implementations. However, it is technically possible (and permitted by the Java Language Specification) for a Java implementation to use some other mechanism for organizing and locating source code or binary code "entities".
For your first question: Java packages are used to do just that, but the CLASSPATH is still in use. The default class loader will look under the CLASSPATH for classes and expect them to be located based on their package names. (There are other class loaders that have different behaviors, but mostly you will use the default one.)
For your second question: No you cannot. As explained above, the default class loader will look under the CLASSPATH for any class you import, and will try to locate based on the package name of classes. (Again, assuming you use the default class loader.)
Java packages are the standard way of structuring your code, and for most cases this structure is also replicated on the file system (for both source and class files).
I'm answering myself because I don't want to confused anyone else.
As far as I've understood:
The "Relative path" I was looking for were in fact java packages.
As #Fererico-klez-Culloca said, having this example:
Folder: "A"
|
|____________ Folder: "B"
| |
| |
| |
| |_________ File Java: "Example.java"
|
|
|
|________ File Java: "Main.Java"
Main just has to import A.B.Example.
However, there are 2 things that must be considered:
Main has to have "package A", Example.java has to have "package A.B".
Supposing I'm using visual studio, in order to compile it I can't do it opening the folder "a" directly as it will give me an error. As I still have to understand more in depth how this works, I'll quote another person words:
"In Visual Studio, you need the "source folder" to be the folder above a, not a itself, because package names are resolved relative to the source folder. "
A way to resolve this would be creating another folder, so the files schema could be something like this:
Folder: "Project_Folder"
|
|
Folder: "A"
|
|____________ Folder: "B"
| |
| |
| |
| |_________ File Java: "Example.java"
|
|
|
|________ File Java: "Main.Java"
Having that, I have to open the folder (project) in "Project_Folder", so that the compiler can find the folder "a", and identify it as a package.
Although "absolute path" doesn't really exist in java, It's true that "classpath" can act similar to it, nevertheless classpath and "absolute path" (of html) are not exactly the same.

How do I fix a “declared package does not match the expected package” error on VSCode [duplicate]

This question already has answers here:
vs code - Expected java package name error
(5 answers)
Closed 2 years ago.
I have a gradle project:
.
|-- src
| |-- java
| | +-- myproj
| | +-- App.java
| +-- test
|-- build.gradle
+-- ...
and App.java file looks like this:
package myproj;
// ^^^^^^ error message
but VSCode tells me “The declared package "myproj" does not match the expected package "main.java.myproj"”. I know this is related to the file path, but I did not find out how to configure it.
I have installed the Java Extension Pack plug-in, what should I do next?
PS. I don’t want the configuration scheme to be too complicated, I’m just writing a very small program. It is best to be able to complete in setting.json.
Try to add "main" directory between src and java folder to match gradle folders structure.
Source: https://docs.gradle.org/current/userguide/organizing_gradle_projects.html

PythonInterpreter importing java classes

I have the following file structure:
src
|___mod
| |__ __init__.py
| |__ pycode.py
| |__ javacode.java
|
|___main
|__ start.java
contents of pycode.py:
from mod import javacode as jv
...
Inside start.java, I try to run pycode.py with the python interpreter.
PythonInterpreter py = new PythonInterpreter();
py.exec("from mod.pycode import *");
However, I get the following error:
ImportError: cannot import name javacode
It's confusing because it seems to be able to find the package, but for some reason fails to find the file. I have infact verified that it found the package because it complains if you supply the wrong package name.
To give more information, I am running the program on windows in eclipse. I am using the pydev plugin for eclipse. I have added the bin folder of the project as a source folder for pydev (as suggested by one source), and I have the following at the start of my program:
static {
PythonInterpreter.initialize(System.getProperties(), PySystemState.getBaseProperties(),
null);
}
Can anyone give me an idea on how I can fix this?
The reason why it was not working is because I placed javacode.java in a python package.
According to the book Jython Essentials, doing this will mark the java file as a python module:
Jython also allows access to Java classes and packages through the import statements. Jython is able to load classes through the underlying Java Virtual Machine (JVM), both from the Java classpath and from the directories in sys.path. Conceptually, you can think that for the purpose of loading Java classes, the directories in sys.path have been appended to the classpath. This means there is no need to mark Java packages on sys.path with __init__.py modules, because that would make them Python packages.
So after this, I organized the files as such:
src
|___pymodules
| |__ __init__.py
| |__ pycode.py
|
|___mod
| |__ javacode.java
|
|___main
|__ start.java
Inside start.java:
PythonInterpreter py = new PythonInterpreter();
py.exec("from pymodules.pycode import *");
The program now executes perfectly both in eclipse and even after making it into a standalone jar

How to compile and run with this folder structure

I have my java source files in src/net/... folders and .jar files in lib folder. How to compile and run this files with command line without writing build script ?
Lets say you have your code files in
[someDirectory]
|
+-[lib]
| |
| +-someLib.jar
| +-someOtherLib.jar
| +-...
|
+--[src]
|
+-[net]
|
+-[name]
|
+-[one]
|
+-[two]
|
+-[main]
|
+-Main.java <- code you want to compile
and execute
then if your console is in
someDirectory>
you can compile it with
someDirectory>javac -cp "lib\*" src\net\name\one\two\main\Main.java
but this will produce Main.class file in same directory as Main.java so to execute code from net.name.one.two.main.Main class you would need to include src directory to classPath because this directory contains package that Main class is placed, so you would need to use command
someDirectory>java -cp "src;lib\*" net.name.one.two.main.Main
But it is good practice to separate class files from source files. To do this you can add -d (directory) parameter while compiling pass directory which should have compiled class files. So first create your classes directory at the same level as src directory and execute
someDirectory>javac -d "classes" -cp "lib\*" src\net\name\one\two\main\Main.java
and now to be able to execute your Main class instead creating confusion by src directory to classPath you will have to add classes directory which is more intuitive.
someDirectory>java -cp "classes;lib\*" net.name.one.two.main.Main.java
Try this
javac -cp .;lib/lib1.jar;lib/lib2.jar src/net/*.java
lib1 and lib2 are your libraries. It assume your libraries are in lib folder. You may also need to change the destination folder for .class files.
To run the application use
java -cp bin;lib/lib1.jar;lib/lib2.jar net.mypackage.MyMainclass
net...
It assume your .class files are in bin folder.

How to use a class from a parent directory in Java?

For example, I have a class called Foo inside Foo.java which will use a class called Bar inside ../Bar.java. Is there any way to make that work when I do javac Foo.java?
Add your class to classpath..
javac -cp "path to your Bar.class" Foo.java
You will need to import that class in your Foo.java also.. Better use a package, and give the classpath till the directory containing your package..That way you will be able to give different namespaces to your classes..
So, if your package is: - pkg1.pkg2.Barand you have saved your .java to a directory named Demo, then your classpath should contain path till Demo.. And your classes will actually be under two more directory pkg1/pkg2/Bar.class inside Demo directory..
Demo+
|
+-- B.java (`Under package pkg1.pkg2)
|
+--pkg1+
| |
| +--pkg2+
| |
| +-- B.class
|
+-- A.java (`Under no package`) - Add - import pkg1.pkg2.B
|
+-- A.class (javac -cp . A.java) - Will search the package pkg1.pkg2 in current directory
Even though . is not needed there, you can replace it with any path, if your B.class is somewhere else..
Assuming these are both your classes and belong to the same module, you should be using packages and both classes should exist in the same package hierarchy. Then it would work automatically.
Packages would be something like com.company.application.module.Bar and com.company.application.module.subcomponent.Foo, for example. See more discussion on correct package naming:
Oracle.com: naming packages
wikipedia: package naming conventions
You can also do javac -sourcepath path/to/src/solution/java;path/to/src/test/java to point to several locations explicitly (note that -classpath will also work, see this discussion about the differences).
If we're talking about separate components that don't exist in the same module, you'd just use classpath to make the code aware of both (or preferrably some dependency mechanism like Maven that works out the stuff under the hood).
Your classes have packages, which are mirrored in the directory structure. E.g. com/company/pk/Foo and com/company/Bar - then you can reference them using the import statement. If your classes are in different directories but don't declare a package, then you are doing it wrong.
Read about packages

Categories