Home Java (root way)
Post
Cancel

Java (root way)


Diario de bordo (2023-12-22)

Aprendendo java, usando apenas o compilador via terminal e nvim como editor de texto

Criando um arquivo ‘main’

Criei um arquivo hello.java com a função main.

1
2
3
4
5
class Hello{
    public static void main(String[] args){
        System.out.println("Hello, world");
    }
}

Para compilar o arquivo

1
javac hello.java

Adiocionando à um arquivo jar

1
jar cf hello.jar Hello.class

Para executar o arquivo JAR, digitei o seguinte comando:

1
java -classpath hello.jar Hello

O argumento -classpath (ou -cp) especifica o caminho da classe dentro do arquivo jar. Por exemplo, em um caso em que a classe esteja na pasta ./com/projeto/main, teria que declarar o empacotamento da classe com a seguinte linha no começo do arquivo:

1
2
package com.projeto.main;
// ...

Para compilar:

1
2
javac com/projeto/main/hello.java
jar cf programa.jar com/projeto/main/Hello.class

Aqui é passado o caminho da classe (classpath) declarada com package

1
java -cp programa.jar com.projeto.main.Hello

Note que é passado primeiro o arquivo jar criado anteriormente e depois a classe main (usado como em um import)

Caso passe o errado de uma classe ou uma classe que não existe, o java deve retornar o seguinte erro:

1
2
3
4
5
$ java -cp programa.jar com.learn.main.Hello

Error: Could not find or load main class com.learn.main.Hello
Caused by: java.lang.ClassNotFoundException: com.learn.main.Hello

Outro problema é se, mesmo passando o caminho correto da classe mas explicitar o package de forma incorreta, o jdk deve retornar o erro:

1
2
3
4
5
$ java -cp programa.jar com.projeto.main.Hello

Error: Could not find or load main class com.projeto.main.Hello
Caused by: java.lang.NoClassDefFoundError: com/learn/main/Hello (wrong name: com/projeto/main/Hello)

Nesse caso a declaração do pacote java esta como:

1
package com.learn.main;

Como a pasta learn não existe, o java não encontra a classe

Criando um pacote

Criei uma segunda classe no mesmo pacote (com/projeto/main/Calc.java)

1
2
3
4
5
6
7
8
9
10
11
package com.projeto.main;


class Calc{

    Calc(){}

    public static int sum(int x, int y){
        return x + y;
    }
}

Depois disso modifiquei a class Main:

1
2
3
4
5
6
7
8
9
10
package com.projeto.main;

class Hello{

    public static void main(String[] args){
        int num = Calc.sum(7,5);
        System.out.println("num: " + num);
    }
}

1
javac com/projeto/main/*java

Teste:

1
java com.projeto.main.Hello

Adicionando à um arquivo JAR, dessa vez de uma forma diferente. Passei a classe main na hora de criar o jar e não quando executar

1
jar cfe main.jar com.projeto.main.Hello com/projeto/main/*class

Para rodar, agora não é preciso dizer onde está a main class:

1
java -jar main.jar

Usando dependencias

Usando log4j2 na hora de rodar o programa (.jar)

Primeiro copiei meu projeto para outra pasta ../logging/ e o pacote mudei para org.foo.bar. Na pasta logging será preciso baixar a dependencia:

1
wget https://dlcdn.apache.org/logging/log4j/2.22.0/apache-log4j-2.22.0-bin.zip
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package org.foo.bar;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.config.Configurator;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.status.StatusLogger;


public class hello {

    static {
        StatusLogger.getLogger().setLevel(Level.OFF);
        Configurator.setRootLevel(Level.INFO);
    }

    private static final Logger logger = LogManager.getLogger(hello.class);

    public static void main(String[] args) {
        logger.info("Olá, mundo! Usando o Log4j!");
        logger.warn("Somando 2 numeros: " + Calc.sum(3,7));

    }
}

A biblioteca log4j, busca um arquivo log4j2.xml para ser configurado, para não precisar desse arquivo, fiz uma configuração basica da classe logger dentro de um bloco estático. A declaração StatusLogger.getLogger().setLevel(Level.OFF); faz com que o log4j não reclame da falta do arquivo log2j2.xml

A classe calc continua a mesma, exceto a declaração do pacote.

1
package org.foo.bar;

Os arquivos JAR do log4j2 que foram necessários para o programa foram:
log4j-api-2.12.4.jar log4j-core-2.12.4.jar log4j-slf4j18-impl-2.12.4.jar \

Movi da pasta apache-log4j-2.12.4-bin baixada anteriormente

Compilando o programa

1
javac -cp .:log4j-api-2.12.4.jar:log4j-core-2.12.4.jar:log4j-slf4j18-impl-2.12.4.jar org/foo/bar/*java

-cp passa o classpath do projeto e das dependencias, separados por “:” dois pontos, o “.” ponto é usado para dizer ao compilador que deve incluir a pasta atual ao classpath

Agora adicione as classes ao jar

1
jar cfv foo.jar org/foo/bar/*class

Executando o programa referenciando as dependencias

1
2
java -cp foo.jar:log4j-core-2.12.4.jar:log4j-api-2.12.4.jar:log4j-slf4j18-impl-2.12.4.jar: \
org.foo.bar.hello

Note que ao invez de um ‘.’ como na compilação, aqui é passado foo.jar para o classpath para a execução

A saída do programa:

1
2
15:10:53.782 [main] INFO  org.foo.bar.hello - Olá, mundo! Usando o Log4j!
15:10:53.785 [main] WARN  org.foo.bar.hello - Somando 2 numeros: 10

Criando um (FAT JAR)

Depois disso vamos criar um JAR autosuficiente (fat jar) com as dependencias dentro do mesmo. Para isso vamos precisar descompactar as dependências. Primeiro, vamos criar um diretório para as dependências, e extraí-las dentro deste diretório:

1
2
3
4
mkdir temp
cd libs/
unzip "*jar" -d ../temp
cd ../

Movi o package para ./src/, deixando o projeto mais organizado. Agora para compilar as classes:

1
javac -d classes -cp libs/*: src/org/foo/bar/*java

Aqui o classpath do compilador pode receber tanto o jar das dependências, quanto o diretório que for recém criado. |-d|diretório de destino das classes|

1
jar cvfe fat_app.jar org.foo.bar.hello -C classes/ . -C temp/ .

Aqui estamos compactando os arquivos do diretório classes e temp para dentro do arquivo fat_app.jar e referenciando a classe org.foo.bar.hello como main.

Executando

Ao criar um esse tipo de JAR, estamos colocando todas as dependências dentro dele, isso significa, que
para executá-lo, não dependemos dos arquivos presentes na máquina, sendo assim, podemos executar o arquivo
em qualquer diretório.

1
java -jar fat_app.jar
This post is licensed under CC BY 4.0 by the author.