How can I import file from outside of package?
example:
// this is a.java
package user.code.gui;
void method_a(){
// do something
}
and
// this is b.java
package user.code;
void method_b(){
// do something
}
and
// this is c.java
package user.extensions;
void method_c(){
// do something
}
If I use "import c" in file a.java, it can't find this file because it's in a different package. The problem is, how can I import file c.java in file a.java?
You need the other package to be there during compilation, and also during runtime; these are different things, but they both have the concept of a classpath.
Java always looks for things by translating type names to dir names; package a.b; class Foo {} is looked for in /a/b/Foo.class.
It scans each entry in the classpath for that. Classpath entries can be either directories, or jar files.
Build systems (maven, gradle, etc) and IDEs (eclipse, intellij, etc) - make this easily configurable and in general take care of it for you. You should use these tools; 99% of all java projects are compiled by IDEs and/or build tools.
Once you start having multiple packages, javac becomes unwieldy.
But, if you must use the command line for it:
Your directory structure:
/Users/Cflowe/workspace/MyAwesomeProject/src/user/code/gui/GuiClass.java
/Users/Cflowe/workspace/MyAwesomeProject/src/user/code/Whatever.java
and so on. To compile:
cd /Users/Cflowe/workspace/MyAwesomeProject
mkdir bin
javac -sourcepath src -d bin src/user/code/Whatever.java src/user/code/gui/GuiClass.java andSpecifyEveryOtherFileByHandHere
java -cp bin com.foo.Main
Related
I'm trying to import Bar.java into Foo.java, where my directory is structured like this:
.
└─bar
└─Bar.java
└─foo
└─Foo.java
So I create Bar.java:
package bar;
public class Bar {}
and Foo.java:
import bar.Bar;
public class Foo {}
I run javac from the foo directory:
javac Foo.java -cp ../bar
and receive the error:
Foo.java:1: error: package bar does not exist
My understanding was that the -cp option should be used to point towards the required class (Bar.java). Could someone shed some light on what I'm doing wrong?
Package bar does not exist because the prompt or terminal "working directory" is inside foo.
Easiest, make a folder java2 and put both folders in it and use use the storage folder as "system working directory" for terminal or prompt,
However, normal "package" hierarchies compiled together are both in a top level starting directory tree.
E.g.
/com/foo/ and /com/bar
So your package would look com.foo and com.bar
Put the com folder in the java2(simply a name you can use any name for the storage folder)folder.
Your import statement at the top of the class files should have the com directory added to import the other file.
Just command inside java2 folder
javac /com/foo/Foo.java
-cp is for specifying to include dependent .jar libraries for the compilation.
If Foo does not import Bar then it will be required to be separately compiled the same way as Foo.
When framework API libraries are made its the user program requires to mark a starting point to unload the jar or look for a package folder and is traditionally "com", however, it does not distinguish which API until a folder lower so your package folder really should be structured
/com/mypersonalapi/foo
/com/mypersonalapi/bar
com.mypersonalapi.foo
com.mypersonalapi.bar
You need to give like this:
javac Foo.java -cp ..
When you give classpath as shown in your question, it expects the package "bar" under the folder "bar"; which is not intended.
I'm a C++ developer - not a java developer, but have to get this code working...
I have 2 public classes that will be used by another product. I used the package directive in each of the java files.
package com.company.thing;
class MyClass ...
When I try to compile a test app that uses that I add
import com.company.thing.*;
The javac compiler fails with errors about com.company does not exist. (even if I compile it in the same directory as the class files I just made a package of)
I am sure I am doing something bone-headed and silly.
I've read the http://java.sun.com/docs/books/tutorial/java/package/usepkgs.html pages and tried to set up a directory structure like /com/company/thing etc, but either I have totally screwed it all up or am missing something else.
EDIT
thanks for the suggestions - I had tried the classpath previously. It does not help.
I tried compiling
javac -classpath <parent> client.java
and the result is:
package com.company does not exist
I have the code I want to import (the two java files) in \com\company\product. I compile those fine. (they contain MyClass) I even made a jar file for them. I copied the jar file up to the parent directory.
I then did (in the parent directory with the client java file)
javac -cp <jarfile> *.java
the result is:
cannot access MyClass
bad class file: MyClass.class(:MyClass.class)
class file contains wrong class: com.company.product.MyClass
Please remove or make sure it appears in the correct subdirectory of the classpath.
EDIT
I got the client code to compile and run if I used the fully qualified name for MyClass and compiled it in the parent directory. I am totally confused now.
compiled with no classpath set - just
javac *.java
in the parent directory - and it worked fine.
I can get a test app to compile, but that is not going to cut it when i have to integrate it into the production code. Still looking for help.
EDIT:
Finally - not sure why it didn't work before - but I cleaned up all the files all over the directory structure and now it works.
Thanks
Okay, just to clarify things that have already been posted.
You should have the directory com, containing the directory company, containing the directory example, containing the file MyClass.java.
From the folder containing com, run:
$ javac com\company\example\MyClass.java
Then:
$ java com.company.example.MyClass
Hello from MyClass!
These must both be done from the root of the source tree. Otherwise, javac and java won't be able to find any other packages (in fact, java wouldn't even be able to run MyClass).
A short example
I created the folders "testpackage" and "testpackage2". Inside testpackage, I created TestPackageClass.java containing the following code:
package testpackage;
import testpackage2.MyClass;
public class TestPackageClass {
public static void main(String[] args) {
System.out.println("Hello from testpackage.TestPackageClass!");
System.out.println("Now accessing " + MyClass.NAME);
}
}
Inside testpackage2, I created MyClass.java containing the following code:
package testpackage2;
public class MyClass {
public static String NAME = "testpackage2.MyClass";
}
From the directory containing the two new folders, I ran:
C:\examples>javac testpackage\*.java
C:\examples>javac testpackage2\*.java
Then:
C:\examples>java testpackage.TestPackageClass
Hello from testpackage.TestPackageClass!
Now accessing testpackage2.MyClass
Does that make things any clearer?
Yes, this is a classpath issue. You need to tell the compiler and runtime that the directory where your .class files live is part of the CLASSPATH. The directory that you need to add is the parent of the "com" directory at the start of your package structure.
You do this using the -classpath argument for both javac.exe and java.exe.
Should also ask how the 3rd party classes you're using are packaged. If they're in a JAR, and I'd recommend that you have them in one, you add the .jar file to the classpath:
java -classpath .;company.jar foo.bar.baz.YourClass
Google for "Java classpath". It'll find links like this.
One more thing: "import" isn't loading classes. All it does it save you typing. When you include an import statement, you don't have to use the fully-resolved class name in your code - you can type "Foo" instead of "com.company.thing.Foo". That's all it's doing.
It sounds like you are on the right track with your directory structure. When you compile the dependent code, specify the -classpath argument of javac. Use the parent directory of the com directory, where com, in turn, contains company/thing/YourClass.class
So, when you do this:
javac -classpath <parent> client.java
The <parent> should be referring to the parent of com. If you are in com, it would be ../.
You got a bunch of good answers, so I'll just throw out a suggestion. If you are going to be working on this project for more than 2 days, download eclipse or netbeans and build your project in there.
If you are not normally a java programmer, then the help it will give you will be invaluable.
It's not worth the 1/2 hour download/install if you are only spending 2 hours on it.
Both have hotkeys/menu items to "Fix imports", with this you should never have to worry about imports again.
The standard Java classloader is a stickler for directory structure. Each entry in the classpath is a directory or jar file (or zip file, really), which it then searches for the given class file. For example, if your classpath is ".;my.jar", it will search for com.example.Foo in the following locations:
./com/example/
my.jar:/com/example/
That is, it will look in the subdirectory that has the 'modified name' of the package, where '.' is replaced with the file separator.
Also, it is noteworthy that you cannot nest .jar files.
Just add classpath entry ( I mean your parent directory location) under System Variables and User Variables menu ...
Follow : Right Click My Computer>Properties>Advanced>Environment Variables
Java and Gradle beginner's question.
I made a project directory for java and gradle test:
The directory hierarchy :
HelloWorld.java:
package foo.bar;
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, world");
}
}
build.gradle:
apply plugin:'java'
Then,gradle build this project and generated what i need.
As you see above, my problem is why doesn't this execute correctly? Even through I cd to .class path.
======================================================================
While, if I remove package foo.bar; in HelloWorld.java, and repeat gradle commands and execute at he.bak directory then the error remained the same.
But when I cd to the directory where HelloWorld.java placed. everything goes OK!Why? something related with CLASSPATH environment variables or other causes?
////////////////////////////////////////////////////////////////////
UPDATE
////////////////////////////////////////////////////////////////////
Thought you guys' warm replies, I know that I should combine the CLASSPATH and the period-separated executable .class file to figure out what's going on when executing java class file.
I experiment my thought resulting in 2 point to this question:
The -cp option path parameter A/B plus the executable file c.d.e.class finally form the A/B/c.d.e.class full path where the class is actually located.
If I specify the package in source code file with package d,I must split the full path in the form of java -cp A/B/c/d e.class. split in other ways all will result in errors.
something I am not sure here is :
When I specify my package path in my source code file, It determined the only classpath when executing corresponding executable, right?
If it is the truth, How does a project with lots of package and sources files work?
What's the root principle?
When in build/classes/main try java foo.bar.HelloWorld instead of java HelloWorld
The reason you need to specify foo.bar.HelloWorld is because you specified package foo.bar;. This tells java that the class should be in foo/bar/HelloWorld and the fully qualified name for HelloWorld is foo.bar.HelloWorld. If you want to execute the class from a different working directory however, you can specify the classpath explicitly using the -cp option, e.g., java -cp c:\myproject\build\classes\main foo.bar.HelloWorld.
By the way, the classpath default is the current working directory (i.e., .) but java -cp c:\myproject\build\classes\main foo.bar.HelloWorld will NOT have the classpath set to the current working directory if it is explicitly set using the -cp option. If you want to include the current working directory but explicitly set it, or even add more directories, you can chain them using semicolons like this: java -cp .;c:\myproject\build\classes\main foo.bar.HelloWorld. So this will include both the current working directory and the directory I specified.
I am an experienced programmer, but haven't used Java in years - mostly C# - and used an IDE in the past. I'm trying to compile some code from the command line on my Mac, but can't get my test file to find my source code. I'm assuming the problem lies somewhere in the space of packages, file structure, classpaths, and import statements - but I've put a couple hours in (including hunting on Stack Overflow) and am still stuck.
Here's what I have:
Directory structure:
ProjectName
|
--src
|
--SourceClass
--test
|
--SourceClassTest
--external
|
--testng-6.8.7.jar
My SourceClass looks like this:
package ProjectName;
public class SourceClass<T>{
}
Very simple. Obviously, there will be more - but I wanted to start with making sure I had all this setup stuff correct before I actually did coding.
My test class looks like this:
package ProjectName;
import java.util.*;
import org.testng.Assert;
import org.testng.annotations.*;
public class SourceClassTest{
#Test
private void createEmptySourceClass(){
SourceClass<Object> sourceClass = new SourceClass<Object>();
Assert.assertTrue(sourceClass.isEmtpy());
}
}
The sourceClass compiles with no issue with "javac src/*.java", run from the "ProjectName" directory. I want to see this fail with an error along the lines of "SourceClass doesn't have an isEmpty() method", but instead I run javac like this from the "ProjectName" directory:
javac test/*.java -classpath external/testng-6.8.7.jar
and get this exception:
test/SourceClassTest.java:12: error: cannot find symbol
SourceClass<Object> tree = new SourceClass<Object>();
^
symbol: class SourceClass
location: class SourceClassTest
test/SourceClassTest.java:12: error: cannot find symbol
SourceClass<Object> sourceClass = new SourceClass<Object>();
^
symbol: class SourceClass
location: class SourceClassTest
2 errors
I've tried a lot of things -adding an import statement, adding a sourcepath to the javac command, compiing the sourceClass as a jar and putting it in the bin directory then adding that to the classpath, but I can't get the test to find the SourceClass symbols.
Any idea what I am missing here?
It works if you compile into a separate target directory. E.g,
mkdir target
javac -d target/ src/*.java
javac -classpath target/ test/*.java
When you do javac src/*.java, it will create the .class file in the src directory itself. By default, any classes you reference are assumed to be in the same package. So even if you add src/ to the classpath, it looks for src/ProjectName/SourceClass.class, which it does not find. When you pass the -d target/ option, it creates the proper package hierarchy, so and finds the class.
Relevant documentation from the javac official doc:
You should arrange source files in a directory tree that reflects
their package tree. For example, if you keep all your source files in
C:\workspace, the source code for com.mysoft.mypack.MyClass should be
in C:\workspace\com\mysoft\mypack\MyClass.java.
By default, the compiler puts each class file in the same directory as
its source file. You can specify a separate destination directory with
-d (see Options, below).
...
...
-d directory Set the destination directory for class files. The directory must already exist; javac will not create it. If a class is
part of a package, javac puts the class file in a subdirectory
reflecting the package name, creating directories as needed. For
example, if you specify -d C:\myclasses and the class is called
com.mypackage.MyClass, then the class file is called
C:\myclasses\com\mypackage\MyClass.class. If -d is not specified,
javac puts each class files in the same directory as the source file
from which it was generated.
Note: The directory specified by -d is not automatically added to your
user class path.
My guess is it can't find SourceClass because the file defining that class is under src, and you didn't mention that directory in your javac command line.
If I were you, I would change the file hierarchy to this:
ProjectName/src/ProjectName/SourceClass.java
ProjectName/src/ProjectName/SourceClassTest.java
ProjectName/external/testng-6.8.7.jar
Then run javac src/ProjectName/*.java -classpath external/testng-6.8.7.jar.
Or keep the file hierarchy the way it is, and run javac src/*.java test/*.java -classpath external/testng-6.8.7.jar
The accepted answer is correct, but it misses one critical point: when javac is asked to compile *.java (as opposed to foo.java, and then foo2.java ...) it treats them as a single package and accepts references between them.
That's the magic. Other languages do this less implicitly with header files.
Even after reading this post, it took me some time to figure that out, against my inherent assumption that a program running singly on files one after the other would (should) produce the same result as running that program on a group of files. My bad; the * is NOT a mere convenience, but critical.
I'm new to working with Java from the command line and I don't get it. I read previous CLASSPATH questions but still didn't get my problem to work.
I have the following class in C:\Temp\a\b\c
package a.b.c;
public class Hello
{
public static void main(String args[])
{
System.out.println("Hello World!");
}
}
The package name is intentional.
I compiled it fine and I put the Hello.class file inside C:\Temp\a\target
Now in the command line I go to C:\Temp\ and execute the following:
java -cp .\a\target a.b.c.Hello
It complains that it cannot find the class a.b.c.Hello
Thanks in advance!!
and I put the Hello.class file inside C:\Temp\a\target
This is wrong. It should be placed in the same folder as the .java file. The source code itself is declared to be in the package a.b.c; so, the .class file should really be kept in \a\b\c folder.
Then, to execute it just do:
C:\Temp>java -cp . a.b.c.Hello
Avoid "putting" the classfiles anywhere. The following should work:
javac -d c:\temp c:\temp\a\b\c\Hello.java
# creates Hello.class in c:\temp\a\b\c
java -cp c:\temp a.b.c.Hello
To expand on BalusC's point: the classpath defines a "root". When java is looking for your classes, it will start at each root (or jar) in your class path and drill down through the directories to match the package strucutre. You still need to have you class in a directory structure that matches its package name. In your case, to execute
java -cp .\a\target a.b.c.Hello
you would move the file to
.\a\target\a\b\c\Hello.class
Years ago, I too found this baffling.
Java will try to search for a directory structure a\b\c from starting in target and as you notice, it wont work.
Move the whole directory into target and you'll be fine, it should look like:
C:\Temp\a\target\a\b\c\Hello.class
You may compile it with the -d option which tall the compiler where to put the class file.
Many project structures are like this.
C:\whatever\projectname\src
C:\whatever\projectname\classes
C:\whatever\projectname\bin
C:\whatever\projectname\lib
C:\whatever\projectname\doc
That way you can always step on your project directory and type:
javac -d classes src\*.java
Which will compile all the sources in the src directory and will place them in the classes directory.
Then execute your program:
java -cp classes a.b.c.Hello
You may optionally place required jars in lib
This works pretty fine for small programs ( < 10 src files and 2 - 3 jar libraries ) If it grows beyond that, you could probably use an IDE or ant
The good thing about following this project structure is that some IDES ( as IntellJ idea ) just pick them very easily when you create a new project. You select "Create project from existing sources" and then you can continue from there.
I like compiling and editing at the command line a lot!!