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.
Related
guys,I am facing a basic but tricky problem.
Recently I am learning JSP.
As we know the "import" sentence help the java program find the class in system java library or your own file.
Here is an example to illustrate my problem: The imagine have some problem,I will upload it later the day .
Assuming I have App.java in path
$main/com/sub
,in the IDE it will belong to package com.sub;
and I have another useApp.java in path
$main/com
,it will be allocated with the package com.
Now if useApp.java need to import App.class.As my textbook say,the manually way of import the java class is to put the .class file in the subdirectory of the src directory .Then in this way the App.class should be located at
$main/com/com/sub/App.class
It is very werid,isn't it.This is the structure I use first.Now I know organize the different class in this way is terrible.So is there any convention way to organize your own file's dependencay .Should I just configure the .classpath file of the project in general?
I have trying to use .classpath file.Got the useApp.class file set.and try to invoke it in jsp file use
<%# page import="fullclassname"%> And keep getting the error"can not resolve to a type".
Classpath is not as straight simple as it seems like on the first glance. Especially Web applications and apps using plugin mechanisms use different classloaders, which can be confusing.
Classloaders
A good starting point is some reads about classloaders:
https://www.baeldung.com/java-classloaders
This will answer the question how "import will find the file" in an overall Java way.
Debugging Classloading
It you need to "find the file" while debuggin your application you can start your java application with the -verbose option (also in an IDE, normally called launch configuration or similar).
java -verbose HelloWorld
https://www.ibm.com/support/pages/using-java-verbose-option-determine-where-jdbc-driver-classes-are-loading
https://dzone.com/articles/how-use-verbose-options-java
Standardized Project Structure
In addition there's some standards hot to build Java project structures. Maven was one of the early dominators here. So adopting a standard MAVEN project structure might not be a bad idea for a beginner.
https://maven.apache.org/guides/getting-started/maven-in-five-minutes.html
my-app
|-- pom.xml
`-- src
|-- main
| `-- java
| `-- com
| `-- mycompany
| `-- app
| `-- App.java
`-- test
`-- java
`-- com
`-- mycompany
`-- app
`-- AppTest.java
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
I am writing a simple plugin that would make some files visible for other plugins during compilation.
Imagine I have this project structure (this structure is present in quite a few projects I maintain):
/
| -- /src
| |---- /main
| |------ /assembly
| |---------- file1
| |---------- file2
| |---------- fileN
| |------ /java
| |------ /resources
|
| -- pom.xml
I want to avoid having to keep everything under /assembly in each of my projects. I want to store the default files in a separate artifact/file e.g.
/
| -- /src
| |---- /main
| |------ /assembly
| |---------- file1
| |---------- file2
| |---------- fileN
I want my plugin to merge my project with the default files during compilation.
I also need to be able to selectively override the default files, so say I have 200 default files in /assembly but in one project I need to provide different file2, or add a fileN+1.
I think I could try a shade or other merging plugin but the merged project is NOT the end result in my case (plus I want to learn writing plugins).
The point is that I'd plug my plugin into generate-resoruces (or sth), and there is a plugin in the project (bound to package) that expects to find it's configuration in /assembly.
And this is what I want to achieve: provide a default set of files (in arbitrary directories), be able to override them and make the merged result visible to next plugins.
I came to this code:
Artifact artifact = project.dependencyArtifacts.find {
/* find the dependency with boilerplate files */
}
JarFile jar = new JarFile(artifact.file)
jar.entries().each {
/* make the entries visible to other next plugins */
}
And this is where I'm stuck. What should I do with the dependency's files in order to make them visible to next plugins?
"I want my plugin to merge my project with the default files during compilation."
Well, this is the way to go:
It doesn't matter where your file resides.
Just copy them to the expected folder , leaving existing files untouched.
Make your default artifact use a different folder for storing the default files,
so that while unpacking there are somehwere located in your current project.
Specify this artifact as dependecy.
Copy them from there .. fine?
If this doesn't fit:
Provide your own implementation for unpacking artifacts.
I did so when building a maven plugin for C / C++ - artifacts, based on the work of Mark Donszelmann's nar-naven-plugin.
It isn't too hard.
List dependencies = this.getMavenProject().getDependencies();
Iterator<Dependency> it = dependencies.iterator();
String baseDir = this.getLocalRepository().getBasedir();
with
getMavenProject() returning MavenProject and getLocalRepository ArtifactRepository.
From there you can construct the path to your zip (jar), then unpack it with java.util.zip - classes and copy the default files.
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
I've been spending hours trying to figure out why I've been getting the java.lang.NoClassDefFoundError, and I've narrowed down the cause to Tomcat's classpath.
I used the code below to see what the path variables hold:
out.println("Classpath: '" + System.getProperty( "java.class.path" ) + "'" );
out.println("Ext dirs: '" + System.getProperty( "java.ext.dirs" ) + "'" );
out.println("Library path: '" + System.getProperty( "java.library.path" ) + "'" );
out.println("Path separator: '" + System.getProperty( "path.separator" ) + "'" );
And the output is:
Classpath: ':/usr/local/tomcat/bin/bootstrap.jar'
Ext dirs: '/usr/lib/jvm/java-6-sun-1.6.0.16/jre/lib/ext:/usr/java/packages/lib/ext'
Library path: '/usr/lib/jvm/java-6-sun-1.6.0.16/jre/lib/i386/server:/usr/lib/jvm/java-6-sun-1.6.0.16/jre/lib/i386:/usr/lib/jvm/java-6-sun-1.6.0.16/jre/../lib/i386:/usr/java/packages/lib/i386:/lib:/usr/lib'
Path separator: ':'
As you can see, Classpath does NOT start with "." as it's supposed to, and I believe that's why my program can't find the classes that I import from subdirectories in my webapp.
To see where the classpath is set, i did grep -R bootstrap.jar /usr/local/tomcat/, and came accross this: CLASSPATH="$CLASSPATH":"$CATALINA_HOME"/bin/bootstrap.jar (in file /usr/local/tomcat/bin/catalina.sh)
This makes me believe that for some reason $CLASSPATH is empty here. However, echo $CLASSPATH successfully returns .:/usr/lib/jvm/java-6-sun/bin:/usr/local/tomcat/lib/servlet-api.jar
Can anybody help pin down the problem here?
EDIT: All my servlet files are in WEB-INF/classes/controllers/, and the libraries i'm trying to load are class files in subdirectories.
For example, if ClassName.class is in the WEB-INF/classes/controllers/packagename/ directory, I add package packagename to the start of ClassName.java, and I import it using import packagename.* in someServlet.java.
EDIT2: I have solved my problem. My main issue was that, as written below, not using the correct package names. Also, I was trying to compile from inside the classes/controllers/ directory, instead of compiling from classes/. Thank you all for your help!
Classes required in a web application should be located within the web application in the WEB-INF/classes folder or packed in JAR files located in WEB-INF/lib. You should normally not use the servlet containers generic classpath settings for this, as you seem to attempt.
Tomcat's classpath is not supposed to be starting with .. Actually, adding . to the classpath is just a convenient way to tell java to look for classes in the current directory without having to use -cp when using it on the command line.
Actually, in most case, you don't have to tweak Tomcat's classpath. To make Tomcat able to find your classes, what you need to do is to deploy your application as a standardized WAR (web archive) which has a specific layout. Something like that:
.
|-- WEB-INF
| |-- classes
| | `-- com
| | `-- mycompany
| | `-- MyServlet.class
| |-- lib
| | |-- bar.jar
| | `-- foo.jar
| `-- web.xml
|-- application.jsp
|-- image.gif
`-- index.html
The WEB-INF/classes directory is where your compiled classes need to be, this is where Tomcat will look for them. If you place your classes in WEB-INF/classes/controllers, controllers will be considered as part of the package name (which is likely not what you want). So you have two options:
remove that controllers directory
or add it to the package name.
But they are mutually exclusive, you can't have both.
CLASSPATH is not "supposed" to start with ".". Since its purpose is configuration of the runtime, it is free to take on any value you choose. Also note that using the CLASSPATH environment variable has been discouraged since Java 1.1 (released in early 1997)—at least 12 years.
The classpath of a web-application, on the other hand is well-specified. Move the contents of the controllers directory (and any other invalid subdirectories) into WEB-INF/classes/, so that the package directory is an immediate child of classes.