Получите доступ к общедоступной переменной-члену класса Java из Ant и используйте ее в задаче сборки.

В моем приложении Java номер версии отображается в нескольких местах, поэтому я сохраняю его как общедоступную конечную переменную в основном классе приложения. Есть ли способ получить доступ к этому в моих задачах сборки Ant? В духе автоматизации процесса сборки я бы хотел, чтобы Ant автоматически называл заархивированный распространяемый файл текущим номером версии, но я не уверен, как это сделать. Я предполагаю, что это будет выглядеть примерно так ...

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

Я просто не знаю, что использовать вместо $ {MyApp.version}. Я понимаю, что могу поместить это в файл свойств сборки, но было бы намного удобнее получить его прямо из файла класса, в котором я его уже храню.


person Ross    schedule 18.06.2009    source источник
comment
Другой вариант: stackoverflow.com/questions/823909/   -  person martinez314    schedule 16.11.2013


Ответы (2)


Я не думаю, что есть какие-либо встроенные в Ant задачи, которые делают то, что вы хотите. Однако вы можете создать свой собственный, воспользовавшись расширяемой природой Ant.

Я взломал действительно (и я имею в виду действительно) грязный пример, который вы можете использовать в качестве трамплина для правильной задачи.

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

Пример файла сборки с использованием этой задачи:

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

Результат сборки с использованием файла Ant:

test:
[echo] StringBind: Я строка!
[echo] IntBind: 1024
[echo] DoubleBind: 3.14159
УСПЕШНО СОЗДАТЬ

У этой задачи есть ряд случайных проблем: она полагается на устаревшие методы, использует файлы вместо имен классов, а сообщения об ошибках оставляют желать лучшего. Однако вы должны понять суть того, что необходимо для специальной задачи, решающей вашу проблему.

person Kevin Montrose    schedule 19.06.2009
comment
Спасибо за помощь! Я баловался с Ant только по мере необходимости;) - person Ross; 19.06.2009
comment
Пожалуйста. Сделайте одолжение моей совести и немного доработайте / исправьте этот код, прежде чем бросать его в производственную среду. :) - person Kevin Montrose; 20.06.2009

Как насчет создания настраиваемой задачи ant, которая расширяет стандартную задачу по умолчанию?

Расширьте класс org.apache.tools.ant.taskdefs.Zip и переопределите метод setDestFile (), чтобы он получал атрибут MyApp.version и устанавливал имя файла назначения, содержащее эту информацию.

Другое решение - использовать функцию подстановки ключевых слов из CVS и SVN (возможно, GIT и Mercurial также имеют эту функцию) и умело используют эту функцию, например, имея файл свойств с чем-то вроде этого (в SVN):

myApp.revision=$Revision$

и ссылайтесь на это свойство через свой код и сценарии сборки.

person Reginaldo    schedule 19.06.2009