2009-04-08 6 views
6

¿Existe un método bien establecido para documentar "propiedades" Java contenido del archivo, incluyendo:de mejores prácticas para la documentación disponible/requerido archivo de propiedades Java contenidos

  • que especifica el tipo de datos/contenido esperado para una clave dada
  • especificando si es necesaria una clave para que la aplicación funcione
  • proporcionar una descripción del significado de la tecla

Actualmente, mantengo (con la mano) un .p archivo roperties que es el predeterminado, y escribo una descripción en prosa del tipo de datos y la descripción de cada clave en un comentario antes. Esto no conduce a un archivo de propiedades accesible mediante programación.

supongo que lo que estoy buscando es un equivalente "getopt" para archivos de propiedades ...

[EDIT: Relacionados]

+0

actualicé mi respuesta para incluir un código que debería comenzar a usarlo. – TofuBeer

+0

guau, acabo de obtener la insignia de "pregunta popular" para esto, con solo 3 votos por alza ... extraño ... todavía estoy trabajando en una solución satisfactoria. – andersoj

Respuesta

1

Nunca he visto una forma estándar de hacerlo. Lo que probablemente haría es:

  • envoltura o extender la clase java.util.Properties
  • anulación (de extender) o proporcionar un método (si envoltorio) el método tienda (o storeToXML, etc) que escribe un comentario para cada línea.
  • tienen el método que almacena las propiedades tiene algún tipo de archivo de entrada donde se describen las propiedades de cada uno.

No obtiene nada sobre lo que está haciendo a mano, excepto que puede administrar la información de una manera diferente que podría ser más fácil de tratar, por ejemplo, podría tener un programa que escupir los comentarios para leer. Posiblemente le daría el acceso programático que necesita, pero es un tipo de cosas propias.

O puede que sea demasiado trabajo para obtener muy poco (por lo que no hay nada obvio).

Si puede especificar el tipo de comentarios que desea ver, podría tagarme de escribir algo si me aburro :-) (es el tipo de cosas que me gusta hacer por diversión, enfermo, lo sé: -)

Ok ... me aburrí ...aquí hay algo que es al menos un comienzo :-)

import java.util.HashMap; 
import java.util.Map; 
import java.util.Map.Entry; 
import java.util.Properties; 


public class PropertiesVerifier 
{ 
    private final Map<String, PropertyInfo> optionalInfo; 
    private final Map<String, PropertyInfo> requiredInfo; 

    { 
     optionalInfo = new HashMap<String, PropertyInfo>(); 
     requiredInfo = new HashMap<String, PropertyInfo>(); 
    } 

    public PropertiesVerifier(final PropertyInfo[] infos) 
    { 
     for(final PropertyInfo info : infos) 
     { 
      final Map<String, PropertyInfo> infoMap; 

      if(info.isRequired()) 
      { 
       infoMap = requiredInfo; 
      } 
      else 
      { 
       infoMap = optionalInfo; 
      } 

      infoMap.put(info.getName(), info); 
     } 
    } 

    public void verifyProperties(final Properties properties) 
    { 
     for(final Entry<Object, Object> property : properties.entrySet())  
     { 
      final String key; 
      final String value; 

      key = (String)property.getKey(); 
      value = (String)property.getValue(); 

      if(!(isValid(key, value))) 
      { 
       throw new IllegalArgumentException(value + " is not valid for: " + key); 
      } 
     } 
    } 

    public boolean isRequired(final String key) 
    { 
     return (requiredInfo.get(key) != null); 
    } 

    public boolean isOptional(final String key) 
    { 
     return (optionalInfo.get(key) != null); 
    } 

    public boolean isKnown(final String key) 
    { 
     return (isRequired(key) || isOptional(key)); 
    } 

    public Class getType(final String key) 
    { 
     final PropertyInfo info; 

     info = getPropertyInfoFor(key); 

     return (info.getType()); 
    } 

    public boolean isValid(final String key, 
          final String value) 
    { 
     final PropertyInfo info; 

     info = getPropertyInfoFor(key); 

     return (info.verify(value)); 
    } 

