Compilar o código Java

Os plug-ins de JDT incluem um compilador de incremento e de agrupamento Java para construir ficheiros .classe Java a partir do código fonte. O compilador não faculta qualquer API directa. É instalado como um construtor em projectos Java. A compilação é activada utilizando os mecanismos de construção de plataforma normais.

O mecanismo de construção de plataforma está descrito em pormenor em Construtores de projectos de incremento .

Código de compilação

Pode compilar de forma programática os ficheiros de fonte Java num projecto com a API de construção.

   IProject myProject;
   IProgressMonitor myProgressMonitor;
   myProject.build(IncrementalProjectBuilder.INCREMENTAL_BUILD, myProgressMonitor);

Para um projecto Java, isto invoca o construtor de projecto de incremento Java (em conjunto com qualquer outro construtor de projecto de incremento que tenha sido adicionado às especificações de construção do projecto). Os ficheiros .class gerados são gravados na pasta de saída designada. Os ficheiros de recursos adicionais também são copiados para a pasta de saída.  

No caso de construção de agrupamento completa, todos os ficheiros .class na pasta de saída pode ser 'scrubbed' (apagados) para garantir que não são encontrados ficheiros obsoletos. Isto é controlado utilizando a Opção do Construtor de Núcleo JDT (CORE_JAVA_BUILD_CLEAN_OUTPUT_FOLDER).  A predefinição para esta opção é limpar as pastas de saída.   Salvo se esta opção for reposta, tem de se certificar que colocou todos os ficheiros .class para os quais não tem ficheiros de fonte correspondentes noutra pasta de ficheiros .class no caminho de classes e não na pasta de saída.

Os construtores de incremento e de agrupamento podem ser configurados com outras opções que controlam quais os recursos a copiar para a pasta de saída. O exemplo seguinte mostra como configurar um filtro de recurso para que os ficheiros que terminem em '.ignore' e as pastas denominadas 'META-INF' não sejam copiados para a pasta de saída:

   Opções da tabela de cálculos de endereço = JavaCore.getOptions();
   options.put(JavaCore.CORE_JAVA_BUILD_RESOURCE_COPY_FILTER, "*.ignore,META-INF/");
   JavaCore.setOptions(options);

Os nomes de ficheiro são filtrados caso correspondam a um dos padrões fornecidos. As pastas são filtradas na sua totalidade se os seus nomes corresponderem a um dos nomes das pastas fornecidas que terminam num separador de caminho.

Os construtores de incremento e de agrupamento podem também ser configurados para gerar apenas um único erro quando o ficheiro .classpath contém erros. Esta opção está configurada por predefinição e elimina vários erros.  Consulte Opções de Construtor de Núcleo JDT para obter uma lista completa das opções relativas a construtores e respectivas predefinições.

O compilador também pode ser configurado utilizando as opções JavaCore.   Por exemplo, pode definir a gravidade que deverá ser utilizada para diversos géneros de problemas encontrados durante uma compilação.  Consulte Opções de Compilador de Núcleo JDT para obter uma lista completa das opções relativas a compiladores e respectivas predefinições.

Sempre que configura programaticamente opções para o construtor ou compilador, deveria especificar o âmbito da opção.  Por exemplo, definir um filtro de recursos pode aplicar-se apenas a um projecto específico:

   
   Opções de tabela de cálculos de endereço = myProject.getOptions(false); // obter apenas as opções configuradas para este projecto
   options.put(JavaCore.CORE_JAVA_BUILD_RESOURCE_COPY_FILTER, "*.ignore,META-INF/");
   myProject.setOptions(options);

utilizar o compilador de agrupamento

Encontrar o compilador de agrupamento

A classe do compilador de agrupamento está localizada nas classes internas do plug-in JDT Core. O nome da classe é org.eclipse.jdt.internal.compiler.batch.Main. Consta no plugins/org.eclipse.jdt.core_3.2.0.jar. Desde o 3.2, está igualmente disponível como uma transferência individual. O nome do ficheiro é ecj.jar. A origem respectiva está igualmente disponível. Para obter o nome e a origem, aceda à página de transferências e procure a secção JDT Core Batch Compiler. Este jar contém o compilador de agrupamento e o javac ant adapter.

Pode, assim, ser utilizado como uma aplicação autónoma, no interior de uma construção Ant fora do Eclipse.

Executar o compilador de agrupamento

Quais as opções disponíveis?

