📜 ⬆️ ⬇️

Working with Java on the command line

Now no one creates a program in the console. Using your favorite IDE, the developer feels uncomfortable behind someone else's computer, where there is none.
Having decided to understand the work of Ant and Maven, I caught myself not being able to build an application without them in the console.
In this article, I tried to fit all the stages of designing a demo application, so as not to look for help on each team on the Internet.

From simple to ...


Each program is usually contained in a separate directory. I adhere to the rule to create at least two folders in this directory: src and bin. The first contains the source code, the second - the result of compilation. These folders will have a directory structure dependent on the packages.

One file


Can be done without unnecessary folders.
Take the file HelloWorld.java.
public class HelloWorld { public static void main(String[] args) { System.out.println("Hello World!"); } } 

Go to the directory where this file is located, and execute the commands.
 javac HelloWorld.java 
The HelloWorld.class file will appear in this folder. So the program is compiled. To start it
 java -classpath . HelloWorld 

Separate binary files from sources


Now we will do the same, but with directories. Create a directory HelloWorld and in it two folders src and bin.
Compile
 javac -d bin src/HelloWorld.java 
Here we have indicated that binary files will be saved in a separate bin folder and not be confused with source codes.

Run
 java -classpath ./bin HelloWorld 

We use packages


And then, suddenly, the program will cease to be just HelloWorld. Packages are better to give a clear and unique name. This will allow the program to be added to another project without a name conflict. After reading some articles, you might think that the name of the package necessarily need a domain. This is not true. Domains are a convenient way to achieve uniqueness. If your domain is not, use your account on the site (for example, ru.habrahabr.mylogin). It will be unique. Note that package names must be lowercase. And avoid using special characters. Problems arise because of different platforms and file systems.
')
Let's put our class in a package called com.qwertovsky.helloworld. To do this, add to the beginning of the file line
 package com.qwertovsky.helloworld; 
Create additional directories in the src directory so that the path to the file looks like this: src / com / qwertovsky / helloworld / HelloWorld.java.
Compile
 javac -d bin src/com/qwertovsky/helloworld/HelloWorld.java 
In the bin directory, a directory structure will automatically be created as in src.
  HelloWorld '---bin ' '---com ' '---qwertovsky ' '---helloworld ' '---HelloWorld.class '---src '---com '---qwertovsky '---helloworld '---HelloWorld.java 

Run
 java -classpath ./bin com.qwertovsky.helloworld.HelloWorld 

If the program has several files


Change the program.

HelloWorld.java
 package com.qwertovsky.helloworld; public class HelloWorld { public static void main(String[] args) { int a=2; int b=3; Calculator calc=new Calculator(); System.out.println("Hello World!"); System.out.println(a+"+"+b+"="+calc.sum(a,b)); } } 

Calculator.java
 package com.qwertovsky.helloworld; import com.qwertovsky.helloworld.operation.Adder; public class Calculator { public int sum(int... a) { Adder adder=new Adder(); for(int i:a) { adder.add(i); } return adder.getSum(); } } 

Adder.java
 package com.qwertovsky.helloworld.operation; public class Adder { private int sum; public Adder() { sum=0; } public Adder(int a) { this.sum=a; } public void add(int b) { sum+=b; } public int getSum() { return sum; } } 

Compile
 javac -d bin src/com/qwertovsky/helloworld/HelloWorld.java src\com\qwertovsky\helloworld\HelloWorld.java:9: cannot find symbol symbol : class Calculator location: class com.qwertovsky.helloworld.HelloWorld Calculator calc=new Calculator(); ^ src\com\qwertovsky\helloworld\HelloWorld.java:9: cannot find symbol symbol : class Calculator location: class com.qwertovsky.helloworld.HelloWorld Calculator calc=new Calculator(); ^ 2 errors 

The error occurred due to the fact that for compilation you need files with source codes of classes that are used (class Calculator). It is necessary to indicate to the compiler a directory with files using the -sourcepath switch.
Compile
 javac -sourcepath ./src -d bin src/com/qwertovsky/helloworld/HelloWorld.java 

Run
 java -classpath ./bin com.qwertovsky.helloworld.HelloWorld Hello Word 2+3=5 

If the result is surprising


It is possible to run the debugger. There is a jdb for this.
We first compile with the -g key so that the debugger has information.
 javac -g -sourcepath ./src -d bin src/com/qwertovsky/helloworld/HelloWorld.java 

Run the debugger
 jdb -classpath bin -sourcepath src com.qwertovsky.helloworld.HelloWorld Initializing jdb ... > 

The debugger runs its internal terminal to enter commands. Help on the latter can be displayed using the help command.
Set the breakpoint on line 9 in the class Calculator
 > stop at com.qwertovsky.helloworld.Calculator:9 Deferring breakpoint com.qwertovsky.helloworld.Calculator:9. It will be set after the class is loaded. 

