2009-06-18 8 views
5

La mia app Java visualizza il numero di versione in alcuni punti, quindi lo memorizzo come variabile finale pubblica nella classe principale dell'app. C'è un modo per accedervi nelle mie attività di build di Ant? Nello spirito dell'automazione del processo di generazione, mi piacerebbe che Ant denomina automaticamente la versione zippata distribuibile con il numero di versione corrente, ma non sono sicuro di come. Sto indovinando che sarebbe simile ...Accedere alla variabile membro pubblico della classe Java da Ant e utilizzarla in un'attività di compilazione

<target name="createZip" depends="build"> 
    <zip destfile="../dist/MyApp_${MyApp.version}.zip"> 
     <fileset dir="../dist"> 
      <include name="**/MyApp"/> 
     </fileset> 
    </zip> 
</target> 

io non sono solo sicuro di cosa mettere al posto di $ {} MyApp.version. Mi rendo conto che potrei inserire questo nel file delle proprietà di build, ma sarebbe molto più comodo essere in grado di estrarlo direttamente dal file di classe in cui lo sto già archiviando.

+0

Un'altra opzione: http://stackoverflow.com/questions/823909/how-ant-can-get-a-value-read-from-a-file-into-a-property-value – whiskeyspider

risposta

2

Non penso che ci siano attività di Ant integrate che fanno ciò che volete. Tuttavia, potresti lanciare il tuo, sfruttando la natura estensibile di Ant.

Ho fatto un vero e proprio esempio (e intendo dire veramente) sporco che puoi usare come un trampolino di lancio per un compito corretto.

package q1015732; 

import java.io.ByteArrayOutputStream; 
import java.io.File; 
import java.io.FileInputStream; 
import java.io.InputStream; 
import java.lang.reflect.Field; 

import org.apache.tools.ant.BuildException; 
import org.apache.tools.ant.Task; 

/** 
* Custom ant task that binds a property name to a static member of a class file. 
* 
* @author Montrose 
*/ 
public class BindPropertyTask extends Task{ 
    private String _classFile = null; 
    private String _fieldName = null; 
    private String _propName = null; 

    /** 
    * Set the field name of the class. 
    * 
    * @param fieldName 
    */ 
    public void setFieldName(String fieldName){ 
     _fieldName = fieldName; 
    } 

    /** 
    * The class file. 
    * @param classFile 
    */ 
    public void setClassFile(String classFile){ 
     _classFile = classFile; 
    } 

    /** 
    * The property name to bind 
    * @param propName 
    */ 
    public void setProperty(String propName) 
    { 
     _propName = propName; 
    } 

    /** 
    * Load the class file, and grab the value of the field. 
    * 
    * Throws exceptions if classfile, fieldname, or property have not been set. 
    * 
    * Throws more execeptions if classfile does not exist, the field does not exist, or the field is not static. 
    */ 
    public void execute() throws BuildException{ 
     if(_classFile == null) throw new BuildException("ClassFile is a required attribute"); 
     if(_fieldName == null) throw new BuildException("FieldName is a required attribute"); 
     if(_propName == null) throw new BuildException("Property is required attribute"); 

     CustomLoader loader = new CustomLoader(); 
     Class toInspect = null; 
     Field toBind = null; 
     Object value = null; 

     try { 
      toInspect = loader.loadClass(new FileInputStream(_classFile)); 
     } catch (Exception e) { 
      throw new BuildException("Couldn't load class ["+e.getMessage()+"], in ["+(new File(_classFile).getAbsolutePath())+"]"); 
     } 

     try{ 
      toBind = toInspect.getField(_fieldName); 
     }catch(NoSuchFieldException e){ 
      throw new BuildException("Couldn't find field, '"+_fieldName+"'"); 
     } 

     //Let us bind to private/protected/package-private fields 
     toBind.setAccessible(true); 

     try{ 
      value = toBind.get(null); 
     }catch(NullPointerException e){ 
      throw new BuildException("Field is not static"); 
     } catch (Exception e) { 
      throw new BuildException("Unable to access field ["+e.getMessage()+"]"); 
     } 

     if(value != null) 
      this.getProject().setProperty(_propName, value.toString()); 
     else 
      this.getProject().setProperty(_propName, null); 
    } 