    private PropertyInfo getPropertyInfoFor(final String key) 
    { 
     PropertyInfo info; 

     info = requiredInfo.get(key); 

     if(info == null) 
     { 
      info = optionalInfo.get(key); 

      if(info == null) 
      { 
       // should be a better exception maybe... depends on how you 
       // want to deal with it 
       throw new IllegalArgumentException(key + " 
                is not a valid property name"); 
      } 
     } 

     return (info); 
    } 

    protected final static class PropertyInfo 
    { 
     private final String name; 
     private final boolean required; 
     private final Class clazz; 
     private final Verifier verifier; 

     protected PropertyInfo(final String nm, 
           final boolean mandatory, 
           final Class c) 
     { 
      this(nm, mandatory, c, getDefaultVerifier(c)); 
     } 

     protected PropertyInfo(final String nm, 
           final boolean mandatory, 
           final Class c, 
           final Verifier v) 
     { 
      // check for null 
      name  = nm; 
      required = mandatory; 
      clazz = c; 
      verifier = v; 
     } 

     @Override 
     public int hashCode() 
     { 
      return (getName().hashCode()); 
     } 

     @Override 
     public boolean equals(final Object o) 
     { 
      final boolean retVal; 

      if(o instanceof PropertyInfo) 
      { 
       final PropertyInfo other; 

       other = (PropertyInfo)o; 
       retVal = getName().equals(other.getName()); 
      } 
      else 
      { 
       retVal = false; 
      } 

      return (retVal); 
     } 

     public boolean verify(final String value) 
     { 
      return (verifier.verify(value)); 
     } 

     public String getName() 
     { 
      return (name); 
     } 

     public boolean isRequired() 
     { 
      return (required); 
     } 

     public Class getType() 
     { 
      return (clazz); 
     } 
    } 

    private static Verifier getDefaultVerifier(final Class clazz) 
    { 
     final Verifier verifier; 

     if(clazz.equals(Boolean.class)) 
     { 
      // shoudl use a singleton to save space... 
      verifier = new BooleanVerifier(); 
     } 
     else 
     { 
      throw new IllegalArgumentException("Unknown property type: " + 
               clazz.getCanonicalName()); 
     } 

     return (verifier); 
    } 

    public static interface Verifier 
    { 
     boolean verify(final String value); 
    } 

    public static class BooleanVerifier 
     implements Verifier 
    { 
     public boolean verify(final String value) 
     { 
      final boolean retVal; 

      if(value.equalsIgnoreCase("true") || 
       value.equalsIgnoreCase("false")) 
      { 
       retVal = true; 
      } 
      else 
      { 
       retVal = false; 
      } 

      return (retVal); 
     } 
    } 
} 

Y una prueba simple para ello:

import java.util.Properties; 


public class Main 
{ 
    public static void main(String[] args) 
    { 
     final Properties   properties; 
     final PropertiesVerifier verifier; 

     properties = new Properties(); 
     properties.put("property.one", "true"); 
     properties.put("property.two", "false"); 
//  properties.put("property.three", "5"); 
     verifier = new PropertiesVerifier(
      new PropertiesVerifier.PropertyInfo[] 
      { 
       new PropertiesVerifier.PropertyInfo("property.one", 
                true, 
                Boolean.class), 
       new PropertiesVerifier.PropertyInfo("property.two", 
                false, 
                Boolean.class), 
//    new PropertiesVerifier.PropertyInfo("property.three", 
//             true, 
//             Boolean.class), 
      }); 

     System.out.println(verifier.isKnown("property.one")); 
     System.out.println(verifier.isKnown("property.two")); 
     System.out.println(verifier.isKnown("property.three")); 

     System.out.println(verifier.isRequired("property.one")); 
     System.out.println(verifier.isRequired("property.two")); 
     System.out.println(verifier.isRequired("property.three")); 

     System.out.println(verifier.isOptional("property.one")); 
     System.out.println(verifier.isOptional("property.two")); 
     System.out.println(verifier.isOptional("property.three")); 

     System.out.println(verifier.getType("property.one")); 
     System.out.println(verifier.getType("property.two")); 

     // System.out.println(verifier.getType("property.tthree")); 
     System.out.println(verifier.isValid("property.one", "true")); 
     System.out.println(verifier.isValid("property.two", "false")); 
     // System.out.println(verifier.isValid("property.tthree", "5")); 


     verifier.verifyProperties(properties); 
    } 
} 
+0

@TofuBeer: Gracias ... Estoy jugando activamente con algo como esto para nuestro proyecto ... JA – andersoj

+0

Bueno, he hecho una investigación exhaustiva y el código que has publicado es lo mejor que hay ... gracias ! --JA – andersoj

1

Una forma fácil es para distribuir su proyecto con un archivo de propiedades de muestra, por ejemplo mi proyecto tiene en svn un "build.properties.example", con propiedades comentadas según sea necesario. Las propiedades correctas localmente no entran en svn.

Como mencionas "getopt", me pregunto si realmente estás pensando en los argumentos de la línea cmd. Si hay un "principal" que necesita propiedades específicas, generalmente pongo las instrucciones relevantes en un mensaje de "uso" que se imprime si los argumentos son incorrectos o "-h".

+0

Su primer párrafo le dice que haga lo que dice que ya está haciendo. Su segundo párrafo es irrelevante para la pregunta (claramente dice que está hablando de archivos de propiedades). –

+0

Bueno, en realidad Parecía que estaba hablando de leer en un archivo predeterminado, no en un ejemplo "muerto". La pregunta también ha sido editada un poco para mayor claridad. –

3

usted podría utilizar algunas de las características en el paquete Apache Commons Configuration. Al menos proporciona acceso de tipo a sus propiedades.

Solo existen convenciones en el archivo de propiedades java tradicional. Algunos de los que he visto incluyen proporcionar, como usted dijo, un archivo de propiedades de ejemplo. Otra es proporcionar la configuración predeterminada con todas las propiedades, pero con comentario.

Si realmente desea requerir algo, tal vez no esté buscando un archivo de propiedades. Puede usar un archivo de configuración XML y especificar un esquema con tipos de datos y requisitos. Puede usar jaxb para compilar el esquema en java y leerlo de esa manera. Con la validación puede asegurarse de que las propiedades requeridas estén allí.

Lo mejor que puede esperar es cuando ejecuta su aplicación, lee, analiza y valida las propiedades en el archivo. Si absolutamente tenía que mantener las propiedades basadas y no quería ir a xml, pero necesitaba este análisis sintáctico. Puede tener un archivo de propiedades secundario que enumere cada propiedad que podría incluirse, su tipo y si era necesario. Luego, deberá escribir un validador de archivos de propiedades que contendrá un archivo para validar, así como un archivo de propiedades de esquema de validación. Algo como

#list of required properties 
required=prop1,prop2,prop3 

#all properties and their types 
prop1.type=Integer 
prop2.type=String 

No he revisado todo el paquete de configuración de Apache, pero a menudo tienen útiles utilidades como esta. No me sorprendería si pudieras encontrar algo allí que simplificara esto.

2

Otra opción para retirar es el proyecto llamado OWNER. Allí, define la interfaz que sirve como el objeto de configuración en su aplicación, usando tipos y anotaciones. A continuación, el PROPIETARIO realiza la búsqueda y el análisis del archivo correcto Properties. Por lo tanto, puede escribir un javadoc para su interfaz y usar eso como la documentación.