java - móviles - manual de programacion android pdf
¿Cómo se crea un MANIFEST.MF que está disponible cuando se está probando y ejecutándose desde un contenedor en producción? (9)
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>
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?
He encontrado que el comentario de McDowell es cierto: qué archivo MANIFEST.MF se recupera depende del classpath y puede que no sea el que se busca. 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());
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.
Puede obtener el manifiesto para una clase arbitraria en un contenedor arbitrario sin analizar la URL de clase (que podría ser frágil). Simplemente ubique un recurso que sepa que está en el contenedor que desea, y luego conecte la conexión a JarURLConnection.
Si desea que el código funcione cuando la clase no está incluida en un contenedor, agregue una instancia de verificación del tipo de conexión URL devuelta. Las clases en una jerarquía de clases desempaquetadas devolverán un Sun FileURLConnection interno en lugar de JarUrlConnection. Luego puede cargar el Manifiesto utilizando uno de los métodos InputStream descritos 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);
}
}
Puede utilizar una clase de utilidad Manifests
de jcabi-manifiestos que automatiza la búsqueda y el análisis sintáctico de todos los archivos MANIFEST.MF
disponibles en classpath. Luego, lees cualquier atributo con un trazador de líneas:
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
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.
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
También usualmente usaré un archivo de versión. Crearé un archivo por contenedor ya que cada contenedor puede tener su propia versión.
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.