Com um fundo laranja são opções sugeridas.

Nome Utilização
Opções de caminho de classes
-bootclasspath <dir 1>;<dir 2>;...;<dir P> Esta é uma lista de directórios de ficheiros jar utilizados para dar instruções de arranque aos ficheiros de classe utilizados pelo compilador.Por predefinição, são utilizadas as bibliotecas de VM em execução. As entradas são separadas pelo separador de caminho de plataforma.
Cada directório ou ficheiro pode especificar regras de acesso para tipos entre '[' e ']'.
-cp
-classpath <dir 1>;<dir 2>;...;<dir P>
Esta é uma lista de directórios de ficheiros jar utilizados para compilar os ficheiros de origem. A predefinição é o valor da propriedade "java.class.path". As entradas são separadas pelo separador de caminho de plataforma.
Cada directório ou ficheiro pode especificar regras de acesso para tipos entre '[' e ']' (por exemplo [-X] para proibir o acesso ao tipo X, [~X] para desencorajar o acesso ao tipo X, [+p/X:-p/*] para proibir o acesso a todos os tipos no pacote p, mas para permitir o acesso ao p/X).
-extdirs <dir 1>;<dir 2>;...;<dir P> Esta é uma lista de directórios utilizados para especificar a localização de ficheiros de extensão zip/jar. As entradas são separadas pelo separador de caminho de plataforma.
-endorseddirs <dir 1>;<dir 2>;...;<dir P> Esta é uma lista de directórios utilizados para especificar a localização de ficheiros suportados zip/jar. As entradas são separadas pelo separador de caminho de plataforma.
-sourcepath <dir 1>;<dir 2>;...;<dir P> Esta é uma lista de directórios utilizados para especificar os ficheiros de origem. As entradas são separadas pelo separador de caminho de plataforma.
Cada directório pode especificar regras de acesso para tipos entre '[' e ']'.
-d <dir 1>|none Isto é utilizado para especificar em que directório os ficheiros .class gerados são copiados. Se for omitido, não é criada qualquer estrutura de directório de pacote.
Se não pretender gerar nenhum .ficheiro de classe, utilize -d none.
-encoding <encoding name> Especificar o formato de codificação de origem predefinido (a codificação personalizada pode igualmente ser especificada num base por ficheiro, inserindo um sufixo em cada nome de ficheiro/pasta de origem de entrada com [<encoding name>], por exemplo, X.java[utf8]).
Opções de compatibilidade
-target 1.1|1.2|1.3|1.4|1.5|5|5.0|1.6|6|6.0 Especifica a definição de destino do ficheiro .class. Os valores possíveis são:
  • 1.1 (versão principal: 45 secundária: 3)
  • 1.2 (versão principal: 46 secundária: 0)
  • 1.3 (versão principal: 47 secundária: 0)
  • 1.4 (versão principal: 48 secundária: 0)
  • 1.5, 5 ou 5.0 (versão principal: 49 secundária: 0)
  • 1.6, 6 ou 6.0 (versão principal: 50 secundária: 0)
As predefinições são:
  • 1.1 no modo -1.3
  • 1.2 no modo -1.4
  • 1.5 no modo -1.5
  • 1.6 no modo -1.6
-1.3 Definir nível de compatibilidade para 1.3. -fonte 1.3 -destino 1.1. implícitos
-1.4 Definir nível de compatibilidade para 1.4 (predefinição). -fonte 1.3 -destino 1.2. implícitos
-1.5 Definir nível de compatibilidade para 1.5. -fonte 1.5 -destino 1.5. implícitos
-1.6 Definir nível de compatibilidade para 1.6. -fonte 1.6 -destino 1.6. implícitos
-source 1.3|1.4|1.5|5|5.0|1.6|6|6.0 É utilizado para especificar o nível de origem esperado pelo compilador.
Os valores possíveis são:
  • 1.3
  • 1.4
  • 1.5, 5 ou 5.0
  • 1.6, 6 ou 6.0
As predefinições são:
  • 1.3 no modo -1.3
  • 1.3 no modo -1.4
  • 1.5 no modo -1.5
  • 1.6 no modo -1.6
No modo 1.4, assert é tratado como um palavra-chave. Em 1.5 e 1.6, enum e assert são considerados palavras-chave.
Opções de aviso
-warn:
allDeprecation
allJavadoc
assertIdentifier
boxing
charConcat
conditionAssign
constructorName
dep-ann
deprecation
discouraged
emptyBlock
enumSwitch
fallthrough
fieldHiding
finalBound
finally
forbidden
hiding
incomplete-switch
indirectStatic
intfAnnotation
intfNonInherited
javadoc
localHiding
maskedCatchBlocks
nls
noEffectAssign
null
over-ann
paramAssign
pkgDefaultMethod
raw
semicolon
serial
specialParamHiding
static-access
staticReceiver
suppress
synthetic-access
syntheticAccess
tasks(<task1>|...|<taskN>)
typeHiding
unchecked
unnecessaryElse
unqualified-field-access
unqualifiedField
unused
unusedArgument
unusedImport
unusedLabel
unusedLocal
unusedPrivate
unusedThrown
uselessTypeCheck
varargsCast
warningToken
Definir nível de aviso.
e.g. -warn:unusedLocal,deprecation

A vermelho estão as predefinições.

    -warn:none                               desactivam todos os avisos
    -warn:<avisos separados por ,>    activam exactamente os avisos listados
    -warn:+<avisos separados por ,>   activam avisos adicionais
    -warn:-<avisos separados por ,>   desactivam determinados avisos
allDeprecation depreciação mesmo dentro de código obsoleto
allJavadoc javadoc inválido ou em falta
assertIdentifier ocorrência de assert utilizada como identificador
boxing conversão autobox
charConcat quando uma tabela de caracteres é utilizada na concatenação de uma cadeia sem ser convertida explicitamente para uma cadeia
conditionAssign possível atribuição acidental booleana
constructorName método com nome de construtor
dep-ann anotação @Deprecated em falta
deprecation utilização de tipo ou membro obsoleto fora de código obsoleto
discouraged utilização de tipos que correspondam a regras de acesso desencorajadas
emptyBlock bloco vazio não documentado
enumSwitch,
incomplete-switch
comutação enum incompleta
fallthrough possível caso de fall-through
fieldHiding campo a ocultar outra variável
finalBound parâmetro de tipo com limite final
´finally bloco finally não que termina normalmente
forbidden utilização de tipos que correspondam a regras de acesso proibidas
hiding macro para fieldHiding, localHiding, typeHiding e maskedCatchBlock
indirectStatic referência indirecta a membro estático
intfAnnotation tipo de anotação utilizado como superinterface
intfNonInherited compatibilidade de método não herdado de interface
javadoc javadoc inválido
localHiding variável local a ocultar outra variável
maskedCatchBlocks bloco catch ocultado
nls literais de cadeia não-nls (ausência de códigos //$NON-NLS-<n>)
noEffectAssign atribuição sem efeito
null verificação nula em falta ou redundante
over-ann anotação @Override em falta
paramAssign atribuição a um parâmetro
pkgDefaultMethod tentativa de sobreposição de método de pacote predefinido
raw utilização de um tipo em bruto (em vez de um tipo parametrizado)
semicolon ponto e vírgula (;) desnecessário ou instrução vazia
serial serialVersionUID em falta
specialParamHiding parâmetro de construtor ou de formatador a ocultar outro campo
static-access macro para indirectStatic e staticReceiver
staticReceiver se for utilizado um receptor não estático para obter um campo estático ou chamar um método estático
suppress activar @SuppressWarnings
syntheticAccess,
synthetic-access
ao efectuar acesso sintético para classe interna
tasks activar suporte para códigos de tarefas em código fonte
typeHiding parâmetro de tipo a ocultar outro tipo
unchecked operação de tipo não verificada
unnecessaryElse cláusula else desnecessária
unqualified-field-access,
unqualifiedField
referência não qualificada a um campo
unused macro para unusedArgument, unusedImport, unusedLabel, unusedLocal, unusedPrivate e unusedThrown
unusedArgument argumento de método não utilizado
unusedImport referência de importação não utilizada
unusedLabel etiqueta não utilizada
unusedLocal variável local não utilizada
unusedPrivate declaração de membro privado não utilizado
unusedThrown excepção lançada declarada não utilizada
uselessTypeCheck operação cast/instanceof desnecessária
varargsCast argumento de varargs requere conversão explícita
warningToken sinal de aviso não tratado em @SuppressWarnings

-nowarn Sem aviso (equivalente a -warn:none)
-deprecation Equivalente a -warn:deprecation.
Opções de depuração
-g[:none|:lines,vars,source] Defina o nível de atributos de depuração
-g Todas as informações de depuração (equivalente a -g:lines,vars,source)
-g:none Sem informações de depuração
-g:[lines,vars,source] Informações de depuração selectivas
-preserveAllLocals Pedir explicitamente ao compilador para manter todas as variáveis locais (para efeitos de depuração). Quando omitidas, o compilador remove locais não utilizados.
Opções ignoradas (para compatibilidade com as opções javac)
-J<option> opção pass para a máquina virtual
-X<option> especificar uma opção não padronizada. -Xemacs não é ignorado.
-X imprimir opções não padronizadas e sair
-O optimiza para tempo de execução
Opções avançadas
@<file> Ler argumentos de linha de comandos de ficheiro
-maxProblems <n> Número máximo de problemas por unidade compilação (100 por predefinição)
-log <filename> Especificar um ficheiro de registo no qual são efectuadas cópias de memória todas as saídas do compilador. Isto é particularmente útil se pretender depurar o compilador de agrupamentos ou obter o ficheiro que contém todos os erros e avisos de um construtor de agrupamento. Caso a extensão seja .xml, o registo gerado será um ficheiro xml.
-Xemacs Utiliza o estilo emacs para apresentar localizações de erros e avisos na consola e em registos de texto regulares.Os registos XML não são afectados por esta opção.Com esta opção activada, a mensagem:
2. WARNING in /workspace/X.java
(at line 8)...

é apresentada como:
/workspace/X.java:8: warning: The method...
-proceedOnError Continua a compilar apesar dos erros, a efectuar cópia de memória de ficheiros de origem com métodos de problemas ou tipos de problemas. Isto é recomendado apenas se pretender executar a aplicação ainda que tenha erros remanescentes.
-verbose Imprimir unidade de compilação acedidas/processadas na consola ou no ficheiro de registos, se especificado.
-referenceInfo Calcular informações de referências. Isto só é útil se ligado ao construtor. De outra forma, as informações de referências são inúteis.
-progress Mostra o progresso (apenas no modo -registo).
-time Apresenta as informações sobre a velocidade.
-noExit Não chamar System.exit(n) no fim da compilação (n=0 na ausência de erros).
-repeat <n> Repetir processo de compilação <n> vezes (análise de rendimento)
-inlineJSR Bytecode JSR incluído (implícito se destino >= 1.5).
-enableJavadoc Considerar referências dentro de javadoc.
Opções de ajuda
-? -help Apresenta mensagens de ajuda.
-v -version Apresentar número de construção do compilador. Isto é particularmente útil para comunicar um defeito.
-showversion Apresentar número de construção do compilador e continuar. Isto é particularmente útil para comunicar um defeito.

Exemplos

d:\temp -classpath rt.jar -time -g -d d:/tmp Compila todos os ficheiro de fonte em d:\temp e respectivas subpastas. O caminho de classes é simplesmente rt.jar. Gera todos os atributos de depuração e todos os ficheiros .class gerados são copiados em d:\tmp. A velocidade do compilador é apresentada assim que o processo de agrupamento é concluído.
d:\temp\Test.java -classpath d:\temp;rt.jar -g:none Compila apenas Test.java e os seus ficheiros dependentes, no caso de existirem alguns, obtendo ficheiros dependentes de d:\temp. O caminho de classe é d:\temp seguido de rt.jar, o que significa que todas as classes necessárias são pesquisadas, primeiramente, em d:\temp e, em seguida, em rt.jar. Não gera nenhum atributo de depuração, sendo que todos os .ficheiros de classe são copiados em d:\temp.

Utilizar o adaptador ant javac

O compilador Eclipse pode ser utilizado num script Ant com adaptador javac. Para utilizar o compilador Eclipse, só tem de definir a propriedade build.compiler no script. Eis um pequeno exemplo.
<?xml version="1.0" encoding="UTF-8"?>
<project name="compile" default="main" basedir="../.">

	<property name="build.compiler" value="org.eclipse.jdt.core.JDTCompilerAdapter"/>

	<property name="root" value="${basedir}/src"/>

	<property name="destdir" value="d:/temp/bin" />

	<target name="main">
		<javac srcdir="${root}" destdir="${destdir}" debug="on" nowarn="on" extdirs="d:/extdirs" source="1.4">
		    <classpath>
		      <pathelement location="${basedir}/../org.eclipse.jdt.core/bin"/>
		    </classpath>
		</javac>		
	</target>
</project> 
A sintaxe utilizada para a tarefa Ant de javac pode ser encontrada na documentação da tarefa Ant de javac. O actual adaptador suporta a tarefa Ant de javac nas versões 1.4.1 até 1.6.5.

Se estiver a utilizar uma versão acima de 1.5.0, pode utilizar o elemento do argumento do compilador imbricado para indicar as opções específicas do compilador.

...
<javac srcdir="${root}" destdir="${destdir}" debug="on" nowarn="on" extdirs="d:/extdirs" source="1.4">
    <classpath>
      <pathelement location="${basedir}/../org.eclipse.jdt.core/bin"/>
    </classpath>
    <compilerarg compiler="org.eclipse.jdt.core.JDTCompilerAdapter" line="-1.5 -warn:+boxing"/>
</javac>		
...

Para evitar obter scripts dependentes do compilador, recomendamos que utilize o argumento de compilador definido para org.eclipse.jdt.core.JDTCompilerAdapter. Se não definir assim, o script só pode ser utilizado com o compilador Eclipse. Se for definido assim, o argumento do compilador imbricado é ignorado se o nome for diferente de nome do compilador especificado na propriedade build.compiler.

Determinação de problemas

O Núcleo JDT define um marcador especializado (tipo de marcador "org.eclipse.jdt.core.problem ") para destacar problemas de compilação. Para descobrir de forma programática os problemas detectados pelo compilador, deve utilizar o protocolo do marcador de plataforma padrão. Consulte Marcadores de Recursos para obter uma descrição geral da utilização de marcadores.

O fragmento seguinte encontra todos os marcadores de problemas Java numa unidade de compilação.

   public IMarker[] findJavaProblemMarkers(ICompilationUnit cu) 
         throws CoreException {
      IResource javaSourceFile = cu.getUnderlyingResource();
      IMarker[] markers = 
         javaSourceFile.findMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER,
            true, IResource.DEPTH_INFINITE);
   }

Os marcadores de problemas Java são mantidos pelo construtor de projecto Java e são removidos automaticamente à medida que os problemas vão sendo resolvidos e a fonte Java recompilada.

O valor do ID do problema é definido para uma das constantes definidas em IProblem . O ID do problema é fiável, mas a mensagem é localizada e, por conseguinte, pode ser alterada de acordo com a locale predefinida. As constantes definidas em IProblem são auto-descritivas.

Deve ser definida uma implementação de IProblemRequestor para recolher os problemas descobertos durante uma operação Java. As cópias de trabalho podem ser reconciliadas com a detecção do problema se for fornecido um IProblemRequestor para a criação da cópia de trabalho. Para tal, pode utilizar o método reconcile. Eis um exemplo:

  ICompilationUnit unit = ..; // get some compilation unit
			
  // create requestor for accumulating discovered problems
  IProblemRequestor problemRequestor = new IProblemRequestor() {
    public void acceptProblem(IProblem problem) {
      System.out.println(problem.getID() + ": " + problem.getMessage());
    }
    public void beginReporting() {}
    public void endReporting() {}
    public boolean isActive() {	return true; } // will detect problems if active
  };
    
  // use working copy to hold source with error
  ICompilationUnit workingCopy = unit.getWorkingCopy(new WorkingCopyOwner() {}, problemRequestor, null);
  ((IOpenable)workingCopy).getBuffer().setContents("public class X extends Zork {}");

  // trigger reconciliation			
  workingCopy.reconcile(NO_AST, true, null, null);
Pode adicionar uma acção aos problemas relatados no método acceptProblem(IProblem). Neste exemplo, o problema relatado é que Zork cannot be resolved or is not a valid superclass (Zork não pode ser resolvido ou não é uma superclasse válida) e o respectivo ID é IProblem.SuperclassNotFound.

Excluir avisos através da utilização do SuppressWarnings

O Java 5.0 oferece ao utilizador a opção de desactivar os avisos de compilação relativos a um subconjunto de uma unidade de compilação, através da utilização da anotação java.lang.SuppressWarning.

	@SuppressWarning("unused") public void foo() {
		String s;
	}

Sem a anotação, o compilador diria que a variável local s nunca é utilizada. Com a anotação, o compilador ignora silenciosa e localmente este aviso para o método foo. Isto permite manter os avisos noutras localizações da mesma unidade de compilação ou do mesmo projecto.

A lista de testemunhos que podem ser utilizados dentro de uma anotação SuppressWarning é: