¿Cómo se crea un MANIFEST.MF que está disponible cuando se está probando y ejecutándose desde un contenedor en producción?

votos
20

He pasado demasiado tiempo tratando de resolver esto. Esto debería ser lo más simple y todos los que distribuyen aplicaciones Java en frascos deben lidiar con él.

Solo quiero saber la forma correcta de agregar versiones a mi aplicación Java para que pueda acceder a la información de la versión cuando estoy probando, por ejemplo, la depuración en Eclipse y la ejecución desde un contenedor.

Esto es lo que tengo en mi build.xml:

<target name=jar depends = compile>
    <property name=version.num value=1.0.0/>
    <buildnumber file=build.num/>
    <tstamp>
        <format property=TODAY pattern=yyyy-MM-dd HH:mm:ss />
    </tstamp>

    <manifest file=${build}/META-INF/MANIFEST.MF>
        <attribute name=Built-By value=${user.name} />
        <attribute name=Built-Date value=${TODAY} />                   
        <attribute name=Implementation-Title value=MyApp />
        <attribute name=Implementation-Vendor value=MyCompany />                
        <attribute name=Implementation-Version value=${version.num}-b${build.number}/>                              
    </manifest>

    <jar destfile=${build}/myapp.jar basedir=${build} excludes=*.jar />                   
</target>

Esto crea /META-INF/MANIFEST.MF y puedo leer los valores cuando estoy depurando en Eclipse de esta manera:

public MyClass()
{
    try
    {                        
        InputStream stream = getClass().getResourceAsStream(/META-INF/MANIFEST.MF);
        Manifest manifest = new Manifest(stream);            

        Attributes attributes = manifest.getMainAttributes();

        String implementationTitle = attributes.getValue(Implementation-Title);
        String implementationVersion = attributes.getValue(Implementation-Version);
        String builtDate = attributes.getValue(Built-Date);
        String builtBy = attributes.getValue(Built-By);
   }
   catch (IOException e)
   {            
        logger.error(Couldn't read manifest.);
   }        

}

Pero cuando creo el archivo jar, carga el manifiesto de otro jar (presumiblemente el primer jar cargado por la aplicación, en mi caso, activation.jar).

Además, el siguiente código tampoco funciona, aunque todos los valores adecuados se encuentran en el archivo de manifiesto.

    Package thisPackage = getClass().getPackage();
    String implementationVersion = thisPackage.getImplementationVersion();

¿Algunas ideas?

Publicado el 17/09/2008 a las 14:28
por usuario
En otros idiomas...                            


9 respuestas

votos
0

Simplemente no use el manifiesto. Cree un archivo foo.properties.original, con un contenido como version = @ VERSION @

Y en la misma tarea que está haciendo, puede hacer una copia a copu foo.properties.original y luego

Respondida el 17/09/2008 a las 14:38
fuente por usuario

votos
0

También usualmente usaré un archivo de versión. Crearé un archivo por contenedor ya que cada contenedor puede tener su propia versión.

Respondida el 17/09/2008 a las 15:11
fuente por usuario

votos
1

Puede acceder al archivo manifiesto (o cualquier otro) dentro de un contenedor si usa el mismo cargador de clases que utilizó para cargar las clases.

this.getClass().getClassLoader().getResourceAsStream( ... ) ;

Si tiene varios subprocesos, use lo siguiente:

Thread.currentThread().getContextClassLoader().getResourceAsStream( ... ) ;

Esta es también una técnica realmente útil para incluir un archivo de configuración predeterminado dentro del contenedor.

Respondida el 17/09/2008 a las 15:17
fuente por usuario

votos
2

Quieres usar esto:

Enumeration<URL> resources = Thread.currentThread().getContextClassLoader().getResources("META-INF/MANIFEST.MF");

Puede analizar la URL para descubrir de qué jar el manifiesto proviene y luego leer la URL a través de getInputStream () para analizar el manifiesto.

Respondida el 18/09/2008 a las 15:44
fuente por usuario

votos
1

Esto es lo que he encontrado que funciona:

packageVersion.java:

package com.company.division.project.packageversion;

import java.io.IOException;
import java.io.InputStream;
import java.util.jar.Attributes;
import java.util.jar.Manifest;

public class packageVersion
{
    void printVersion()
    {
        try
        {         
            InputStream stream = getClass().getResourceAsStream("/META-INF/MANIFEST.MF");

            if (stream == null)
            {
                System.out.println("Couldn't find manifest.");
                System.exit(0);
            }

            Manifest manifest = new Manifest(stream);

            Attributes attributes = manifest.getMainAttributes();

            String impTitle = attributes.getValue("Implementation-Title");
            String impVersion = attributes.getValue("Implementation-Version");
            String impBuildDate = attributes.getValue("Built-Date");
            String impBuiltBy = attributes.getValue("Built-By");

            if (impTitle != null)
            {
                System.out.println("Implementation-Title:   " + impTitle);
            }            
            if (impVersion != null)
            {
                System.out.println("Implementation-Version: " + impVersion);
            }
            if (impBuildDate != null)
            {
                System.out.println("Built-Date: " + impBuildDate);
            }
            if (impBuiltBy != null)
            {
                System.out.println("Built-By:   " + impBuiltBy);
            }

            System.exit(0);
        }
        catch (IOException e)
        {            
            System.out.println("Couldn't read manifest.");
        }        
    }

    /**
     * @param args
     */
    public static void main(String[] args)
    {
        packageVersion version = new packageVersion();
        version.printVersion();        
    }

}

Aquí está el build.xml coincidente:

<project name="packageVersion" default="run" basedir=".">

    <property name="src" location="src"/>
    <property name="build" location="bin"/>
    <property name="dist" location="dist"/>

    <target name="init">
        <tstamp>
            <format property="TIMESTAMP" pattern="yyyy-MM-dd HH:mm:ss" />
        </tstamp>
        <mkdir dir="${build}"/>
        <mkdir dir="${build}/META-INF"/>
    </target>

    <target name="compile" depends="init">
        <javac debug="on" srcdir="${src}" destdir="${build}"/>
    </target>

    <target name="dist" depends = "compile">        
        <mkdir dir="${dist}"/>      
        <property name="version.num" value="1.0.0"/>
        <buildnumber file="build.num"/>
        <manifest file="${build}/META-INF/MANIFEST.MF">
            <attribute name="Built-By" value="${user.name}" />
            <attribute name="Built-Date" value="${TIMESTAMP}" />                                
            <attribute name="Implementation-Vendor" value="Company" />
            <attribute name="Implementation-Title" value="PackageVersion" />
            <attribute name="Implementation-Version" value="${version.num} (b${build.number})"/>
            <section name="com/company/division/project/packageversion">
                <attribute name="Sealed" value="false"/>
            </section>          
        </manifest>     
        <jar destfile="${dist}/packageversion-${version.num}.jar" basedir="${build}" manifest="${build}/META-INF/MANIFEST.MF"/>                 
    </target>

    <target name="clean">
        <delete dir="${build}"/>
        <delete dir="${dist}"/>
    </target>

    <target name="run" depends="dist">      
        <java classname="com.company.division.project.packageversion.packageVersion">
            <arg value="-h"/>
            <classpath>
                <pathelement location="${dist}/packageversion-${version.num}.jar"/>
                <pathelement path="${java.class.path}"/>
            </classpath>
        </java>
    </target>

</project>
Respondida el 29/09/2008 a las 15:28
fuente por usuario

votos
1

ClassLoader.getResource (String) cargará el primer manifiesto que encuentre en classpath, que puede ser el manifiesto para algún otro archivo JAR. Por lo tanto, puede enumerar todos los manifiestos para encontrar el que desee o utilizar algún otro mecanismo, como un archivo de propiedades con un nombre único.

Respondida el 05/03/2009 a las 15:06
fuente por usuario

votos
1

He encontrado el comentario de McDowell para ser verdad - qué archivo MANIFEST.MF es recogido depende de la ruta de clase y podría no ser el que quería. yo uso esto

String cp = PCAS.class.getResource(PCAS.class.getSimpleName() + ".class").toString();
cp = cp.substring(0, cp.indexOf(PCAS.class.getPackage().getName())) 
              +  "META-INF/MANIFEST.MF";
Manifest mf = new Manifest((new URL(cp)).openStream());

que I Adaptado de texto del enlace

Respondida el 18/06/2010 a las 10:30
fuente por usuario

votos
10

Usted puede obtener el manifiesto para una clase arbitraria en un frasco arbitraria sin necesidad de analizar la url de clase (que podría ser frágil). Sólo localice un recurso que sabe que está en el frasco que desea, y luego emitir la conexión a JarURLConnection.

Si desea que el código funcione cuando la clase no se incluye en un frasco, añadir una comprobación instanceof del tipo de conexión de URL devuelto. Las clases en una jerarquía de clases sin envasar volverán un Sol FileURLConnection interna en lugar de la JarUrlConnection. A continuación, puede cargar el manifiesto mediante uno de los métodos descritos InputStream en otras respuestas.

@Test
public void testManifest() throws IOException {
    URL res = org.junit.Assert.class.getResource(org.junit.Assert.class.getSimpleName() + ".class");
    JarURLConnection conn = (JarURLConnection) res.openConnection();
    Manifest mf = conn.getManifest();
    Attributes atts = mf.getMainAttributes();
    for (Object v : atts.values()) {
        System.out.println(v);
    }
}
Respondida el 18/06/2010 a las 15:55
fuente por usuario

votos
0

Se puede utilizar una clase de utilidad Manifestsde jcabi manifiestos que automatiza la búsqueda y el análisis de todos los MANIFEST.MFarchivos disponibles en la ruta de clase. A continuación, se lee cualquier atributo con un chiste:

final String name = Manifests.read("Build-By");
final String date = Manifests.read("Build-Date");

Además, mira esto: http://www.yegor256.com/2014/07/03/how-to-read-manifest-mf.html

Respondida el 30/12/2012 a las 07:02
fuente por usuario

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more