2009-06-18 12 views
5

Moja aplikacja Java wyświetla numer wersji w kilku miejscach, więc zapisuję ją jako publiczną zmienną końcową w głównej klasie aplikacji. Czy jest jakiś sposób dostępu do tego w moich zadaniach budowania Ant? W duchu automatyzacji procesu kompilacji chciałbym, aby Ant automatycznie nadał nazwę spakowanej dystrybucji z aktualnym numerem wersji, ale nie jestem pewien jak. Zgaduję, że to wyglądać mniej więcej tak ...Dostęp do publicznej zmiennej członkowskiej klasy Javy z Ant i wykorzystanie jej w zadaniu kompilacji

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

ja po prostu nie jestem pewien, co umieścić w miejscu $ {MyApp.version}. Rozumiem, że mogę umieścić to w pliku właściwości kompilacji, ale byłoby o wiele wygodniej móc wyciągnąć go bezpośrednio z pliku klasy, w którym go już przechowuję.

+0

Inna opcja: http://stackoverflow.com/questions/823909/how-ant-can-get-a-value-read-from-a-file-into-a-property-value – whiskeyspider

Odpowiedz

2

Nie sądzę, że istnieją jakieś wbudowane zadania Ant, które robią to, co chcesz. Można jednak rzucić własną, korzystając z rozszerzalnej natury Ant.

Zrobiłem naprawdę (i mam na myśli naprawdę) brudny przykład, którego można użyć jako deski wiosną do właściwego zadania.

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(); 
     } 
    } 
} 

Przykładowy plik build przy użyciu tego zadania:

<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; 
} 

Wynikiem kompilacji przy użyciu pliku Ant:

testową :
[e cho] StringBind: Jestem struny!
[echo] IntBind: 1024
[echo] podwójne wiązanie: 3.14159
tworzenia skutecznych

Istnieje szereg losowych problemów z tego zadania: opiera się na przestarzałych metod, trwa plików zamiast nazwy klas , a zgłaszanie błędów pozostawia nieco do życzenia. Jednak powinieneś poznać istotę tego, co jest potrzebne do niestandardowego zadania, które rozwiązuje twój problem.

+0

Dzięki za pomoc ! Mam tylko parał się w Ant na "w razie potrzeby";) – Ross

+0

Nie ma za co.Czy moje sumienie przysługi i rozszerzyć/naprawić, że kod trochę przed wprowadzeniem go do środowiska produkcyjnego. :) –

1

Co z tworzeniem custom ant task, które rozszerza domyślny ?

Rozszerz klasę org.apache.tools.ant.taskdefs.Zip i nadpisaj metodę setDestFile() , aby uzyskać atrybut MyApp.version i ustawić nazwę pliku docelowego tak, aby zawierała te informacje.

Innym rozwiązaniem jest użycie funkcji podstawiania słów kluczowych z CVS i SVN (być może Git i Mercurial tej funkcji zbyt) i dokonać mądrego wykorzystania tej funkcji jakby plik działce z czymś takim (w SVN):

 
myApp.revision=$Revision$ 

i odsyłasz tę właściwość za pomocą kodu i skryptów kompilacji.

Powiązane problemy