90 votes

Comment puis-je exécuter une classe dans un fichier WAR à partir de la ligne de commande ?

J'ai une classe Java qui a une méthode principale et que j'avais l'habitude d'exécuter en tant qu'application autonome à partir de la ligne de commande, par exemple.

java -jar monjar.jar params

J'ai dû reconditionner le code pour qu'il s'exécute sous Apache et tout mon code, y compris la classe du point d'entrée de l'ancien jar, s'est retrouvé dans un fichier WAR pour un déploiement facile sur le serveur web.

Cependant, je veux toujours être capable de l'exécuter à partir de la ligne de commande et le code n'a pas changé et est toujours là, je n'arrive juste pas à trouver comment le faire fonctionner.

Voici ce que j'ai essayé...

Je pensais que le WAR était juste comme un jar, donc

java -jar monwar.war params

Cela a échoué en indiquant qu'aucune classe principale n'était définie dans le manifeste.

J'ai ajouté manuellement un manifeste au war et essayé à nouveau, avec le même effet.

J'ai remarqué que dans mon war j'avais un dossier appelé META-INF contenant un manifest.mf, donc j'ai ajouté une ligne déclarant ma classe principale comme je le ferais pour un manifeste normal...

Manifest-Version: 1.0
Main-Class: mypackage.MyEntryPointClass

Cela a donné une noClassDefFoundError mypackage.MyEntryPointClass, ce qui est un progrès en quelque sorte. Cela m'a amené à penser que c'était juste un problème de chemin, donc j'ai essayé

Manifest-Version: 1.0
Main-Class: WEB-INF.classes.mypackage.MyEntryPointClass

J'obtiens maintenant la même erreur, mais avec une trace de pile...

Exception in thread "main" java.lang.NoClassDefFoundError: WEB-INF/classes/mypackage/MyEntryPointClass (wrong name: mypackage/MyEntryPointClass)
        at java.lang.ClassLoader.defineClass1(Native Method)
        at java.lang.ClassLoader.defineClass(Unknown Source)
        at java.security.SecureClassLoader.defineClass(Unknown Source)
        at java.net.URLClassLoader.defineClass(Unknown Source)
        at java.net.URLClassLoader.access$100(Unknown Source)
        at java.net.URLClassLoader$1.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClassInternal(Unknown Source)

J'ai fait des recherches sur Google mais je n'ai rien trouvé qui réponde à ma question, et j'ai lu quelques autres questions ici qui sont légèrement différentes, donc j'ai pensé que je posterais.

Java 1.5, pas que je pense que cela devrait faire une différence.

1 votes

N'ai pas essayé cela, mais que diriez-vous d'ajouter une entrée 'Class-Path' au manifeste?

0 votes

Avez-vous des raisons pour cela? Pourquoi ne pas essayer de garder deux assemblages différents - un pour le web et un comme une application autonome?

0 votes

Avez-vous essayé de mettre un classpath dans le manifest.mf qui avait WEB-INF/classes et de laisser Main-Class comme mypackage.MyEntryPointClass ?

56voto

Yonatan Maman Points 884