We start on performance.
 > run run com.qwertovsky.helloworld.HelloWorld Set uncaught java.lang.Throwable Set deferred uncaught java.lang.Throwable > VM Started: Set deferred breakpoint com.qwertovsky.helloworld.Calculator:9 Hello World! Breakpoint hit: "thread=main", com.qwertovsky.helloworld.Calculator.sum(), line=9 bci=0 9 Adder adder=new Adder(); 

To navigate, you can display a piece of source code where the cursor is currently located.
 main[1] list 5 public class Calculator 6 { 7 public int sum(int... a) 8 { 9 => Adder adder=new Adder(); 10 for(int i:a) 11 { 12 adder.add(i); 13 } 14 return adder.getSum(); 

We learn what a variable is.
 main[1] print a a = instance of int[2] (id=340) main[1] dump a a = { 2, 3 } main[1] stop at com.qwertovsky.helloworld.operation.Adder:19 Deferring breakpoint com.qwertovsky.helloworld.operation.Adder:19. It will be set after the class is loaded. 

We continue the execution.
 main[1] cont > Set deferred breakpoint com.qwertovsky.helloworld.operation.Adder:19 Breakpoint hit: "thread=main", com.qwertovsky.helloworld.operation.Adder.add(), line=19 bci=0 19 sum+=b; main[1] list 15 } 16 17 public void add(int b) 18 { 19 => sum+=b; 20 } 21 22 public int getSum() 23 { 24 return sum; main[1] print sum sum = 0 main[1] print b b = 2 

Run the code in the current line and see that the sum has become equal to 2.
 main[1] step > Step completed: "thread=main", com.qwertovsky.helloworld.operation.Adder.add(), line=20 bci=10 20 } main[1] print sum sum = 2 

We rise from the class Adder to the class Calculator that caused it.
 main[1] step up > Step completed: "thread=main", com.qwertovsky.helloworld.Calculator.sum(), line=10 bci=36 10 for(int i:a) 

Remove the breakpoint
 main[1] clear com.qwertovsky.helloworld.operation.Adder:19 Removed: breakpoint com.qwertovsky.helloworld.operation.Adder:19 main[1] step > Step completed: "thread=main", com.qwertovsky.helloworld.Calculator.sum(), line=12 bci=30 12 adder.add(i); 

You can avoid calling methods using the next command.
 main[1] next > Step completed: "thread=main", com.qwertovsky.helloworld.Calculator.sum(), line=10 bci=36 10 for(int i:a) main[1] next > Step completed: "thread=main", com.qwertovsky.helloworld.Calculator.sum(), line=14 bci=42 14 return adder.getSum(); 

Check the value of the expression and complete the execution.
 main[1] eval adder.getSum() adder.getSum() = 5 main[1] cont > 2+3=5 The application exited 

It would be nice to test


We use JUnit.
 package com.qwertovsky.helloworld; import static org.junit.Assert.*; import java.util.Arrays; import java.util.Collection; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized.Parameters; @RunWith(value=org.junit.runners.Parameterized.class) public class TestCalculator { int expected; int[] arg; @Parameters public static Collection<int[][]> parameters() { return Arrays.asList(new int[][][]{ {{4}, {2, 2}} ,{{-1},{4, -5}} ,{{0},{0,0,0}} ,{{0},{}} }); } public TestCalculator(int[] expected, int[] arg) { this.expected=expected[0]; this.arg=arg; } @Test public void testSum() { Calculator c=new Calculator(); assertEquals(expected,c.sum(arg)); } } 

Compile
 mkdir test_bin javac -classpath lib/path/junit-4.8.2.jar -sourcepath ./src -d test_bin test/com/qwertovsky/helloworld/TestCalculator.java 

We start. In Windows, the ';' is used as a separator for multiple paths in the classpath, and ':' in Linux. Both separators do not work in the Cygwin console. Perhaps it should work ';', but it is perceived as a command separator.
 java -classpath lib/path/junit-4.8.2.jar:./test_bin org.junit.runner.JUnitCore com.qwertovsky.helloworld.TestCalculator JUnit version 4.8.2 .... Time: 0,031 OK (4 tests) 

Create a library


The Calculator class has proven useful and can be used in many projects. Let's transfer everything that concerns the class Calculator to a separate project.
  HelloWorld '---bin '---src '---com '---qwertovsky '---helloworld '---HelloWorld.java alculator '---bin '---src ' '---com ' '---qwertovsky ' '---calculator ' '---Calculator.java ' '---operation ' '---Adder.java '---test '---com '---qwertovsky '---calculator '---TestCalculator.java 

Also change the naming of packages in the source code. Add a line to HelloWorld.java
 import com.qwertovsky.calculator.Calculator; 

Compile.
 cd Calculator javac -sourcepath src -d bin src/com/qwertovsky/calculator/Calculator.java 

Making the archive jar
 jar cvf calculator.jar -C bin . added manifest adding: com/(in = 0) (out= 0)(stored 0%) adding: com/qwertovsky/(in = 0) (out= 0)(stored 0%) adding: com/qwertovsky/calculator/(in = 0) (out= 0)(stored 0%) adding: com/qwertovsky/calculator/Calculator.class(in = 497) (out= 373)(deflated 24%) adding: com/qwertovsky/calculator/operation/(in = 0) (out= 0)(stored 0%) adding: com/qwertovsky/calculator/operation/Adder.class(in = 441) (out= 299)(deflated 32%) 

Using the -C switch, we run the program in the bin directory.

We need to know that the library inside


You can unzip the archive with a zip-unpacker and see what classes are in the library.
Information about any class can be obtained using javap disassembler.
 javap -c -classpath calculator.jar com.qwertovsky.calculator.Calculator Compiled from "Calculator.java" public class com.qwertovsky.calculator.Calculator extends java.lang.Object{ public com.qwertovsky.calculator.Calculator(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return public int sum(int[]); Code: 0: new #2; //class com/qwertovsky/calculator/operation/Adder 3: dup 4: invokespecial #3; //Method com/qwertovsky/calculator/operation/Adder."<init>":()V 7: astore_2 8: aload_1 9: astore_3 10: aload_3 11: arraylength 12: istore 4 14: iconst_0 15: istore 5 17: iload 5 19: iload 4 21: if_icmpge 42 24: aload_3 25: iload 5 27: iaload 28: istore 6 30: aload_2 31: iload 6 33: invokevirtual #4; //Method com/qwertovsky/calculator/operation/Adder.add:(I)V 36: iinc 5, 1 39: goto 17 42: aload_2 43: invokevirtual #5; //Method com/qwertovsky/calculator/operation/Adder.getSum:()I 46: ireturn } 

The result shows that the class contains in addition to the empty constructor, another sum method, inside which the add method of the Adder class is called in a loop. When the sum method is complete, Adder.getSum () is called.
Without the -c switch, the program will display only a list of variables and methods (if you use -private, then all).
 javap -private -classpath calculator.jar com.qwertovsky.calculator.operation.Adder Compiled from "Adder.java" public class com.qwertovsky.calculator.operation.Adder extends java.lang.Object{ private int sum; public com.qwertovsky.calculator.operation.Adder(); public com.qwertovsky.calculator.operation.Adder(int); public void add(int); public int getSum(); } 

It is better to provide the library with documentation.


Let's change the calculator class for this.
 package com.qwertovsky.calculator; import com.qwertovsky.calculator.operation.Adder; /** * ,    * @author Qwertovsky * */ public class Calculator { /** *    * @param a   * @return  */ public int sum(int... a) { Adder adder=new Adder(); for(int i:a) { adder.add(i); } return adder.getSum(); } } 

Documentation can be created with the following command. If an error occurs, the program will display a list of possible options.
 mkdir doc javadoc -d doc -charset utf-8 -sourcepath src -author -subpackages com.qwertovsky.calculator 

The result is the following.
image

You can sign the jar-archive


If you want to digitally sign your library, keytool and jarsigner come to the rescue.
We generate the signature.
 keytool -genkey -keyalg rsa -keysize 2048 -alias qwertokey -keystore path/to/qwerto.keystore Enter keystore password: Re-enter new password: What is your first and last name? [Unknown]: Valery Qwertovsky What is the name of your organizational unit? [Unknown]: Qwertovsky What is the name of your organization? [Unknown]: Qwertovsky What is the name of your City or Locality? [Unknown]: Tver What is the name of your State or Province? [Unknown]: Tverskaya obl. What is the two-letter country code for this unit? [Unknown]: RU Is CN=Valery Qwertovsky, OU=Qwertovsky, O=Qwertovsky, L=Tver, ST=Tverskaya obl., C=RU correct? [no]: y Enter key password for <qwertokey> (RETURN if same as keystore password): Re-enter new password: 

We generate Certificate Signing Request (CSR)
 keytool -certreq -file path/to/qwertokey.crt -alias qwertokey -keystore path/to/qwerto.keystore 

The contents of the file are sent to the certification center. From the certification center we receive a certificate. Save it in a file (for example, qwertokey.cer) and import it into the storage
 keytool -import -trustcacerts -keystore path/to/qwert.keystore -alias qwertokey -file path/to/qwertokey.cer 

Sign the jar-archive
 jarsigner -keystore path/to/qwerto.keystore calculator.jar qwertokey 

The qwertokey.cer file is sent to anyone who wants to check the archive. It is checked so
 jarsigner -verify -verbose -certs -keystore path/to/qwerto.keystore calculator.jar 

Library use


There is a HelloWorld program that uses the library class Calculator. To compile and run the program, you need to attach the library.
Compile
 cd HelloWorld javac -sourcepath src -d bin -classpath path/to/calculator.jar src/com/qwertovsky/helloworld/HelloWorld.java 

Run
 java -classpath bin:path/to/calculator.jar com.qwertovsky.helloworld.HelloWorld 

We collect the program


This can be done in different ways.

First way


 cd HelloWorld echo main-class: com.qwertovsky.helloworld.HelloWorld>manifest.mf echo class-path: lib/calculator.jar >>manifest.mf mkdir lib cp path/to/calculator.jar lib/calculator.jar jar -cmf manifest.mf helloworld.jar -C bin . 

There are subtleties.
In line
 main-class: com.qwertovsky.helloworld.HelloWorld 

There should be no spaces at the end.
The second subtlety is described in [3]: in the same line there should be a transfer to the next line. This is if the manifest is placed in the archive by a third-party archiver.
The jar program will not include the last line from the manifest in the manifest, if there is no line wrapping at the end.
Another point: the manifest should not have empty lines between the lines. The error “java.io.IOException: invalid manifest format” will be displayed.

When using the echo command, you only need to monitor the space at the end of the line with the main-class.

Second way


 cd HelloWorld echo class-path: lib/calculator.jar >manifest.mf mkdir lib cp path/to/calculator.jar lib/calculator.jar jar -cmef manifest.mf com.qwertovsky.helloworld.HelloWorld helloworld.jar -C bin . 

In this method, we avoid errors with a space in the main-class.

Third way


 cd HelloWorld mkdir lib cd lib jar -xvf path/to/calculator.jar com/ created: com/ created: com/qwertovsky/ created: com/qwertovsky/calculator/ inflated: com/qwertovsky/calculator/Calculator.class created: com/qwertovsky/calculator/operation/ inflated: com/qwertovsky/calculator/operation/Adder.class cd .. cp -r bin/* lib/ jar -cef com.qwertovsky.helloworld.HelloWorld helloworld.jar -C lib . rm -r lib 

Include the code of the desired library in the executable file.

Run jar executable


The file calculator.jar is not executable. But helloworld.jar can be run.
If the archive was created by the first two methods, then next to it in the same directory should be the lib folder with the file calculator.jar. Such restrictions are due to the fact that the manifest in the class-path is a path relative to the executable file.
 cd Calculator ls ../HelloWorld/lib calculator.jar java -jar ../HelloWorld/helloworld.jar 

When using the third method, the necessary libraries are included in the executable file. Keep nearby the right library is not required. Runs similarly.
 java -jar ../HelloWorld/helloworld.jar 

How to deal with JavaEE applications


Similarly. Only libraries to compile need to be taken from the application server that is used. If I use JBoss, then to compile the servlet, I will need to do something like
 javac -classpath path/to/jboss/common/lib/jboss-servlet*.jar -d ./classes src/com/qwertovsky/app/servlets/MenuSt.java 

The archive structure of a JavaEE application must conform to a specific format. for example
  my.ear `---META-INF | `---manifest.mf `---lib | `---mylib.jar `---my.war | `---META-INF | | `---manifest.mf | `---WEB-INF | | `---lib | | | `---myweblib.jar | | `---classes | | | `---com | | | `---... | | `---web.xml | `---index.html | `---< - (, )> `---myejb.jar 

The methods for running the application on the server itself using the command line for each server are different.

I hope this article will be a cheat sheet for someone to work with Java on the command line. These skills will help to understand the content and meaning of Ant-scripts and to answer interviews for more tricky questions than “Which IDE do you like more?”.

More to read


1. Elliotte Rusty Harold. "Recommendations for managing the classpath in UNIX and Mac OS X"
2. Elliotte Rusty Harold. "Recommendations for managing the classpath on Windows"
3. Evgeny Matyushkin aka Skipy. "Likbez"
4. Lesson: Packaging Programs in JAR Files
5. Brian Goetz. “Java theory and practice: Do I need to document IT?”
6. Evgeny Matyushkin aka Skipy. "Creating your own javadoc tags"
7. Creating and using Java archives
8. Sun Java Signing
9. javac - Java programming language compiler
10. java - the Java application launcher
11. jdb - The Java Debugger
12. javap - The Java Class File Disassembler
13. javadoc - The Java API Documentation Generator
14. jarsigner - JAR Signing and Verification Tool
15. jar - The Java Archive Tool
16. keytool - Key and Certificate Management Tool

Source: https://habr.com/ru/post/125210/


All Articles