    /** 
    * Custom class loader, for loading a class directly from a file. 
    * 
    * This is hacky and relies on deprecated methods, be wary. 
    * 
    * @author Montrose 
    */ 
    class CustomLoader extends ClassLoader{ 
     public CustomLoader(){ 
      super(ClassLoader.getSystemClassLoader()); 
     } 

     /** 
     * Warning, here be (deprecated) dragons. 
     * @param in 
     * @return 
     * @throws Exception 
     */ 
     @SuppressWarnings("deprecation") 
     public Class loadClass(InputStream in) throws Exception{ 
      byte[] classData = loadData(in); 
      return this.defineClass(classData, 0, classData.length); 
     } 

     private byte[] loadData(InputStream in) throws Exception{ 
      byte[] buffer = new byte[1024]; 
      ByteArrayOutputStream out = new ByteArrayOutputStream(); 
      int i; 


      while((i = in.read(buffer)) != -1){ 
       out.write(buffer, 0, i); 
      } 

      return out.toByteArray(); 
     } 
    } 
} 

Un file di esempio build usando questo compito:

<project name="q1015732"> 

<target name="test"> 
<taskdef name="static_bind" classname="q1015732.BindPropertyTask" /> 

<static_bind fieldname="StringBind" classfile="C:\Users\Montrose\workspace\StackOverflow Questions\q1015732\test\DummyMain.class" property="string.value" /> 
<static_bind fieldname="IntBind" classfile="C:\Users\Montrose\workspace\StackOverflow Questions\q1015732\test\DummyMain.class" property="int.value" /> 
<static_bind fieldname="DoubleBind" classfile="C:\Users\Montrose\workspace\StackOverflow Questions\q1015732\test\DummyMain.class" property="double.value" /> 

<echo message="StringBind: ${string.value}" /> 
<echo message="IntBind: ${int.value}" /> 
<echo message="DoubleBind: ${double.value}" /> 

</target> 

</project> 

DummyMain.java:

package q1015732.test; 

public class DummyMain { 
    public static String StringBind = "I'm a String!"; 
    public static int IntBind = 1024; 
    public static double DoubleBind = 3.14159; 
} 

Il risultato di una generazione utilizzando il file Ant:

prova :
[e cho] StringBind: I'm a String!
[eco] IntBind: 1024
[eco] doppio legame: 3.14159
BUILD SUCCESSFUL

Ci sono una serie di problemi casuali con questo compito: si basa su metodi deprecati, ci vogliono i file invece di nomi di classe e la segnalazione degli errori lascia un po 'a desiderare. Tuttavia, dovresti ottenere il succo di ciò che è necessario per un'attività personalizzata che risolva il tuo problema.

+0

Grazie per l'aiuto ! Ho solo dilettato in Ant su base "come necessario";) – Ross

+0

Prego.Fa 'alla mia coscienza un favore ed espandi/aggiusti quel codice un po' prima di gettarlo in un ambiente di produzione. :) –

1

Che dire creare un custom ant task che si estende il predefinito ?

Estendere la classe org.apache.tools.ant.taskdefs.Zip e sovrascrivere il metodo setDestFile() in modo da ottenere l'attributo MyApp.version e impostare il nome del file di destinazione in modo che contenga tali informazioni.

Un'altra soluzione è quella di utilizzare la funzione di sostituzione parola chiave da CVS e SVN (forse GIT e Mercurial hanno questa caratteristica troppo) e fare un uso intelligente di questa funzione come avere un file di proprietà con qualcosa di simile (in SVN):

 
myApp.revision=$Revision$ 

e fare riferimento a tale proprietà tramite il codice e creare script.