Vous pouvez faire ce que Hudson (projet d'intégration continue) fait. vous téléchargez un war qui peut être déployé dans Tomcat ou exécuté en utilisant

java -jar hudson.war

(Parce qu'il a un moteur Jetty intégré, le lancer depuis la ligne de commande lance un serveur). Quoi qu'il en soit, en regardant le manifeste de Hudson, je comprends qu'ils ont mis une classe Main à la racine de l'archive. Dans votre cas, la structure de votre war devrait ressembler à ceci:

sous la racine:

  • mypackage/MyEntryPointClass.class
  • WEB-INF/lib
  • WEB-INF/classes
  • META-INF/MANIFEST.MF

tandis que le manifeste devrait inclure la ligne suivante:

Main-Class: mypackage.MyEntryPointClass

veuillez noter que le fichier mypackage/MyEntryPointClass.class est accessible uniquement depuis la ligne de commande, et que les classes sous WEB-INF/classes sont accessibles uniquement depuis le serveur d'application.

HTH

2 votes

Ne vais pas voter négativement car la réponse contient des informations intéressantes. Cependant, elle ne répond pas à la question initiale "...exécuter en tant qu'une application autonome à partir de la ligne de commande..."

10voto

Bozho Points 273663

Une guerre est une application web. Si vous souhaitez avoir une application console/autonome réutilisant les mêmes classes que votre application web, envisagez de regrouper vos classes partagées dans un jar, que vous pouvez placer dans WEB-INF/lib. Ensuite, utilisez ce jar à partir de la ligne de commande. Ainsi, vous obtenez à la fois votre application console et vous pouvez utiliser les mêmes classes dans vos servlets, sans créer deux packages différents. Cela est bien sûr vrai lorsque la guerre est déployée.

0 votes

Bien sûr, mais ce n'est pas toujours possible. Parfois, vous avez seulement un fichier JAR et aimeriez exécuter rapidement la classe principale.

8voto

Richard Detsch Points 51

Pour exécuter SomeClass.main(String [] args) à partir d'un fichier war déployé, faites :

  1. Écrivez la classe SomeClass.java qui a une méthode main, c'est-à-dire (public static void main(String[] args) {...})
  2. Déployez votre WAR
  3. cd /usr/local//tomcat/webapps/projectName/WEB-INF
  4. java -cp "lib/jar1.jar:lib/jar2.jar: ... :lib/jarn.jar" com.mypackage.SomeClass arg1 arg2 ... arg3

Note1: pour voir si la classe SomeOtherClass.class se trouve dans /usr/tomcat/webapps//WEB-INF/lib, exécutez :

cd /usr/tomcat/webapps/projectName/WEB-INF/lib && 
find . -name '*.jar' | while read jarfile; do if jar tf "$jarfile" | grep SomeOtherClass.class; then echo "$jarfile"; fi; done 

Note2: Écrivez sur la sortie standard pour voir si votre méthode main fonctionne effectivement via des instructions print dans la console. Cela est appelé une porte dérobée.

Note3: Le commentaire ci-dessus de Bozhidar Bozhanov semble correct

1 votes

Ceci est techniquement correct, donc je lui ai donné un +1, mais je ne pense pas que cette solution soit une bonne idée. Cela nécessite de construire manuellement un chemin de classe, et est très sujet aux erreurs.

0 votes

D'accord avec JBCP ci-dessus. Mais j'utilise Netbeans et là vous pouvez demander les propriétés de votre classe Java, et il y a une entrée Runtime Classpath qui rassemble le chemin absolu complet de la classe (le mien fait 4000 caractères :) ) Une belle manière de transformer quelques éléments internes de votre application web en classes scriptables.

7voto

Jason Gritman Points 3339

Les règles de localisation des classes dans un fichier d'archive sont que l'emplacement de la déclaration de package du fichier et l'emplacement du fichier dans l'archive doivent correspondre. Comme votre classe est située dans WEB-INF/classes, elle pense que la classe n'est pas valide pour s'exécuter dans le contexte actuel.

La seule façon de faire ce que vous demandez est de reconditionner le war afin que le fichier .class soit situé dans le répertoire mypackage à la racine de l'archive plutôt que dans le répertoire WEB-INF/classes. Cependant, si vous faites cela, vous ne pourrez plus accéder au fichier depuis aucune de vos classes web.

Si vous souhaitez réutiliser cette classe à la fois dans le war et en dehors en ligne de commande java, envisagez de créer un jar exécutable que vous pouvez exécuter depuis la ligne de commande, puis placez ce jar dans le répertoire WEB-INF/lib du fichier war.

6voto

marioosh Points 4673

Dans le projet Maven, vous pouvez construire automatiquement un jar en utilisant le plugin Maven War en définissant archiveClasses sur true. Exemple ci-dessous.

       org.apache.maven.plugins
       maven-war-plugin

        true

0 votes

Exécuter maven clean install

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X